15373Sraghuram /*
25373Sraghuram * CDDL HEADER START
35373Sraghuram *
45373Sraghuram * The contents of this file are subject to the terms of the
55373Sraghuram * Common Development and Distribution License (the "License").
65373Sraghuram * You may not use this file except in compliance with the License.
75373Sraghuram *
85373Sraghuram * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95373Sraghuram * or http://www.opensolaris.org/os/licensing.
105373Sraghuram * See the License for the specific language governing permissions
115373Sraghuram * and limitations under the License.
125373Sraghuram *
135373Sraghuram * When distributing Covered Code, include this CDDL HEADER in each
145373Sraghuram * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155373Sraghuram * If applicable, add the following below this CDDL HEADER, with the
165373Sraghuram * fields enclosed by brackets "[]" replaced with your own identifying
175373Sraghuram * information: Portions Copyright [yyyy] [name of copyright owner]
185373Sraghuram *
195373Sraghuram * CDDL HEADER END
205373Sraghuram */
215373Sraghuram
225373Sraghuram /*
2312300SSriharsha.Basavapatna@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245373Sraghuram */
255373Sraghuram
265373Sraghuram #include <sys/types.h>
275373Sraghuram #include <sys/errno.h>
285373Sraghuram #include <sys/debug.h>
295373Sraghuram #include <sys/time.h>
305373Sraghuram #include <sys/sysmacros.h>
315373Sraghuram #include <sys/systm.h>
325373Sraghuram #include <sys/user.h>
335373Sraghuram #include <sys/stropts.h>
345373Sraghuram #include <sys/stream.h>
355373Sraghuram #include <sys/strlog.h>
365373Sraghuram #include <sys/strsubr.h>
375373Sraghuram #include <sys/cmn_err.h>
385373Sraghuram #include <sys/cpu.h>
395373Sraghuram #include <sys/kmem.h>
405373Sraghuram #include <sys/conf.h>
415373Sraghuram #include <sys/ddi.h>
425373Sraghuram #include <sys/sunddi.h>
435373Sraghuram #include <sys/ksynch.h>
445373Sraghuram #include <sys/stat.h>
455373Sraghuram #include <sys/kstat.h>
465373Sraghuram #include <sys/vtrace.h>
475373Sraghuram #include <sys/strsun.h>
485373Sraghuram #include <sys/dlpi.h>
495373Sraghuram #include <sys/ethernet.h>
505373Sraghuram #include <net/if.h>
515373Sraghuram #include <sys/varargs.h>
525373Sraghuram #include <sys/machsystm.h>
535373Sraghuram #include <sys/modctl.h>
545373Sraghuram #include <sys/modhash.h>
555373Sraghuram #include <sys/mac.h>
565373Sraghuram #include <sys/mac_ether.h>
575373Sraghuram #include <sys/taskq.h>
585373Sraghuram #include <sys/note.h>
595373Sraghuram #include <sys/mach_descrip.h>
605373Sraghuram #include <sys/mdeg.h>
615373Sraghuram #include <sys/ldc.h>
625373Sraghuram #include <sys/vsw_fdb.h>
635373Sraghuram #include <sys/vsw.h>
645373Sraghuram #include <sys/vio_mailbox.h>
655373Sraghuram #include <sys/vnet_mailbox.h>
665373Sraghuram #include <sys/vnet_common.h>
675373Sraghuram #include <sys/vio_util.h>
685373Sraghuram #include <sys/sdt.h>
695373Sraghuram #include <sys/atomic.h>
705373Sraghuram #include <sys/callb.h>
716419Ssb155480 #include <sys/vlan.h>
725373Sraghuram
735373Sraghuram /* Port add/deletion/etc routines */
749217SWentao.Yang@Sun.COM static void vsw_port_delete(vsw_port_t *port);
755373Sraghuram static int vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id);
7612011SSriharsha.Basavapatna@Sun.COM static void vsw_ldc_detach(vsw_ldc_t *ldcp);
775373Sraghuram static int vsw_ldc_init(vsw_ldc_t *ldcp);
789217SWentao.Yang@Sun.COM static void vsw_ldc_uninit(vsw_ldc_t *ldcp);
7912011SSriharsha.Basavapatna@Sun.COM static void vsw_ldc_drain(vsw_ldc_t *ldcp);
809217SWentao.Yang@Sun.COM static void vsw_drain_port_taskq(vsw_port_t *port);
815373Sraghuram static void vsw_marker_task(void *);
825373Sraghuram static int vsw_plist_del_node(vsw_t *, vsw_port_t *port);
839217SWentao.Yang@Sun.COM void vsw_detach_ports(vsw_t *vswp);
845373Sraghuram int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node);
855373Sraghuram mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr);
865373Sraghuram int vsw_port_detach(vsw_t *vswp, int p_instance);
878275SEric Cheng int vsw_portsend(vsw_port_t *port, mblk_t *mp);
886419Ssb155480 int vsw_port_attach(vsw_port_t *portp);
895373Sraghuram vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance);
906419Ssb155480 void vsw_vlan_unaware_port_reset(vsw_port_t *portp);
916724Sraghuram void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate);
927529SSriharsha.Basavapatna@Sun.COM void vsw_reset_ports(vsw_t *vswp);
937529SSriharsha.Basavapatna@Sun.COM void vsw_port_reset(vsw_port_t *portp);
949336SSriharsha.Basavapatna@Sun.COM void vsw_physlink_update_ports(vsw_t *vswp);
959336SSriharsha.Basavapatna@Sun.COM static void vsw_port_physlink_update(vsw_port_t *portp);
965373Sraghuram
975373Sraghuram /* Interrupt routines */
985373Sraghuram static uint_t vsw_ldc_cb(uint64_t cb, caddr_t arg);
995373Sraghuram
1005373Sraghuram /* Handshake routines */
1015373Sraghuram static void vsw_ldc_reinit(vsw_ldc_t *);
1025373Sraghuram static void vsw_conn_task(void *);
1035373Sraghuram static int vsw_check_flag(vsw_ldc_t *, int, uint64_t);
1045373Sraghuram static void vsw_next_milestone(vsw_ldc_t *);
1055373Sraghuram static int vsw_supported_version(vio_ver_msg_t *);
1065935Ssb155480 static void vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp);
1075935Ssb155480 static void vsw_reset_vnet_proto_ops(vsw_ldc_t *ldcp);
10812011SSriharsha.Basavapatna@Sun.COM void vsw_process_conn_evt(vsw_ldc_t *, uint16_t);
1095373Sraghuram
1105373Sraghuram /* Data processing routines */
11112011SSriharsha.Basavapatna@Sun.COM void vsw_process_pkt(void *);
11212011SSriharsha.Basavapatna@Sun.COM static void vsw_dispatch_ctrl_task(vsw_ldc_t *, void *, vio_msg_tag_t *, int);
1135373Sraghuram static void vsw_process_ctrl_pkt(void *);
1145373Sraghuram static void vsw_process_ctrl_ver_pkt(vsw_ldc_t *, void *);
1155373Sraghuram static void vsw_process_ctrl_attr_pkt(vsw_ldc_t *, void *);
1165373Sraghuram static void vsw_process_ctrl_mcst_pkt(vsw_ldc_t *, void *);
1175373Sraghuram static void vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *, void *);
1185373Sraghuram static void vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *, void *);
1195373Sraghuram static void vsw_process_ctrl_rdx_pkt(vsw_ldc_t *, void *);
1209336SSriharsha.Basavapatna@Sun.COM static void vsw_process_physlink_msg(vsw_ldc_t *, void *);
1215935Ssb155480 static void vsw_process_data_pkt(vsw_ldc_t *, void *, vio_msg_tag_t *,
1225935Ssb155480 uint32_t);
1235935Ssb155480 static void vsw_process_pkt_data_nop(void *, void *, uint32_t);
1245935Ssb155480 static void vsw_process_pkt_data(void *, void *, uint32_t);
1255373Sraghuram static void vsw_process_data_ibnd_pkt(vsw_ldc_t *, void *);
1265935Ssb155480 static void vsw_process_err_pkt(vsw_ldc_t *, void *, vio_msg_tag_t *);
12712011SSriharsha.Basavapatna@Sun.COM static void vsw_process_evt_read(vsw_ldc_t *ldcp);
12812011SSriharsha.Basavapatna@Sun.COM static void vsw_ldc_rcv(vsw_ldc_t *ldcp);
1295373Sraghuram
1305373Sraghuram /* Switching/data transmit routines */
1315373Sraghuram static int vsw_descrsend(vsw_ldc_t *, mblk_t *);
1325935Ssb155480 static void vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp);
1335935Ssb155480 static int vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries);
1345935Ssb155480 static int vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count);
1355935Ssb155480 static int vsw_ldctx(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count);
1365373Sraghuram
1375373Sraghuram /* Packet creation routines */
1385373Sraghuram static void vsw_send_ver(void *);
1395373Sraghuram static void vsw_send_attr(vsw_ldc_t *);
1405373Sraghuram static void vsw_send_dring_info(vsw_ldc_t *);
1415373Sraghuram static void vsw_send_rdx(vsw_ldc_t *);
1429336SSriharsha.Basavapatna@Sun.COM static void vsw_send_physlink_msg(vsw_ldc_t *ldcp, link_state_t plink_state);
1435373Sraghuram
1445373Sraghuram /* Dring routines */
1455373Sraghuram static void vsw_create_privring(vsw_ldc_t *);
14612011SSriharsha.Basavapatna@Sun.COM static dring_info_t *vsw_map_dring(vsw_ldc_t *ldcp, void *pkt);
14712011SSriharsha.Basavapatna@Sun.COM static void vsw_unmap_dring(vsw_ldc_t *ldcp);
14812011SSriharsha.Basavapatna@Sun.COM static void vsw_destroy_dring(vsw_ldc_t *ldcp);
14912011SSriharsha.Basavapatna@Sun.COM static void vsw_free_lane_resources(vsw_ldc_t *, uint64_t);
15012011SSriharsha.Basavapatna@Sun.COM static int vsw_map_data(vsw_ldc_t *ldcp, dring_info_t *dp, void *pkt);
1515373Sraghuram static void vsw_set_lane_attr(vsw_t *, lane_t *);
15212011SSriharsha.Basavapatna@Sun.COM dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp,
15312011SSriharsha.Basavapatna@Sun.COM vio_dring_reg_msg_t *dring_pkt);
154*13098SWentao.Yang@Sun.COM static int vsw_mapin_avail(vsw_ldc_t *ldcp);
15512011SSriharsha.Basavapatna@Sun.COM
15612011SSriharsha.Basavapatna@Sun.COM /* tx/msg/rcv thread routines */
1575373Sraghuram static void vsw_stop_tx_thread(vsw_ldc_t *ldcp);
1585373Sraghuram static void vsw_ldc_tx_worker(void *arg);
1595373Sraghuram
1605373Sraghuram /* Misc support routines */
1615373Sraghuram static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr);
1625373Sraghuram static int vsw_get_same_dest_list(struct ether_header *ehp,
1635373Sraghuram mblk_t **rhead, mblk_t **rtail, mblk_t **mpp);
1645373Sraghuram static mblk_t *vsw_dupmsgchain(mblk_t *mp);
1655373Sraghuram
1665373Sraghuram /* Debugging routines */
1675373Sraghuram static void dump_flags(uint64_t);
1685373Sraghuram static void display_state(void);
1695373Sraghuram static void display_lane(lane_t *);
1705373Sraghuram static void display_ring(dring_info_t *);
1715373Sraghuram
1725373Sraghuram /*
1735373Sraghuram * Functions imported from other files.
1745373Sraghuram */
1755373Sraghuram extern int vsw_set_hw(vsw_t *, vsw_port_t *, int);
1768275SEric Cheng extern void vsw_unset_hw(vsw_t *, vsw_port_t *, int);
1775373Sraghuram extern int vsw_add_rem_mcst(vnet_mcast_msg_t *mcst_pkt, vsw_port_t *port);
1785373Sraghuram extern void vsw_del_mcst_port(vsw_port_t *port);
1795373Sraghuram extern int vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg);
1805373Sraghuram extern int vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg);
1816419Ssb155480 extern void vsw_fdbe_add(vsw_t *vswp, void *port);
1826419Ssb155480 extern void vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr);
1836419Ssb155480 extern void vsw_create_vlans(void *arg, int type);
1846419Ssb155480 extern void vsw_destroy_vlans(void *arg, int type);
1856419Ssb155480 extern void vsw_vlan_add_ids(void *arg, int type);
1866419Ssb155480 extern void vsw_vlan_remove_ids(void *arg, int type);
1876419Ssb155480 extern boolean_t vsw_frame_lookup_vid(void *arg, int caller,
1886419Ssb155480 struct ether_header *ehp, uint16_t *vidp);
1896419Ssb155480 extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp);
1906419Ssb155480 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np,
1916419Ssb155480 mblk_t **npt);
1926419Ssb155480 extern boolean_t vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
1936495Sspeer extern void vsw_hio_start(vsw_t *vswp, vsw_ldc_t *ldcp);
1946495Sspeer extern void vsw_hio_stop(vsw_t *vswp, vsw_ldc_t *ldcp);
1956495Sspeer extern void vsw_process_dds_msg(vsw_t *vswp, vsw_ldc_t *ldcp, void *msg);
1966495Sspeer extern void vsw_hio_stop_port(vsw_port_t *portp);
1978275SEric Cheng extern void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp);
1988275SEric Cheng extern int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type);
1998275SEric Cheng extern void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type);
20010041SWentao.Yang@Sun.COM extern void vsw_destroy_rxpools(void *arg);
20112011SSriharsha.Basavapatna@Sun.COM extern void vsw_stop_msg_thread(vsw_ldc_t *ldcp);
20212011SSriharsha.Basavapatna@Sun.COM extern int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t);
20312011SSriharsha.Basavapatna@Sun.COM extern int vsw_dringsend(vsw_ldc_t *, mblk_t *);
20412011SSriharsha.Basavapatna@Sun.COM extern int vsw_reclaim_dring(dring_info_t *dp, int start);
20512011SSriharsha.Basavapatna@Sun.COM extern int vsw_dring_find_free_desc(dring_info_t *, vsw_private_desc_t **,
20612011SSriharsha.Basavapatna@Sun.COM int *);
20712011SSriharsha.Basavapatna@Sun.COM extern vio_dring_reg_msg_t *vsw_create_tx_dring_info(vsw_ldc_t *);
20812011SSriharsha.Basavapatna@Sun.COM extern int vsw_setup_tx_dring(vsw_ldc_t *ldcp, dring_info_t *dp);
20912011SSriharsha.Basavapatna@Sun.COM extern void vsw_destroy_tx_dring(vsw_ldc_t *ldcp);
21012011SSriharsha.Basavapatna@Sun.COM extern dring_info_t *vsw_map_rx_dring(vsw_ldc_t *ldcp, void *pkt);
21112011SSriharsha.Basavapatna@Sun.COM extern void vsw_unmap_rx_dring(vsw_ldc_t *ldcp);
21212011SSriharsha.Basavapatna@Sun.COM extern void vsw_ldc_msg_worker(void *arg);
21312011SSriharsha.Basavapatna@Sun.COM extern void vsw_process_dringdata(void *, void *);
21412011SSriharsha.Basavapatna@Sun.COM extern vio_dring_reg_msg_t *vsw_create_rx_dring_info(vsw_ldc_t *);
21512011SSriharsha.Basavapatna@Sun.COM extern void vsw_destroy_rx_dring(vsw_ldc_t *ldcp);
21612011SSriharsha.Basavapatna@Sun.COM extern dring_info_t *vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt);
21712011SSriharsha.Basavapatna@Sun.COM extern void vsw_unmap_tx_dring(vsw_ldc_t *ldcp);
21812011SSriharsha.Basavapatna@Sun.COM extern void vsw_ldc_rcv_worker(void *arg);
21912011SSriharsha.Basavapatna@Sun.COM extern void vsw_stop_rcv_thread(vsw_ldc_t *ldcp);
22012011SSriharsha.Basavapatna@Sun.COM extern int vsw_dringsend_shm(vsw_ldc_t *, mblk_t *);
22112011SSriharsha.Basavapatna@Sun.COM extern void vsw_process_dringdata_shm(void *, void *);
2225373Sraghuram
2235373Sraghuram /*
2245373Sraghuram * Tunables used in this file.
2255373Sraghuram */
2265373Sraghuram extern int vsw_num_handshakes;
2275373Sraghuram extern int vsw_ldc_tx_delay;
2285373Sraghuram extern int vsw_ldc_tx_retries;
2299217SWentao.Yang@Sun.COM extern int vsw_ldc_retries;
2309217SWentao.Yang@Sun.COM extern int vsw_ldc_delay;
2315373Sraghuram extern boolean_t vsw_ldc_rxthr_enabled;
2325373Sraghuram extern boolean_t vsw_ldc_txthr_enabled;
23312011SSriharsha.Basavapatna@Sun.COM extern uint32_t vsw_num_descriptors;
23412011SSriharsha.Basavapatna@Sun.COM extern uint8_t vsw_dring_mode;
2355935Ssb155480 extern uint32_t vsw_max_tx_qcount;
2365935Ssb155480 extern boolean_t vsw_obp_ver_proto_workaround;
2377027Ssb155480 extern uint32_t vsw_publish_macaddr_count;
238*13098SWentao.Yang@Sun.COM extern uint32_t vsw_nrbufs_factor;
2395373Sraghuram
2405373Sraghuram #define LDC_ENTER_LOCK(ldcp) \
2415373Sraghuram mutex_enter(&((ldcp)->ldc_cblock));\
2425373Sraghuram mutex_enter(&((ldcp)->ldc_rxlock));\
2435373Sraghuram mutex_enter(&((ldcp)->ldc_txlock));
2445373Sraghuram #define LDC_EXIT_LOCK(ldcp) \
2455373Sraghuram mutex_exit(&((ldcp)->ldc_txlock));\
2465373Sraghuram mutex_exit(&((ldcp)->ldc_rxlock));\
2475373Sraghuram mutex_exit(&((ldcp)->ldc_cblock));
2485373Sraghuram
2495935Ssb155480 #define VSW_VER_EQ(ldcp, major, minor) \
2505935Ssb155480 ((ldcp)->lane_out.ver_major == (major) && \
2515935Ssb155480 (ldcp)->lane_out.ver_minor == (minor))
2525935Ssb155480
2535935Ssb155480 #define VSW_VER_LT(ldcp, major, minor) \
2545935Ssb155480 (((ldcp)->lane_out.ver_major < (major)) || \
2555935Ssb155480 ((ldcp)->lane_out.ver_major == (major) && \
2565935Ssb155480 (ldcp)->lane_out.ver_minor < (minor)))
2575373Sraghuram
2586419Ssb155480 #define VSW_VER_GTEQ(ldcp, major, minor) \
2596419Ssb155480 (((ldcp)->lane_out.ver_major > (major)) || \
2606419Ssb155480 ((ldcp)->lane_out.ver_major == (major) && \
2616419Ssb155480 (ldcp)->lane_out.ver_minor >= (minor)))
2626419Ssb155480
26312011SSriharsha.Basavapatna@Sun.COM #define VSW_VER_LTEQ(ldcp, major, minor) \
26412011SSriharsha.Basavapatna@Sun.COM (((ldcp)->lane_out.ver_major < (major)) || \
26512011SSriharsha.Basavapatna@Sun.COM ((ldcp)->lane_out.ver_major == (major) && \
26612011SSriharsha.Basavapatna@Sun.COM (ldcp)->lane_out.ver_minor <= (minor)))
26712011SSriharsha.Basavapatna@Sun.COM
2689336SSriharsha.Basavapatna@Sun.COM /*
2699336SSriharsha.Basavapatna@Sun.COM * VIO Protocol Version Info:
2709336SSriharsha.Basavapatna@Sun.COM *
2719336SSriharsha.Basavapatna@Sun.COM * The version specified below represents the version of protocol currently
2729336SSriharsha.Basavapatna@Sun.COM * supported in the driver. It means the driver can negotiate with peers with
2739336SSriharsha.Basavapatna@Sun.COM * versions <= this version. Here is a summary of the feature(s) that are
2749336SSriharsha.Basavapatna@Sun.COM * supported at each version of the protocol:
2759336SSriharsha.Basavapatna@Sun.COM *
2769336SSriharsha.Basavapatna@Sun.COM * 1.0 Basic VIO protocol.
2779336SSriharsha.Basavapatna@Sun.COM * 1.1 vDisk protocol update (no virtual network update).
2789336SSriharsha.Basavapatna@Sun.COM * 1.2 Support for priority frames (priority-ether-types).
2799336SSriharsha.Basavapatna@Sun.COM * 1.3 VLAN and HybridIO support.
2809336SSriharsha.Basavapatna@Sun.COM * 1.4 Jumbo Frame support.
2819336SSriharsha.Basavapatna@Sun.COM * 1.5 Link State Notification support with optional support
2829336SSriharsha.Basavapatna@Sun.COM * for Physical Link information.
28312011SSriharsha.Basavapatna@Sun.COM * 1.6 Support for RxDringData mode.
2849336SSriharsha.Basavapatna@Sun.COM */
28512011SSriharsha.Basavapatna@Sun.COM static ver_sup_t vsw_versions[] = { {1, 6} };
2865373Sraghuram
2875373Sraghuram /*
2885373Sraghuram * For the moment the state dump routines have their own
2895373Sraghuram * private flag.
2905373Sraghuram */
2915373Sraghuram #define DUMP_STATE 0
2925373Sraghuram
2935373Sraghuram #if DUMP_STATE
2945373Sraghuram
2955373Sraghuram #define DUMP_TAG(tag) \
2965373Sraghuram { \
2975373Sraghuram D1(NULL, "DUMP_TAG: type 0x%llx", (tag).vio_msgtype); \
2985373Sraghuram D1(NULL, "DUMP_TAG: stype 0x%llx", (tag).vio_subtype); \
2995373Sraghuram D1(NULL, "DUMP_TAG: senv 0x%llx", (tag).vio_subtype_env); \
3005373Sraghuram }
3015373Sraghuram
3025373Sraghuram #define DUMP_TAG_PTR(tag) \
3035373Sraghuram { \
3045373Sraghuram D1(NULL, "DUMP_TAG: type 0x%llx", (tag)->vio_msgtype); \
3055373Sraghuram D1(NULL, "DUMP_TAG: stype 0x%llx", (tag)->vio_subtype); \
3065373Sraghuram D1(NULL, "DUMP_TAG: senv 0x%llx", (tag)->vio_subtype_env); \
3075373Sraghuram }
3085373Sraghuram
3095373Sraghuram #define DUMP_FLAGS(flags) dump_flags(flags);
3105373Sraghuram #define DISPLAY_STATE() display_state()
3115373Sraghuram
3125373Sraghuram #else
3135373Sraghuram
3145373Sraghuram #define DUMP_TAG(tag)
3155373Sraghuram #define DUMP_TAG_PTR(tag)
3165373Sraghuram #define DUMP_FLAGS(state)
3175373Sraghuram #define DISPLAY_STATE()
3185373Sraghuram
3195373Sraghuram #endif /* DUMP_STATE */
3205373Sraghuram
3215373Sraghuram /*
3225373Sraghuram * Attach the specified port.
3235373Sraghuram *
3245373Sraghuram * Returns 0 on success, 1 on failure.
3255373Sraghuram */
3265373Sraghuram int
vsw_port_attach(vsw_port_t * port)3276419Ssb155480 vsw_port_attach(vsw_port_t *port)
3285373Sraghuram {
3296419Ssb155480 vsw_t *vswp = port->p_vswp;
3305373Sraghuram vsw_port_list_t *plist = &vswp->plist;
3316419Ssb155480 vsw_port_t *p, **pp;
3326419Ssb155480 int nids = port->num_ldcs;
3336419Ssb155480 uint64_t *ldcids;
3348275SEric Cheng int rv;
3356419Ssb155480
3366419Ssb155480 D1(vswp, "%s: enter : port %d", __func__, port->p_instance);
3375373Sraghuram
3385373Sraghuram /* port already exists? */
3395373Sraghuram READ_ENTER(&plist->lockrw);
3406419Ssb155480 for (p = plist->head; p != NULL; p = p->p_next) {
3416419Ssb155480 if (p->p_instance == port->p_instance) {
3425373Sraghuram DWARN(vswp, "%s: port instance %d already attached",
3436419Ssb155480 __func__, p->p_instance);
3445373Sraghuram RW_EXIT(&plist->lockrw);
3455373Sraghuram return (1);
3465373Sraghuram }
3475373Sraghuram }
3485373Sraghuram RW_EXIT(&plist->lockrw);
3495373Sraghuram
3505373Sraghuram mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL);
3515373Sraghuram mutex_init(&port->mca_lock, NULL, MUTEX_DRIVER, NULL);
3528275SEric Cheng rw_init(&port->maccl_rwlock, NULL, RW_DRIVER, NULL);
3535373Sraghuram
3545373Sraghuram mutex_init(&port->state_lock, NULL, MUTEX_DRIVER, NULL);
3555373Sraghuram cv_init(&port->state_cv, NULL, CV_DRIVER, NULL);
3565373Sraghuram port->state = VSW_PORT_INIT;
3575373Sraghuram
3585373Sraghuram D2(vswp, "%s: %d nids", __func__, nids);
3596419Ssb155480 ldcids = port->ldc_ids;
36012011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: ldcid (%llx)", __func__, (uint64_t)ldcids[0]);
36112011SSriharsha.Basavapatna@Sun.COM if (vsw_ldc_attach(port, (uint64_t)ldcids[0]) != 0) {
36212011SSriharsha.Basavapatna@Sun.COM DERR(vswp, "%s: ldc_attach failed", __func__);
36312011SSriharsha.Basavapatna@Sun.COM goto exit_error;
3645373Sraghuram }
3655373Sraghuram
3665373Sraghuram if (vswp->switching_setup_done == B_TRUE) {
3675373Sraghuram /*
3688275SEric Cheng * If the underlying network device has been setup,
3698275SEric Cheng * then open a mac client and porgram the mac address
3708275SEric Cheng * for this port.
3715373Sraghuram */
3728275SEric Cheng rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT);
3738275SEric Cheng if (rv != 0) {
3748275SEric Cheng goto exit_error;
3758275SEric Cheng }
3765373Sraghuram }
3775373Sraghuram
3786419Ssb155480 /* create the fdb entry for this port/mac address */
3796419Ssb155480 vsw_fdbe_add(vswp, port);
3806419Ssb155480
3816419Ssb155480 vsw_create_vlans(port, VSW_VNETPORT);
3826419Ssb155480
3835373Sraghuram WRITE_ENTER(&plist->lockrw);
3845373Sraghuram
3855373Sraghuram /* link it into the list of ports for this vsw instance */
3866419Ssb155480 pp = (vsw_port_t **)(&plist->head);
3876419Ssb155480 port->p_next = *pp;
3886419Ssb155480 *pp = port;
3895373Sraghuram plist->num_ports++;
3905373Sraghuram
3915373Sraghuram RW_EXIT(&plist->lockrw);
3925373Sraghuram
3935373Sraghuram /*
3945373Sraghuram * Initialise the port and any ldc's under it.
3955373Sraghuram */
39612011SSriharsha.Basavapatna@Sun.COM (void) vsw_ldc_init(port->ldcp);
3975373Sraghuram
3987027Ssb155480 /* announce macaddr of vnet to the physical switch */
3997027Ssb155480 if (vsw_publish_macaddr_count != 0) { /* enabled */
4008275SEric Cheng vsw_publish_macaddr(vswp, port);
4017027Ssb155480 }
4027027Ssb155480
4035373Sraghuram D1(vswp, "%s: exit", __func__);
4045373Sraghuram return (0);
4058275SEric Cheng
4068275SEric Cheng exit_error:
4078275SEric Cheng
4088275SEric Cheng cv_destroy(&port->state_cv);
4098275SEric Cheng mutex_destroy(&port->state_lock);
4108275SEric Cheng
4118275SEric Cheng rw_destroy(&port->maccl_rwlock);
4128275SEric Cheng mutex_destroy(&port->tx_lock);
4138275SEric Cheng mutex_destroy(&port->mca_lock);
4148275SEric Cheng kmem_free(port, sizeof (vsw_port_t));
4158275SEric Cheng return (1);
4165373Sraghuram }
4175373Sraghuram
4185373Sraghuram /*
4195373Sraghuram * Detach the specified port.
4205373Sraghuram *
4215373Sraghuram * Returns 0 on success, 1 on failure.
4225373Sraghuram */
4235373Sraghuram int
vsw_port_detach(vsw_t * vswp,int p_instance)4245373Sraghuram vsw_port_detach(vsw_t *vswp, int p_instance)
4255373Sraghuram {
4265373Sraghuram vsw_port_t *port = NULL;
4275373Sraghuram vsw_port_list_t *plist = &vswp->plist;
4285373Sraghuram
4295373Sraghuram D1(vswp, "%s: enter: port id %d", __func__, p_instance);
4305373Sraghuram
4315373Sraghuram WRITE_ENTER(&plist->lockrw);
4325373Sraghuram
4335373Sraghuram if ((port = vsw_lookup_port(vswp, p_instance)) == NULL) {
4345373Sraghuram RW_EXIT(&plist->lockrw);
4355373Sraghuram return (1);
4365373Sraghuram }
4375373Sraghuram
4385373Sraghuram if (vsw_plist_del_node(vswp, port)) {
4395373Sraghuram RW_EXIT(&plist->lockrw);
4405373Sraghuram return (1);
4415373Sraghuram }
4425373Sraghuram
4436495Sspeer /* cleanup any HybridIO for this port */
4446495Sspeer vsw_hio_stop_port(port);
4456495Sspeer
4465373Sraghuram /*
4475373Sraghuram * No longer need to hold writer lock on port list now
4485373Sraghuram * that we have unlinked the target port from the list.
4495373Sraghuram */
4505373Sraghuram RW_EXIT(&plist->lockrw);
4515373Sraghuram
4528275SEric Cheng /* Cleanup and close the mac client */
4538275SEric Cheng vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT);
4548275SEric Cheng
4556419Ssb155480 /* Remove the fdb entry for this port/mac address */
4566419Ssb155480 vsw_fdbe_del(vswp, &(port->p_macaddr));
4576419Ssb155480 vsw_destroy_vlans(port, VSW_VNETPORT);
4586419Ssb155480
4596419Ssb155480 /* Remove any multicast addresses.. */
4606419Ssb155480 vsw_del_mcst_port(port);
4616419Ssb155480
4629217SWentao.Yang@Sun.COM vsw_port_delete(port);
4635373Sraghuram
4645373Sraghuram D1(vswp, "%s: exit: p_instance(%d)", __func__, p_instance);
4655373Sraghuram return (0);
4665373Sraghuram }
4675373Sraghuram
4685373Sraghuram /*
4695373Sraghuram * Detach all active ports.
4705373Sraghuram */
4719217SWentao.Yang@Sun.COM void
vsw_detach_ports(vsw_t * vswp)4725373Sraghuram vsw_detach_ports(vsw_t *vswp)
4735373Sraghuram {
4745373Sraghuram vsw_port_list_t *plist = &vswp->plist;
4755373Sraghuram vsw_port_t *port = NULL;
4765373Sraghuram
4775373Sraghuram D1(vswp, "%s: enter", __func__);
4785373Sraghuram
4795373Sraghuram WRITE_ENTER(&plist->lockrw);
4805373Sraghuram
4815373Sraghuram while ((port = plist->head) != NULL) {
4829217SWentao.Yang@Sun.COM (void) vsw_plist_del_node(vswp, port);
4839217SWentao.Yang@Sun.COM
4849217SWentao.Yang@Sun.COM /* cleanup any HybridIO for this port */
4859217SWentao.Yang@Sun.COM vsw_hio_stop_port(port);
4865373Sraghuram
4878275SEric Cheng /* Cleanup and close the mac client */
4888275SEric Cheng vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT);
4895373Sraghuram
4905373Sraghuram /* Remove the fdb entry for this port/mac address */
4916419Ssb155480 vsw_fdbe_del(vswp, &(port->p_macaddr));
4926419Ssb155480 vsw_destroy_vlans(port, VSW_VNETPORT);
4935373Sraghuram
4945373Sraghuram /* Remove any multicast addresses.. */
4955373Sraghuram vsw_del_mcst_port(port);
4965373Sraghuram
4975373Sraghuram /*
4985373Sraghuram * No longer need to hold the lock on the port list
4995373Sraghuram * now that we have unlinked the target port from the
5005373Sraghuram * list.
5015373Sraghuram */
5025373Sraghuram RW_EXIT(&plist->lockrw);
5039217SWentao.Yang@Sun.COM vsw_port_delete(port);
5045373Sraghuram WRITE_ENTER(&plist->lockrw);
5055373Sraghuram }
5065373Sraghuram RW_EXIT(&plist->lockrw);
5075373Sraghuram
5085373Sraghuram D1(vswp, "%s: exit", __func__);
5095373Sraghuram }
5105373Sraghuram
5115373Sraghuram /*
5125373Sraghuram * Delete the specified port.
5135373Sraghuram */
5149217SWentao.Yang@Sun.COM static void
vsw_port_delete(vsw_port_t * port)5155373Sraghuram vsw_port_delete(vsw_port_t *port)
5165373Sraghuram {
5175373Sraghuram vsw_t *vswp = port->p_vswp;
5185373Sraghuram
5195373Sraghuram D1(vswp, "%s: enter : port id %d", __func__, port->p_instance);
5205373Sraghuram
52112011SSriharsha.Basavapatna@Sun.COM vsw_ldc_uninit(port->ldcp);
5225373Sraghuram
5235373Sraghuram /*
5245373Sraghuram * Wait for any pending ctrl msg tasks which reference this
5255373Sraghuram * port to finish.
5265373Sraghuram */
5279217SWentao.Yang@Sun.COM vsw_drain_port_taskq(port);
5285373Sraghuram
5295373Sraghuram /*
5305373Sraghuram * Wait for any active callbacks to finish
5315373Sraghuram */
53212011SSriharsha.Basavapatna@Sun.COM vsw_ldc_drain(port->ldcp);
53312011SSriharsha.Basavapatna@Sun.COM
53412011SSriharsha.Basavapatna@Sun.COM vsw_ldc_detach(port->ldcp);
5355373Sraghuram
5368275SEric Cheng rw_destroy(&port->maccl_rwlock);
5375373Sraghuram mutex_destroy(&port->mca_lock);
5385373Sraghuram mutex_destroy(&port->tx_lock);
5396419Ssb155480
5405373Sraghuram cv_destroy(&port->state_cv);
5415373Sraghuram mutex_destroy(&port->state_lock);
5425373Sraghuram
5436419Ssb155480 if (port->num_ldcs != 0) {
5446419Ssb155480 kmem_free(port->ldc_ids, port->num_ldcs * sizeof (uint64_t));
5456419Ssb155480 port->num_ldcs = 0;
5466419Ssb155480 }
5478275SEric Cheng
5488275SEric Cheng if (port->nvids != 0) {
5498275SEric Cheng kmem_free(port->vids, sizeof (vsw_vlanid_t) * port->nvids);
5508275SEric Cheng }
5518275SEric Cheng
5525373Sraghuram kmem_free(port, sizeof (vsw_port_t));
5535373Sraghuram
5545373Sraghuram D1(vswp, "%s: exit", __func__);
5555373Sraghuram }
5565373Sraghuram
5575373Sraghuram /*
5585373Sraghuram * Attach a logical domain channel (ldc) under a specified port.
5595373Sraghuram *
5605373Sraghuram * Returns 0 on success, 1 on failure.
5615373Sraghuram */
5625373Sraghuram static int
vsw_ldc_attach(vsw_port_t * port,uint64_t ldc_id)5635373Sraghuram vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id)
5645373Sraghuram {
5655373Sraghuram vsw_t *vswp = port->p_vswp;
5665373Sraghuram vsw_ldc_t *ldcp = NULL;
5675373Sraghuram ldc_attr_t attr;
5685373Sraghuram ldc_status_t istatus;
5695373Sraghuram int status = DDI_FAILURE;
5705373Sraghuram char kname[MAXNAMELEN];
5717529SSriharsha.Basavapatna@Sun.COM enum { PROG_init = 0x0,
57212011SSriharsha.Basavapatna@Sun.COM PROG_callback = 0x1,
57312011SSriharsha.Basavapatna@Sun.COM PROG_tx_thread = 0x2}
5745373Sraghuram progress;
5755373Sraghuram
5765373Sraghuram progress = PROG_init;
5775373Sraghuram
5785373Sraghuram D1(vswp, "%s: enter", __func__);
5795373Sraghuram
5805373Sraghuram ldcp = kmem_zalloc(sizeof (vsw_ldc_t), KM_NOSLEEP);
5815373Sraghuram if (ldcp == NULL) {
5825373Sraghuram DERR(vswp, "%s: kmem_zalloc failed", __func__);
5835373Sraghuram return (1);
5845373Sraghuram }
5855373Sraghuram ldcp->ldc_id = ldc_id;
5865373Sraghuram
5875373Sraghuram mutex_init(&ldcp->ldc_txlock, NULL, MUTEX_DRIVER, NULL);
5885373Sraghuram mutex_init(&ldcp->ldc_rxlock, NULL, MUTEX_DRIVER, NULL);
5895373Sraghuram mutex_init(&ldcp->ldc_cblock, NULL, MUTEX_DRIVER, NULL);
59012011SSriharsha.Basavapatna@Sun.COM ldcp->msg_thr_flags = 0;
59112011SSriharsha.Basavapatna@Sun.COM mutex_init(&ldcp->msg_thr_lock, NULL, MUTEX_DRIVER, NULL);
59212011SSriharsha.Basavapatna@Sun.COM cv_init(&ldcp->msg_thr_cv, NULL, CV_DRIVER, NULL);
59312011SSriharsha.Basavapatna@Sun.COM ldcp->rcv_thr_flags = 0;
59412011SSriharsha.Basavapatna@Sun.COM mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL);
59512011SSriharsha.Basavapatna@Sun.COM cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL);
5965373Sraghuram mutex_init(&ldcp->drain_cv_lock, NULL, MUTEX_DRIVER, NULL);
5975373Sraghuram cv_init(&ldcp->drain_cv, NULL, CV_DRIVER, NULL);
5985373Sraghuram
5995373Sraghuram /* required for handshake with peer */
6005373Sraghuram ldcp->local_session = (uint64_t)ddi_get_lbolt();
6015373Sraghuram ldcp->peer_session = 0;
6025373Sraghuram ldcp->session_status = 0;
6035373Sraghuram ldcp->hss_id = 1; /* Initial handshake session id */
60412011SSriharsha.Basavapatna@Sun.COM ldcp->hphase = VSW_MILESTONE0;
6055373Sraghuram
6066495Sspeer (void) atomic_swap_32(&port->p_hio_capable, B_FALSE);
6076495Sspeer
6085373Sraghuram /* only set for outbound lane, inbound set by peer */
6095373Sraghuram vsw_set_lane_attr(vswp, &ldcp->lane_out);
6105373Sraghuram
6115373Sraghuram attr.devclass = LDC_DEV_NT_SVC;
6125373Sraghuram attr.instance = ddi_get_instance(vswp->dip);
6135373Sraghuram attr.mode = LDC_MODE_UNRELIABLE;
6145373Sraghuram attr.mtu = VSW_LDC_MTU;
6155373Sraghuram status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
6165373Sraghuram if (status != 0) {
6175373Sraghuram DERR(vswp, "%s(%lld): ldc_init failed, rv (%d)",
6185373Sraghuram __func__, ldc_id, status);
6195373Sraghuram goto ldc_attach_fail;
6205373Sraghuram }
6215373Sraghuram
6225373Sraghuram if (vsw_ldc_txthr_enabled) {
6235373Sraghuram ldcp->tx_thr_flags = 0;
6245373Sraghuram ldcp->tx_mhead = ldcp->tx_mtail = NULL;
6255373Sraghuram
6265373Sraghuram mutex_init(&ldcp->tx_thr_lock, NULL, MUTEX_DRIVER, NULL);
6275373Sraghuram cv_init(&ldcp->tx_thr_cv, NULL, CV_DRIVER, NULL);
6285373Sraghuram ldcp->tx_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
6295373Sraghuram vsw_ldc_tx_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
6305373Sraghuram
6315373Sraghuram progress |= PROG_tx_thread;
6325373Sraghuram if (ldcp->tx_thread == NULL) {
6335373Sraghuram DWARN(vswp, "%s(%lld): Failed to create worker thread",
6345373Sraghuram __func__, ldc_id);
6355373Sraghuram goto ldc_attach_fail;
6365373Sraghuram }
6375373Sraghuram }
6385373Sraghuram
6395373Sraghuram status = ldc_reg_callback(ldcp->ldc_handle, vsw_ldc_cb, (caddr_t)ldcp);
6405373Sraghuram if (status != 0) {
6415373Sraghuram DERR(vswp, "%s(%lld): ldc_reg_callback failed, rv (%d)",
6425373Sraghuram __func__, ldc_id, status);
6435373Sraghuram (void) ldc_fini(ldcp->ldc_handle);
6445373Sraghuram goto ldc_attach_fail;
6455373Sraghuram }
6465935Ssb155480 /*
6475935Ssb155480 * allocate a message for ldc_read()s, big enough to hold ctrl and
6485935Ssb155480 * data msgs, including raw data msgs used to recv priority frames.
6495935Ssb155480 */
6506419Ssb155480 ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vswp->max_frame_size;
6515935Ssb155480 ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP);
6525373Sraghuram
6535373Sraghuram progress |= PROG_callback;
6545373Sraghuram
6555373Sraghuram mutex_init(&ldcp->status_lock, NULL, MUTEX_DRIVER, NULL);
6565373Sraghuram
6575373Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
6585373Sraghuram DERR(vswp, "%s: ldc_status failed", __func__);
6595373Sraghuram mutex_destroy(&ldcp->status_lock);
6605373Sraghuram goto ldc_attach_fail;
6615373Sraghuram }
6625373Sraghuram
6635373Sraghuram ldcp->ldc_status = istatus;
6645373Sraghuram ldcp->ldc_port = port;
6655373Sraghuram ldcp->ldc_vswp = vswp;
6665373Sraghuram
6675935Ssb155480 vsw_reset_vnet_proto_ops(ldcp);
6685935Ssb155480
6695373Sraghuram (void) sprintf(kname, "%sldc0x%lx", DRV_NAME, ldcp->ldc_id);
6705373Sraghuram ldcp->ksp = vgen_setup_kstats(DRV_NAME, vswp->instance,
6715373Sraghuram kname, &ldcp->ldc_stats);
6725373Sraghuram if (ldcp->ksp == NULL) {
6735373Sraghuram DERR(vswp, "%s: kstats setup failed", __func__);
6745373Sraghuram goto ldc_attach_fail;
6755373Sraghuram }
6765373Sraghuram
67712011SSriharsha.Basavapatna@Sun.COM /* link it into this port */
67812011SSriharsha.Basavapatna@Sun.COM port->ldcp = ldcp;
6795373Sraghuram
6805373Sraghuram D1(vswp, "%s: exit", __func__);
6815373Sraghuram return (0);
6825373Sraghuram
6835373Sraghuram ldc_attach_fail:
6845373Sraghuram
6855373Sraghuram if (progress & PROG_callback) {
6865373Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle);
6875935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen);
6885373Sraghuram }
6895373Sraghuram
6905373Sraghuram if (progress & PROG_tx_thread) {
6915373Sraghuram if (ldcp->tx_thread != NULL) {
6925373Sraghuram vsw_stop_tx_thread(ldcp);
6935373Sraghuram }
6945373Sraghuram mutex_destroy(&ldcp->tx_thr_lock);
6955373Sraghuram cv_destroy(&ldcp->tx_thr_cv);
6965373Sraghuram }
6975373Sraghuram if (ldcp->ksp != NULL) {
6985373Sraghuram vgen_destroy_kstats(ldcp->ksp);
6995373Sraghuram }
70012011SSriharsha.Basavapatna@Sun.COM mutex_destroy(&ldcp->msg_thr_lock);
70112011SSriharsha.Basavapatna@Sun.COM mutex_destroy(&ldcp->rcv_thr_lock);
7025373Sraghuram mutex_destroy(&ldcp->ldc_txlock);
7035373Sraghuram mutex_destroy(&ldcp->ldc_rxlock);
7045373Sraghuram mutex_destroy(&ldcp->ldc_cblock);
7055373Sraghuram mutex_destroy(&ldcp->drain_cv_lock);
70612011SSriharsha.Basavapatna@Sun.COM cv_destroy(&ldcp->msg_thr_cv);
70712011SSriharsha.Basavapatna@Sun.COM cv_destroy(&ldcp->rcv_thr_cv);
7085373Sraghuram cv_destroy(&ldcp->drain_cv);
7095373Sraghuram
7105373Sraghuram kmem_free(ldcp, sizeof (vsw_ldc_t));
7115373Sraghuram
7125373Sraghuram return (1);
7135373Sraghuram }
7145373Sraghuram
7155373Sraghuram /*
7165373Sraghuram * Detach a logical domain channel (ldc) belonging to a
7175373Sraghuram * particular port.
7185373Sraghuram */
7199217SWentao.Yang@Sun.COM static void
vsw_ldc_detach(vsw_ldc_t * ldcp)72012011SSriharsha.Basavapatna@Sun.COM vsw_ldc_detach(vsw_ldc_t *ldcp)
7215373Sraghuram {
7225373Sraghuram int rv;
72312011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_port->p_vswp;
7249217SWentao.Yang@Sun.COM int retries = 0;
7255373Sraghuram
7265373Sraghuram D2(vswp, "%s: detaching channel %lld", __func__, ldcp->ldc_id);
7275373Sraghuram
72812011SSriharsha.Basavapatna@Sun.COM /* Stop msg/rcv thread */
72912011SSriharsha.Basavapatna@Sun.COM if (ldcp->rcv_thread != NULL) {
73012011SSriharsha.Basavapatna@Sun.COM vsw_stop_rcv_thread(ldcp);
73112011SSriharsha.Basavapatna@Sun.COM } else if (ldcp->msg_thread != NULL) {
73212011SSriharsha.Basavapatna@Sun.COM vsw_stop_msg_thread(ldcp);
7335373Sraghuram }
7345935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen);
7355373Sraghuram
7365373Sraghuram /* Stop the tx thread */
7375373Sraghuram if (ldcp->tx_thread != NULL) {
7385373Sraghuram vsw_stop_tx_thread(ldcp);
7395373Sraghuram mutex_destroy(&ldcp->tx_thr_lock);
7405373Sraghuram cv_destroy(&ldcp->tx_thr_cv);
7415373Sraghuram if (ldcp->tx_mhead != NULL) {
7425373Sraghuram freemsgchain(ldcp->tx_mhead);
7435373Sraghuram ldcp->tx_mhead = ldcp->tx_mtail = NULL;
7445935Ssb155480 ldcp->tx_cnt = 0;
7455373Sraghuram }
7465373Sraghuram }
7475373Sraghuram
7485373Sraghuram /* Destory kstats */
7495373Sraghuram vgen_destroy_kstats(ldcp->ksp);
7505373Sraghuram
7515373Sraghuram /*
7525373Sraghuram * Before we can close the channel we must release any mapped
7535373Sraghuram * resources (e.g. drings).
7545373Sraghuram */
7555373Sraghuram vsw_free_lane_resources(ldcp, INBOUND);
7565373Sraghuram vsw_free_lane_resources(ldcp, OUTBOUND);
7575373Sraghuram
7585373Sraghuram /*
7599217SWentao.Yang@Sun.COM * Close the channel, retry on EAAGIN.
7605373Sraghuram */
7619217SWentao.Yang@Sun.COM while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) {
7629217SWentao.Yang@Sun.COM if (++retries > vsw_ldc_retries) {
7639217SWentao.Yang@Sun.COM break;
7649217SWentao.Yang@Sun.COM }
7659217SWentao.Yang@Sun.COM drv_usecwait(vsw_ldc_delay);
7669217SWentao.Yang@Sun.COM }
7679217SWentao.Yang@Sun.COM if (rv != 0) {
7689217SWentao.Yang@Sun.COM cmn_err(CE_NOTE,
7699217SWentao.Yang@Sun.COM "!vsw%d: Error(%d) closing the channel(0x%lx)\n",
7709217SWentao.Yang@Sun.COM vswp->instance, rv, ldcp->ldc_id);
7715373Sraghuram }
7725373Sraghuram
7735373Sraghuram (void) ldc_fini(ldcp->ldc_handle);
7745373Sraghuram
7755373Sraghuram ldcp->ldc_status = LDC_INIT;
7765373Sraghuram ldcp->ldc_handle = NULL;
7775373Sraghuram ldcp->ldc_vswp = NULL;
7785373Sraghuram
77912011SSriharsha.Basavapatna@Sun.COM mutex_destroy(&ldcp->msg_thr_lock);
78012011SSriharsha.Basavapatna@Sun.COM mutex_destroy(&ldcp->rcv_thr_lock);
7815373Sraghuram mutex_destroy(&ldcp->ldc_txlock);
7825373Sraghuram mutex_destroy(&ldcp->ldc_rxlock);
7835373Sraghuram mutex_destroy(&ldcp->ldc_cblock);
7845373Sraghuram mutex_destroy(&ldcp->drain_cv_lock);
7855373Sraghuram mutex_destroy(&ldcp->status_lock);
78612011SSriharsha.Basavapatna@Sun.COM cv_destroy(&ldcp->msg_thr_cv);
78712011SSriharsha.Basavapatna@Sun.COM cv_destroy(&ldcp->rcv_thr_cv);
78812011SSriharsha.Basavapatna@Sun.COM cv_destroy(&ldcp->drain_cv);
7895373Sraghuram
7905373Sraghuram kmem_free(ldcp, sizeof (vsw_ldc_t));
7915373Sraghuram }
7925373Sraghuram
7935373Sraghuram /*
7945373Sraghuram * Open and attempt to bring up the channel. Note that channel
7955373Sraghuram * can only be brought up if peer has also opened channel.
7965373Sraghuram *
7975373Sraghuram * Returns 0 if can open and bring up channel, otherwise
7985373Sraghuram * returns 1.
7995373Sraghuram */
8005373Sraghuram static int
vsw_ldc_init(vsw_ldc_t * ldcp)8015373Sraghuram vsw_ldc_init(vsw_ldc_t *ldcp)
8025373Sraghuram {
8035373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
8045373Sraghuram ldc_status_t istatus = 0;
8055373Sraghuram int rv;
8065373Sraghuram
8075373Sraghuram D1(vswp, "%s: enter", __func__);
8085373Sraghuram
8095373Sraghuram LDC_ENTER_LOCK(ldcp);
8105373Sraghuram
8115373Sraghuram /* don't start at 0 in case clients don't like that */
8125373Sraghuram ldcp->next_ident = 1;
8135373Sraghuram
8145373Sraghuram rv = ldc_open(ldcp->ldc_handle);
8155373Sraghuram if (rv != 0) {
8165373Sraghuram DERR(vswp, "%s: ldc_open failed: id(%lld) rv(%d)",
8175373Sraghuram __func__, ldcp->ldc_id, rv);
8185373Sraghuram LDC_EXIT_LOCK(ldcp);
8195373Sraghuram return (1);
8205373Sraghuram }
8215373Sraghuram
8225373Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
8235373Sraghuram DERR(vswp, "%s: unable to get status", __func__);
8245373Sraghuram LDC_EXIT_LOCK(ldcp);
8255373Sraghuram return (1);
8265373Sraghuram
8275373Sraghuram } else if (istatus != LDC_OPEN && istatus != LDC_READY) {
8285373Sraghuram DERR(vswp, "%s: id (%lld) status(%d) is not OPEN/READY",
8295373Sraghuram __func__, ldcp->ldc_id, istatus);
8305373Sraghuram LDC_EXIT_LOCK(ldcp);
8315373Sraghuram return (1);
8325373Sraghuram }
8335373Sraghuram
8345373Sraghuram mutex_enter(&ldcp->status_lock);
8355373Sraghuram ldcp->ldc_status = istatus;
8365373Sraghuram mutex_exit(&ldcp->status_lock);
8375373Sraghuram
8385373Sraghuram rv = ldc_up(ldcp->ldc_handle);
8395373Sraghuram if (rv != 0) {
8405373Sraghuram /*
8415373Sraghuram * Not a fatal error for ldc_up() to fail, as peer
8425373Sraghuram * end point may simply not be ready yet.
8435373Sraghuram */
8445373Sraghuram D2(vswp, "%s: ldc_up err id(%lld) rv(%d)", __func__,
8455373Sraghuram ldcp->ldc_id, rv);
8465373Sraghuram LDC_EXIT_LOCK(ldcp);
8475373Sraghuram return (1);
8485373Sraghuram }
8495373Sraghuram
8505373Sraghuram /*
8515373Sraghuram * ldc_up() call is non-blocking so need to explicitly
8525373Sraghuram * check channel status to see if in fact the channel
8535373Sraghuram * is UP.
8545373Sraghuram */
8555373Sraghuram mutex_enter(&ldcp->status_lock);
8565373Sraghuram if (ldc_status(ldcp->ldc_handle, &ldcp->ldc_status) != 0) {
8575373Sraghuram DERR(vswp, "%s: unable to get status", __func__);
8585373Sraghuram mutex_exit(&ldcp->status_lock);
8595373Sraghuram LDC_EXIT_LOCK(ldcp);
8605373Sraghuram return (1);
8615373Sraghuram
8625373Sraghuram }
8635373Sraghuram
8645373Sraghuram if (ldcp->ldc_status == LDC_UP) {
8655373Sraghuram D2(vswp, "%s: channel %ld now UP (%ld)", __func__,
8665373Sraghuram ldcp->ldc_id, istatus);
8675373Sraghuram mutex_exit(&ldcp->status_lock);
8685373Sraghuram LDC_EXIT_LOCK(ldcp);
8695373Sraghuram
8705373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_UP);
8715373Sraghuram return (0);
8725373Sraghuram }
8735373Sraghuram
8745373Sraghuram mutex_exit(&ldcp->status_lock);
8755373Sraghuram LDC_EXIT_LOCK(ldcp);
8765373Sraghuram
8775373Sraghuram D1(vswp, "%s: exit", __func__);
8785373Sraghuram return (0);
8795373Sraghuram }
8805373Sraghuram
8815373Sraghuram /* disable callbacks on the channel */
8829217SWentao.Yang@Sun.COM static void
vsw_ldc_uninit(vsw_ldc_t * ldcp)8835373Sraghuram vsw_ldc_uninit(vsw_ldc_t *ldcp)
8845373Sraghuram {
8855373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
8865373Sraghuram int rv;
8875373Sraghuram
8885373Sraghuram D1(vswp, "vsw_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id);
8895373Sraghuram
8905373Sraghuram LDC_ENTER_LOCK(ldcp);
8915373Sraghuram
8925373Sraghuram rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
8935373Sraghuram if (rv != 0) {
8949217SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!vsw_ldc_uninit(%ld): error disabling "
8955373Sraghuram "interrupts (rv = %d)\n", ldcp->ldc_id, rv);
8965373Sraghuram }
8975373Sraghuram
8985373Sraghuram mutex_enter(&ldcp->status_lock);
8995373Sraghuram ldcp->ldc_status = LDC_INIT;
9005373Sraghuram mutex_exit(&ldcp->status_lock);
9015373Sraghuram
9025373Sraghuram LDC_EXIT_LOCK(ldcp);
9035373Sraghuram
9045373Sraghuram D1(vswp, "vsw_ldc_uninit: exit: id(%lx)", ldcp->ldc_id);
9055373Sraghuram }
9065373Sraghuram
9075373Sraghuram /*
9085373Sraghuram * Wait until the callback(s) associated with the ldcs under the specified
9095373Sraghuram * port have completed.
9105373Sraghuram *
9115373Sraghuram * Prior to this function being invoked each channel under this port
9125373Sraghuram * should have been quiesced via ldc_set_cb_mode(DISABLE).
9135373Sraghuram *
9145373Sraghuram * A short explaination of what we are doing below..
9155373Sraghuram *
9165373Sraghuram * The simplest approach would be to have a reference counter in
9175373Sraghuram * the ldc structure which is increment/decremented by the callbacks as
9185373Sraghuram * they use the channel. The drain function could then simply disable any
9195373Sraghuram * further callbacks and do a cv_wait for the ref to hit zero. Unfortunately
9205373Sraghuram * there is a tiny window here - before the callback is able to get the lock
9215373Sraghuram * on the channel it is interrupted and this function gets to execute. It
9225373Sraghuram * sees that the ref count is zero and believes its free to delete the
9235373Sraghuram * associated data structures.
9245373Sraghuram *
9255373Sraghuram * We get around this by taking advantage of the fact that before the ldc
9265373Sraghuram * framework invokes a callback it sets a flag to indicate that there is a
9275373Sraghuram * callback active (or about to become active). If when we attempt to
9285373Sraghuram * unregister a callback when this active flag is set then the unregister
9295373Sraghuram * will fail with EWOULDBLOCK.
9305373Sraghuram *
9315373Sraghuram * If the unregister fails we do a cv_timedwait. We will either be signaled
9325373Sraghuram * by the callback as it is exiting (note we have to wait a short period to
9335373Sraghuram * allow the callback to return fully to the ldc framework and it to clear
9345373Sraghuram * the active flag), or by the timer expiring. In either case we again attempt
9355373Sraghuram * the unregister. We repeat this until we can succesfully unregister the
9365373Sraghuram * callback.
9375373Sraghuram *
9385373Sraghuram * The reason we use a cv_timedwait rather than a simple cv_wait is to catch
9395373Sraghuram * the case where the callback has finished but the ldc framework has not yet
9405373Sraghuram * cleared the active flag. In this case we would never get a cv_signal.
9415373Sraghuram */
9429217SWentao.Yang@Sun.COM static void
vsw_ldc_drain(vsw_ldc_t * ldcp)94312011SSriharsha.Basavapatna@Sun.COM vsw_ldc_drain(vsw_ldc_t *ldcp)
9445373Sraghuram {
94512011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_port->p_vswp;
9465373Sraghuram
9475373Sraghuram D1(vswp, "%s: enter", __func__);
9485373Sraghuram
94912011SSriharsha.Basavapatna@Sun.COM /*
95012011SSriharsha.Basavapatna@Sun.COM * If we can unregister the channel callback then we
95112011SSriharsha.Basavapatna@Sun.COM * know that there is no callback either running or
95212011SSriharsha.Basavapatna@Sun.COM * scheduled to run for this channel so move on to next
95312011SSriharsha.Basavapatna@Sun.COM * channel in the list.
95412011SSriharsha.Basavapatna@Sun.COM */
95512011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->drain_cv_lock);
95612011SSriharsha.Basavapatna@Sun.COM
95712011SSriharsha.Basavapatna@Sun.COM /* prompt active callbacks to quit */
95812011SSriharsha.Basavapatna@Sun.COM ldcp->drain_state = VSW_LDC_DRAINING;
95912011SSriharsha.Basavapatna@Sun.COM
96012011SSriharsha.Basavapatna@Sun.COM if ((ldc_unreg_callback(ldcp->ldc_handle)) == 0) {
96112011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: unreg callback for chan %ld", __func__,
96212011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_id);
96312011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->drain_cv_lock);
96412011SSriharsha.Basavapatna@Sun.COM } else {
9655373Sraghuram /*
96612011SSriharsha.Basavapatna@Sun.COM * If we end up here we know that either 1) a callback
96712011SSriharsha.Basavapatna@Sun.COM * is currently executing, 2) is about to start (i.e.
96812011SSriharsha.Basavapatna@Sun.COM * the ldc framework has set the active flag but
96912011SSriharsha.Basavapatna@Sun.COM * has not actually invoked the callback yet, or 3)
97012011SSriharsha.Basavapatna@Sun.COM * has finished and has returned to the ldc framework
97112011SSriharsha.Basavapatna@Sun.COM * but the ldc framework has not yet cleared the
97212011SSriharsha.Basavapatna@Sun.COM * active bit.
97312011SSriharsha.Basavapatna@Sun.COM *
97412011SSriharsha.Basavapatna@Sun.COM * Wait for it to finish.
9755373Sraghuram */
97612011SSriharsha.Basavapatna@Sun.COM while (ldc_unreg_callback(ldcp->ldc_handle) == EWOULDBLOCK) {
97712011SSriharsha.Basavapatna@Sun.COM (void) cv_timedwait(&ldcp->drain_cv,
97812011SSriharsha.Basavapatna@Sun.COM &ldcp->drain_cv_lock, ddi_get_lbolt() + hz);
9795373Sraghuram }
98012011SSriharsha.Basavapatna@Sun.COM
98112011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->drain_cv_lock);
98212011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: unreg callback for chan %ld after "
98312011SSriharsha.Basavapatna@Sun.COM "timeout", __func__, ldcp->ldc_id);
9845373Sraghuram }
9855373Sraghuram
9865373Sraghuram D1(vswp, "%s: exit", __func__);
9875373Sraghuram }
9885373Sraghuram
9895373Sraghuram /*
9905373Sraghuram * Wait until all tasks which reference this port have completed.
9915373Sraghuram *
9925373Sraghuram * Prior to this function being invoked each channel under this port
9935373Sraghuram * should have been quiesced via ldc_set_cb_mode(DISABLE).
9945373Sraghuram */
9959217SWentao.Yang@Sun.COM static void
vsw_drain_port_taskq(vsw_port_t * port)9965373Sraghuram vsw_drain_port_taskq(vsw_port_t *port)
9975373Sraghuram {
9985373Sraghuram vsw_t *vswp = port->p_vswp;
9995373Sraghuram
10005373Sraghuram D1(vswp, "%s: enter", __func__);
10015373Sraghuram
10025373Sraghuram /*
10035373Sraghuram * Mark the port as in the process of being detached, and
10045373Sraghuram * dispatch a marker task to the queue so we know when all
10055373Sraghuram * relevant tasks have completed.
10065373Sraghuram */
10075373Sraghuram mutex_enter(&port->state_lock);
10085373Sraghuram port->state = VSW_PORT_DETACHING;
10095373Sraghuram
10105373Sraghuram if ((vswp->taskq_p == NULL) ||
10115373Sraghuram (ddi_taskq_dispatch(vswp->taskq_p, vsw_marker_task,
10125373Sraghuram port, DDI_NOSLEEP) != DDI_SUCCESS)) {
10139217SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!vsw%d: unable to dispatch marker task",
10149217SWentao.Yang@Sun.COM vswp->instance);
10155373Sraghuram mutex_exit(&port->state_lock);
10169217SWentao.Yang@Sun.COM return;
10175373Sraghuram }
10185373Sraghuram
10195373Sraghuram /*
10205373Sraghuram * Wait for the marker task to finish.
10215373Sraghuram */
10225373Sraghuram while (port->state != VSW_PORT_DETACHABLE)
10235373Sraghuram cv_wait(&port->state_cv, &port->state_lock);
10245373Sraghuram
10255373Sraghuram mutex_exit(&port->state_lock);
10265373Sraghuram
10275373Sraghuram D1(vswp, "%s: exit", __func__);
10285373Sraghuram }
10295373Sraghuram
10305373Sraghuram static void
vsw_marker_task(void * arg)10315373Sraghuram vsw_marker_task(void *arg)
10325373Sraghuram {
10335373Sraghuram vsw_port_t *port = arg;
10345373Sraghuram vsw_t *vswp = port->p_vswp;
10355373Sraghuram
10365373Sraghuram D1(vswp, "%s: enter", __func__);
10375373Sraghuram
10385373Sraghuram mutex_enter(&port->state_lock);
10395373Sraghuram
10405373Sraghuram /*
10415373Sraghuram * No further tasks should be dispatched which reference
10425373Sraghuram * this port so ok to mark it as safe to detach.
10435373Sraghuram */
10445373Sraghuram port->state = VSW_PORT_DETACHABLE;
10455373Sraghuram
10465373Sraghuram cv_signal(&port->state_cv);
10475373Sraghuram
10485373Sraghuram mutex_exit(&port->state_lock);
10495373Sraghuram
10505373Sraghuram D1(vswp, "%s: exit", __func__);
10515373Sraghuram }
10525373Sraghuram
10535373Sraghuram vsw_port_t *
vsw_lookup_port(vsw_t * vswp,int p_instance)10545373Sraghuram vsw_lookup_port(vsw_t *vswp, int p_instance)
10555373Sraghuram {
10565373Sraghuram vsw_port_list_t *plist = &vswp->plist;
10575373Sraghuram vsw_port_t *port;
10585373Sraghuram
10595373Sraghuram for (port = plist->head; port != NULL; port = port->p_next) {
10605373Sraghuram if (port->p_instance == p_instance) {
10615373Sraghuram D2(vswp, "vsw_lookup_port: found p_instance\n");
10625373Sraghuram return (port);
10635373Sraghuram }
10645373Sraghuram }
10655373Sraghuram
10665373Sraghuram return (NULL);
10675373Sraghuram }
10685373Sraghuram
10696419Ssb155480 void
vsw_vlan_unaware_port_reset(vsw_port_t * portp)10706419Ssb155480 vsw_vlan_unaware_port_reset(vsw_port_t *portp)
10716419Ssb155480 {
107212011SSriharsha.Basavapatna@Sun.COM vsw_ldc_t *ldcp = portp->ldcp;
10736419Ssb155480
10746419Ssb155480 mutex_enter(&ldcp->ldc_cblock);
10756419Ssb155480
10766419Ssb155480 /*
10776419Ssb155480 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
10786419Ssb155480 * the connection. See comments in vsw_set_vnet_proto_ops().
10796419Ssb155480 */
10806419Ssb155480 if (ldcp->hphase == VSW_MILESTONE4 && VSW_VER_LT(ldcp, 1, 3) &&
10816419Ssb155480 portp->nvids != 0) {
10826419Ssb155480 vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
10836419Ssb155480 }
10846419Ssb155480
10856419Ssb155480 mutex_exit(&ldcp->ldc_cblock);
10866419Ssb155480 }
10876419Ssb155480
10886495Sspeer void
vsw_hio_port_reset(vsw_port_t * portp,boolean_t immediate)10896724Sraghuram vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate)
10906495Sspeer {
109112011SSriharsha.Basavapatna@Sun.COM vsw_ldc_t *ldcp = portp->ldcp;
10926495Sspeer
10936495Sspeer mutex_enter(&ldcp->ldc_cblock);
10946495Sspeer
10956495Sspeer /*
10966495Sspeer * If the peer is HybridIO capable (ver >= 1.3), reset channel
10976495Sspeer * to trigger re-negotiation, which inturn trigger HybridIO
10986495Sspeer * setup/cleanup.
10996495Sspeer */
11006495Sspeer if ((ldcp->hphase == VSW_MILESTONE4) &&
11016495Sspeer (portp->p_hio_capable == B_TRUE)) {
11026724Sraghuram if (immediate == B_TRUE) {
11036724Sraghuram (void) ldc_down(ldcp->ldc_handle);
11046724Sraghuram } else {
11056724Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
11066724Sraghuram }
11076495Sspeer }
11086495Sspeer
11096495Sspeer mutex_exit(&ldcp->ldc_cblock);
11106495Sspeer }
11116495Sspeer
11127529SSriharsha.Basavapatna@Sun.COM void
vsw_port_reset(vsw_port_t * portp)11137529SSriharsha.Basavapatna@Sun.COM vsw_port_reset(vsw_port_t *portp)
11147529SSriharsha.Basavapatna@Sun.COM {
111512011SSriharsha.Basavapatna@Sun.COM vsw_ldc_t *ldcp = portp->ldcp;
11167529SSriharsha.Basavapatna@Sun.COM
11177529SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->ldc_cblock);
11187529SSriharsha.Basavapatna@Sun.COM
11197529SSriharsha.Basavapatna@Sun.COM /*
11207529SSriharsha.Basavapatna@Sun.COM * reset channel and terminate the connection.
11217529SSriharsha.Basavapatna@Sun.COM */
11227529SSriharsha.Basavapatna@Sun.COM vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
11237529SSriharsha.Basavapatna@Sun.COM
11247529SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->ldc_cblock);
11257529SSriharsha.Basavapatna@Sun.COM }
11267529SSriharsha.Basavapatna@Sun.COM
11277529SSriharsha.Basavapatna@Sun.COM void
vsw_reset_ports(vsw_t * vswp)11287529SSriharsha.Basavapatna@Sun.COM vsw_reset_ports(vsw_t *vswp)
11297529SSriharsha.Basavapatna@Sun.COM {
11307529SSriharsha.Basavapatna@Sun.COM vsw_port_list_t *plist = &vswp->plist;
11317529SSriharsha.Basavapatna@Sun.COM vsw_port_t *portp;
11327529SSriharsha.Basavapatna@Sun.COM
11337529SSriharsha.Basavapatna@Sun.COM READ_ENTER(&plist->lockrw);
11347529SSriharsha.Basavapatna@Sun.COM for (portp = plist->head; portp != NULL; portp = portp->p_next) {
11357529SSriharsha.Basavapatna@Sun.COM if ((portp->p_hio_capable) && (portp->p_hio_enabled)) {
11367529SSriharsha.Basavapatna@Sun.COM vsw_hio_stop_port(portp);
11377529SSriharsha.Basavapatna@Sun.COM }
11387529SSriharsha.Basavapatna@Sun.COM vsw_port_reset(portp);
11397529SSriharsha.Basavapatna@Sun.COM }
11407529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&plist->lockrw);
11417529SSriharsha.Basavapatna@Sun.COM }
11427529SSriharsha.Basavapatna@Sun.COM
11439336SSriharsha.Basavapatna@Sun.COM static void
vsw_send_physlink_msg(vsw_ldc_t * ldcp,link_state_t plink_state)11449336SSriharsha.Basavapatna@Sun.COM vsw_send_physlink_msg(vsw_ldc_t *ldcp, link_state_t plink_state)
11459336SSriharsha.Basavapatna@Sun.COM {
11469336SSriharsha.Basavapatna@Sun.COM vnet_physlink_msg_t msg;
11479336SSriharsha.Basavapatna@Sun.COM vnet_physlink_msg_t *msgp = &msg;
11489336SSriharsha.Basavapatna@Sun.COM uint32_t physlink_info = 0;
11499336SSriharsha.Basavapatna@Sun.COM
11509336SSriharsha.Basavapatna@Sun.COM if (plink_state == LINK_STATE_UP) {
11519336SSriharsha.Basavapatna@Sun.COM physlink_info |= VNET_PHYSLINK_STATE_UP;
11529336SSriharsha.Basavapatna@Sun.COM } else {
11539336SSriharsha.Basavapatna@Sun.COM physlink_info |= VNET_PHYSLINK_STATE_DOWN;
11549336SSriharsha.Basavapatna@Sun.COM }
11559336SSriharsha.Basavapatna@Sun.COM
11569336SSriharsha.Basavapatna@Sun.COM msgp->tag.vio_msgtype = VIO_TYPE_CTRL;
11579336SSriharsha.Basavapatna@Sun.COM msgp->tag.vio_subtype = VIO_SUBTYPE_INFO;
11589336SSriharsha.Basavapatna@Sun.COM msgp->tag.vio_subtype_env = VNET_PHYSLINK_INFO;
11599336SSriharsha.Basavapatna@Sun.COM msgp->tag.vio_sid = ldcp->local_session;
11609336SSriharsha.Basavapatna@Sun.COM msgp->physlink_info = physlink_info;
11619336SSriharsha.Basavapatna@Sun.COM
11629336SSriharsha.Basavapatna@Sun.COM (void) vsw_send_msg(ldcp, msgp, sizeof (msg), B_TRUE);
11639336SSriharsha.Basavapatna@Sun.COM }
11649336SSriharsha.Basavapatna@Sun.COM
11659336SSriharsha.Basavapatna@Sun.COM static void
vsw_port_physlink_update(vsw_port_t * portp)11669336SSriharsha.Basavapatna@Sun.COM vsw_port_physlink_update(vsw_port_t *portp)
11679336SSriharsha.Basavapatna@Sun.COM {
11689336SSriharsha.Basavapatna@Sun.COM vsw_ldc_t *ldcp;
11699336SSriharsha.Basavapatna@Sun.COM vsw_t *vswp;
11709336SSriharsha.Basavapatna@Sun.COM
11719336SSriharsha.Basavapatna@Sun.COM vswp = portp->p_vswp;
117212011SSriharsha.Basavapatna@Sun.COM ldcp = portp->ldcp;
11739336SSriharsha.Basavapatna@Sun.COM
11749336SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->ldc_cblock);
11759336SSriharsha.Basavapatna@Sun.COM
11769336SSriharsha.Basavapatna@Sun.COM /*
11779336SSriharsha.Basavapatna@Sun.COM * If handshake has completed successfully and if the vnet device
11789336SSriharsha.Basavapatna@Sun.COM * has negotiated to get physical link state updates, send a message
11799336SSriharsha.Basavapatna@Sun.COM * with the current state.
11809336SSriharsha.Basavapatna@Sun.COM */
11819336SSriharsha.Basavapatna@Sun.COM if (ldcp->hphase == VSW_MILESTONE4 && ldcp->pls_negotiated == B_TRUE) {
11829336SSriharsha.Basavapatna@Sun.COM vsw_send_physlink_msg(ldcp, vswp->phys_link_state);
11839336SSriharsha.Basavapatna@Sun.COM }
11849336SSriharsha.Basavapatna@Sun.COM
11859336SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->ldc_cblock);
11869336SSriharsha.Basavapatna@Sun.COM }
11879336SSriharsha.Basavapatna@Sun.COM
11889336SSriharsha.Basavapatna@Sun.COM void
vsw_physlink_update_ports(vsw_t * vswp)11899336SSriharsha.Basavapatna@Sun.COM vsw_physlink_update_ports(vsw_t *vswp)
11909336SSriharsha.Basavapatna@Sun.COM {
11919336SSriharsha.Basavapatna@Sun.COM vsw_port_list_t *plist = &vswp->plist;
11929336SSriharsha.Basavapatna@Sun.COM vsw_port_t *portp;
11939336SSriharsha.Basavapatna@Sun.COM
11949336SSriharsha.Basavapatna@Sun.COM READ_ENTER(&plist->lockrw);
11959336SSriharsha.Basavapatna@Sun.COM for (portp = plist->head; portp != NULL; portp = portp->p_next) {
11969336SSriharsha.Basavapatna@Sun.COM vsw_port_physlink_update(portp);
11979336SSriharsha.Basavapatna@Sun.COM }
11989336SSriharsha.Basavapatna@Sun.COM RW_EXIT(&plist->lockrw);
11999336SSriharsha.Basavapatna@Sun.COM }
12007529SSriharsha.Basavapatna@Sun.COM
12015373Sraghuram /*
12025373Sraghuram * Search for and remove the specified port from the port
12035373Sraghuram * list. Returns 0 if able to locate and remove port, otherwise
12045373Sraghuram * returns 1.
12055373Sraghuram */
12065373Sraghuram static int
vsw_plist_del_node(vsw_t * vswp,vsw_port_t * port)12075373Sraghuram vsw_plist_del_node(vsw_t *vswp, vsw_port_t *port)
12085373Sraghuram {
12095373Sraghuram vsw_port_list_t *plist = &vswp->plist;
12105373Sraghuram vsw_port_t *curr_p, *prev_p;
12115373Sraghuram
12125373Sraghuram if (plist->head == NULL)
12135373Sraghuram return (1);
12145373Sraghuram
12155373Sraghuram curr_p = prev_p = plist->head;
12165373Sraghuram
12175373Sraghuram while (curr_p != NULL) {
12185373Sraghuram if (curr_p == port) {
12195373Sraghuram if (prev_p == curr_p) {
12205373Sraghuram plist->head = curr_p->p_next;
12215373Sraghuram } else {
12225373Sraghuram prev_p->p_next = curr_p->p_next;
12235373Sraghuram }
12245373Sraghuram plist->num_ports--;
12255373Sraghuram break;
12265373Sraghuram } else {
12275373Sraghuram prev_p = curr_p;
12285373Sraghuram curr_p = curr_p->p_next;
12295373Sraghuram }
12305373Sraghuram }
12315373Sraghuram return (0);
12325373Sraghuram }
12335373Sraghuram
12345373Sraghuram /*
12355373Sraghuram * Interrupt handler for ldc messages.
12365373Sraghuram */
12375373Sraghuram static uint_t
vsw_ldc_cb(uint64_t event,caddr_t arg)12385373Sraghuram vsw_ldc_cb(uint64_t event, caddr_t arg)
12395373Sraghuram {
12405373Sraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
12415373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
12425373Sraghuram
12435373Sraghuram D1(vswp, "%s: enter: ldcid (%lld)\n", __func__, ldcp->ldc_id);
12445373Sraghuram
12455373Sraghuram mutex_enter(&ldcp->ldc_cblock);
12465373Sraghuram ldcp->ldc_stats.callbacks++;
12475373Sraghuram
12485373Sraghuram mutex_enter(&ldcp->status_lock);
12495373Sraghuram if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
12505373Sraghuram mutex_exit(&ldcp->status_lock);
12515373Sraghuram mutex_exit(&ldcp->ldc_cblock);
12525373Sraghuram return (LDC_SUCCESS);
12535373Sraghuram }
12545373Sraghuram mutex_exit(&ldcp->status_lock);
12555373Sraghuram
12565373Sraghuram if (event & LDC_EVT_UP) {
12575373Sraghuram /*
12585373Sraghuram * Channel has come up.
12595373Sraghuram */
12605373Sraghuram D2(vswp, "%s: id(%ld) event(%llx) UP: status(%ld)",
12615373Sraghuram __func__, ldcp->ldc_id, event, ldcp->ldc_status);
12625373Sraghuram
12635373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_UP);
12645373Sraghuram
12655373Sraghuram ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
12665373Sraghuram }
12675373Sraghuram
12685373Sraghuram if (event & LDC_EVT_READ) {
12695373Sraghuram /*
12705373Sraghuram * Data available for reading.
12715373Sraghuram */
12725373Sraghuram D2(vswp, "%s: id(ld) event(%llx) data READ",
12735373Sraghuram __func__, ldcp->ldc_id, event);
12745373Sraghuram
127512011SSriharsha.Basavapatna@Sun.COM vsw_process_evt_read(ldcp);
12765373Sraghuram
12775373Sraghuram ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
12785373Sraghuram
12795373Sraghuram goto vsw_cb_exit;
12805373Sraghuram }
12815373Sraghuram
12825373Sraghuram if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) {
12835373Sraghuram D2(vswp, "%s: id(%ld) event (%lx) DOWN/RESET: status(%ld)",
12845373Sraghuram __func__, ldcp->ldc_id, event, ldcp->ldc_status);
12855373Sraghuram
12865373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
12875373Sraghuram }
12885373Sraghuram
12895373Sraghuram /*
12905373Sraghuram * Catch either LDC_EVT_WRITE which we don't support or any
12915373Sraghuram * unknown event.
12925373Sraghuram */
12935373Sraghuram if (event &
12945373Sraghuram ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ)) {
12955373Sraghuram DERR(vswp, "%s: id(%ld) Unexpected event=(%llx) status(%ld)",
12965373Sraghuram __func__, ldcp->ldc_id, event, ldcp->ldc_status);
12975373Sraghuram }
12985373Sraghuram
12995373Sraghuram vsw_cb_exit:
13005373Sraghuram mutex_exit(&ldcp->ldc_cblock);
13015373Sraghuram
13025373Sraghuram /*
13035373Sraghuram * Let the drain function know we are finishing if it
13045373Sraghuram * is waiting.
13055373Sraghuram */
13065373Sraghuram mutex_enter(&ldcp->drain_cv_lock);
13075373Sraghuram if (ldcp->drain_state == VSW_LDC_DRAINING)
13085373Sraghuram cv_signal(&ldcp->drain_cv);
13095373Sraghuram mutex_exit(&ldcp->drain_cv_lock);
13105373Sraghuram
13115373Sraghuram return (LDC_SUCCESS);
13125373Sraghuram }
13135373Sraghuram
13145373Sraghuram /*
13155373Sraghuram * Reinitialise data structures associated with the channel.
13165373Sraghuram */
13175373Sraghuram static void
vsw_ldc_reinit(vsw_ldc_t * ldcp)13185373Sraghuram vsw_ldc_reinit(vsw_ldc_t *ldcp)
13195373Sraghuram {
13205373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
13215373Sraghuram vsw_port_t *port;
13225373Sraghuram
13235373Sraghuram D1(vswp, "%s: enter", __func__);
13245373Sraghuram
13255373Sraghuram port = ldcp->ldc_port;
13265373Sraghuram
13275373Sraghuram D2(vswp, "%s: in 0x%llx : out 0x%llx", __func__,
13285373Sraghuram ldcp->lane_in.lstate, ldcp->lane_out.lstate);
13295373Sraghuram
13305373Sraghuram vsw_free_lane_resources(ldcp, INBOUND);
13315373Sraghuram vsw_free_lane_resources(ldcp, OUTBOUND);
13325373Sraghuram
13335373Sraghuram ldcp->lane_in.lstate = 0;
13345373Sraghuram ldcp->lane_out.lstate = 0;
13355373Sraghuram
13365373Sraghuram /*
13375373Sraghuram * Remove parent port from any multicast groups
13385373Sraghuram * it may have registered with. Client must resend
13395373Sraghuram * multicast add command after handshake completes.
13405373Sraghuram */
13415373Sraghuram vsw_del_mcst_port(port);
13425373Sraghuram
13435373Sraghuram ldcp->peer_session = 0;
13445373Sraghuram ldcp->session_status = 0;
13455373Sraghuram ldcp->hcnt = 0;
13465373Sraghuram ldcp->hphase = VSW_MILESTONE0;
13475935Ssb155480
13485935Ssb155480 vsw_reset_vnet_proto_ops(ldcp);
13495373Sraghuram
13505373Sraghuram D1(vswp, "%s: exit", __func__);
13515373Sraghuram }
13525373Sraghuram
13535373Sraghuram /*
13545373Sraghuram * Process a connection event.
13555373Sraghuram */
135612011SSriharsha.Basavapatna@Sun.COM void
vsw_process_conn_evt(vsw_ldc_t * ldcp,uint16_t evt)13575373Sraghuram vsw_process_conn_evt(vsw_ldc_t *ldcp, uint16_t evt)
13585373Sraghuram {
13595373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
13605373Sraghuram vsw_conn_evt_t *conn = NULL;
13615373Sraghuram
13625373Sraghuram D1(vswp, "%s: enter", __func__);
13635373Sraghuram
13645373Sraghuram /*
13655373Sraghuram * Check if either a reset or restart event is pending
13665373Sraghuram * or in progress. If so just return.
13675373Sraghuram *
13685373Sraghuram * A VSW_CONN_RESET event originates either with a LDC_RESET_EVT
13695373Sraghuram * being received by the callback handler, or a ECONNRESET error
13705373Sraghuram * code being returned from a ldc_read() or ldc_write() call.
13715373Sraghuram *
13725373Sraghuram * A VSW_CONN_RESTART event occurs when some error checking code
13735373Sraghuram * decides that there is a problem with data from the channel,
13745373Sraghuram * and that the handshake should be restarted.
13755373Sraghuram */
13765373Sraghuram if (((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART)) &&
13775373Sraghuram (ldstub((uint8_t *)&ldcp->reset_active)))
13785373Sraghuram return;
13795373Sraghuram
13805373Sraghuram /*
13815373Sraghuram * If it is an LDC_UP event we first check the recorded
13825373Sraghuram * state of the channel. If this is UP then we know that
13835373Sraghuram * the channel moving to the UP state has already been dealt
13845373Sraghuram * with and don't need to dispatch a new task.
13855373Sraghuram *
13865373Sraghuram * The reason for this check is that when we do a ldc_up(),
13875373Sraghuram * depending on the state of the peer, we may or may not get
13885373Sraghuram * a LDC_UP event. As we can't depend on getting a LDC_UP evt
13895373Sraghuram * every time we do ldc_up() we explicitly check the channel
13905373Sraghuram * status to see has it come up (ldc_up() is asynch and will
13915373Sraghuram * complete at some undefined time), and take the appropriate
13925373Sraghuram * action.
13935373Sraghuram *
13945373Sraghuram * The flip side of this is that we may get a LDC_UP event
13955373Sraghuram * when we have already seen that the channel is up and have
13965373Sraghuram * dealt with that.
13975373Sraghuram */
13985373Sraghuram mutex_enter(&ldcp->status_lock);
13995373Sraghuram if (evt == VSW_CONN_UP) {
14005373Sraghuram if ((ldcp->ldc_status == LDC_UP) || (ldcp->reset_active != 0)) {
14015373Sraghuram mutex_exit(&ldcp->status_lock);
14025373Sraghuram return;
14035373Sraghuram }
14045373Sraghuram }
14055373Sraghuram mutex_exit(&ldcp->status_lock);
14065373Sraghuram
14075373Sraghuram /*
14085373Sraghuram * The transaction group id allows us to identify and discard
14095373Sraghuram * any tasks which are still pending on the taskq and refer
14105373Sraghuram * to the handshake session we are about to restart or reset.
14115373Sraghuram * These stale messages no longer have any real meaning.
14125373Sraghuram */
14135373Sraghuram (void) atomic_inc_32(&ldcp->hss_id);
14145373Sraghuram
14155373Sraghuram ASSERT(vswp->taskq_p != NULL);
14165373Sraghuram
14175373Sraghuram if ((conn = kmem_zalloc(sizeof (vsw_conn_evt_t), KM_NOSLEEP)) == NULL) {
14185373Sraghuram cmn_err(CE_WARN, "!vsw%d: unable to allocate memory for"
14195373Sraghuram " connection event", vswp->instance);
14205373Sraghuram goto err_exit;
14215373Sraghuram }
14225373Sraghuram
14235373Sraghuram conn->evt = evt;
14245373Sraghuram conn->ldcp = ldcp;
14255373Sraghuram
14265373Sraghuram if (ddi_taskq_dispatch(vswp->taskq_p, vsw_conn_task, conn,
14275373Sraghuram DDI_NOSLEEP) != DDI_SUCCESS) {
14285373Sraghuram cmn_err(CE_WARN, "!vsw%d: Can't dispatch connection task",
14295373Sraghuram vswp->instance);
14305373Sraghuram
14315373Sraghuram kmem_free(conn, sizeof (vsw_conn_evt_t));
14325373Sraghuram goto err_exit;
14335373Sraghuram }
14345373Sraghuram
14355373Sraghuram D1(vswp, "%s: exit", __func__);
14365373Sraghuram return;
14375373Sraghuram
14385373Sraghuram err_exit:
14395373Sraghuram /*
14405373Sraghuram * Have mostly likely failed due to memory shortage. Clear the flag so
14415373Sraghuram * that future requests will at least be attempted and will hopefully
14425373Sraghuram * succeed.
14435373Sraghuram */
14445373Sraghuram if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART))
14455373Sraghuram ldcp->reset_active = 0;
14465373Sraghuram }
14475373Sraghuram
14485373Sraghuram /*
14495373Sraghuram * Deal with events relating to a connection. Invoked from a taskq.
14505373Sraghuram */
14515373Sraghuram static void
vsw_conn_task(void * arg)14525373Sraghuram vsw_conn_task(void *arg)
14535373Sraghuram {
14545373Sraghuram vsw_conn_evt_t *conn = (vsw_conn_evt_t *)arg;
14555373Sraghuram vsw_ldc_t *ldcp = NULL;
14566495Sspeer vsw_port_t *portp;
14575373Sraghuram vsw_t *vswp = NULL;
14585373Sraghuram uint16_t evt;
14595373Sraghuram ldc_status_t curr_status;
14605373Sraghuram
14615373Sraghuram ldcp = conn->ldcp;
14625373Sraghuram evt = conn->evt;
14635373Sraghuram vswp = ldcp->ldc_vswp;
14646495Sspeer portp = ldcp->ldc_port;
14655373Sraghuram
14665373Sraghuram D1(vswp, "%s: enter", __func__);
14675373Sraghuram
14685373Sraghuram /* can safely free now have copied out data */
14695373Sraghuram kmem_free(conn, sizeof (vsw_conn_evt_t));
14705373Sraghuram
147112011SSriharsha.Basavapatna@Sun.COM if (ldcp->rcv_thread != NULL) {
147212011SSriharsha.Basavapatna@Sun.COM vsw_stop_rcv_thread(ldcp);
147312011SSriharsha.Basavapatna@Sun.COM } else if (ldcp->msg_thread != NULL) {
147412011SSriharsha.Basavapatna@Sun.COM vsw_stop_msg_thread(ldcp);
147512011SSriharsha.Basavapatna@Sun.COM }
147612011SSriharsha.Basavapatna@Sun.COM
14775373Sraghuram mutex_enter(&ldcp->status_lock);
14785373Sraghuram if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) {
14795373Sraghuram cmn_err(CE_WARN, "!vsw%d: Unable to read status of "
14805373Sraghuram "channel %ld", vswp->instance, ldcp->ldc_id);
14815373Sraghuram mutex_exit(&ldcp->status_lock);
14825373Sraghuram return;
14835373Sraghuram }
14845373Sraghuram
14855373Sraghuram /*
14865373Sraghuram * If we wish to restart the handshake on this channel, then if
14875373Sraghuram * the channel is UP we bring it DOWN to flush the underlying
14885373Sraghuram * ldc queue.
14895373Sraghuram */
14905373Sraghuram if ((evt == VSW_CONN_RESTART) && (curr_status == LDC_UP))
14915373Sraghuram (void) ldc_down(ldcp->ldc_handle);
14925373Sraghuram
14936724Sraghuram if ((portp->p_hio_capable) && (portp->p_hio_enabled)) {
14946495Sspeer vsw_hio_stop(vswp, ldcp);
14956495Sspeer }
14966495Sspeer
14975373Sraghuram /*
14985373Sraghuram * re-init all the associated data structures.
14995373Sraghuram */
15005373Sraghuram vsw_ldc_reinit(ldcp);
15015373Sraghuram
15025373Sraghuram /*
15035373Sraghuram * Bring the channel back up (note it does no harm to
15045373Sraghuram * do this even if the channel is already UP, Just
15055373Sraghuram * becomes effectively a no-op).
15065373Sraghuram */
15075373Sraghuram (void) ldc_up(ldcp->ldc_handle);
15085373Sraghuram
15095373Sraghuram /*
15105373Sraghuram * Check if channel is now UP. This will only happen if
15115373Sraghuram * peer has also done a ldc_up().
15125373Sraghuram */
15135373Sraghuram if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) {
15145373Sraghuram cmn_err(CE_WARN, "!vsw%d: Unable to read status of "
15155373Sraghuram "channel %ld", vswp->instance, ldcp->ldc_id);
15165373Sraghuram mutex_exit(&ldcp->status_lock);
15175373Sraghuram return;
15185373Sraghuram }
15195373Sraghuram
15205373Sraghuram ldcp->ldc_status = curr_status;
15215373Sraghuram
15225373Sraghuram /* channel UP so restart handshake by sending version info */
15235373Sraghuram if (curr_status == LDC_UP) {
15245373Sraghuram if (ldcp->hcnt++ > vsw_num_handshakes) {
15255373Sraghuram cmn_err(CE_WARN, "!vsw%d: exceeded number of permitted"
15265373Sraghuram " handshake attempts (%d) on channel %ld",
15275373Sraghuram vswp->instance, ldcp->hcnt, ldcp->ldc_id);
15285373Sraghuram mutex_exit(&ldcp->status_lock);
15295373Sraghuram return;
15305373Sraghuram }
15315373Sraghuram
15325935Ssb155480 if (vsw_obp_ver_proto_workaround == B_FALSE &&
15335935Ssb155480 (ddi_taskq_dispatch(vswp->taskq_p, vsw_send_ver, ldcp,
15345935Ssb155480 DDI_NOSLEEP) != DDI_SUCCESS)) {
15355373Sraghuram cmn_err(CE_WARN, "!vsw%d: Can't dispatch version task",
15365373Sraghuram vswp->instance);
15375373Sraghuram
15385373Sraghuram /*
15395373Sraghuram * Don't count as valid restart attempt if couldn't
15405373Sraghuram * send version msg.
15415373Sraghuram */
15425373Sraghuram if (ldcp->hcnt > 0)
15435373Sraghuram ldcp->hcnt--;
15445373Sraghuram }
15455373Sraghuram }
15465373Sraghuram
15475373Sraghuram /*
15485373Sraghuram * Mark that the process is complete by clearing the flag.
15495373Sraghuram *
15505373Sraghuram * Note is it possible that the taskq dispatch above may have failed,
15515373Sraghuram * most likely due to memory shortage. We still clear the flag so
15525373Sraghuram * future attempts will at least be attempted and will hopefully
15535373Sraghuram * succeed.
15545373Sraghuram */
15555373Sraghuram if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART))
15565373Sraghuram ldcp->reset_active = 0;
15575373Sraghuram
15585373Sraghuram mutex_exit(&ldcp->status_lock);
15595373Sraghuram
15605373Sraghuram D1(vswp, "%s: exit", __func__);
15615373Sraghuram }
15625373Sraghuram
15635373Sraghuram /*
15645373Sraghuram * returns 0 if legal for event signified by flag to have
15655373Sraghuram * occured at the time it did. Otherwise returns 1.
15665373Sraghuram */
15675373Sraghuram int
vsw_check_flag(vsw_ldc_t * ldcp,int dir,uint64_t flag)15685373Sraghuram vsw_check_flag(vsw_ldc_t *ldcp, int dir, uint64_t flag)
15695373Sraghuram {
15705373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
15715373Sraghuram uint64_t state;
15725373Sraghuram uint64_t phase;
15735373Sraghuram
15745373Sraghuram if (dir == INBOUND)
15755373Sraghuram state = ldcp->lane_in.lstate;
15765373Sraghuram else
15775373Sraghuram state = ldcp->lane_out.lstate;
15785373Sraghuram
15795373Sraghuram phase = ldcp->hphase;
15805373Sraghuram
15815373Sraghuram switch (flag) {
15825373Sraghuram case VSW_VER_INFO_RECV:
15835373Sraghuram if (phase > VSW_MILESTONE0) {
15845373Sraghuram DERR(vswp, "vsw_check_flag (%d): VER_INFO_RECV"
15855373Sraghuram " when in state %d\n", ldcp->ldc_id, phase);
15865373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
15875373Sraghuram return (1);
15885373Sraghuram }
15895373Sraghuram break;
15905373Sraghuram
15915373Sraghuram case VSW_VER_ACK_RECV:
15925373Sraghuram case VSW_VER_NACK_RECV:
15935373Sraghuram if (!(state & VSW_VER_INFO_SENT)) {
15945373Sraghuram DERR(vswp, "vsw_check_flag (%d): spurious VER_ACK or "
15955373Sraghuram "VER_NACK when in state %d\n", ldcp->ldc_id, phase);
15965373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
15975373Sraghuram return (1);
15985373Sraghuram } else
15995373Sraghuram state &= ~VSW_VER_INFO_SENT;
16005373Sraghuram break;
16015373Sraghuram
16025373Sraghuram case VSW_ATTR_INFO_RECV:
16035373Sraghuram if ((phase < VSW_MILESTONE1) || (phase >= VSW_MILESTONE2)) {
16045373Sraghuram DERR(vswp, "vsw_check_flag (%d): ATTR_INFO_RECV"
16055373Sraghuram " when in state %d\n", ldcp->ldc_id, phase);
16065373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16075373Sraghuram return (1);
16085373Sraghuram }
16095373Sraghuram break;
16105373Sraghuram
16115373Sraghuram case VSW_ATTR_ACK_RECV:
16125373Sraghuram case VSW_ATTR_NACK_RECV:
16135373Sraghuram if (!(state & VSW_ATTR_INFO_SENT)) {
16145373Sraghuram DERR(vswp, "vsw_check_flag (%d): spurious ATTR_ACK"
16155373Sraghuram " or ATTR_NACK when in state %d\n",
16165373Sraghuram ldcp->ldc_id, phase);
16175373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16185373Sraghuram return (1);
16195373Sraghuram } else
16205373Sraghuram state &= ~VSW_ATTR_INFO_SENT;
16215373Sraghuram break;
16225373Sraghuram
16235373Sraghuram case VSW_DRING_INFO_RECV:
16245373Sraghuram if (phase < VSW_MILESTONE1) {
16255373Sraghuram DERR(vswp, "vsw_check_flag (%d): DRING_INFO_RECV"
16265373Sraghuram " when in state %d\n", ldcp->ldc_id, phase);
16275373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16285373Sraghuram return (1);
16295373Sraghuram }
16305373Sraghuram break;
16315373Sraghuram
16325373Sraghuram case VSW_DRING_ACK_RECV:
16335373Sraghuram case VSW_DRING_NACK_RECV:
16345373Sraghuram if (!(state & VSW_DRING_INFO_SENT)) {
16355373Sraghuram DERR(vswp, "vsw_check_flag (%d): spurious DRING_ACK "
16365373Sraghuram " or DRING_NACK when in state %d\n",
16375373Sraghuram ldcp->ldc_id, phase);
16385373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16395373Sraghuram return (1);
16405373Sraghuram } else
16415373Sraghuram state &= ~VSW_DRING_INFO_SENT;
16425373Sraghuram break;
16435373Sraghuram
16445373Sraghuram case VSW_RDX_INFO_RECV:
16455373Sraghuram if (phase < VSW_MILESTONE3) {
16465373Sraghuram DERR(vswp, "vsw_check_flag (%d): RDX_INFO_RECV"
16475373Sraghuram " when in state %d\n", ldcp->ldc_id, phase);
16485373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16495373Sraghuram return (1);
16505373Sraghuram }
16515373Sraghuram break;
16525373Sraghuram
16535373Sraghuram case VSW_RDX_ACK_RECV:
16545373Sraghuram case VSW_RDX_NACK_RECV:
16555373Sraghuram if (!(state & VSW_RDX_INFO_SENT)) {
16565373Sraghuram DERR(vswp, "vsw_check_flag (%d): spurious RDX_ACK or "
16575373Sraghuram "RDX_NACK when in state %d\n", ldcp->ldc_id, phase);
16585373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16595373Sraghuram return (1);
16605373Sraghuram } else
16615373Sraghuram state &= ~VSW_RDX_INFO_SENT;
16625373Sraghuram break;
16635373Sraghuram
16645373Sraghuram case VSW_MCST_INFO_RECV:
16655373Sraghuram if (phase < VSW_MILESTONE3) {
16665373Sraghuram DERR(vswp, "vsw_check_flag (%d): VSW_MCST_INFO_RECV"
16675373Sraghuram " when in state %d\n", ldcp->ldc_id, phase);
16685373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
16695373Sraghuram return (1);
16705373Sraghuram }
16715373Sraghuram break;
16725373Sraghuram
16735373Sraghuram default:
16745373Sraghuram DERR(vswp, "vsw_check_flag (%lld): unknown flag (%llx)",
16755373Sraghuram ldcp->ldc_id, flag);
16765373Sraghuram return (1);
16775373Sraghuram }
16785373Sraghuram
16795373Sraghuram if (dir == INBOUND)
16805373Sraghuram ldcp->lane_in.lstate = state;
16815373Sraghuram else
16825373Sraghuram ldcp->lane_out.lstate = state;
16835373Sraghuram
16845373Sraghuram D1(vswp, "vsw_check_flag (chan %lld): exit", ldcp->ldc_id);
16855373Sraghuram
16865373Sraghuram return (0);
16875373Sraghuram }
16885373Sraghuram
16895373Sraghuram void
vsw_next_milestone(vsw_ldc_t * ldcp)16905373Sraghuram vsw_next_milestone(vsw_ldc_t *ldcp)
16915373Sraghuram {
16925373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
16936495Sspeer vsw_port_t *portp = ldcp->ldc_port;
169412011SSriharsha.Basavapatna@Sun.COM lane_t *lane_out = &ldcp->lane_out;
169512011SSriharsha.Basavapatna@Sun.COM lane_t *lane_in = &ldcp->lane_in;
16965373Sraghuram
16975373Sraghuram D1(vswp, "%s (chan %lld): enter (phase %ld)", __func__,
16985373Sraghuram ldcp->ldc_id, ldcp->hphase);
16995373Sraghuram
170012011SSriharsha.Basavapatna@Sun.COM DUMP_FLAGS(lane_in->lstate);
170112011SSriharsha.Basavapatna@Sun.COM DUMP_FLAGS(lane_out->lstate);
17025373Sraghuram
17035373Sraghuram switch (ldcp->hphase) {
17045373Sraghuram
17055373Sraghuram case VSW_MILESTONE0:
17065373Sraghuram /*
17075373Sraghuram * If we haven't started to handshake with our peer,
17085373Sraghuram * start to do so now.
17095373Sraghuram */
171012011SSriharsha.Basavapatna@Sun.COM if (lane_out->lstate == 0) {
17115373Sraghuram D2(vswp, "%s: (chan %lld) starting handshake "
17125373Sraghuram "with peer", __func__, ldcp->ldc_id);
17135373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_UP);
17145373Sraghuram }
17155373Sraghuram
17165373Sraghuram /*
17175373Sraghuram * Only way to pass this milestone is to have successfully
17185373Sraghuram * negotiated version info.
17195373Sraghuram */
172012011SSriharsha.Basavapatna@Sun.COM if ((lane_in->lstate & VSW_VER_ACK_SENT) &&
172112011SSriharsha.Basavapatna@Sun.COM (lane_out->lstate & VSW_VER_ACK_RECV)) {
17225373Sraghuram
17235373Sraghuram D2(vswp, "%s: (chan %lld) leaving milestone 0",
17245373Sraghuram __func__, ldcp->ldc_id);
17255373Sraghuram
17265935Ssb155480 vsw_set_vnet_proto_ops(ldcp);
17275935Ssb155480
17285373Sraghuram /*
17295373Sraghuram * Next milestone is passed when attribute
17305373Sraghuram * information has been successfully exchanged.
17315373Sraghuram */
17325373Sraghuram ldcp->hphase = VSW_MILESTONE1;
17335373Sraghuram vsw_send_attr(ldcp);
17345373Sraghuram
17355373Sraghuram }
17365373Sraghuram break;
17375373Sraghuram
17385373Sraghuram case VSW_MILESTONE1:
17395373Sraghuram /*
17405373Sraghuram * Only way to pass this milestone is to have successfully
174112011SSriharsha.Basavapatna@Sun.COM * negotiated attribute information, in both directions.
174212011SSriharsha.Basavapatna@Sun.COM */
174312011SSriharsha.Basavapatna@Sun.COM if (!((lane_in->lstate & VSW_ATTR_ACK_SENT) &&
174412011SSriharsha.Basavapatna@Sun.COM (lane_out->lstate & VSW_ATTR_ACK_RECV))) {
174512011SSriharsha.Basavapatna@Sun.COM break;
174612011SSriharsha.Basavapatna@Sun.COM }
174712011SSriharsha.Basavapatna@Sun.COM
174812011SSriharsha.Basavapatna@Sun.COM ldcp->hphase = VSW_MILESTONE2;
174912011SSriharsha.Basavapatna@Sun.COM
175012011SSriharsha.Basavapatna@Sun.COM /*
175112011SSriharsha.Basavapatna@Sun.COM * If the peer device has said it wishes to
175212011SSriharsha.Basavapatna@Sun.COM * use descriptor rings then we send it our ring
175312011SSriharsha.Basavapatna@Sun.COM * info, otherwise we just set up a private ring
175412011SSriharsha.Basavapatna@Sun.COM * which we use an internal buffer
17555373Sraghuram */
175612011SSriharsha.Basavapatna@Sun.COM if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
175712011SSriharsha.Basavapatna@Sun.COM (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
175812011SSriharsha.Basavapatna@Sun.COM (VSW_VER_LT(ldcp, 1, 2) &&
175912011SSriharsha.Basavapatna@Sun.COM (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) {
176012011SSriharsha.Basavapatna@Sun.COM vsw_send_dring_info(ldcp);
176112011SSriharsha.Basavapatna@Sun.COM break;
17625373Sraghuram }
176312011SSriharsha.Basavapatna@Sun.COM
176412011SSriharsha.Basavapatna@Sun.COM /*
176512011SSriharsha.Basavapatna@Sun.COM * The peer doesn't operate in dring mode; we
176612011SSriharsha.Basavapatna@Sun.COM * can simply fallthru to the RDX phase from
176712011SSriharsha.Basavapatna@Sun.COM * here.
176812011SSriharsha.Basavapatna@Sun.COM */
176912011SSriharsha.Basavapatna@Sun.COM /*FALLTHRU*/
17705373Sraghuram
17715373Sraghuram case VSW_MILESTONE2:
17725373Sraghuram /*
17735373Sraghuram * If peer has indicated in its attribute message that
17745373Sraghuram * it wishes to use descriptor rings then the only way
17755373Sraghuram * to pass this milestone is for us to have received
17765373Sraghuram * valid dring info.
17775373Sraghuram *
17785373Sraghuram * If peer is not using descriptor rings then just fall
17795373Sraghuram * through.
17805373Sraghuram */
17816419Ssb155480 if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
178212011SSriharsha.Basavapatna@Sun.COM (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
17835935Ssb155480 (VSW_VER_LT(ldcp, 1, 2) &&
178412011SSriharsha.Basavapatna@Sun.COM (lane_in->xfer_mode ==
17855935Ssb155480 VIO_DRING_MODE_V1_0))) {
178612011SSriharsha.Basavapatna@Sun.COM if (!(lane_in->lstate & VSW_DRING_ACK_SENT))
17875935Ssb155480 break;
17885935Ssb155480 }
17895373Sraghuram
17905373Sraghuram D2(vswp, "%s: (chan %lld) leaving milestone 2",
17915373Sraghuram __func__, ldcp->ldc_id);
17925373Sraghuram
17935373Sraghuram ldcp->hphase = VSW_MILESTONE3;
17945373Sraghuram vsw_send_rdx(ldcp);
17955373Sraghuram break;
17965373Sraghuram
17975373Sraghuram case VSW_MILESTONE3:
17985373Sraghuram /*
17995373Sraghuram * Pass this milestone when all paramaters have been
18005373Sraghuram * successfully exchanged and RDX sent in both directions.
18015373Sraghuram *
180212011SSriharsha.Basavapatna@Sun.COM * Mark the relevant lane as available to transmit data. In
180312011SSriharsha.Basavapatna@Sun.COM * RxDringData mode, lane_in is associated with transmit and
180412011SSriharsha.Basavapatna@Sun.COM * lane_out is associated with receive. It is the reverse in
180512011SSriharsha.Basavapatna@Sun.COM * TxDring mode.
18065373Sraghuram */
180712011SSriharsha.Basavapatna@Sun.COM if ((lane_out->lstate & VSW_RDX_ACK_SENT) &&
180812011SSriharsha.Basavapatna@Sun.COM (lane_in->lstate & VSW_RDX_ACK_RECV)) {
18095373Sraghuram
18105373Sraghuram D2(vswp, "%s: (chan %lld) leaving milestone 3",
18115373Sraghuram __func__, ldcp->ldc_id);
18125373Sraghuram D2(vswp, "%s: ** handshake complete (0x%llx : "
181312011SSriharsha.Basavapatna@Sun.COM "0x%llx) **", __func__, lane_in->lstate,
181412011SSriharsha.Basavapatna@Sun.COM lane_out->lstate);
181512011SSriharsha.Basavapatna@Sun.COM if (lane_out->dring_mode == VIO_RX_DRING_DATA) {
181612011SSriharsha.Basavapatna@Sun.COM lane_in->lstate |= VSW_LANE_ACTIVE;
181712011SSriharsha.Basavapatna@Sun.COM } else {
181812011SSriharsha.Basavapatna@Sun.COM lane_out->lstate |= VSW_LANE_ACTIVE;
181912011SSriharsha.Basavapatna@Sun.COM }
18205373Sraghuram ldcp->hphase = VSW_MILESTONE4;
18215373Sraghuram ldcp->hcnt = 0;
18225373Sraghuram DISPLAY_STATE();
18236495Sspeer /* Start HIO if enabled and capable */
18246495Sspeer if ((portp->p_hio_enabled) && (portp->p_hio_capable)) {
18256495Sspeer D2(vswp, "%s: start HybridIO setup", __func__);
18266495Sspeer vsw_hio_start(vswp, ldcp);
18276495Sspeer }
18289336SSriharsha.Basavapatna@Sun.COM
18299336SSriharsha.Basavapatna@Sun.COM if (ldcp->pls_negotiated == B_TRUE) {
18309336SSriharsha.Basavapatna@Sun.COM /*
18319336SSriharsha.Basavapatna@Sun.COM * The vnet device has negotiated to get phys
18329336SSriharsha.Basavapatna@Sun.COM * link updates. Now that the handshake with
18339336SSriharsha.Basavapatna@Sun.COM * the vnet device is complete, send an initial
18349336SSriharsha.Basavapatna@Sun.COM * update with the current physical link state.
18359336SSriharsha.Basavapatna@Sun.COM */
18369336SSriharsha.Basavapatna@Sun.COM vsw_send_physlink_msg(ldcp,
18379336SSriharsha.Basavapatna@Sun.COM vswp->phys_link_state);
18389336SSriharsha.Basavapatna@Sun.COM }
18399336SSriharsha.Basavapatna@Sun.COM
18405373Sraghuram } else {
18415373Sraghuram D2(vswp, "%s: still in milestone 3 (0x%llx : 0x%llx)",
184212011SSriharsha.Basavapatna@Sun.COM __func__, lane_in->lstate,
184312011SSriharsha.Basavapatna@Sun.COM lane_out->lstate);
18445373Sraghuram }
18455373Sraghuram break;
18465373Sraghuram
18475373Sraghuram case VSW_MILESTONE4:
18485373Sraghuram D2(vswp, "%s: (chan %lld) in milestone 4", __func__,
18495373Sraghuram ldcp->ldc_id);
18505373Sraghuram break;
18515373Sraghuram
18525373Sraghuram default:
18535373Sraghuram DERR(vswp, "%s: (chan %lld) Unknown Phase %x", __func__,
18545373Sraghuram ldcp->ldc_id, ldcp->hphase);
18555373Sraghuram }
18565373Sraghuram
18575373Sraghuram D1(vswp, "%s (chan %lld): exit (phase %ld)", __func__, ldcp->ldc_id,
18585373Sraghuram ldcp->hphase);
18595373Sraghuram }
18605373Sraghuram
18615373Sraghuram /*
18625373Sraghuram * Check if major version is supported.
18635373Sraghuram *
18645373Sraghuram * Returns 0 if finds supported major number, and if necessary
18655373Sraghuram * adjusts the minor field.
18665373Sraghuram *
18675373Sraghuram * Returns 1 if can't match major number exactly. Sets mjor/minor
18685373Sraghuram * to next lowest support values, or to zero if no other values possible.
18695373Sraghuram */
18705373Sraghuram static int
vsw_supported_version(vio_ver_msg_t * vp)18715373Sraghuram vsw_supported_version(vio_ver_msg_t *vp)
18725373Sraghuram {
18735373Sraghuram int i;
18745373Sraghuram
18755373Sraghuram D1(NULL, "vsw_supported_version: enter");
18765373Sraghuram
18775373Sraghuram for (i = 0; i < VSW_NUM_VER; i++) {
18785373Sraghuram if (vsw_versions[i].ver_major == vp->ver_major) {
18795373Sraghuram /*
18805373Sraghuram * Matching or lower major version found. Update
18815373Sraghuram * minor number if necessary.
18825373Sraghuram */
18835373Sraghuram if (vp->ver_minor > vsw_versions[i].ver_minor) {
18845373Sraghuram D2(NULL, "%s: adjusting minor value from %d "
18855373Sraghuram "to %d", __func__, vp->ver_minor,
18865373Sraghuram vsw_versions[i].ver_minor);
18875373Sraghuram vp->ver_minor = vsw_versions[i].ver_minor;
18885373Sraghuram }
18895373Sraghuram
18905373Sraghuram return (0);
18915373Sraghuram }
18925373Sraghuram
18935935Ssb155480 /*
18945935Ssb155480 * If the message contains a higher major version number, set
18955935Ssb155480 * the message's major/minor versions to the current values
18965935Ssb155480 * and return false, so this message will get resent with
18975935Ssb155480 * these values.
18985935Ssb155480 */
18995373Sraghuram if (vsw_versions[i].ver_major < vp->ver_major) {
19005935Ssb155480 D2(NULL, "%s: adjusting major and minor "
19015935Ssb155480 "values to %d, %d\n",
19025935Ssb155480 __func__, vsw_versions[i].ver_major,
19035935Ssb155480 vsw_versions[i].ver_minor);
19045935Ssb155480 vp->ver_major = vsw_versions[i].ver_major;
19055935Ssb155480 vp->ver_minor = vsw_versions[i].ver_minor;
19065373Sraghuram return (1);
19075373Sraghuram }
19085373Sraghuram }
19095373Sraghuram
19105373Sraghuram /* No match was possible, zero out fields */
19115373Sraghuram vp->ver_major = 0;
19125373Sraghuram vp->ver_minor = 0;
19135373Sraghuram
19145373Sraghuram D1(NULL, "vsw_supported_version: exit");
19155373Sraghuram
19165373Sraghuram return (1);
19175373Sraghuram }
19185373Sraghuram
19195373Sraghuram /*
19205935Ssb155480 * Set vnet-protocol-version dependent functions based on version.
19215935Ssb155480 */
19225935Ssb155480 static void
vsw_set_vnet_proto_ops(vsw_ldc_t * ldcp)19235935Ssb155480 vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp)
19245935Ssb155480 {
19255935Ssb155480 vsw_t *vswp = ldcp->ldc_vswp;
19265935Ssb155480 lane_t *lp = &ldcp->lane_out;
19275935Ssb155480
192812011SSriharsha.Basavapatna@Sun.COM /*
192912011SSriharsha.Basavapatna@Sun.COM * Setup the appropriate dring data processing routine and any
193012011SSriharsha.Basavapatna@Sun.COM * associated thread based on the version.
193112011SSriharsha.Basavapatna@Sun.COM *
193212011SSriharsha.Basavapatna@Sun.COM * In versions < 1.6, we support only TxDring mode. In this mode, the
193312011SSriharsha.Basavapatna@Sun.COM * msg worker thread processes all types of VIO msgs (ctrl and data).
193412011SSriharsha.Basavapatna@Sun.COM *
193512011SSriharsha.Basavapatna@Sun.COM * In versions >= 1.6, we also support RxDringData mode. In this mode,
193612011SSriharsha.Basavapatna@Sun.COM * the rcv worker thread processes dring data messages (msgtype:
193712011SSriharsha.Basavapatna@Sun.COM * VIO_TYPE_DATA, subtype: VIO_SUBTYPE_INFO, env: VIO_DRING_DATA). The
193812011SSriharsha.Basavapatna@Sun.COM * rest of the data messages (including acks) and ctrl messages are
193912011SSriharsha.Basavapatna@Sun.COM * handled directly by the callback (intr) thread.
194012011SSriharsha.Basavapatna@Sun.COM *
194112011SSriharsha.Basavapatna@Sun.COM * However, for versions >= 1.6, we could still fallback to TxDring
194212011SSriharsha.Basavapatna@Sun.COM * mode. This could happen if RxDringData mode has been disabled (see
1943*13098SWentao.Yang@Sun.COM * below) on this guest or on the peer guest. This info is determined
1944*13098SWentao.Yang@Sun.COM * as part of attr exchange phase of handshake. Hence, we setup these
1945*13098SWentao.Yang@Sun.COM * pointers for v1.6 after attr msg phase completes during handshake.
194612011SSriharsha.Basavapatna@Sun.COM */
194712011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 6)) {
194812011SSriharsha.Basavapatna@Sun.COM /*
194912011SSriharsha.Basavapatna@Sun.COM * Set data dring mode for vsw_send_attr(). We setup msg worker
195012011SSriharsha.Basavapatna@Sun.COM * thread in TxDring mode or rcv worker thread in RxDringData
195112011SSriharsha.Basavapatna@Sun.COM * mode when attr phase of handshake completes.
195212011SSriharsha.Basavapatna@Sun.COM */
1953*13098SWentao.Yang@Sun.COM if (vsw_mapin_avail(ldcp) == B_TRUE) {
195412011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = (VIO_RX_DRING_DATA | VIO_TX_DRING);
195512011SSriharsha.Basavapatna@Sun.COM } else {
195612011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = VIO_TX_DRING;
195712011SSriharsha.Basavapatna@Sun.COM }
195812011SSriharsha.Basavapatna@Sun.COM } else {
195912011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = VIO_TX_DRING;
196012011SSriharsha.Basavapatna@Sun.COM }
196112011SSriharsha.Basavapatna@Sun.COM
196212011SSriharsha.Basavapatna@Sun.COM /*
196312011SSriharsha.Basavapatna@Sun.COM * Setup the MTU for attribute negotiation based on the version.
196412011SSriharsha.Basavapatna@Sun.COM */
19657529SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 4)) {
19666419Ssb155480 /*
19677529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is >= 1.4(Jumbo Frame
19687529SSriharsha.Basavapatna@Sun.COM * Support), set the mtu in our attributes to max_frame_size.
19696419Ssb155480 */
19706419Ssb155480 lp->mtu = vswp->max_frame_size;
19717529SSriharsha.Basavapatna@Sun.COM } else if (VSW_VER_EQ(ldcp, 1, 3)) {
19727529SSriharsha.Basavapatna@Sun.COM /*
19737529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is == 1.3 (Vlan Tag
19747529SSriharsha.Basavapatna@Sun.COM * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ.
19757529SSriharsha.Basavapatna@Sun.COM */
19767529SSriharsha.Basavapatna@Sun.COM lp->mtu = ETHERMAX + VLAN_TAGSZ;
19776419Ssb155480 } else {
19786419Ssb155480 vsw_port_t *portp = ldcp->ldc_port;
19796419Ssb155480 /*
19806419Ssb155480 * Pre-1.3 peers expect max frame size of ETHERMAX.
19817529SSriharsha.Basavapatna@Sun.COM * We can negotiate that size with those peers provided only
19827529SSriharsha.Basavapatna@Sun.COM * pvid is defined for our peer and there are no vids. Then we
19837529SSriharsha.Basavapatna@Sun.COM * can send/recv only untagged frames of max size ETHERMAX.
19847529SSriharsha.Basavapatna@Sun.COM * Note that pvid of the peer can be different, as vsw has to
19857529SSriharsha.Basavapatna@Sun.COM * serve the vnet in that vlan even if itself is not assigned
19867529SSriharsha.Basavapatna@Sun.COM * to that vlan.
19876419Ssb155480 */
19887529SSriharsha.Basavapatna@Sun.COM if (portp->nvids == 0) {
19896419Ssb155480 lp->mtu = ETHERMAX;
19906419Ssb155480 }
19916419Ssb155480 }
19926419Ssb155480
199312011SSriharsha.Basavapatna@Sun.COM /*
199412011SSriharsha.Basavapatna@Sun.COM * Setup version dependent data processing functions.
199512011SSriharsha.Basavapatna@Sun.COM */
19966419Ssb155480 if (VSW_VER_GTEQ(ldcp, 1, 2)) {
19976419Ssb155480 /* Versions >= 1.2 */
19985935Ssb155480
19995935Ssb155480 if (VSW_PRI_ETH_DEFINED(vswp)) {
20005935Ssb155480 /*
20015935Ssb155480 * enable priority routines and pkt mode only if
20025935Ssb155480 * at least one pri-eth-type is specified in MD.
20035935Ssb155480 */
20045935Ssb155480 ldcp->tx = vsw_ldctx_pri;
20055935Ssb155480 ldcp->rx_pktdata = vsw_process_pkt_data;
20065935Ssb155480
20075935Ssb155480 /* set xfer mode for vsw_send_attr() */
20085935Ssb155480 lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2;
20095935Ssb155480 } else {
20105935Ssb155480 /* no priority eth types defined in MD */
20115935Ssb155480
20125935Ssb155480 ldcp->tx = vsw_ldctx;
20135935Ssb155480 ldcp->rx_pktdata = vsw_process_pkt_data_nop;
20145935Ssb155480
20155935Ssb155480 /* set xfer mode for vsw_send_attr() */
20165935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_2;
20175935Ssb155480 }
20186419Ssb155480
20195935Ssb155480 } else {
20205935Ssb155480 /* Versions prior to 1.2 */
20215935Ssb155480
20225935Ssb155480 vsw_reset_vnet_proto_ops(ldcp);
20235935Ssb155480 }
20245935Ssb155480 }
20255935Ssb155480
20265935Ssb155480 /*
20275935Ssb155480 * Reset vnet-protocol-version dependent functions to v1.0.
20285935Ssb155480 */
20295935Ssb155480 static void
vsw_reset_vnet_proto_ops(vsw_ldc_t * ldcp)20305935Ssb155480 vsw_reset_vnet_proto_ops(vsw_ldc_t *ldcp)
20315935Ssb155480 {
20325935Ssb155480 lane_t *lp = &ldcp->lane_out;
20335935Ssb155480
20345935Ssb155480 ldcp->tx = vsw_ldctx;
20355935Ssb155480 ldcp->rx_pktdata = vsw_process_pkt_data_nop;
20365935Ssb155480
20375935Ssb155480 /* set xfer mode for vsw_send_attr() */
20385935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0;
20395935Ssb155480 }
20405935Ssb155480
204112011SSriharsha.Basavapatna@Sun.COM static void
vsw_process_evt_read(vsw_ldc_t * ldcp)204212011SSriharsha.Basavapatna@Sun.COM vsw_process_evt_read(vsw_ldc_t *ldcp)
204312011SSriharsha.Basavapatna@Sun.COM {
204412011SSriharsha.Basavapatna@Sun.COM if (ldcp->msg_thread != NULL) {
204512011SSriharsha.Basavapatna@Sun.COM /*
204612011SSriharsha.Basavapatna@Sun.COM * TxDring mode; wakeup message worker
204712011SSriharsha.Basavapatna@Sun.COM * thread to process the VIO messages.
204812011SSriharsha.Basavapatna@Sun.COM */
204912011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->ldc_cblock);
205012011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->msg_thr_lock);
205112011SSriharsha.Basavapatna@Sun.COM if (!(ldcp->msg_thr_flags & VSW_WTHR_DATARCVD)) {
205212011SSriharsha.Basavapatna@Sun.COM ldcp->msg_thr_flags |= VSW_WTHR_DATARCVD;
205312011SSriharsha.Basavapatna@Sun.COM cv_signal(&ldcp->msg_thr_cv);
205412011SSriharsha.Basavapatna@Sun.COM }
205512011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->msg_thr_lock);
205612011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->ldc_cblock);
205712011SSriharsha.Basavapatna@Sun.COM } else {
205812011SSriharsha.Basavapatna@Sun.COM /*
205912011SSriharsha.Basavapatna@Sun.COM * We invoke vsw_process_pkt() in the context of the LDC
206012011SSriharsha.Basavapatna@Sun.COM * callback (vsw_ldc_cb()) during handshake, until the dring
206112011SSriharsha.Basavapatna@Sun.COM * mode is negotiated. After the dring mode is negotiated, the
206212011SSriharsha.Basavapatna@Sun.COM * msgs are processed by the msg worker thread (above case) if
206312011SSriharsha.Basavapatna@Sun.COM * the dring mode is TxDring. Otherwise (in RxDringData mode)
206412011SSriharsha.Basavapatna@Sun.COM * we continue to process the msgs directly in the callback
206512011SSriharsha.Basavapatna@Sun.COM * context.
206612011SSriharsha.Basavapatna@Sun.COM */
206712011SSriharsha.Basavapatna@Sun.COM vsw_process_pkt(ldcp);
206812011SSriharsha.Basavapatna@Sun.COM }
206912011SSriharsha.Basavapatna@Sun.COM }
207012011SSriharsha.Basavapatna@Sun.COM
20715935Ssb155480 /*
20725373Sraghuram * Main routine for processing messages received over LDC.
20735373Sraghuram */
207412011SSriharsha.Basavapatna@Sun.COM void
vsw_process_pkt(void * arg)20755373Sraghuram vsw_process_pkt(void *arg)
20765373Sraghuram {
20775373Sraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
20785373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
20795373Sraghuram size_t msglen;
20805935Ssb155480 vio_msg_tag_t *tagp;
20815935Ssb155480 uint64_t *ldcmsg;
20825373Sraghuram int rv = 0;
20835373Sraghuram
20845373Sraghuram
20855373Sraghuram D1(vswp, "%s enter: ldcid (%lld)\n", __func__, ldcp->ldc_id);
20865373Sraghuram
20875373Sraghuram ASSERT(MUTEX_HELD(&ldcp->ldc_cblock));
20885373Sraghuram
20895935Ssb155480 ldcmsg = ldcp->ldcmsg;
20905373Sraghuram /*
20915373Sraghuram * If channel is up read messages until channel is empty.
20925373Sraghuram */
20935373Sraghuram do {
20945935Ssb155480 msglen = ldcp->msglen;
20955935Ssb155480 rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen);
20965373Sraghuram
20975373Sraghuram if (rv != 0) {
20985373Sraghuram DERR(vswp, "%s :ldc_read err id(%lld) rv(%d) len(%d)\n",
20995373Sraghuram __func__, ldcp->ldc_id, rv, msglen);
21005373Sraghuram }
21015373Sraghuram
21025373Sraghuram /* channel has been reset */
21035373Sraghuram if (rv == ECONNRESET) {
21045373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
21055373Sraghuram break;
21065373Sraghuram }
21075373Sraghuram
21085373Sraghuram if (msglen == 0) {
21095373Sraghuram D2(vswp, "%s: ldc_read id(%lld) NODATA", __func__,
21105373Sraghuram ldcp->ldc_id);
21115373Sraghuram break;
21125373Sraghuram }
21135373Sraghuram
21145373Sraghuram D2(vswp, "%s: ldc_read id(%lld): msglen(%d)", __func__,
21155373Sraghuram ldcp->ldc_id, msglen);
21165373Sraghuram
21175373Sraghuram /*
21185373Sraghuram * Figure out what sort of packet we have gotten by
21195373Sraghuram * examining the msg tag, and then switch it appropriately.
21205373Sraghuram */
21215935Ssb155480 tagp = (vio_msg_tag_t *)ldcmsg;
21225935Ssb155480
21235935Ssb155480 switch (tagp->vio_msgtype) {
21245373Sraghuram case VIO_TYPE_CTRL:
212512011SSriharsha.Basavapatna@Sun.COM vsw_dispatch_ctrl_task(ldcp, ldcmsg, tagp, msglen);
21265373Sraghuram break;
21275373Sraghuram case VIO_TYPE_DATA:
21285935Ssb155480 vsw_process_data_pkt(ldcp, ldcmsg, tagp, msglen);
21295373Sraghuram break;
21305373Sraghuram case VIO_TYPE_ERR:
21315935Ssb155480 vsw_process_err_pkt(ldcp, ldcmsg, tagp);
21325373Sraghuram break;
21335373Sraghuram default:
21345373Sraghuram DERR(vswp, "%s: Unknown tag(%lx) ", __func__,
21355935Ssb155480 "id(%lx)\n", tagp->vio_msgtype, ldcp->ldc_id);
21365373Sraghuram break;
21375373Sraghuram }
21385373Sraghuram } while (msglen);
21395373Sraghuram
21405373Sraghuram D1(vswp, "%s exit: ldcid (%lld)\n", __func__, ldcp->ldc_id);
21415373Sraghuram }
21425373Sraghuram
21435373Sraghuram /*
21445373Sraghuram * Dispatch a task to process a VIO control message.
21455373Sraghuram */
21465373Sraghuram static void
vsw_dispatch_ctrl_task(vsw_ldc_t * ldcp,void * cpkt,vio_msg_tag_t * tagp,int msglen)214712011SSriharsha.Basavapatna@Sun.COM vsw_dispatch_ctrl_task(vsw_ldc_t *ldcp, void *cpkt, vio_msg_tag_t *tagp,
214812011SSriharsha.Basavapatna@Sun.COM int msglen)
21495373Sraghuram {
21505373Sraghuram vsw_ctrl_task_t *ctaskp = NULL;
21515373Sraghuram vsw_port_t *port = ldcp->ldc_port;
21525373Sraghuram vsw_t *vswp = port->p_vswp;
21535373Sraghuram
21545373Sraghuram D1(vswp, "%s: enter", __func__);
21555373Sraghuram
21565373Sraghuram /*
21575373Sraghuram * We need to handle RDX ACK messages in-band as once they
21585373Sraghuram * are exchanged it is possible that we will get an
21595373Sraghuram * immediate (legitimate) data packet.
21605373Sraghuram */
21615935Ssb155480 if ((tagp->vio_subtype_env == VIO_RDX) &&
21625935Ssb155480 (tagp->vio_subtype == VIO_SUBTYPE_ACK)) {
21635373Sraghuram
21645373Sraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_ACK_RECV))
21655373Sraghuram return;
21665373Sraghuram
21675373Sraghuram ldcp->lane_in.lstate |= VSW_RDX_ACK_RECV;
21685373Sraghuram D2(vswp, "%s (%ld) handling RDX_ACK in place "
21695373Sraghuram "(ostate 0x%llx : hphase %d)", __func__,
21705373Sraghuram ldcp->ldc_id, ldcp->lane_in.lstate, ldcp->hphase);
21715373Sraghuram vsw_next_milestone(ldcp);
21725373Sraghuram return;
21735373Sraghuram }
21745373Sraghuram
21755373Sraghuram ctaskp = kmem_alloc(sizeof (vsw_ctrl_task_t), KM_NOSLEEP);
21765373Sraghuram
21775373Sraghuram if (ctaskp == NULL) {
21785373Sraghuram DERR(vswp, "%s: unable to alloc space for ctrl msg", __func__);
21795373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
21805373Sraghuram return;
21815373Sraghuram }
21825373Sraghuram
21835373Sraghuram ctaskp->ldcp = ldcp;
218412011SSriharsha.Basavapatna@Sun.COM bcopy((def_msg_t *)cpkt, &ctaskp->pktp, msglen);
21855373Sraghuram ctaskp->hss_id = ldcp->hss_id;
21865373Sraghuram
21875373Sraghuram /*
21885373Sraghuram * Dispatch task to processing taskq if port is not in
21895373Sraghuram * the process of being detached.
21905373Sraghuram */
21915373Sraghuram mutex_enter(&port->state_lock);
21925373Sraghuram if (port->state == VSW_PORT_INIT) {
21935373Sraghuram if ((vswp->taskq_p == NULL) ||
21945373Sraghuram (ddi_taskq_dispatch(vswp->taskq_p, vsw_process_ctrl_pkt,
21955373Sraghuram ctaskp, DDI_NOSLEEP) != DDI_SUCCESS)) {
21967481SWentao.Yang@Sun.COM mutex_exit(&port->state_lock);
21975373Sraghuram DERR(vswp, "%s: unable to dispatch task to taskq",
21985373Sraghuram __func__);
21997481SWentao.Yang@Sun.COM vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
22005373Sraghuram kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22015373Sraghuram return;
22025373Sraghuram }
22035373Sraghuram } else {
22047481SWentao.Yang@Sun.COM kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22055373Sraghuram DWARN(vswp, "%s: port %d detaching, not dispatching "
22065373Sraghuram "task", __func__, port->p_instance);
22075373Sraghuram }
22085373Sraghuram
22095373Sraghuram mutex_exit(&port->state_lock);
22105373Sraghuram
22115373Sraghuram D2(vswp, "%s: dispatched task to taskq for chan %d", __func__,
22125373Sraghuram ldcp->ldc_id);
22135373Sraghuram D1(vswp, "%s: exit", __func__);
22145373Sraghuram }
22155373Sraghuram
22165373Sraghuram /*
22175373Sraghuram * Process a VIO ctrl message. Invoked from taskq.
22185373Sraghuram */
22195373Sraghuram static void
vsw_process_ctrl_pkt(void * arg)22205373Sraghuram vsw_process_ctrl_pkt(void *arg)
22215373Sraghuram {
22225373Sraghuram vsw_ctrl_task_t *ctaskp = (vsw_ctrl_task_t *)arg;
22235373Sraghuram vsw_ldc_t *ldcp = ctaskp->ldcp;
22245373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
22255373Sraghuram vio_msg_tag_t tag;
22265373Sraghuram uint16_t env;
22275373Sraghuram
22285373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
22295373Sraghuram
22305373Sraghuram bcopy(&ctaskp->pktp, &tag, sizeof (vio_msg_tag_t));
22315373Sraghuram env = tag.vio_subtype_env;
22325373Sraghuram
22335373Sraghuram /* stale pkt check */
22345373Sraghuram if (ctaskp->hss_id < ldcp->hss_id) {
22355373Sraghuram DWARN(vswp, "%s: discarding stale packet belonging to earlier"
22365373Sraghuram " (%ld) handshake session", __func__, ctaskp->hss_id);
22377481SWentao.Yang@Sun.COM kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22385373Sraghuram return;
22395373Sraghuram }
22405373Sraghuram
22415373Sraghuram /* session id check */
22425373Sraghuram if (ldcp->session_status & VSW_PEER_SESSION) {
22435373Sraghuram if (ldcp->peer_session != tag.vio_sid) {
22445373Sraghuram DERR(vswp, "%s (chan %d): invalid session id (%llx)",
22455373Sraghuram __func__, ldcp->ldc_id, tag.vio_sid);
22465373Sraghuram kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22475373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
22485373Sraghuram return;
22495373Sraghuram }
22505373Sraghuram }
22515373Sraghuram
22525373Sraghuram /*
22535373Sraghuram * Switch on vio_subtype envelope, then let lower routines
22545373Sraghuram * decide if its an INFO, ACK or NACK packet.
22555373Sraghuram */
22565373Sraghuram switch (env) {
22575373Sraghuram case VIO_VER_INFO:
22585373Sraghuram vsw_process_ctrl_ver_pkt(ldcp, &ctaskp->pktp);
22595373Sraghuram break;
22605373Sraghuram case VIO_DRING_REG:
22615373Sraghuram vsw_process_ctrl_dring_reg_pkt(ldcp, &ctaskp->pktp);
22625373Sraghuram break;
22635373Sraghuram case VIO_DRING_UNREG:
22645373Sraghuram vsw_process_ctrl_dring_unreg_pkt(ldcp, &ctaskp->pktp);
22655373Sraghuram break;
22665373Sraghuram case VIO_ATTR_INFO:
22675373Sraghuram vsw_process_ctrl_attr_pkt(ldcp, &ctaskp->pktp);
22685373Sraghuram break;
22695373Sraghuram case VNET_MCAST_INFO:
22705373Sraghuram vsw_process_ctrl_mcst_pkt(ldcp, &ctaskp->pktp);
22715373Sraghuram break;
22725373Sraghuram case VIO_RDX:
22735373Sraghuram vsw_process_ctrl_rdx_pkt(ldcp, &ctaskp->pktp);
22745373Sraghuram break;
22756495Sspeer case VIO_DDS_INFO:
22766495Sspeer vsw_process_dds_msg(vswp, ldcp, &ctaskp->pktp);
22776495Sspeer break;
22789336SSriharsha.Basavapatna@Sun.COM
22799336SSriharsha.Basavapatna@Sun.COM case VNET_PHYSLINK_INFO:
22809336SSriharsha.Basavapatna@Sun.COM vsw_process_physlink_msg(ldcp, &ctaskp->pktp);
22819336SSriharsha.Basavapatna@Sun.COM break;
22825373Sraghuram default:
22835373Sraghuram DERR(vswp, "%s: unknown vio_subtype_env (%x)\n", __func__, env);
22845373Sraghuram }
22855373Sraghuram
22865373Sraghuram kmem_free(ctaskp, sizeof (vsw_ctrl_task_t));
22875373Sraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
22885373Sraghuram }
22895373Sraghuram
22905373Sraghuram /*
22915373Sraghuram * Version negotiation. We can end up here either because our peer
22925373Sraghuram * has responded to a handshake message we have sent it, or our peer
22935373Sraghuram * has initiated a handshake with us. If its the former then can only
22945373Sraghuram * be ACK or NACK, if its the later can only be INFO.
22955373Sraghuram *
22965373Sraghuram * If its an ACK we move to the next stage of the handshake, namely
22975373Sraghuram * attribute exchange. If its a NACK we see if we can specify another
22985373Sraghuram * version, if we can't we stop.
22995373Sraghuram *
23005373Sraghuram * If it is an INFO we reset all params associated with communication
23015373Sraghuram * in that direction over this channel (remember connection is
23025373Sraghuram * essentially 2 independent simplex channels).
23035373Sraghuram */
23045373Sraghuram void
vsw_process_ctrl_ver_pkt(vsw_ldc_t * ldcp,void * pkt)23055373Sraghuram vsw_process_ctrl_ver_pkt(vsw_ldc_t *ldcp, void *pkt)
23065373Sraghuram {
23075373Sraghuram vio_ver_msg_t *ver_pkt;
23085373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
23095373Sraghuram
23105373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
23115373Sraghuram
23125373Sraghuram /*
23135373Sraghuram * We know this is a ctrl/version packet so
23145373Sraghuram * cast it into the correct structure.
23155373Sraghuram */
23165373Sraghuram ver_pkt = (vio_ver_msg_t *)pkt;
23175373Sraghuram
23185373Sraghuram switch (ver_pkt->tag.vio_subtype) {
23195373Sraghuram case VIO_SUBTYPE_INFO:
23205373Sraghuram D2(vswp, "vsw_process_ctrl_ver_pkt: VIO_SUBTYPE_INFO\n");
23215373Sraghuram
23225373Sraghuram /*
23235373Sraghuram * Record the session id, which we will use from now
23245373Sraghuram * until we see another VER_INFO msg. Even then the
23255373Sraghuram * session id in most cases will be unchanged, execpt
23265373Sraghuram * if channel was reset.
23275373Sraghuram */
23285373Sraghuram if ((ldcp->session_status & VSW_PEER_SESSION) &&
23295373Sraghuram (ldcp->peer_session != ver_pkt->tag.vio_sid)) {
23305373Sraghuram DERR(vswp, "%s: updating session id for chan %lld "
23315373Sraghuram "from %llx to %llx", __func__, ldcp->ldc_id,
23325373Sraghuram ldcp->peer_session, ver_pkt->tag.vio_sid);
23335373Sraghuram }
23345373Sraghuram
23355373Sraghuram ldcp->peer_session = ver_pkt->tag.vio_sid;
23365373Sraghuram ldcp->session_status |= VSW_PEER_SESSION;
23375373Sraghuram
23385373Sraghuram /* Legal message at this time ? */
23395373Sraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_VER_INFO_RECV))
23405373Sraghuram return;
23415373Sraghuram
23425373Sraghuram /*
23435373Sraghuram * First check the device class. Currently only expect
23445373Sraghuram * to be talking to a network device. In the future may
23455373Sraghuram * also talk to another switch.
23465373Sraghuram */
23475373Sraghuram if (ver_pkt->dev_class != VDEV_NETWORK) {
23485373Sraghuram DERR(vswp, "%s: illegal device class %d", __func__,
23495373Sraghuram ver_pkt->dev_class);
23505373Sraghuram
23515373Sraghuram ver_pkt->tag.vio_sid = ldcp->local_session;
23525373Sraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
23535373Sraghuram
23545373Sraghuram DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
23555373Sraghuram
23565373Sraghuram (void) vsw_send_msg(ldcp, (void *)ver_pkt,
23575373Sraghuram sizeof (vio_ver_msg_t), B_TRUE);
23585373Sraghuram
23595373Sraghuram ldcp->lane_in.lstate |= VSW_VER_NACK_SENT;
23605373Sraghuram vsw_next_milestone(ldcp);
23615373Sraghuram return;
23625373Sraghuram } else {
23635373Sraghuram ldcp->dev_class = ver_pkt->dev_class;
23645373Sraghuram }
23655373Sraghuram
23665373Sraghuram /*
23675373Sraghuram * Now check the version.
23685373Sraghuram */
23695373Sraghuram if (vsw_supported_version(ver_pkt) == 0) {
23705373Sraghuram /*
23715373Sraghuram * Support this major version and possibly
23725373Sraghuram * adjusted minor version.
23735373Sraghuram */
23745373Sraghuram
23755373Sraghuram D2(vswp, "%s: accepted ver %d:%d", __func__,
23765373Sraghuram ver_pkt->ver_major, ver_pkt->ver_minor);
23775373Sraghuram
23785373Sraghuram /* Store accepted values */
23795373Sraghuram ldcp->lane_in.ver_major = ver_pkt->ver_major;
23805373Sraghuram ldcp->lane_in.ver_minor = ver_pkt->ver_minor;
23815373Sraghuram
23825373Sraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
23835373Sraghuram
23845373Sraghuram ldcp->lane_in.lstate |= VSW_VER_ACK_SENT;
23855935Ssb155480
23865935Ssb155480 if (vsw_obp_ver_proto_workaround == B_TRUE) {
23875935Ssb155480 /*
23885935Ssb155480 * Send a version info message
23895935Ssb155480 * using the accepted version that
23905935Ssb155480 * we are about to ack. Also note that
23915935Ssb155480 * we send our ver info before we ack.
23925935Ssb155480 * Otherwise, as soon as receiving the
23935935Ssb155480 * ack, obp sends attr info msg, which
23945935Ssb155480 * breaks vsw_check_flag() invoked
23955935Ssb155480 * from vsw_process_ctrl_attr_pkt();
23965935Ssb155480 * as we also need VSW_VER_ACK_RECV to
23975935Ssb155480 * be set in lane_out.lstate, before
23985935Ssb155480 * we can receive attr info.
23995935Ssb155480 */
24005935Ssb155480 vsw_send_ver(ldcp);
24015935Ssb155480 }
24025373Sraghuram } else {
24035373Sraghuram /*
24045373Sraghuram * NACK back with the next lower major/minor
24055373Sraghuram * pairing we support (if don't suuport any more
24065373Sraghuram * versions then they will be set to zero.
24075373Sraghuram */
24085373Sraghuram
24095373Sraghuram D2(vswp, "%s: replying with ver %d:%d", __func__,
24105373Sraghuram ver_pkt->ver_major, ver_pkt->ver_minor);
24115373Sraghuram
24125373Sraghuram /* Store updated values */
24135373Sraghuram ldcp->lane_in.ver_major = ver_pkt->ver_major;
24145373Sraghuram ldcp->lane_in.ver_minor = ver_pkt->ver_minor;
24155373Sraghuram
24165373Sraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
24175373Sraghuram
24185373Sraghuram ldcp->lane_in.lstate |= VSW_VER_NACK_SENT;
24195373Sraghuram }
24205373Sraghuram
24215373Sraghuram DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
24225373Sraghuram ver_pkt->tag.vio_sid = ldcp->local_session;
24235373Sraghuram (void) vsw_send_msg(ldcp, (void *)ver_pkt,
24245373Sraghuram sizeof (vio_ver_msg_t), B_TRUE);
24255373Sraghuram
24265373Sraghuram vsw_next_milestone(ldcp);
24275373Sraghuram break;
24285373Sraghuram
24295373Sraghuram case VIO_SUBTYPE_ACK:
24305373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_ACK\n", __func__);
24315373Sraghuram
24325373Sraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_ACK_RECV))
24335373Sraghuram return;
24345373Sraghuram
24355373Sraghuram /* Store updated values */
24365935Ssb155480 ldcp->lane_out.ver_major = ver_pkt->ver_major;
24375935Ssb155480 ldcp->lane_out.ver_minor = ver_pkt->ver_minor;
24385373Sraghuram
24395373Sraghuram ldcp->lane_out.lstate |= VSW_VER_ACK_RECV;
24405373Sraghuram vsw_next_milestone(ldcp);
24415373Sraghuram
24425373Sraghuram break;
24435373Sraghuram
24445373Sraghuram case VIO_SUBTYPE_NACK:
24455373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK\n", __func__);
24465373Sraghuram
24475373Sraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_NACK_RECV))
24485373Sraghuram return;
24495373Sraghuram
24505373Sraghuram /*
24515373Sraghuram * If our peer sent us a NACK with the ver fields set to
24525373Sraghuram * zero then there is nothing more we can do. Otherwise see
24535373Sraghuram * if we support either the version suggested, or a lesser
24545373Sraghuram * one.
24555373Sraghuram */
24565373Sraghuram if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) {
24575373Sraghuram DERR(vswp, "%s: peer unable to negotiate any "
24585373Sraghuram "further.", __func__);
24595373Sraghuram ldcp->lane_out.lstate |= VSW_VER_NACK_RECV;
24605373Sraghuram vsw_next_milestone(ldcp);
24615373Sraghuram return;
24625373Sraghuram }
24635373Sraghuram
24645373Sraghuram /*
24655373Sraghuram * Check to see if we support this major version or
24665373Sraghuram * a lower one. If we don't then maj/min will be set
24675373Sraghuram * to zero.
24685373Sraghuram */
24695373Sraghuram (void) vsw_supported_version(ver_pkt);
24705373Sraghuram if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) {
24715373Sraghuram /* Nothing more we can do */
24725373Sraghuram DERR(vswp, "%s: version negotiation failed.\n",
24735373Sraghuram __func__);
24745373Sraghuram ldcp->lane_out.lstate |= VSW_VER_NACK_RECV;
24755373Sraghuram vsw_next_milestone(ldcp);
24765373Sraghuram } else {
24775373Sraghuram /* found a supported major version */
24785373Sraghuram ldcp->lane_out.ver_major = ver_pkt->ver_major;
24795373Sraghuram ldcp->lane_out.ver_minor = ver_pkt->ver_minor;
24805373Sraghuram
24815373Sraghuram D2(vswp, "%s: resending with updated values (%x, %x)",
24825373Sraghuram __func__, ver_pkt->ver_major, ver_pkt->ver_minor);
24835373Sraghuram
24845373Sraghuram ldcp->lane_out.lstate |= VSW_VER_INFO_SENT;
24855373Sraghuram ver_pkt->tag.vio_sid = ldcp->local_session;
24865373Sraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
24875373Sraghuram
24885373Sraghuram DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt);
24895373Sraghuram
24905373Sraghuram (void) vsw_send_msg(ldcp, (void *)ver_pkt,
24915373Sraghuram sizeof (vio_ver_msg_t), B_TRUE);
24925373Sraghuram
24935373Sraghuram vsw_next_milestone(ldcp);
24945373Sraghuram
24955373Sraghuram }
24965373Sraghuram break;
24975373Sraghuram
24985373Sraghuram default:
24995373Sraghuram DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
25005373Sraghuram ver_pkt->tag.vio_subtype);
25015373Sraghuram }
25025373Sraghuram
25035373Sraghuram D1(vswp, "%s(%lld): exit\n", __func__, ldcp->ldc_id);
25045373Sraghuram }
25055373Sraghuram
250612011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_attr_info(vsw_ldc_t * ldcp,vnet_attr_msg_t * msg)250712011SSriharsha.Basavapatna@Sun.COM vsw_process_attr_info(vsw_ldc_t *ldcp, vnet_attr_msg_t *msg)
250812011SSriharsha.Basavapatna@Sun.COM {
250912011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
251012011SSriharsha.Basavapatna@Sun.COM vsw_port_t *port = ldcp->ldc_port;
251112011SSriharsha.Basavapatna@Sun.COM struct ether_addr ea;
251212011SSriharsha.Basavapatna@Sun.COM uint64_t macaddr = 0;
251312011SSriharsha.Basavapatna@Sun.COM lane_t *lane_out = &ldcp->lane_out;
251412011SSriharsha.Basavapatna@Sun.COM lane_t *lane_in = &ldcp->lane_in;
251512011SSriharsha.Basavapatna@Sun.COM uint32_t mtu;
251612011SSriharsha.Basavapatna@Sun.COM int i;
251712011SSriharsha.Basavapatna@Sun.COM uint8_t dring_mode;
251812011SSriharsha.Basavapatna@Sun.COM
251912011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
252012011SSriharsha.Basavapatna@Sun.COM
252112011SSriharsha.Basavapatna@Sun.COM if (vsw_check_flag(ldcp, INBOUND, VSW_ATTR_INFO_RECV)) {
252212011SSriharsha.Basavapatna@Sun.COM return (1);
252312011SSriharsha.Basavapatna@Sun.COM }
252412011SSriharsha.Basavapatna@Sun.COM
252512011SSriharsha.Basavapatna@Sun.COM if ((msg->xfer_mode != VIO_DESC_MODE) &&
252612011SSriharsha.Basavapatna@Sun.COM (msg->xfer_mode != lane_out->xfer_mode)) {
252712011SSriharsha.Basavapatna@Sun.COM D2(NULL, "%s: unknown mode %x\n", __func__, msg->xfer_mode);
252812011SSriharsha.Basavapatna@Sun.COM return (1);
252912011SSriharsha.Basavapatna@Sun.COM }
253012011SSriharsha.Basavapatna@Sun.COM
253112011SSriharsha.Basavapatna@Sun.COM /* Only support MAC addresses at moment. */
253212011SSriharsha.Basavapatna@Sun.COM if ((msg->addr_type != ADDR_TYPE_MAC) || (msg->addr == 0)) {
253312011SSriharsha.Basavapatna@Sun.COM D2(NULL, "%s: invalid addr_type %x, or address 0x%llx\n",
253412011SSriharsha.Basavapatna@Sun.COM __func__, msg->addr_type, msg->addr);
253512011SSriharsha.Basavapatna@Sun.COM return (1);
253612011SSriharsha.Basavapatna@Sun.COM }
253712011SSriharsha.Basavapatna@Sun.COM
253812011SSriharsha.Basavapatna@Sun.COM /*
253912011SSriharsha.Basavapatna@Sun.COM * MAC address supplied by device should match that stored
254012011SSriharsha.Basavapatna@Sun.COM * in the vsw-port OBP node. Need to decide what to do if they
254112011SSriharsha.Basavapatna@Sun.COM * don't match, for the moment just warn but don't fail.
254212011SSriharsha.Basavapatna@Sun.COM */
254312011SSriharsha.Basavapatna@Sun.COM vnet_macaddr_ultostr(msg->addr, ea.ether_addr_octet);
254412011SSriharsha.Basavapatna@Sun.COM if (ether_cmp(&ea, &port->p_macaddr) != 0) {
254512011SSriharsha.Basavapatna@Sun.COM DERR(NULL, "%s: device supplied address "
254612011SSriharsha.Basavapatna@Sun.COM "0x%llx doesn't match node address 0x%llx\n",
254712011SSriharsha.Basavapatna@Sun.COM __func__, msg->addr, port->p_macaddr);
254812011SSriharsha.Basavapatna@Sun.COM }
254912011SSriharsha.Basavapatna@Sun.COM
255012011SSriharsha.Basavapatna@Sun.COM /*
255112011SSriharsha.Basavapatna@Sun.COM * Ack freq only makes sense in pkt mode, in shared
255212011SSriharsha.Basavapatna@Sun.COM * mode the ring descriptors say whether or not to
255312011SSriharsha.Basavapatna@Sun.COM * send back an ACK.
255412011SSriharsha.Basavapatna@Sun.COM */
255512011SSriharsha.Basavapatna@Sun.COM if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
255612011SSriharsha.Basavapatna@Sun.COM (msg->xfer_mode & VIO_DRING_MODE_V1_2)) ||
255712011SSriharsha.Basavapatna@Sun.COM (VSW_VER_LT(ldcp, 1, 2) &&
255812011SSriharsha.Basavapatna@Sun.COM (msg->xfer_mode == VIO_DRING_MODE_V1_0))) {
255912011SSriharsha.Basavapatna@Sun.COM if (msg->ack_freq > 0) {
256012011SSriharsha.Basavapatna@Sun.COM D2(NULL, "%s: non zero ack freq in SHM mode\n",
256112011SSriharsha.Basavapatna@Sun.COM __func__);
256212011SSriharsha.Basavapatna@Sun.COM return (1);
256312011SSriharsha.Basavapatna@Sun.COM }
256412011SSriharsha.Basavapatna@Sun.COM }
256512011SSriharsha.Basavapatna@Sun.COM
256612011SSriharsha.Basavapatna@Sun.COM /*
256712011SSriharsha.Basavapatna@Sun.COM * Process dring mode attribute.
256812011SSriharsha.Basavapatna@Sun.COM */
256912011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 6)) {
257012011SSriharsha.Basavapatna@Sun.COM /*
257112011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.6:
257212011SSriharsha.Basavapatna@Sun.COM * Though we are operating in v1.6 mode, it is possible that
257312011SSriharsha.Basavapatna@Sun.COM * RxDringData mode has been disabled either on this guest or
257412011SSriharsha.Basavapatna@Sun.COM * on the peer guest. If so, we revert to pre v1.6 behavior of
257512011SSriharsha.Basavapatna@Sun.COM * TxDring mode. But this must be agreed upon in both
257612011SSriharsha.Basavapatna@Sun.COM * directions of attr exchange. We first determine the mode
257712011SSriharsha.Basavapatna@Sun.COM * that can be negotiated.
257812011SSriharsha.Basavapatna@Sun.COM */
257912011SSriharsha.Basavapatna@Sun.COM if ((msg->options & VIO_RX_DRING_DATA) != 0 &&
2580*13098SWentao.Yang@Sun.COM vsw_mapin_avail(ldcp) == B_TRUE) {
258112011SSriharsha.Basavapatna@Sun.COM /*
258212011SSriharsha.Basavapatna@Sun.COM * The peer is capable of handling RxDringData AND we
258312011SSriharsha.Basavapatna@Sun.COM * are also capable of it; we enable RxDringData mode
258412011SSriharsha.Basavapatna@Sun.COM * on this channel.
258512011SSriharsha.Basavapatna@Sun.COM */
258612011SSriharsha.Basavapatna@Sun.COM dring_mode = VIO_RX_DRING_DATA;
258712011SSriharsha.Basavapatna@Sun.COM } else if ((msg->options & VIO_TX_DRING) != 0) {
258812011SSriharsha.Basavapatna@Sun.COM /*
258912011SSriharsha.Basavapatna@Sun.COM * If the peer is capable of TxDring mode, we
259012011SSriharsha.Basavapatna@Sun.COM * negotiate TxDring mode on this channel.
259112011SSriharsha.Basavapatna@Sun.COM */
259212011SSriharsha.Basavapatna@Sun.COM dring_mode = VIO_TX_DRING;
259312011SSriharsha.Basavapatna@Sun.COM } else {
259412011SSriharsha.Basavapatna@Sun.COM /*
259512011SSriharsha.Basavapatna@Sun.COM * We support only VIO_TX_DRING and VIO_RX_DRING_DATA
259612011SSriharsha.Basavapatna@Sun.COM * modes. We don't support VIO_RX_DRING mode.
259712011SSriharsha.Basavapatna@Sun.COM */
259812011SSriharsha.Basavapatna@Sun.COM return (1);
259912011SSriharsha.Basavapatna@Sun.COM }
260012011SSriharsha.Basavapatna@Sun.COM
260112011SSriharsha.Basavapatna@Sun.COM /*
260212011SSriharsha.Basavapatna@Sun.COM * If we have received an ack for the attr info that we sent,
260312011SSriharsha.Basavapatna@Sun.COM * then check if the dring mode matches what the peer had ack'd
260412011SSriharsha.Basavapatna@Sun.COM * (saved in lane_out). If they don't match, we fail the
260512011SSriharsha.Basavapatna@Sun.COM * handshake.
260612011SSriharsha.Basavapatna@Sun.COM */
260712011SSriharsha.Basavapatna@Sun.COM if (lane_out->lstate & VSW_ATTR_ACK_RECV) {
260812011SSriharsha.Basavapatna@Sun.COM if (msg->options != lane_out->dring_mode) {
260912011SSriharsha.Basavapatna@Sun.COM /* send NACK */
261012011SSriharsha.Basavapatna@Sun.COM return (1);
261112011SSriharsha.Basavapatna@Sun.COM }
261212011SSriharsha.Basavapatna@Sun.COM } else {
261312011SSriharsha.Basavapatna@Sun.COM /*
261412011SSriharsha.Basavapatna@Sun.COM * Save the negotiated dring mode in our attr
261512011SSriharsha.Basavapatna@Sun.COM * parameters, so it gets sent in the attr info from us
261612011SSriharsha.Basavapatna@Sun.COM * to the peer.
261712011SSriharsha.Basavapatna@Sun.COM */
261812011SSriharsha.Basavapatna@Sun.COM lane_out->dring_mode = dring_mode;
261912011SSriharsha.Basavapatna@Sun.COM }
262012011SSriharsha.Basavapatna@Sun.COM
262112011SSriharsha.Basavapatna@Sun.COM /* save the negotiated dring mode in the msg to be replied */
262212011SSriharsha.Basavapatna@Sun.COM msg->options = dring_mode;
262312011SSriharsha.Basavapatna@Sun.COM }
262412011SSriharsha.Basavapatna@Sun.COM
262512011SSriharsha.Basavapatna@Sun.COM /*
262612011SSriharsha.Basavapatna@Sun.COM * Process MTU attribute.
262712011SSriharsha.Basavapatna@Sun.COM */
262812011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 4)) {
262912011SSriharsha.Basavapatna@Sun.COM /*
263012011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4:
263112011SSriharsha.Basavapatna@Sun.COM * Validate mtu of the peer is at least ETHERMAX. Then, the mtu
263212011SSriharsha.Basavapatna@Sun.COM * is negotiated down to the minimum of our mtu and peer's mtu.
263312011SSriharsha.Basavapatna@Sun.COM */
263412011SSriharsha.Basavapatna@Sun.COM if (msg->mtu < ETHERMAX) {
263512011SSriharsha.Basavapatna@Sun.COM return (1);
263612011SSriharsha.Basavapatna@Sun.COM }
263712011SSriharsha.Basavapatna@Sun.COM
263812011SSriharsha.Basavapatna@Sun.COM mtu = MIN(msg->mtu, vswp->max_frame_size);
263912011SSriharsha.Basavapatna@Sun.COM
264012011SSriharsha.Basavapatna@Sun.COM /*
264112011SSriharsha.Basavapatna@Sun.COM * If we have received an ack for the attr info
264212011SSriharsha.Basavapatna@Sun.COM * that we sent, then check if the mtu computed
264312011SSriharsha.Basavapatna@Sun.COM * above matches the mtu that the peer had ack'd
264412011SSriharsha.Basavapatna@Sun.COM * (saved in local hparams). If they don't
264512011SSriharsha.Basavapatna@Sun.COM * match, we fail the handshake.
264612011SSriharsha.Basavapatna@Sun.COM */
264712011SSriharsha.Basavapatna@Sun.COM if (lane_out->lstate & VSW_ATTR_ACK_RECV) {
264812011SSriharsha.Basavapatna@Sun.COM if (mtu != lane_out->mtu) {
264912011SSriharsha.Basavapatna@Sun.COM /* send NACK */
265012011SSriharsha.Basavapatna@Sun.COM return (1);
265112011SSriharsha.Basavapatna@Sun.COM }
265212011SSriharsha.Basavapatna@Sun.COM } else {
265312011SSriharsha.Basavapatna@Sun.COM /*
265412011SSriharsha.Basavapatna@Sun.COM * Save the mtu computed above in our
265512011SSriharsha.Basavapatna@Sun.COM * attr parameters, so it gets sent in
265612011SSriharsha.Basavapatna@Sun.COM * the attr info from us to the peer.
265712011SSriharsha.Basavapatna@Sun.COM */
265812011SSriharsha.Basavapatna@Sun.COM lane_out->mtu = mtu;
265912011SSriharsha.Basavapatna@Sun.COM }
266012011SSriharsha.Basavapatna@Sun.COM
266112011SSriharsha.Basavapatna@Sun.COM /* save the MIN mtu in the msg to be replied */
266212011SSriharsha.Basavapatna@Sun.COM msg->mtu = mtu;
266312011SSriharsha.Basavapatna@Sun.COM } else {
266412011SSriharsha.Basavapatna@Sun.COM /* Versions < 1.4, mtu must match */
266512011SSriharsha.Basavapatna@Sun.COM if (msg->mtu != lane_out->mtu) {
266612011SSriharsha.Basavapatna@Sun.COM D2(NULL, "%s: invalid MTU (0x%llx)\n",
266712011SSriharsha.Basavapatna@Sun.COM __func__, msg->mtu);
266812011SSriharsha.Basavapatna@Sun.COM return (1);
266912011SSriharsha.Basavapatna@Sun.COM }
267012011SSriharsha.Basavapatna@Sun.COM }
267112011SSriharsha.Basavapatna@Sun.COM
267212011SSriharsha.Basavapatna@Sun.COM /*
267312011SSriharsha.Basavapatna@Sun.COM * Otherwise store attributes for this lane and update
267412011SSriharsha.Basavapatna@Sun.COM * lane state.
267512011SSriharsha.Basavapatna@Sun.COM */
267612011SSriharsha.Basavapatna@Sun.COM lane_in->mtu = msg->mtu;
267712011SSriharsha.Basavapatna@Sun.COM lane_in->addr = msg->addr;
267812011SSriharsha.Basavapatna@Sun.COM lane_in->addr_type = msg->addr_type;
267912011SSriharsha.Basavapatna@Sun.COM lane_in->xfer_mode = msg->xfer_mode;
268012011SSriharsha.Basavapatna@Sun.COM lane_in->ack_freq = msg->ack_freq;
268112011SSriharsha.Basavapatna@Sun.COM lane_in->physlink_update = msg->physlink_update;
268212011SSriharsha.Basavapatna@Sun.COM lane_in->dring_mode = msg->options;
268312011SSriharsha.Basavapatna@Sun.COM
268412011SSriharsha.Basavapatna@Sun.COM /*
268512011SSriharsha.Basavapatna@Sun.COM * Check if the client has requested physlink state updates.
268612011SSriharsha.Basavapatna@Sun.COM * If there is a physical device bound to this vswitch (L2
268712011SSriharsha.Basavapatna@Sun.COM * mode), set the ack bits to indicate it is supported.
268812011SSriharsha.Basavapatna@Sun.COM * Otherwise, set the nack bits.
268912011SSriharsha.Basavapatna@Sun.COM */
269012011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 5)) { /* Protocol ver >= 1.5 */
269112011SSriharsha.Basavapatna@Sun.COM
269212011SSriharsha.Basavapatna@Sun.COM /* Does the vnet need phys link state updates ? */
269312011SSriharsha.Basavapatna@Sun.COM if ((lane_in->physlink_update &
269412011SSriharsha.Basavapatna@Sun.COM PHYSLINK_UPDATE_STATE_MASK) ==
269512011SSriharsha.Basavapatna@Sun.COM PHYSLINK_UPDATE_STATE) {
269612011SSriharsha.Basavapatna@Sun.COM
269712011SSriharsha.Basavapatna@Sun.COM if (vswp->smode & VSW_LAYER2) {
269812011SSriharsha.Basavapatna@Sun.COM /* is a net-dev assigned to us ? */
269912011SSriharsha.Basavapatna@Sun.COM msg->physlink_update =
270012011SSriharsha.Basavapatna@Sun.COM PHYSLINK_UPDATE_STATE_ACK;
270112011SSriharsha.Basavapatna@Sun.COM ldcp->pls_negotiated = B_TRUE;
270212011SSriharsha.Basavapatna@Sun.COM } else {
270312011SSriharsha.Basavapatna@Sun.COM /* not in L2 mode */
270412011SSriharsha.Basavapatna@Sun.COM msg->physlink_update =
270512011SSriharsha.Basavapatna@Sun.COM PHYSLINK_UPDATE_STATE_NACK;
270612011SSriharsha.Basavapatna@Sun.COM ldcp->pls_negotiated = B_FALSE;
270712011SSriharsha.Basavapatna@Sun.COM }
270812011SSriharsha.Basavapatna@Sun.COM
270912011SSriharsha.Basavapatna@Sun.COM } else {
271012011SSriharsha.Basavapatna@Sun.COM msg->physlink_update =
271112011SSriharsha.Basavapatna@Sun.COM PHYSLINK_UPDATE_NONE;
271212011SSriharsha.Basavapatna@Sun.COM ldcp->pls_negotiated = B_FALSE;
271312011SSriharsha.Basavapatna@Sun.COM }
271412011SSriharsha.Basavapatna@Sun.COM
271512011SSriharsha.Basavapatna@Sun.COM } else {
271612011SSriharsha.Basavapatna@Sun.COM /*
271712011SSriharsha.Basavapatna@Sun.COM * physlink_update bits are ignored
271812011SSriharsha.Basavapatna@Sun.COM * if set by clients < v1.5 protocol.
271912011SSriharsha.Basavapatna@Sun.COM */
272012011SSriharsha.Basavapatna@Sun.COM msg->physlink_update = PHYSLINK_UPDATE_NONE;
272112011SSriharsha.Basavapatna@Sun.COM ldcp->pls_negotiated = B_FALSE;
272212011SSriharsha.Basavapatna@Sun.COM }
272312011SSriharsha.Basavapatna@Sun.COM
272412011SSriharsha.Basavapatna@Sun.COM macaddr = lane_in->addr;
272512011SSriharsha.Basavapatna@Sun.COM for (i = ETHERADDRL - 1; i >= 0; i--) {
272612011SSriharsha.Basavapatna@Sun.COM port->p_macaddr.ether_addr_octet[i] = macaddr & 0xFF;
272712011SSriharsha.Basavapatna@Sun.COM macaddr >>= 8;
272812011SSriharsha.Basavapatna@Sun.COM }
272912011SSriharsha.Basavapatna@Sun.COM
273012011SSriharsha.Basavapatna@Sun.COM /*
273112011SSriharsha.Basavapatna@Sun.COM * Setup device specific xmit routines. Note this could be changed
273212011SSriharsha.Basavapatna@Sun.COM * further in vsw_send_dring_info() for versions >= 1.6 if operating in
273312011SSriharsha.Basavapatna@Sun.COM * RxDringData mode.
273412011SSriharsha.Basavapatna@Sun.COM */
273512011SSriharsha.Basavapatna@Sun.COM mutex_enter(&port->tx_lock);
273612011SSriharsha.Basavapatna@Sun.COM
273712011SSriharsha.Basavapatna@Sun.COM if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
273812011SSriharsha.Basavapatna@Sun.COM (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
273912011SSriharsha.Basavapatna@Sun.COM (VSW_VER_LT(ldcp, 1, 2) &&
274012011SSriharsha.Basavapatna@Sun.COM (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) {
274112011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: mode = VIO_DRING_MODE", __func__);
274212011SSriharsha.Basavapatna@Sun.COM port->transmit = vsw_dringsend;
274312011SSriharsha.Basavapatna@Sun.COM } else if (lane_in->xfer_mode == VIO_DESC_MODE) {
274412011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: mode = VIO_DESC_MODE", __func__);
274512011SSriharsha.Basavapatna@Sun.COM vsw_create_privring(ldcp);
274612011SSriharsha.Basavapatna@Sun.COM port->transmit = vsw_descrsend;
274712011SSriharsha.Basavapatna@Sun.COM lane_out->xfer_mode = VIO_DESC_MODE;
274812011SSriharsha.Basavapatna@Sun.COM }
274912011SSriharsha.Basavapatna@Sun.COM
275012011SSriharsha.Basavapatna@Sun.COM /*
275112011SSriharsha.Basavapatna@Sun.COM * HybridIO is supported only vnet, not by OBP.
275212011SSriharsha.Basavapatna@Sun.COM * So, set hio_capable to true only when in DRING mode.
275312011SSriharsha.Basavapatna@Sun.COM */
275412011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 3) &&
275512011SSriharsha.Basavapatna@Sun.COM (lane_in->xfer_mode != VIO_DESC_MODE)) {
275612011SSriharsha.Basavapatna@Sun.COM (void) atomic_swap_32(&port->p_hio_capable, B_TRUE);
275712011SSriharsha.Basavapatna@Sun.COM } else {
275812011SSriharsha.Basavapatna@Sun.COM (void) atomic_swap_32(&port->p_hio_capable, B_FALSE);
275912011SSriharsha.Basavapatna@Sun.COM }
276012011SSriharsha.Basavapatna@Sun.COM
276112011SSriharsha.Basavapatna@Sun.COM mutex_exit(&port->tx_lock);
276212011SSriharsha.Basavapatna@Sun.COM
276312011SSriharsha.Basavapatna@Sun.COM return (0);
276412011SSriharsha.Basavapatna@Sun.COM }
276512011SSriharsha.Basavapatna@Sun.COM
276612011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_attr_ack(vsw_ldc_t * ldcp,vnet_attr_msg_t * msg)276712011SSriharsha.Basavapatna@Sun.COM vsw_process_attr_ack(vsw_ldc_t *ldcp, vnet_attr_msg_t *msg)
276812011SSriharsha.Basavapatna@Sun.COM {
276912011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
277012011SSriharsha.Basavapatna@Sun.COM lane_t *lane_out = &ldcp->lane_out;
277112011SSriharsha.Basavapatna@Sun.COM lane_t *lane_in = &ldcp->lane_in;
277212011SSriharsha.Basavapatna@Sun.COM
277312011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
277412011SSriharsha.Basavapatna@Sun.COM
277512011SSriharsha.Basavapatna@Sun.COM if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_ACK_RECV)) {
277612011SSriharsha.Basavapatna@Sun.COM return (1);
277712011SSriharsha.Basavapatna@Sun.COM }
277812011SSriharsha.Basavapatna@Sun.COM
277912011SSriharsha.Basavapatna@Sun.COM /*
278012011SSriharsha.Basavapatna@Sun.COM * Process dring mode attribute.
278112011SSriharsha.Basavapatna@Sun.COM */
278212011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 6)) {
278312011SSriharsha.Basavapatna@Sun.COM /*
278412011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.6:
278512011SSriharsha.Basavapatna@Sun.COM * The ack msg sent by the peer contains the negotiated dring
278612011SSriharsha.Basavapatna@Sun.COM * mode between our capability (that we had sent in our attr
278712011SSriharsha.Basavapatna@Sun.COM * info) and the peer's capability.
278812011SSriharsha.Basavapatna@Sun.COM */
278912011SSriharsha.Basavapatna@Sun.COM if (lane_in->lstate & VSW_ATTR_ACK_SENT) {
279012011SSriharsha.Basavapatna@Sun.COM /*
279112011SSriharsha.Basavapatna@Sun.COM * If we have sent an ack for the attr info msg from
279212011SSriharsha.Basavapatna@Sun.COM * the peer, check if the dring mode that was
279312011SSriharsha.Basavapatna@Sun.COM * negotiated then (saved in lane_out) matches the
279412011SSriharsha.Basavapatna@Sun.COM * mode that the peer has ack'd. If they don't match,
279512011SSriharsha.Basavapatna@Sun.COM * we fail the handshake.
279612011SSriharsha.Basavapatna@Sun.COM */
279712011SSriharsha.Basavapatna@Sun.COM if (lane_out->dring_mode != msg->options) {
279812011SSriharsha.Basavapatna@Sun.COM return (1);
279912011SSriharsha.Basavapatna@Sun.COM }
280012011SSriharsha.Basavapatna@Sun.COM } else {
280112011SSriharsha.Basavapatna@Sun.COM if ((msg->options & lane_out->dring_mode) == 0) {
280212011SSriharsha.Basavapatna@Sun.COM /*
280312011SSriharsha.Basavapatna@Sun.COM * Peer ack'd with a mode that we don't
280412011SSriharsha.Basavapatna@Sun.COM * support; we fail the handshake.
280512011SSriharsha.Basavapatna@Sun.COM */
280612011SSriharsha.Basavapatna@Sun.COM return (1);
280712011SSriharsha.Basavapatna@Sun.COM }
280812011SSriharsha.Basavapatna@Sun.COM if ((msg->options & (VIO_TX_DRING|VIO_RX_DRING_DATA))
280912011SSriharsha.Basavapatna@Sun.COM == (VIO_TX_DRING|VIO_RX_DRING_DATA)) {
281012011SSriharsha.Basavapatna@Sun.COM /*
281112011SSriharsha.Basavapatna@Sun.COM * Peer must ack with only one negotiated mode.
281212011SSriharsha.Basavapatna@Sun.COM * Otherwise fail handshake.
281312011SSriharsha.Basavapatna@Sun.COM */
281412011SSriharsha.Basavapatna@Sun.COM return (1);
281512011SSriharsha.Basavapatna@Sun.COM }
281612011SSriharsha.Basavapatna@Sun.COM
281712011SSriharsha.Basavapatna@Sun.COM /*
281812011SSriharsha.Basavapatna@Sun.COM * Save the negotiated mode, so we can validate it when
281912011SSriharsha.Basavapatna@Sun.COM * we receive attr info from the peer.
282012011SSriharsha.Basavapatna@Sun.COM */
282112011SSriharsha.Basavapatna@Sun.COM lane_out->dring_mode = msg->options;
282212011SSriharsha.Basavapatna@Sun.COM }
282312011SSriharsha.Basavapatna@Sun.COM }
282412011SSriharsha.Basavapatna@Sun.COM
282512011SSriharsha.Basavapatna@Sun.COM /*
282612011SSriharsha.Basavapatna@Sun.COM * Process MTU attribute.
282712011SSriharsha.Basavapatna@Sun.COM */
282812011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 4)) {
282912011SSriharsha.Basavapatna@Sun.COM /*
283012011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4:
283112011SSriharsha.Basavapatna@Sun.COM * The ack msg sent by the peer contains the minimum of
283212011SSriharsha.Basavapatna@Sun.COM * our mtu (that we had sent in our attr info) and the
283312011SSriharsha.Basavapatna@Sun.COM * peer's mtu.
283412011SSriharsha.Basavapatna@Sun.COM *
283512011SSriharsha.Basavapatna@Sun.COM * If we have sent an ack for the attr info msg from
283612011SSriharsha.Basavapatna@Sun.COM * the peer, check if the mtu that was computed then
283712011SSriharsha.Basavapatna@Sun.COM * (saved in lane_out params) matches the mtu that the
283812011SSriharsha.Basavapatna@Sun.COM * peer has ack'd. If they don't match, we fail the
283912011SSriharsha.Basavapatna@Sun.COM * handshake.
284012011SSriharsha.Basavapatna@Sun.COM */
284112011SSriharsha.Basavapatna@Sun.COM if (lane_in->lstate & VSW_ATTR_ACK_SENT) {
284212011SSriharsha.Basavapatna@Sun.COM if (lane_out->mtu != msg->mtu) {
284312011SSriharsha.Basavapatna@Sun.COM return (1);
284412011SSriharsha.Basavapatna@Sun.COM }
284512011SSriharsha.Basavapatna@Sun.COM } else {
284612011SSriharsha.Basavapatna@Sun.COM /*
284712011SSriharsha.Basavapatna@Sun.COM * If the mtu ack'd by the peer is > our mtu
284812011SSriharsha.Basavapatna@Sun.COM * fail handshake. Otherwise, save the mtu, so
284912011SSriharsha.Basavapatna@Sun.COM * we can validate it when we receive attr info
285012011SSriharsha.Basavapatna@Sun.COM * from our peer.
285112011SSriharsha.Basavapatna@Sun.COM */
285212011SSriharsha.Basavapatna@Sun.COM if (msg->mtu <= lane_out->mtu) {
285312011SSriharsha.Basavapatna@Sun.COM lane_out->mtu = msg->mtu;
285412011SSriharsha.Basavapatna@Sun.COM } else {
285512011SSriharsha.Basavapatna@Sun.COM return (1);
285612011SSriharsha.Basavapatna@Sun.COM }
285712011SSriharsha.Basavapatna@Sun.COM }
285812011SSriharsha.Basavapatna@Sun.COM }
285912011SSriharsha.Basavapatna@Sun.COM
286012011SSriharsha.Basavapatna@Sun.COM return (0);
286112011SSriharsha.Basavapatna@Sun.COM }
286212011SSriharsha.Basavapatna@Sun.COM
28635373Sraghuram /*
28645373Sraghuram * Process an attribute packet. We can end up here either because our peer
28655373Sraghuram * has ACK/NACK'ed back to an earlier ATTR msg we had sent it, or our
28665373Sraghuram * peer has sent us an attribute INFO message
28675373Sraghuram *
28685373Sraghuram * If its an ACK we then move to the next stage of the handshake which
28695373Sraghuram * is to send our descriptor ring info to our peer. If its a NACK then
28705373Sraghuram * there is nothing more we can (currently) do.
28715373Sraghuram *
28725373Sraghuram * If we get a valid/acceptable INFO packet (and we have already negotiated
28735373Sraghuram * a version) we ACK back and set channel state to ATTR_RECV, otherwise we
28745373Sraghuram * NACK back and reset channel state to INACTIV.
28755373Sraghuram *
28765373Sraghuram * FUTURE: in time we will probably negotiate over attributes, but for
28775373Sraghuram * the moment unacceptable attributes are regarded as a fatal error.
28785373Sraghuram *
28795373Sraghuram */
28805373Sraghuram void
vsw_process_ctrl_attr_pkt(vsw_ldc_t * ldcp,void * pkt)28815373Sraghuram vsw_process_ctrl_attr_pkt(vsw_ldc_t *ldcp, void *pkt)
28825373Sraghuram {
288312011SSriharsha.Basavapatna@Sun.COM vnet_attr_msg_t *attr_pkt;
288412011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
288512011SSriharsha.Basavapatna@Sun.COM lane_t *lane_out = &ldcp->lane_out;
288612011SSriharsha.Basavapatna@Sun.COM lane_t *lane_in = &ldcp->lane_in;
288712011SSriharsha.Basavapatna@Sun.COM int rv;
28885373Sraghuram
28895373Sraghuram D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
28905373Sraghuram
28915373Sraghuram /*
28925373Sraghuram * We know this is a ctrl/attr packet so
28935373Sraghuram * cast it into the correct structure.
28945373Sraghuram */
28955373Sraghuram attr_pkt = (vnet_attr_msg_t *)pkt;
28965373Sraghuram
28975373Sraghuram switch (attr_pkt->tag.vio_subtype) {
28985373Sraghuram case VIO_SUBTYPE_INFO:
289912011SSriharsha.Basavapatna@Sun.COM
290012011SSriharsha.Basavapatna@Sun.COM rv = vsw_process_attr_info(ldcp, attr_pkt);
290112011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
290212011SSriharsha.Basavapatna@Sun.COM vsw_free_lane_resources(ldcp, INBOUND);
290312011SSriharsha.Basavapatna@Sun.COM attr_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK;
290412011SSriharsha.Basavapatna@Sun.COM ldcp->lane_in.lstate |= VSW_ATTR_NACK_SENT;
29057529SSriharsha.Basavapatna@Sun.COM } else {
290612011SSriharsha.Basavapatna@Sun.COM attr_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
290712011SSriharsha.Basavapatna@Sun.COM lane_in->lstate |= VSW_ATTR_ACK_SENT;
29085373Sraghuram }
29095373Sraghuram attr_pkt->tag.vio_sid = ldcp->local_session;
29105373Sraghuram DUMP_TAG_PTR((vio_msg_tag_t *)attr_pkt);
29115373Sraghuram (void) vsw_send_msg(ldcp, (void *)attr_pkt,
29125373Sraghuram sizeof (vnet_attr_msg_t), B_TRUE);
29135373Sraghuram vsw_next_milestone(ldcp);
29145373Sraghuram break;
29155373Sraghuram
29165373Sraghuram case VIO_SUBTYPE_ACK:
291712011SSriharsha.Basavapatna@Sun.COM
291812011SSriharsha.Basavapatna@Sun.COM rv = vsw_process_attr_ack(ldcp, attr_pkt);
291912011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
29205373Sraghuram return;
29217529SSriharsha.Basavapatna@Sun.COM }
29227529SSriharsha.Basavapatna@Sun.COM lane_out->lstate |= VSW_ATTR_ACK_RECV;
29235373Sraghuram vsw_next_milestone(ldcp);
29245373Sraghuram break;
29255373Sraghuram
29265373Sraghuram case VIO_SUBTYPE_NACK:
29275373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
29285373Sraghuram
29295373Sraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_NACK_RECV))
29305373Sraghuram return;
29315373Sraghuram
29327529SSriharsha.Basavapatna@Sun.COM lane_out->lstate |= VSW_ATTR_NACK_RECV;
29335373Sraghuram vsw_next_milestone(ldcp);
29345373Sraghuram break;
29355373Sraghuram
29365373Sraghuram default:
29375373Sraghuram DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
29385373Sraghuram attr_pkt->tag.vio_subtype);
29395373Sraghuram }
29405373Sraghuram
29415373Sraghuram D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
29425373Sraghuram }
29435373Sraghuram
294412011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_dring_reg_info(vsw_ldc_t * ldcp,vio_msg_tag_t * tagp)294512011SSriharsha.Basavapatna@Sun.COM vsw_process_dring_reg_info(vsw_ldc_t *ldcp, vio_msg_tag_t *tagp)
294612011SSriharsha.Basavapatna@Sun.COM {
294712011SSriharsha.Basavapatna@Sun.COM int rv;
294812011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
294912011SSriharsha.Basavapatna@Sun.COM lane_t *lp = &ldcp->lane_out;
295012011SSriharsha.Basavapatna@Sun.COM dring_info_t *dp = NULL;
295112011SSriharsha.Basavapatna@Sun.COM
295212011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
295312011SSriharsha.Basavapatna@Sun.COM
295412011SSriharsha.Basavapatna@Sun.COM rv = vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV);
295512011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
295612011SSriharsha.Basavapatna@Sun.COM return (1);
295712011SSriharsha.Basavapatna@Sun.COM }
295812011SSriharsha.Basavapatna@Sun.COM
295912011SSriharsha.Basavapatna@Sun.COM if (VSW_VER_GTEQ(ldcp, 1, 6) &&
296012011SSriharsha.Basavapatna@Sun.COM (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) {
296112011SSriharsha.Basavapatna@Sun.COM /*
296212011SSriharsha.Basavapatna@Sun.COM * The earlier version of Solaris vnet driver doesn't set the
296312011SSriharsha.Basavapatna@Sun.COM * option (VIO_TX_DRING in its case) correctly in its dring reg
296412011SSriharsha.Basavapatna@Sun.COM * message. We workaround that here by doing the check only
296512011SSriharsha.Basavapatna@Sun.COM * for versions >= v1.6.
296612011SSriharsha.Basavapatna@Sun.COM */
296712011SSriharsha.Basavapatna@Sun.COM DWARN(vswp, "%s(%lld): Rcvd dring reg option (%d), "
296812011SSriharsha.Basavapatna@Sun.COM "negotiated mode (%d)\n", __func__, ldcp->ldc_id,
296912011SSriharsha.Basavapatna@Sun.COM ((vio_dring_reg_msg_t *)tagp)->options, lp->dring_mode);
297012011SSriharsha.Basavapatna@Sun.COM return (1);
297112011SSriharsha.Basavapatna@Sun.COM }
297212011SSriharsha.Basavapatna@Sun.COM
297312011SSriharsha.Basavapatna@Sun.COM /*
297412011SSriharsha.Basavapatna@Sun.COM * Map dring exported by the peer.
297512011SSriharsha.Basavapatna@Sun.COM */
297612011SSriharsha.Basavapatna@Sun.COM dp = vsw_map_dring(ldcp, (void *)tagp);
297712011SSriharsha.Basavapatna@Sun.COM if (dp == NULL) {
297812011SSriharsha.Basavapatna@Sun.COM return (1);
297912011SSriharsha.Basavapatna@Sun.COM }
298012011SSriharsha.Basavapatna@Sun.COM
298112011SSriharsha.Basavapatna@Sun.COM /*
298212011SSriharsha.Basavapatna@Sun.COM * Map data buffers exported by the peer if we are in RxDringData mode.
298312011SSriharsha.Basavapatna@Sun.COM */
298412011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
298512011SSriharsha.Basavapatna@Sun.COM rv = vsw_map_data(ldcp, dp, (void *)tagp);
298612011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
298712011SSriharsha.Basavapatna@Sun.COM vsw_unmap_dring(ldcp);
298812011SSriharsha.Basavapatna@Sun.COM return (1);
298912011SSriharsha.Basavapatna@Sun.COM }
299012011SSriharsha.Basavapatna@Sun.COM }
299112011SSriharsha.Basavapatna@Sun.COM
299212011SSriharsha.Basavapatna@Sun.COM return (0);
299312011SSriharsha.Basavapatna@Sun.COM }
299412011SSriharsha.Basavapatna@Sun.COM
299512011SSriharsha.Basavapatna@Sun.COM static int
vsw_process_dring_reg_ack(vsw_ldc_t * ldcp,vio_msg_tag_t * tagp)299612011SSriharsha.Basavapatna@Sun.COM vsw_process_dring_reg_ack(vsw_ldc_t *ldcp, vio_msg_tag_t *tagp)
299712011SSriharsha.Basavapatna@Sun.COM {
299812011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
299912011SSriharsha.Basavapatna@Sun.COM dring_info_t *dp;
300012011SSriharsha.Basavapatna@Sun.COM
300112011SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
300212011SSriharsha.Basavapatna@Sun.COM
300312011SSriharsha.Basavapatna@Sun.COM if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_ACK_RECV)) {
300412011SSriharsha.Basavapatna@Sun.COM return (1);
300512011SSriharsha.Basavapatna@Sun.COM }
300612011SSriharsha.Basavapatna@Sun.COM
300712011SSriharsha.Basavapatna@Sun.COM dp = ldcp->lane_out.dringp;
300812011SSriharsha.Basavapatna@Sun.COM
300912011SSriharsha.Basavapatna@Sun.COM /* save dring_ident acked by peer */
301012011SSriharsha.Basavapatna@Sun.COM dp->ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident;
301112011SSriharsha.Basavapatna@Sun.COM
301212011SSriharsha.Basavapatna@Sun.COM return (0);
301312011SSriharsha.Basavapatna@Sun.COM }
301412011SSriharsha.Basavapatna@Sun.COM
30155373Sraghuram /*
30165373Sraghuram * Process a dring info packet. We can end up here either because our peer
30175373Sraghuram * has ACK/NACK'ed back to an earlier DRING msg we had sent it, or our
30185373Sraghuram * peer has sent us a dring INFO message.
30195373Sraghuram *
30205373Sraghuram * If we get a valid/acceptable INFO packet (and we have already negotiated
30215373Sraghuram * a version) we ACK back and update the lane state, otherwise we NACK back.
30225373Sraghuram *
30235373Sraghuram * FUTURE: nothing to stop client from sending us info on multiple dring's
30245373Sraghuram * but for the moment we will just use the first one we are given.
30255373Sraghuram *
30265373Sraghuram */
30275373Sraghuram void
vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t * ldcp,void * pkt)30285373Sraghuram vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *ldcp, void *pkt)
30295373Sraghuram {
303012011SSriharsha.Basavapatna@Sun.COM int rv;
303112011SSriharsha.Basavapatna@Sun.COM int msgsize;
303212011SSriharsha.Basavapatna@Sun.COM dring_info_t *dp;
303312011SSriharsha.Basavapatna@Sun.COM vio_msg_tag_t *tagp = (vio_msg_tag_t *)pkt;
303412011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
303512011SSriharsha.Basavapatna@Sun.COM lane_t *lane_out = &ldcp->lane_out;
303612011SSriharsha.Basavapatna@Sun.COM lane_t *lane_in = &ldcp->lane_in;
30375373Sraghuram
30385373Sraghuram D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
30395373Sraghuram
304012011SSriharsha.Basavapatna@Sun.COM switch (tagp->vio_subtype) {
30415373Sraghuram case VIO_SUBTYPE_INFO:
304212011SSriharsha.Basavapatna@Sun.COM rv = vsw_process_dring_reg_info(ldcp, tagp);
304312011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
30445373Sraghuram vsw_free_lane_resources(ldcp, INBOUND);
304512011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_NACK;
304612011SSriharsha.Basavapatna@Sun.COM lane_in->lstate |= VSW_DRING_NACK_SENT;
30475373Sraghuram } else {
304812011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_ACK;
304912011SSriharsha.Basavapatna@Sun.COM lane_in->lstate |= VSW_DRING_ACK_SENT;
30505373Sraghuram }
305112011SSriharsha.Basavapatna@Sun.COM tagp->vio_sid = ldcp->local_session;
305212011SSriharsha.Basavapatna@Sun.COM DUMP_TAG_PTR(tagp);
305312011SSriharsha.Basavapatna@Sun.COM if (lane_out->dring_mode == VIO_RX_DRING_DATA) {
305412011SSriharsha.Basavapatna@Sun.COM dp = lane_in->dringp;
305512011SSriharsha.Basavapatna@Sun.COM msgsize =
305612011SSriharsha.Basavapatna@Sun.COM VNET_DRING_REG_EXT_MSG_SIZE(dp->data_ncookies);
30575373Sraghuram } else {
305812011SSriharsha.Basavapatna@Sun.COM msgsize = sizeof (vio_dring_reg_msg_t);
30595373Sraghuram }
306012011SSriharsha.Basavapatna@Sun.COM (void) vsw_send_msg(ldcp, (void *)tagp, msgsize, B_TRUE);
30615373Sraghuram vsw_next_milestone(ldcp);
30625373Sraghuram break;
30635373Sraghuram
30645373Sraghuram case VIO_SUBTYPE_ACK:
306512011SSriharsha.Basavapatna@Sun.COM rv = vsw_process_dring_reg_ack(ldcp, tagp);
306612011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
30675373Sraghuram return;
30685373Sraghuram }
306912011SSriharsha.Basavapatna@Sun.COM lane_out->lstate |= VSW_DRING_ACK_RECV;
30705373Sraghuram vsw_next_milestone(ldcp);
30715373Sraghuram break;
30725373Sraghuram
30735373Sraghuram case VIO_SUBTYPE_NACK:
30745373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
30755373Sraghuram
30765373Sraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_NACK_RECV))
30775373Sraghuram return;
30785373Sraghuram
307912011SSriharsha.Basavapatna@Sun.COM lane_out->lstate |= VSW_DRING_NACK_RECV;
30805373Sraghuram vsw_next_milestone(ldcp);
30815373Sraghuram break;
30825373Sraghuram
30835373Sraghuram default:
30845373Sraghuram DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
308512011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype);
30865373Sraghuram }
30875373Sraghuram
30885373Sraghuram D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
30895373Sraghuram }
30905373Sraghuram
30915373Sraghuram /*
30925373Sraghuram * Process a request from peer to unregister a dring.
30935373Sraghuram *
30945373Sraghuram * For the moment we just restart the handshake if our
30955373Sraghuram * peer endpoint attempts to unregister a dring.
30965373Sraghuram */
30975373Sraghuram void
vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t * ldcp,void * pkt)30985373Sraghuram vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *ldcp, void *pkt)
30995373Sraghuram {
31005373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
31015373Sraghuram vio_dring_unreg_msg_t *dring_pkt;
31025373Sraghuram
31035373Sraghuram /*
31045373Sraghuram * We know this is a ctrl/dring packet so
31055373Sraghuram * cast it into the correct structure.
31065373Sraghuram */
31075373Sraghuram dring_pkt = (vio_dring_unreg_msg_t *)pkt;
31085373Sraghuram
31095373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
31105373Sraghuram
31115373Sraghuram switch (dring_pkt->tag.vio_subtype) {
31125373Sraghuram case VIO_SUBTYPE_INFO:
31135373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
31145373Sraghuram
31155373Sraghuram DWARN(vswp, "%s: restarting handshake..", __func__);
31165373Sraghuram break;
31175373Sraghuram
31185373Sraghuram case VIO_SUBTYPE_ACK:
31195373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
31205373Sraghuram
31215373Sraghuram DWARN(vswp, "%s: restarting handshake..", __func__);
31225373Sraghuram break;
31235373Sraghuram
31245373Sraghuram case VIO_SUBTYPE_NACK:
31255373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
31265373Sraghuram
31275373Sraghuram DWARN(vswp, "%s: restarting handshake..", __func__);
31285373Sraghuram break;
31295373Sraghuram
31305373Sraghuram default:
31315373Sraghuram DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
31325373Sraghuram dring_pkt->tag.vio_subtype);
31335373Sraghuram }
31345373Sraghuram
31355373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
31365373Sraghuram
31375373Sraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
31385373Sraghuram }
31395373Sraghuram
31405373Sraghuram #define SND_MCST_NACK(ldcp, pkt) \
31415373Sraghuram pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; \
31425373Sraghuram pkt->tag.vio_sid = ldcp->local_session; \
31435373Sraghuram (void) vsw_send_msg(ldcp, (void *)pkt, \
31445373Sraghuram sizeof (vnet_mcast_msg_t), B_TRUE);
31455373Sraghuram
31465373Sraghuram /*
31475373Sraghuram * Process a multicast request from a vnet.
31485373Sraghuram *
31495373Sraghuram * Vnet's specify a multicast address that they are interested in. This
31505373Sraghuram * address is used as a key into the hash table which forms the multicast
31515373Sraghuram * forwarding database (mFDB).
31525373Sraghuram *
31535373Sraghuram * The table keys are the multicast addresses, while the table entries
31545373Sraghuram * are pointers to lists of ports which wish to receive packets for the
31555373Sraghuram * specified multicast address.
31565373Sraghuram *
31575373Sraghuram * When a multicast packet is being switched we use the address as a key
31585373Sraghuram * into the hash table, and then walk the appropriate port list forwarding
31595373Sraghuram * the pkt to each port in turn.
31605373Sraghuram *
31615373Sraghuram * If a vnet is no longer interested in a particular multicast grouping
31625373Sraghuram * we simply find the correct location in the hash table and then delete
31635373Sraghuram * the relevant port from the port list.
31645373Sraghuram *
31655373Sraghuram * To deal with the case whereby a port is being deleted without first
31665373Sraghuram * removing itself from the lists in the hash table, we maintain a list
31675373Sraghuram * of multicast addresses the port has registered an interest in, within
31685373Sraghuram * the port structure itself. We then simply walk that list of addresses
31695373Sraghuram * using them as keys into the hash table and remove the port from the
31705373Sraghuram * appropriate lists.
31715373Sraghuram */
31725373Sraghuram static void
vsw_process_ctrl_mcst_pkt(vsw_ldc_t * ldcp,void * pkt)31735373Sraghuram vsw_process_ctrl_mcst_pkt(vsw_ldc_t *ldcp, void *pkt)
31745373Sraghuram {
31755373Sraghuram vnet_mcast_msg_t *mcst_pkt;
31765373Sraghuram vsw_port_t *port = ldcp->ldc_port;
31775373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
31785373Sraghuram int i;
31795373Sraghuram
31805373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
31815373Sraghuram
31825373Sraghuram /*
31835373Sraghuram * We know this is a ctrl/mcast packet so
31845373Sraghuram * cast it into the correct structure.
31855373Sraghuram */
31865373Sraghuram mcst_pkt = (vnet_mcast_msg_t *)pkt;
31875373Sraghuram
31885373Sraghuram switch (mcst_pkt->tag.vio_subtype) {
31895373Sraghuram case VIO_SUBTYPE_INFO:
31905373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
31915373Sraghuram
31925373Sraghuram /*
31935373Sraghuram * Check if in correct state to receive a multicast
31945373Sraghuram * message (i.e. handshake complete). If not reset
31955373Sraghuram * the handshake.
31965373Sraghuram */
31975373Sraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_MCST_INFO_RECV))
31985373Sraghuram return;
31995373Sraghuram
32005373Sraghuram /*
32015373Sraghuram * Before attempting to add or remove address check
32025373Sraghuram * that they are valid multicast addresses.
32035373Sraghuram * If not, then NACK back.
32045373Sraghuram */
32055373Sraghuram for (i = 0; i < mcst_pkt->count; i++) {
32065373Sraghuram if ((mcst_pkt->mca[i].ether_addr_octet[0] & 01) != 1) {
32075373Sraghuram DERR(vswp, "%s: invalid multicast address",
32085373Sraghuram __func__);
32095373Sraghuram SND_MCST_NACK(ldcp, mcst_pkt);
32105373Sraghuram return;
32115373Sraghuram }
32125373Sraghuram }
32135373Sraghuram
32145373Sraghuram /*
32155373Sraghuram * Now add/remove the addresses. If this fails we
32165373Sraghuram * NACK back.
32175373Sraghuram */
32185373Sraghuram if (vsw_add_rem_mcst(mcst_pkt, port) != 0) {
32195373Sraghuram SND_MCST_NACK(ldcp, mcst_pkt);
32205373Sraghuram return;
32215373Sraghuram }
32225373Sraghuram
32235373Sraghuram mcst_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
32245373Sraghuram mcst_pkt->tag.vio_sid = ldcp->local_session;
32255373Sraghuram
32265373Sraghuram DUMP_TAG_PTR((vio_msg_tag_t *)mcst_pkt);
32275373Sraghuram
32285373Sraghuram (void) vsw_send_msg(ldcp, (void *)mcst_pkt,
32295373Sraghuram sizeof (vnet_mcast_msg_t), B_TRUE);
32305373Sraghuram break;
32315373Sraghuram
32325373Sraghuram case VIO_SUBTYPE_ACK:
32335373Sraghuram DWARN(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
32345373Sraghuram
32355373Sraghuram /*
32365373Sraghuram * We shouldn't ever get a multicast ACK message as
32375373Sraghuram * at the moment we never request multicast addresses
32385373Sraghuram * to be set on some other device. This may change in
32395373Sraghuram * the future if we have cascading switches.
32405373Sraghuram */
32415373Sraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_ACK_RECV))
32425373Sraghuram return;
32435373Sraghuram
32445373Sraghuram /* Do nothing */
32455373Sraghuram break;
32465373Sraghuram
32475373Sraghuram case VIO_SUBTYPE_NACK:
32485373Sraghuram DWARN(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
32495373Sraghuram
32505373Sraghuram /*
32515373Sraghuram * We shouldn't get a multicast NACK packet for the
32525373Sraghuram * same reasons as we shouldn't get a ACK packet.
32535373Sraghuram */
32545373Sraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_NACK_RECV))
32555373Sraghuram return;
32565373Sraghuram
32575373Sraghuram /* Do nothing */
32585373Sraghuram break;
32595373Sraghuram
32605373Sraghuram default:
32615373Sraghuram DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
32625373Sraghuram mcst_pkt->tag.vio_subtype);
32635373Sraghuram }
32645373Sraghuram
32655373Sraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
32665373Sraghuram }
32675373Sraghuram
32685373Sraghuram static void
vsw_process_ctrl_rdx_pkt(vsw_ldc_t * ldcp,void * pkt)32695373Sraghuram vsw_process_ctrl_rdx_pkt(vsw_ldc_t *ldcp, void *pkt)
32705373Sraghuram {
32715373Sraghuram vio_rdx_msg_t *rdx_pkt;
32725373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
32735373Sraghuram
32745373Sraghuram /*
32755373Sraghuram * We know this is a ctrl/rdx packet so
32765373Sraghuram * cast it into the correct structure.
32775373Sraghuram */
32785373Sraghuram rdx_pkt = (vio_rdx_msg_t *)pkt;
32795373Sraghuram
32805373Sraghuram D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
32815373Sraghuram
32825373Sraghuram switch (rdx_pkt->tag.vio_subtype) {
32835373Sraghuram case VIO_SUBTYPE_INFO:
32845373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
32855373Sraghuram
32865373Sraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_RDX_INFO_RECV))
32875373Sraghuram return;
32885373Sraghuram
32895373Sraghuram rdx_pkt->tag.vio_sid = ldcp->local_session;
32905373Sraghuram rdx_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
32915373Sraghuram
32925373Sraghuram DUMP_TAG_PTR((vio_msg_tag_t *)rdx_pkt);
32935373Sraghuram
32945373Sraghuram ldcp->lane_out.lstate |= VSW_RDX_ACK_SENT;
32955373Sraghuram
32965373Sraghuram (void) vsw_send_msg(ldcp, (void *)rdx_pkt,
32975373Sraghuram sizeof (vio_rdx_msg_t), B_TRUE);
32985373Sraghuram
32995373Sraghuram vsw_next_milestone(ldcp);
33005373Sraghuram break;
33015373Sraghuram
33025373Sraghuram case VIO_SUBTYPE_ACK:
33035373Sraghuram /*
33045373Sraghuram * Should be handled in-band by callback handler.
33055373Sraghuram */
33065373Sraghuram DERR(vswp, "%s: Unexpected VIO_SUBTYPE_ACK", __func__);
33075373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33085373Sraghuram break;
33095373Sraghuram
33105373Sraghuram case VIO_SUBTYPE_NACK:
33115373Sraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
33125373Sraghuram
33135373Sraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_NACK_RECV))
33145373Sraghuram return;
33155373Sraghuram
33165373Sraghuram ldcp->lane_in.lstate |= VSW_RDX_NACK_RECV;
33175373Sraghuram vsw_next_milestone(ldcp);
33185373Sraghuram break;
33195373Sraghuram
33205373Sraghuram default:
33215373Sraghuram DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
33225373Sraghuram rdx_pkt->tag.vio_subtype);
33235373Sraghuram }
33245373Sraghuram
33255373Sraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
33265373Sraghuram }
33275373Sraghuram
33285373Sraghuram static void
vsw_process_physlink_msg(vsw_ldc_t * ldcp,void * pkt)33299336SSriharsha.Basavapatna@Sun.COM vsw_process_physlink_msg(vsw_ldc_t *ldcp, void *pkt)
33309336SSriharsha.Basavapatna@Sun.COM {
33319336SSriharsha.Basavapatna@Sun.COM vnet_physlink_msg_t *msgp;
33329336SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
33339336SSriharsha.Basavapatna@Sun.COM
33349336SSriharsha.Basavapatna@Sun.COM msgp = (vnet_physlink_msg_t *)pkt;
33359336SSriharsha.Basavapatna@Sun.COM
33369336SSriharsha.Basavapatna@Sun.COM D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
33379336SSriharsha.Basavapatna@Sun.COM
33389336SSriharsha.Basavapatna@Sun.COM switch (msgp->tag.vio_subtype) {
33399336SSriharsha.Basavapatna@Sun.COM case VIO_SUBTYPE_INFO:
33409336SSriharsha.Basavapatna@Sun.COM
33419336SSriharsha.Basavapatna@Sun.COM /* vsw shouldn't recv physlink info */
33429336SSriharsha.Basavapatna@Sun.COM DWARN(vswp, "%s: Unexpected VIO_SUBTYPE_INFO", __func__);
33439336SSriharsha.Basavapatna@Sun.COM break;
33449336SSriharsha.Basavapatna@Sun.COM
33459336SSriharsha.Basavapatna@Sun.COM case VIO_SUBTYPE_ACK:
33469336SSriharsha.Basavapatna@Sun.COM
33479336SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
33489336SSriharsha.Basavapatna@Sun.COM break;
33499336SSriharsha.Basavapatna@Sun.COM
33509336SSriharsha.Basavapatna@Sun.COM case VIO_SUBTYPE_NACK:
33519336SSriharsha.Basavapatna@Sun.COM
33529336SSriharsha.Basavapatna@Sun.COM D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
33539336SSriharsha.Basavapatna@Sun.COM break;
33549336SSriharsha.Basavapatna@Sun.COM
33559336SSriharsha.Basavapatna@Sun.COM default:
33569336SSriharsha.Basavapatna@Sun.COM DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
33579336SSriharsha.Basavapatna@Sun.COM msgp->tag.vio_subtype);
33589336SSriharsha.Basavapatna@Sun.COM }
33599336SSriharsha.Basavapatna@Sun.COM
33609336SSriharsha.Basavapatna@Sun.COM D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
33619336SSriharsha.Basavapatna@Sun.COM }
33629336SSriharsha.Basavapatna@Sun.COM
33639336SSriharsha.Basavapatna@Sun.COM static void
vsw_process_data_pkt(vsw_ldc_t * ldcp,void * dpkt,vio_msg_tag_t * tagp,uint32_t msglen)33645935Ssb155480 vsw_process_data_pkt(vsw_ldc_t *ldcp, void *dpkt, vio_msg_tag_t *tagp,
33655935Ssb155480 uint32_t msglen)
33665373Sraghuram {
33675935Ssb155480 uint16_t env = tagp->vio_subtype_env;
33685373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
336912011SSriharsha.Basavapatna@Sun.COM lane_t *lp = &ldcp->lane_out;
337012011SSriharsha.Basavapatna@Sun.COM uint8_t dring_mode = lp->dring_mode;
33715373Sraghuram
33725373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
33735373Sraghuram
33745373Sraghuram /* session id check */
33755373Sraghuram if (ldcp->session_status & VSW_PEER_SESSION) {
33765935Ssb155480 if (ldcp->peer_session != tagp->vio_sid) {
33775373Sraghuram DERR(vswp, "%s (chan %d): invalid session id (%llx)",
33785935Ssb155480 __func__, ldcp->ldc_id, tagp->vio_sid);
33795373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33805373Sraghuram return;
33815373Sraghuram }
33825373Sraghuram }
33835373Sraghuram
33845373Sraghuram /*
33855373Sraghuram * It is an error for us to be getting data packets
33865373Sraghuram * before the handshake has completed.
33875373Sraghuram */
33885373Sraghuram if (ldcp->hphase != VSW_MILESTONE4) {
33895373Sraghuram DERR(vswp, "%s: got data packet before handshake complete "
33905373Sraghuram "hphase %d (%x: %x)", __func__, ldcp->hphase,
33915373Sraghuram ldcp->lane_in.lstate, ldcp->lane_out.lstate);
33925373Sraghuram DUMP_FLAGS(ldcp->lane_in.lstate);
33935373Sraghuram DUMP_FLAGS(ldcp->lane_out.lstate);
33945373Sraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33955373Sraghuram return;
33965373Sraghuram }
339712011SSriharsha.Basavapatna@Sun.COM if (dring_mode == VIO_TX_DRING) {
339812011SSriharsha.Basavapatna@Sun.COM /*
339912011SSriharsha.Basavapatna@Sun.COM * To reduce the locking contention, release the ldc_cblock
340012011SSriharsha.Basavapatna@Sun.COM * here and re-acquire it once we are done receiving packets.
340112011SSriharsha.Basavapatna@Sun.COM * We do this only in TxDring mode to allow further callbaks to
340212011SSriharsha.Basavapatna@Sun.COM * continue while the msg worker thread processes the messages.
340312011SSriharsha.Basavapatna@Sun.COM * In RxDringData mode, we process the messages in the callback
340412011SSriharsha.Basavapatna@Sun.COM * itself and wake up rcv worker thread to process only data
340512011SSriharsha.Basavapatna@Sun.COM * info messages.
340612011SSriharsha.Basavapatna@Sun.COM */
340712011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->ldc_cblock);
340812011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->ldc_rxlock);
340912011SSriharsha.Basavapatna@Sun.COM }
34105373Sraghuram
34115373Sraghuram /*
34125373Sraghuram * Switch on vio_subtype envelope, then let lower routines
34135373Sraghuram * decide if its an INFO, ACK or NACK packet.
34145373Sraghuram */
34155373Sraghuram if (env == VIO_DRING_DATA) {
341612011SSriharsha.Basavapatna@Sun.COM ldcp->rx_dringdata(ldcp, dpkt);
34175373Sraghuram } else if (env == VIO_PKT_DATA) {
34185935Ssb155480 ldcp->rx_pktdata(ldcp, dpkt, msglen);
34195373Sraghuram } else if (env == VIO_DESC_DATA) {
34205373Sraghuram vsw_process_data_ibnd_pkt(ldcp, dpkt);
34215373Sraghuram } else {
342212011SSriharsha.Basavapatna@Sun.COM DERR(vswp, "%s: unknown vio_subtype_env (%x)\n",
342312011SSriharsha.Basavapatna@Sun.COM __func__, env);
34245373Sraghuram }
34255373Sraghuram
342612011SSriharsha.Basavapatna@Sun.COM if (dring_mode == VIO_TX_DRING) {
342712011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->ldc_rxlock);
342812011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->ldc_cblock);
342912011SSriharsha.Basavapatna@Sun.COM }
34305373Sraghuram
34315373Sraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
34325373Sraghuram }
34335373Sraghuram
34345373Sraghuram /*
34355935Ssb155480 * dummy pkt data handler function for vnet protocol version 1.0
34365935Ssb155480 */
34375935Ssb155480 static void
vsw_process_pkt_data_nop(void * arg1,void * arg2,uint32_t msglen)34385935Ssb155480 vsw_process_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
34395935Ssb155480 {
34405935Ssb155480 _NOTE(ARGUNUSED(arg1, arg2, msglen))
34415935Ssb155480 }
34425935Ssb155480
34435935Ssb155480 /*
34445935Ssb155480 * This function handles raw pkt data messages received over the channel.
34455935Ssb155480 * Currently, only priority-eth-type frames are received through this mechanism.
34465935Ssb155480 * In this case, the frame(data) is present within the message itself which
34475935Ssb155480 * is copied into an mblk before switching it.
34485373Sraghuram */
34495373Sraghuram static void
vsw_process_pkt_data(void * arg1,void * arg2,uint32_t msglen)34505935Ssb155480 vsw_process_pkt_data(void *arg1, void *arg2, uint32_t msglen)
34515373Sraghuram {
34525935Ssb155480 vsw_ldc_t *ldcp = (vsw_ldc_t *)arg1;
34535935Ssb155480 vio_raw_data_msg_t *dpkt = (vio_raw_data_msg_t *)arg2;
34545935Ssb155480 uint32_t size;
34555935Ssb155480 mblk_t *mp;
345612011SSriharsha.Basavapatna@Sun.COM vio_mblk_t *vmp;
34575935Ssb155480 vsw_t *vswp = ldcp->ldc_vswp;
34585935Ssb155480 vgen_stats_t *statsp = &ldcp->ldc_stats;
34596419Ssb155480 lane_t *lp = &ldcp->lane_out;
34605935Ssb155480
34615935Ssb155480 size = msglen - VIO_PKT_DATA_HDRSIZE;
34626419Ssb155480 if (size < ETHERMIN || size > lp->mtu) {
34635935Ssb155480 (void) atomic_inc_32(&statsp->rx_pri_fail);
34645935Ssb155480 DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__,
34655935Ssb155480 ldcp->ldc_id, size);
34665935Ssb155480 return;
34675935Ssb155480 }
34685935Ssb155480
346912011SSriharsha.Basavapatna@Sun.COM vmp = vio_multipool_allocb(&ldcp->vmp, size + VLAN_TAGSZ);
347012011SSriharsha.Basavapatna@Sun.COM if (vmp == NULL) {
34716419Ssb155480 mp = allocb(size + VLAN_TAGSZ, BPRI_MED);
34725935Ssb155480 if (mp == NULL) {
34735935Ssb155480 (void) atomic_inc_32(&statsp->rx_pri_fail);
34745935Ssb155480 DWARN(vswp, "%s(%lld) allocb failure, "
34755935Ssb155480 "unable to process priority frame\n", __func__,
34765935Ssb155480 ldcp->ldc_id);
34775935Ssb155480 return;
34785935Ssb155480 }
347912011SSriharsha.Basavapatna@Sun.COM } else {
348012011SSriharsha.Basavapatna@Sun.COM mp = vmp->mp;
34815935Ssb155480 }
34825935Ssb155480
34836419Ssb155480 /* skip over the extra space for vlan tag */
34846419Ssb155480 mp->b_rptr += VLAN_TAGSZ;
34856419Ssb155480
34865935Ssb155480 /* copy the frame from the payload of raw data msg into the mblk */
34875935Ssb155480 bcopy(dpkt->data, mp->b_rptr, size);
34885935Ssb155480 mp->b_wptr = mp->b_rptr + size;
34895935Ssb155480
349012011SSriharsha.Basavapatna@Sun.COM if (vmp != NULL) {
349112011SSriharsha.Basavapatna@Sun.COM vmp->state = VIO_MBLK_HAS_DATA;
349212011SSriharsha.Basavapatna@Sun.COM }
349312011SSriharsha.Basavapatna@Sun.COM
34945935Ssb155480 /* update stats */
34955935Ssb155480 (void) atomic_inc_64(&statsp->rx_pri_packets);
34965935Ssb155480 (void) atomic_add_64(&statsp->rx_pri_bytes, size);
34975935Ssb155480
34986419Ssb155480 /*
34996419Ssb155480 * VLAN_TAGSZ of extra space has been pre-alloc'd if tag is needed.
35006419Ssb155480 */
35016419Ssb155480 (void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp);
35026419Ssb155480
35035935Ssb155480 /* switch the frame to destination */
35045935Ssb155480 vswp->vsw_switch_frame(vswp, mp, VSW_VNETPORT, ldcp->ldc_port, NULL);
35055373Sraghuram }
35065373Sraghuram
35075373Sraghuram /*
35085373Sraghuram * Process an in-band descriptor message (most likely from
35095373Sraghuram * OBP).
35105373Sraghuram */
35115373Sraghuram static void
vsw_process_data_ibnd_pkt(vsw_ldc_t * ldcp,void * pkt)35125373Sraghuram vsw_process_data_ibnd_pkt(vsw_ldc_t *ldcp, void *pkt)
35135373Sraghuram {
35145373Sraghuram vnet_ibnd_desc_t *ibnd_desc;
35155373Sraghuram dring_info_t *dp = NULL;
35165373Sraghuram vsw_private_desc_t *priv_addr = NULL;
35175373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
35185373Sraghuram mblk_t *mp = NULL;
35195373Sraghuram size_t nbytes = 0;
35205373Sraghuram size_t off = 0;
35215373Sraghuram uint64_t idx = 0;
35225373Sraghuram uint32_t num = 1, len, datalen = 0;
35235373Sraghuram uint64_t ncookies = 0;
35245373Sraghuram int i, rv;
35255373Sraghuram int j = 0;
35265373Sraghuram
35275373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
35285373Sraghuram
35295373Sraghuram ibnd_desc = (vnet_ibnd_desc_t *)pkt;
35305373Sraghuram
35315373Sraghuram switch (ibnd_desc->hdr.tag.vio_subtype) {
35325373Sraghuram case VIO_SUBTYPE_INFO:
35335373Sraghuram D1(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
35345373Sraghuram
35355373Sraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV))
35365373Sraghuram return;
35375373Sraghuram
35385373Sraghuram /*
35395373Sraghuram * Data is padded to align on a 8 byte boundary,
35405373Sraghuram * nbytes is actual data length, i.e. minus that
35415373Sraghuram * padding.
35425373Sraghuram */
35435373Sraghuram datalen = ibnd_desc->nbytes;
35445373Sraghuram
35455373Sraghuram D2(vswp, "%s(%lld): processing inband desc : "
35465373Sraghuram ": datalen 0x%lx", __func__, ldcp->ldc_id, datalen);
35475373Sraghuram
35485373Sraghuram ncookies = ibnd_desc->ncookies;
35495373Sraghuram
35505373Sraghuram /*
35515373Sraghuram * allocb(9F) returns an aligned data block. We
35525373Sraghuram * need to ensure that we ask ldc for an aligned
35535373Sraghuram * number of bytes also.
35545373Sraghuram */
35555373Sraghuram nbytes = datalen;
35565373Sraghuram if (nbytes & 0x7) {
35575373Sraghuram off = 8 - (nbytes & 0x7);
35585373Sraghuram nbytes += off;
35595373Sraghuram }
35605373Sraghuram
35616419Ssb155480 /* alloc extra space for VLAN_TAG */
35626419Ssb155480 mp = allocb(datalen + 8, BPRI_MED);
35635373Sraghuram if (mp == NULL) {
35645373Sraghuram DERR(vswp, "%s(%lld): allocb failed",
35655373Sraghuram __func__, ldcp->ldc_id);
35665373Sraghuram ldcp->ldc_stats.rx_allocb_fail++;
35675373Sraghuram return;
35685373Sraghuram }
35695373Sraghuram
35706419Ssb155480 /* skip over the extra space for VLAN_TAG */
35716419Ssb155480 mp->b_rptr += 8;
35726419Ssb155480
35735373Sraghuram rv = ldc_mem_copy(ldcp->ldc_handle, (caddr_t)mp->b_rptr,
35745373Sraghuram 0, &nbytes, ibnd_desc->memcookie, (uint64_t)ncookies,
35755373Sraghuram LDC_COPY_IN);
35765373Sraghuram
35775373Sraghuram if (rv != 0) {
35785373Sraghuram DERR(vswp, "%s(%d): unable to copy in data from "
35795373Sraghuram "%d cookie(s)", __func__, ldcp->ldc_id, ncookies);
35805373Sraghuram freemsg(mp);
35815373Sraghuram ldcp->ldc_stats.ierrors++;
35825373Sraghuram return;
35835373Sraghuram }
35845373Sraghuram
35855373Sraghuram D2(vswp, "%s(%d): copied in %ld bytes using %d cookies",
35865373Sraghuram __func__, ldcp->ldc_id, nbytes, ncookies);
35875373Sraghuram
35885373Sraghuram /* point to the actual end of data */
35895373Sraghuram mp->b_wptr = mp->b_rptr + datalen;
35905373Sraghuram ldcp->ldc_stats.ipackets++;
35915373Sraghuram ldcp->ldc_stats.rbytes += datalen;
35925373Sraghuram
35935373Sraghuram /*
35945373Sraghuram * We ACK back every in-band descriptor message we process
35955373Sraghuram */
35965373Sraghuram ibnd_desc->hdr.tag.vio_subtype = VIO_SUBTYPE_ACK;
35975373Sraghuram ibnd_desc->hdr.tag.vio_sid = ldcp->local_session;
35985373Sraghuram (void) vsw_send_msg(ldcp, (void *)ibnd_desc,
35995373Sraghuram sizeof (vnet_ibnd_desc_t), B_TRUE);
36005373Sraghuram
36016419Ssb155480 /*
36026419Ssb155480 * there is extra space alloc'd for VLAN_TAG
36036419Ssb155480 */
36046419Ssb155480 (void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp);
36056419Ssb155480
36065373Sraghuram /* send the packet to be switched */
36075373Sraghuram vswp->vsw_switch_frame(vswp, mp, VSW_VNETPORT,
36085373Sraghuram ldcp->ldc_port, NULL);
36095373Sraghuram
36105373Sraghuram break;
36115373Sraghuram
36125373Sraghuram case VIO_SUBTYPE_ACK:
36135373Sraghuram D1(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
36145373Sraghuram
36155373Sraghuram /* Verify the ACK is valid */
36165373Sraghuram idx = ibnd_desc->hdr.desc_handle;
36175373Sraghuram
361812011SSriharsha.Basavapatna@Sun.COM if (idx >= vsw_num_descriptors) {
36195373Sraghuram cmn_err(CE_WARN, "!vsw%d: corrupted ACK received "
36205373Sraghuram "(idx %ld)", vswp->instance, idx);
36215373Sraghuram return;
36225373Sraghuram }
36235373Sraghuram
36245373Sraghuram if ((dp = ldcp->lane_out.dringp) == NULL) {
36255373Sraghuram DERR(vswp, "%s: no dring found", __func__);
36265373Sraghuram return;
36275373Sraghuram }
36285373Sraghuram
36295373Sraghuram len = dp->num_descriptors;
36305373Sraghuram /*
36315373Sraghuram * If the descriptor we are being ACK'ed for is not the
36325373Sraghuram * one we expected, then pkts were lost somwhere, either
36335373Sraghuram * when we tried to send a msg, or a previous ACK msg from
36345373Sraghuram * our peer. In either case we now reclaim the descriptors
36355373Sraghuram * in the range from the last ACK we received up to the
36365373Sraghuram * current ACK.
36375373Sraghuram */
36385373Sraghuram if (idx != dp->last_ack_recv) {
36395373Sraghuram DWARN(vswp, "%s: dropped pkts detected, (%ld, %ld)",
36405373Sraghuram __func__, dp->last_ack_recv, idx);
36415373Sraghuram num = idx >= dp->last_ack_recv ?
36425373Sraghuram idx - dp->last_ack_recv + 1:
36435373Sraghuram (len - dp->last_ack_recv + 1) + idx;
36445373Sraghuram }
36455373Sraghuram
36465373Sraghuram /*
36475373Sraghuram * When we sent the in-band message to our peer we
36485373Sraghuram * marked the copy in our private ring as READY. We now
36495373Sraghuram * check that the descriptor we are being ACK'ed for is in
36505373Sraghuram * fact READY, i.e. it is one we have shared with our peer.
36515373Sraghuram *
36525373Sraghuram * If its not we flag an error, but still reset the descr
36535373Sraghuram * back to FREE.
36545373Sraghuram */
36555373Sraghuram for (i = dp->last_ack_recv; j < num; i = (i + 1) % len, j++) {
36565373Sraghuram priv_addr = (vsw_private_desc_t *)dp->priv_addr + i;
36575373Sraghuram mutex_enter(&priv_addr->dstate_lock);
36585373Sraghuram if (priv_addr->dstate != VIO_DESC_READY) {
36595373Sraghuram DERR(vswp, "%s: (%ld) desc at index %ld not "
36605373Sraghuram "READY (0x%lx)", __func__,
36615373Sraghuram ldcp->ldc_id, idx, priv_addr->dstate);
36625373Sraghuram DERR(vswp, "%s: bound %d: ncookies %ld : "
36635373Sraghuram "datalen %ld", __func__,
36645373Sraghuram priv_addr->bound, priv_addr->ncookies,
36655373Sraghuram priv_addr->datalen);
36665373Sraghuram }
36675373Sraghuram D2(vswp, "%s: (%lld) freeing descp at %lld", __func__,
36685373Sraghuram ldcp->ldc_id, idx);
36695373Sraghuram /* release resources associated with sent msg */
36705373Sraghuram priv_addr->datalen = 0;
36715373Sraghuram priv_addr->dstate = VIO_DESC_FREE;
36725373Sraghuram mutex_exit(&priv_addr->dstate_lock);
36735373Sraghuram }
36745373Sraghuram /* update to next expected value */
36755373Sraghuram dp->last_ack_recv = (idx + 1) % dp->num_descriptors;
36765373Sraghuram
36775373Sraghuram break;
36785373Sraghuram
36795373Sraghuram case VIO_SUBTYPE_NACK:
36805373Sraghuram DERR(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
36815373Sraghuram
36825373Sraghuram /*
36835373Sraghuram * We should only get a NACK if our peer doesn't like
36845373Sraghuram * something about a message we have sent it. If this
36855373Sraghuram * happens we just release the resources associated with
36865373Sraghuram * the message. (We are relying on higher layers to decide
36875373Sraghuram * whether or not to resend.
36885373Sraghuram */
36895373Sraghuram
36905373Sraghuram /* limit check */
36915373Sraghuram idx = ibnd_desc->hdr.desc_handle;
36925373Sraghuram
369312011SSriharsha.Basavapatna@Sun.COM if (idx >= vsw_num_descriptors) {
36945373Sraghuram DERR(vswp, "%s: corrupted NACK received (idx %lld)",
36955373Sraghuram __func__, idx);
36965373Sraghuram return;
36975373Sraghuram }
36985373Sraghuram
36995373Sraghuram if ((dp = ldcp->lane_out.dringp) == NULL) {
37005373Sraghuram DERR(vswp, "%s: no dring found", __func__);
37015373Sraghuram return;
37025373Sraghuram }
37035373Sraghuram
37045373Sraghuram priv_addr = (vsw_private_desc_t *)dp->priv_addr;
37055373Sraghuram
37065373Sraghuram /* move to correct location in ring */
37075373Sraghuram priv_addr += idx;
37085373Sraghuram
37095373Sraghuram /* release resources associated with sent msg */
37105373Sraghuram mutex_enter(&priv_addr->dstate_lock);
37115373Sraghuram priv_addr->datalen = 0;
37125373Sraghuram priv_addr->dstate = VIO_DESC_FREE;
37135373Sraghuram mutex_exit(&priv_addr->dstate_lock);
37145373Sraghuram
37155373Sraghuram break;
37165373Sraghuram
37175373Sraghuram default:
37185373Sraghuram DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__,
37195373Sraghuram ldcp->ldc_id, ibnd_desc->hdr.tag.vio_subtype);
37205373Sraghuram }
37215373Sraghuram
37225373Sraghuram D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
37235373Sraghuram }
37245373Sraghuram
37255373Sraghuram static void
vsw_process_err_pkt(vsw_ldc_t * ldcp,void * epkt,vio_msg_tag_t * tagp)37265935Ssb155480 vsw_process_err_pkt(vsw_ldc_t *ldcp, void *epkt, vio_msg_tag_t *tagp)
37275373Sraghuram {
37285373Sraghuram _NOTE(ARGUNUSED(epkt))
37295373Sraghuram
37305373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
37315935Ssb155480 uint16_t env = tagp->vio_subtype_env;
37325373Sraghuram
37335373Sraghuram D1(vswp, "%s (%lld): enter\n", __func__, ldcp->ldc_id);
37345373Sraghuram
37355373Sraghuram /*
37365373Sraghuram * Error vio_subtypes have yet to be defined. So for
37375373Sraghuram * the moment we can't do anything.
37385373Sraghuram */
37395373Sraghuram D2(vswp, "%s: (%x) vio_subtype env", __func__, env);
37405373Sraghuram
37415373Sraghuram D1(vswp, "%s (%lld): exit\n", __func__, ldcp->ldc_id);
37425373Sraghuram }
37435373Sraghuram
37445373Sraghuram /* transmit the packet over the given port */
37455373Sraghuram int
vsw_portsend(vsw_port_t * port,mblk_t * mp)37468275SEric Cheng vsw_portsend(vsw_port_t *port, mblk_t *mp)
37475373Sraghuram {
37488275SEric Cheng mblk_t *mpt;
37498275SEric Cheng int count;
375012011SSriharsha.Basavapatna@Sun.COM vsw_ldc_t *ldcp = port->ldcp;
37515373Sraghuram int status = 0;
37525373Sraghuram
37538275SEric Cheng count = vsw_vlan_frame_untag(port, VSW_VNETPORT, &mp, &mpt);
37548275SEric Cheng if (count != 0) {
37558275SEric Cheng status = ldcp->tx(ldcp, mp, mpt, count);
37566419Ssb155480 }
37575935Ssb155480 return (status);
37585935Ssb155480 }
37595935Ssb155480
37605935Ssb155480 /*
37615935Ssb155480 * Break up frames into 2 seperate chains: normal and
37625935Ssb155480 * priority, based on the frame type. The number of
37635935Ssb155480 * priority frames is also counted and returned.
37645935Ssb155480 *
37655935Ssb155480 * Params:
37665935Ssb155480 * vswp: pointer to the instance of vsw
37675935Ssb155480 * np: head of packet chain to be broken
37685935Ssb155480 * npt: tail of packet chain to be broken
37695935Ssb155480 *
37705935Ssb155480 * Returns:
37715935Ssb155480 * np: head of normal data packets
37725935Ssb155480 * npt: tail of normal data packets
37735935Ssb155480 * hp: head of high priority packets
37745935Ssb155480 * hpt: tail of high priority packets
37755935Ssb155480 */
37765935Ssb155480 static uint32_t
vsw_get_pri_packets(vsw_t * vswp,mblk_t ** np,mblk_t ** npt,mblk_t ** hp,mblk_t ** hpt)37775935Ssb155480 vsw_get_pri_packets(vsw_t *vswp, mblk_t **np, mblk_t **npt,
37785935Ssb155480 mblk_t **hp, mblk_t **hpt)
37795935Ssb155480 {
37805935Ssb155480 mblk_t *tmp = NULL;
37815935Ssb155480 mblk_t *smp = NULL;
37825935Ssb155480 mblk_t *hmp = NULL; /* high prio pkts head */
37835935Ssb155480 mblk_t *hmpt = NULL; /* high prio pkts tail */
37845935Ssb155480 mblk_t *nmp = NULL; /* normal pkts head */
37855935Ssb155480 mblk_t *nmpt = NULL; /* normal pkts tail */
37865935Ssb155480 uint32_t count = 0;
37875935Ssb155480 int i;
37885935Ssb155480 struct ether_header *ehp;
37895935Ssb155480 uint32_t num_types;
37905935Ssb155480 uint16_t *types;
37915935Ssb155480
37925935Ssb155480 tmp = *np;
37935935Ssb155480 while (tmp != NULL) {
37945935Ssb155480
37955935Ssb155480 smp = tmp;
37965935Ssb155480 tmp = tmp->b_next;
37975935Ssb155480 smp->b_next = NULL;
37985935Ssb155480 smp->b_prev = NULL;
37995935Ssb155480
38005935Ssb155480 ehp = (struct ether_header *)smp->b_rptr;
38015935Ssb155480 num_types = vswp->pri_num_types;
38025935Ssb155480 types = vswp->pri_types;
38035935Ssb155480 for (i = 0; i < num_types; i++) {
38045935Ssb155480 if (ehp->ether_type == types[i]) {
38055935Ssb155480 /* high priority frame */
38065935Ssb155480
38075935Ssb155480 if (hmp != NULL) {
38085935Ssb155480 hmpt->b_next = smp;
38095935Ssb155480 hmpt = smp;
38105935Ssb155480 } else {
38115935Ssb155480 hmp = hmpt = smp;
38125935Ssb155480 }
38135935Ssb155480 count++;
38145935Ssb155480 break;
38155935Ssb155480 }
38165935Ssb155480 }
38175935Ssb155480 if (i == num_types) {
38185935Ssb155480 /* normal data frame */
38195935Ssb155480
38205935Ssb155480 if (nmp != NULL) {
38215935Ssb155480 nmpt->b_next = smp;
38225935Ssb155480 nmpt = smp;
38235935Ssb155480 } else {
38245935Ssb155480 nmp = nmpt = smp;
38255935Ssb155480 }
38265935Ssb155480 }
38275935Ssb155480 }
38285935Ssb155480
38295935Ssb155480 *hp = hmp;
38305935Ssb155480 *hpt = hmpt;
38315935Ssb155480 *np = nmp;
38325935Ssb155480 *npt = nmpt;
38335935Ssb155480
38345935Ssb155480 return (count);
38355935Ssb155480 }
38365935Ssb155480
38375935Ssb155480 /*
38385935Ssb155480 * Wrapper function to transmit normal and/or priority frames over the channel.
38395935Ssb155480 */
38405935Ssb155480 static int
vsw_ldctx_pri(void * arg,mblk_t * mp,mblk_t * mpt,uint32_t count)38415935Ssb155480 vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count)
38425935Ssb155480 {
38435935Ssb155480 vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
38445935Ssb155480 mblk_t *tmp;
38455935Ssb155480 mblk_t *smp;
38465935Ssb155480 mblk_t *hmp; /* high prio pkts head */
38475935Ssb155480 mblk_t *hmpt; /* high prio pkts tail */
38485935Ssb155480 mblk_t *nmp; /* normal pkts head */
38495935Ssb155480 mblk_t *nmpt; /* normal pkts tail */
38505935Ssb155480 uint32_t n = 0;
38515935Ssb155480 vsw_t *vswp = ldcp->ldc_vswp;
38525935Ssb155480
38535935Ssb155480 ASSERT(VSW_PRI_ETH_DEFINED(vswp));
38545935Ssb155480 ASSERT(count != 0);
38555935Ssb155480
38565935Ssb155480 nmp = mp;
38575935Ssb155480 nmpt = mpt;
38585935Ssb155480
38595935Ssb155480 /* gather any priority frames from the chain of packets */
38605935Ssb155480 n = vsw_get_pri_packets(vswp, &nmp, &nmpt, &hmp, &hmpt);
38615935Ssb155480
38625935Ssb155480 /* transmit priority frames */
38635935Ssb155480 tmp = hmp;
38645935Ssb155480 while (tmp != NULL) {
38655935Ssb155480 smp = tmp;
38665935Ssb155480 tmp = tmp->b_next;
38675935Ssb155480 smp->b_next = NULL;
38685935Ssb155480 vsw_ldcsend_pkt(ldcp, smp);
38695935Ssb155480 }
38705935Ssb155480
38715935Ssb155480 count -= n;
38725935Ssb155480
38735935Ssb155480 if (count == 0) {
38745935Ssb155480 /* no normal data frames to process */
38755935Ssb155480 return (0);
38765935Ssb155480 }
38775935Ssb155480
38785935Ssb155480 return (vsw_ldctx(ldcp, nmp, nmpt, count));
38795935Ssb155480 }
38805935Ssb155480
38815935Ssb155480 /*
38825935Ssb155480 * Wrapper function to transmit normal frames over the channel.
38835935Ssb155480 */
38845935Ssb155480 static int
vsw_ldctx(void * arg,mblk_t * mp,mblk_t * mpt,uint32_t count)38855935Ssb155480 vsw_ldctx(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count)
38865935Ssb155480 {
38875935Ssb155480 vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
38885935Ssb155480 mblk_t *tmp = NULL;
38895935Ssb155480
38905935Ssb155480 ASSERT(count != 0);
38915373Sraghuram /*
38925935Ssb155480 * If the TX thread is enabled, then queue the
38935935Ssb155480 * ordinary frames and signal the tx thread.
38945373Sraghuram */
38955373Sraghuram if (ldcp->tx_thread != NULL) {
38965935Ssb155480
38975373Sraghuram mutex_enter(&ldcp->tx_thr_lock);
38985935Ssb155480
38995935Ssb155480 if ((ldcp->tx_cnt + count) >= vsw_max_tx_qcount) {
39005935Ssb155480 /*
39015935Ssb155480 * If we reached queue limit,
39025935Ssb155480 * do not queue new packets,
39035935Ssb155480 * drop them.
39045935Ssb155480 */
39055935Ssb155480 ldcp->ldc_stats.tx_qfull += count;
39065935Ssb155480 mutex_exit(&ldcp->tx_thr_lock);
39075935Ssb155480 freemsgchain(mp);
39085935Ssb155480 goto exit;
39095935Ssb155480 }
39105373Sraghuram if (ldcp->tx_mhead == NULL) {
39115373Sraghuram ldcp->tx_mhead = mp;
39125373Sraghuram ldcp->tx_mtail = mpt;
39135373Sraghuram cv_signal(&ldcp->tx_thr_cv);
39145373Sraghuram } else {
39155373Sraghuram ldcp->tx_mtail->b_next = mp;
39165373Sraghuram ldcp->tx_mtail = mpt;
39175373Sraghuram }
39185935Ssb155480 ldcp->tx_cnt += count;
39195373Sraghuram mutex_exit(&ldcp->tx_thr_lock);
39205373Sraghuram } else {
39215373Sraghuram while (mp != NULL) {
39225373Sraghuram tmp = mp->b_next;
39235373Sraghuram mp->b_next = mp->b_prev = NULL;
39245373Sraghuram (void) vsw_ldcsend(ldcp, mp, 1);
39255373Sraghuram mp = tmp;
39265373Sraghuram }
39275373Sraghuram }
39285373Sraghuram
39295935Ssb155480 exit:
39305935Ssb155480 return (0);
39315935Ssb155480 }
39325935Ssb155480
39335935Ssb155480 /*
39345935Ssb155480 * This function transmits the frame in the payload of a raw data
39355935Ssb155480 * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
39365935Ssb155480 * send special frames with high priorities, without going through
39375935Ssb155480 * the normal data path which uses descriptor ring mechanism.
39385935Ssb155480 */
39395935Ssb155480 static void
vsw_ldcsend_pkt(vsw_ldc_t * ldcp,mblk_t * mp)39405935Ssb155480 vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp)
39415935Ssb155480 {
39425935Ssb155480 vio_raw_data_msg_t *pkt;
39435935Ssb155480 mblk_t *bp;
39445935Ssb155480 mblk_t *nmp = NULL;
394512011SSriharsha.Basavapatna@Sun.COM vio_mblk_t *vmp;
39465935Ssb155480 caddr_t dst;
39475935Ssb155480 uint32_t mblksz;
39485935Ssb155480 uint32_t size;
39495935Ssb155480 uint32_t nbytes;
39505935Ssb155480 int rv;
39515935Ssb155480 vsw_t *vswp = ldcp->ldc_vswp;
39525935Ssb155480 vgen_stats_t *statsp = &ldcp->ldc_stats;
39535935Ssb155480
39545935Ssb155480 if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
39555935Ssb155480 (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) {
39565935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
39575935Ssb155480 DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping "
39585935Ssb155480 "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status,
39595935Ssb155480 ldcp->lane_out.lstate);
39605935Ssb155480 goto send_pkt_exit;
39615935Ssb155480 }
39625935Ssb155480
39635935Ssb155480 size = msgsize(mp);
39645935Ssb155480
39655935Ssb155480 /* frame size bigger than available payload len of raw data msg ? */
39665935Ssb155480 if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
39675935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
39685935Ssb155480 DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__,
39695935Ssb155480 ldcp->ldc_id, size);
39705935Ssb155480 goto send_pkt_exit;
39715935Ssb155480 }
39725935Ssb155480
39735935Ssb155480 if (size < ETHERMIN)
39745935Ssb155480 size = ETHERMIN;
39755935Ssb155480
39765935Ssb155480 /* alloc space for a raw data message */
397712011SSriharsha.Basavapatna@Sun.COM vmp = vio_allocb(vswp->pri_tx_vmp);
397812011SSriharsha.Basavapatna@Sun.COM if (vmp == NULL) {
39795935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
39805935Ssb155480 DWARN(vswp, "vio_allocb failed\n");
39815935Ssb155480 goto send_pkt_exit;
398212011SSriharsha.Basavapatna@Sun.COM } else {
398312011SSriharsha.Basavapatna@Sun.COM nmp = vmp->mp;
39845935Ssb155480 }
39855935Ssb155480 pkt = (vio_raw_data_msg_t *)nmp->b_rptr;
39865935Ssb155480
39875935Ssb155480 /* copy frame into the payload of raw data message */
39885935Ssb155480 dst = (caddr_t)pkt->data;
39895935Ssb155480 for (bp = mp; bp != NULL; bp = bp->b_cont) {
39905935Ssb155480 mblksz = MBLKL(bp);
39915935Ssb155480 bcopy(bp->b_rptr, dst, mblksz);
39925935Ssb155480 dst += mblksz;
39935935Ssb155480 }
39945935Ssb155480
399512011SSriharsha.Basavapatna@Sun.COM vmp->state = VIO_MBLK_HAS_DATA;
399612011SSriharsha.Basavapatna@Sun.COM
39975935Ssb155480 /* setup the raw data msg */
39985935Ssb155480 pkt->tag.vio_msgtype = VIO_TYPE_DATA;
39995935Ssb155480 pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
40005935Ssb155480 pkt->tag.vio_subtype_env = VIO_PKT_DATA;
40015935Ssb155480 pkt->tag.vio_sid = ldcp->local_session;
40025935Ssb155480 nbytes = VIO_PKT_DATA_HDRSIZE + size;
40035935Ssb155480
40045935Ssb155480 /* send the msg over ldc */
40055935Ssb155480 rv = vsw_send_msg(ldcp, (void *)pkt, nbytes, B_TRUE);
40065935Ssb155480 if (rv != 0) {
40075935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
40085935Ssb155480 DWARN(vswp, "%s(%lld) Error sending priority frame\n", __func__,
40095935Ssb155480 ldcp->ldc_id);
40105935Ssb155480 goto send_pkt_exit;
40115935Ssb155480 }
40125935Ssb155480
40135935Ssb155480 /* update stats */
40145935Ssb155480 (void) atomic_inc_64(&statsp->tx_pri_packets);
40155935Ssb155480 (void) atomic_add_64(&statsp->tx_pri_packets, size);
40165935Ssb155480
40175935Ssb155480 send_pkt_exit:
40185935Ssb155480 if (nmp != NULL)
40195935Ssb155480 freemsg(nmp);
40205935Ssb155480 freemsg(mp);
40215373Sraghuram }
40225373Sraghuram
40235373Sraghuram /*
40245373Sraghuram * Transmit the packet over the given LDC channel.
40255373Sraghuram *
40265373Sraghuram * The 'retries' argument indicates how many times a packet
40275373Sraghuram * is retried before it is dropped. Note, the retry is done
40285373Sraghuram * only for a resource related failure, for all other failures
40295373Sraghuram * the packet is dropped immediately.
40305373Sraghuram */
40315373Sraghuram static int
vsw_ldcsend(vsw_ldc_t * ldcp,mblk_t * mp,uint32_t retries)40325935Ssb155480 vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries)
40335373Sraghuram {
403412011SSriharsha.Basavapatna@Sun.COM int i;
403512011SSriharsha.Basavapatna@Sun.COM int rc;
403612011SSriharsha.Basavapatna@Sun.COM int status = 0;
403712011SSriharsha.Basavapatna@Sun.COM vsw_port_t *port = ldcp->ldc_port;
403812011SSriharsha.Basavapatna@Sun.COM dring_info_t *dp = NULL;
403912011SSriharsha.Basavapatna@Sun.COM lane_t *lp = &ldcp->lane_out;
40405373Sraghuram
40415373Sraghuram for (i = 0; i < retries; ) {
40425373Sraghuram /*
40435373Sraghuram * Send the message out using the appropriate
40445373Sraghuram * transmit function which will free mblock when it
40455373Sraghuram * is finished with it.
40465373Sraghuram */
40475373Sraghuram mutex_enter(&port->tx_lock);
40485373Sraghuram if (port->transmit != NULL) {
40495373Sraghuram status = (*port->transmit)(ldcp, mp);
40505373Sraghuram }
40515373Sraghuram if (status == LDC_TX_SUCCESS) {
40525373Sraghuram mutex_exit(&port->tx_lock);
40535373Sraghuram break;
40545373Sraghuram }
40555373Sraghuram i++; /* increment the counter here */
40565373Sraghuram
40575373Sraghuram /* If its the last retry, then update the oerror */
40585373Sraghuram if ((i == retries) && (status == LDC_TX_NORESOURCES)) {
40595373Sraghuram ldcp->ldc_stats.oerrors++;
40605373Sraghuram }
40615373Sraghuram mutex_exit(&port->tx_lock);
40625373Sraghuram
40635373Sraghuram if (status != LDC_TX_NORESOURCES) {
40645373Sraghuram /*
40655373Sraghuram * No retrying required for errors un-related
40665373Sraghuram * to resources.
40675373Sraghuram */
40685373Sraghuram break;
40695373Sraghuram }
40705464Sraghuram if (((dp = ldcp->lane_out.dringp) != NULL) &&
40716419Ssb155480 ((VSW_VER_GTEQ(ldcp, 1, 2) &&
40725935Ssb155480 (ldcp->lane_out.xfer_mode & VIO_DRING_MODE_V1_2)) ||
40735935Ssb155480 ((VSW_VER_LT(ldcp, 1, 2) &&
40745935Ssb155480 (ldcp->lane_out.xfer_mode == VIO_DRING_MODE_V1_0))))) {
407512011SSriharsha.Basavapatna@Sun.COM
407612011SSriharsha.Basavapatna@Sun.COM /* Need to reclaim in TxDring mode. */
407712011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_TX_DRING) {
407812011SSriharsha.Basavapatna@Sun.COM rc = vsw_reclaim_dring(dp, dp->end_idx);
407912011SSriharsha.Basavapatna@Sun.COM }
408012011SSriharsha.Basavapatna@Sun.COM
40815464Sraghuram } else {
40825464Sraghuram /*
40835464Sraghuram * If there is no dring or the xfer_mode is
40845464Sraghuram * set to DESC_MODE(ie., OBP), then simply break here.
40855464Sraghuram */
40865373Sraghuram break;
40875373Sraghuram }
40885373Sraghuram
40895373Sraghuram /*
40905373Sraghuram * Delay only if none were reclaimed
40915373Sraghuram * and its not the last retry.
40925373Sraghuram */
40935373Sraghuram if ((rc == 0) && (i < retries)) {
40945373Sraghuram delay(drv_usectohz(vsw_ldc_tx_delay));
40955373Sraghuram }
40965373Sraghuram }
40975373Sraghuram freemsg(mp);
40985373Sraghuram return (status);
40995373Sraghuram }
41005373Sraghuram
41015373Sraghuram /*
41025373Sraghuram * Send an in-band descriptor message over ldc.
41035373Sraghuram */
41045373Sraghuram static int
vsw_descrsend(vsw_ldc_t * ldcp,mblk_t * mp)41055373Sraghuram vsw_descrsend(vsw_ldc_t *ldcp, mblk_t *mp)
41065373Sraghuram {
41075373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
41085373Sraghuram vnet_ibnd_desc_t ibnd_msg;
41095373Sraghuram vsw_private_desc_t *priv_desc = NULL;
41105373Sraghuram dring_info_t *dp = NULL;
41115373Sraghuram size_t n, size = 0;
41125373Sraghuram caddr_t bufp;
41135373Sraghuram mblk_t *bp;
41145373Sraghuram int idx, i;
41155373Sraghuram int status = LDC_TX_SUCCESS;
41165373Sraghuram static int warn_msg = 1;
41176419Ssb155480 lane_t *lp = &ldcp->lane_out;
41185373Sraghuram
41195373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
41205373Sraghuram
41215373Sraghuram ASSERT(mp != NULL);
41225373Sraghuram
41235373Sraghuram if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
41245373Sraghuram (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) {
41255373Sraghuram DERR(vswp, "%s(%lld) status(%d) state (0x%llx), dropping pkt",
41265373Sraghuram __func__, ldcp->ldc_id, ldcp->ldc_status,
41275373Sraghuram ldcp->lane_out.lstate);
41285373Sraghuram ldcp->ldc_stats.oerrors++;
41295373Sraghuram return (LDC_TX_FAILURE);
41305373Sraghuram }
41315373Sraghuram
41325373Sraghuram /*
413312011SSriharsha.Basavapatna@Sun.COM * The dring here is as an internal buffer,
413412011SSriharsha.Basavapatna@Sun.COM * rather than a transfer channel.
41355373Sraghuram */
41365373Sraghuram if ((dp = ldcp->lane_out.dringp) == NULL) {
41375373Sraghuram DERR(vswp, "%s(%lld): no dring for outbound lane",
41385373Sraghuram __func__, ldcp->ldc_id);
41395373Sraghuram DERR(vswp, "%s(%lld) status(%d) state (0x%llx)", __func__,
41405373Sraghuram ldcp->ldc_id, ldcp->ldc_status, ldcp->lane_out.lstate);
41415373Sraghuram ldcp->ldc_stats.oerrors++;
41425373Sraghuram return (LDC_TX_FAILURE);
41435373Sraghuram }
41445373Sraghuram
41455373Sraghuram size = msgsize(mp);
41466419Ssb155480 if (size > (size_t)lp->mtu) {
41475373Sraghuram DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__,
41485373Sraghuram ldcp->ldc_id, size);
41495373Sraghuram ldcp->ldc_stats.oerrors++;
41505373Sraghuram return (LDC_TX_FAILURE);
41515373Sraghuram }
41525373Sraghuram
41535373Sraghuram /*
41545373Sraghuram * Find a free descriptor in our buffer ring
41555373Sraghuram */
41565373Sraghuram if (vsw_dring_find_free_desc(dp, &priv_desc, &idx) != 0) {
41575373Sraghuram if (warn_msg) {
41585373Sraghuram DERR(vswp, "%s(%lld): no descriptor available for ring "
41595373Sraghuram "at 0x%llx", __func__, ldcp->ldc_id, dp);
41605373Sraghuram warn_msg = 0;
41615373Sraghuram }
41625373Sraghuram
41635373Sraghuram /* nothing more we can do */
41645373Sraghuram status = LDC_TX_NORESOURCES;
41655373Sraghuram goto vsw_descrsend_free_exit;
41665373Sraghuram } else {
41675373Sraghuram D2(vswp, "%s(%lld): free private descriptor found at pos "
41685373Sraghuram "%ld addr 0x%x\n", __func__, ldcp->ldc_id, idx, priv_desc);
41695373Sraghuram warn_msg = 1;
41705373Sraghuram }
41715373Sraghuram
41725373Sraghuram /* copy data into the descriptor */
41735373Sraghuram bufp = priv_desc->datap;
41745373Sraghuram for (bp = mp, n = 0; bp != NULL; bp = bp->b_cont) {
41755373Sraghuram n = MBLKL(bp);
41765373Sraghuram bcopy(bp->b_rptr, bufp, n);
41775373Sraghuram bufp += n;
41785373Sraghuram }
41795373Sraghuram
41805373Sraghuram priv_desc->datalen = (size < (size_t)ETHERMIN) ? ETHERMIN : size;
41815373Sraghuram
41825373Sraghuram /* create and send the in-band descp msg */
41835373Sraghuram ibnd_msg.hdr.tag.vio_msgtype = VIO_TYPE_DATA;
41845373Sraghuram ibnd_msg.hdr.tag.vio_subtype = VIO_SUBTYPE_INFO;
41855373Sraghuram ibnd_msg.hdr.tag.vio_subtype_env = VIO_DESC_DATA;
41865373Sraghuram ibnd_msg.hdr.tag.vio_sid = ldcp->local_session;
41875373Sraghuram
41885373Sraghuram /*
41895373Sraghuram * Copy the mem cookies describing the data from the
41905373Sraghuram * private region of the descriptor ring into the inband
41915373Sraghuram * descriptor.
41925373Sraghuram */
41935373Sraghuram for (i = 0; i < priv_desc->ncookies; i++) {
41945373Sraghuram bcopy(&priv_desc->memcookie[i], &ibnd_msg.memcookie[i],
41955373Sraghuram sizeof (ldc_mem_cookie_t));
41965373Sraghuram }
41975373Sraghuram
41985373Sraghuram ibnd_msg.hdr.desc_handle = idx;
41995373Sraghuram ibnd_msg.ncookies = priv_desc->ncookies;
42005373Sraghuram ibnd_msg.nbytes = size;
42015373Sraghuram
42025373Sraghuram ldcp->ldc_stats.opackets++;
42035373Sraghuram ldcp->ldc_stats.obytes += size;
42045373Sraghuram
42055373Sraghuram (void) vsw_send_msg(ldcp, (void *)&ibnd_msg,
42065373Sraghuram sizeof (vnet_ibnd_desc_t), B_TRUE);
42075373Sraghuram
42085373Sraghuram vsw_descrsend_free_exit:
42095373Sraghuram
42105373Sraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
42115373Sraghuram return (status);
42125373Sraghuram }
42135373Sraghuram
42145373Sraghuram static void
vsw_send_ver(void * arg)42155373Sraghuram vsw_send_ver(void *arg)
42165373Sraghuram {
42175373Sraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
42185373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
42195373Sraghuram lane_t *lp = &ldcp->lane_out;
42205373Sraghuram vio_ver_msg_t ver_msg;
42215373Sraghuram
42225373Sraghuram D1(vswp, "%s enter", __func__);
42235373Sraghuram
42245373Sraghuram ver_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
42255373Sraghuram ver_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
42265373Sraghuram ver_msg.tag.vio_subtype_env = VIO_VER_INFO;
42275373Sraghuram ver_msg.tag.vio_sid = ldcp->local_session;
42285373Sraghuram
42295935Ssb155480 if (vsw_obp_ver_proto_workaround == B_FALSE) {
42305935Ssb155480 ver_msg.ver_major = vsw_versions[0].ver_major;
42315935Ssb155480 ver_msg.ver_minor = vsw_versions[0].ver_minor;
42325935Ssb155480 } else {
42335935Ssb155480 /* use the major,minor that we've ack'd */
42345935Ssb155480 lane_t *lpi = &ldcp->lane_in;
42355935Ssb155480 ver_msg.ver_major = lpi->ver_major;
42365935Ssb155480 ver_msg.ver_minor = lpi->ver_minor;
42375935Ssb155480 }
42385373Sraghuram ver_msg.dev_class = VDEV_NETWORK_SWITCH;
42395373Sraghuram
42405373Sraghuram lp->lstate |= VSW_VER_INFO_SENT;
42415373Sraghuram lp->ver_major = ver_msg.ver_major;
42425373Sraghuram lp->ver_minor = ver_msg.ver_minor;
42435373Sraghuram
42445373Sraghuram DUMP_TAG(ver_msg.tag);
42455373Sraghuram
42465373Sraghuram (void) vsw_send_msg(ldcp, &ver_msg, sizeof (vio_ver_msg_t), B_TRUE);
42475373Sraghuram
42485373Sraghuram D1(vswp, "%s (%d): exit", __func__, ldcp->ldc_id);
42495373Sraghuram }
42505373Sraghuram
42515373Sraghuram static void
vsw_send_attr(vsw_ldc_t * ldcp)42525373Sraghuram vsw_send_attr(vsw_ldc_t *ldcp)
42535373Sraghuram {
42545373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
42555373Sraghuram lane_t *lp = &ldcp->lane_out;
42565373Sraghuram vnet_attr_msg_t attr_msg;
42575373Sraghuram
42585373Sraghuram D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id);
42595373Sraghuram
42605373Sraghuram /*
42615373Sraghuram * Subtype is set to INFO by default
42625373Sraghuram */
42635373Sraghuram attr_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
42645373Sraghuram attr_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
42655373Sraghuram attr_msg.tag.vio_subtype_env = VIO_ATTR_INFO;
42665373Sraghuram attr_msg.tag.vio_sid = ldcp->local_session;
42675373Sraghuram
42685373Sraghuram /* payload copied from default settings for lane */
42695373Sraghuram attr_msg.mtu = lp->mtu;
42705373Sraghuram attr_msg.addr_type = lp->addr_type;
42715373Sraghuram attr_msg.xfer_mode = lp->xfer_mode;
42725373Sraghuram attr_msg.ack_freq = lp->xfer_mode;
427312011SSriharsha.Basavapatna@Sun.COM attr_msg.options = lp->dring_mode;
42745373Sraghuram
42755373Sraghuram READ_ENTER(&vswp->if_lockrw);
42765462Swentaoy attr_msg.addr = vnet_macaddr_strtoul((vswp->if_addr).ether_addr_octet);
42775373Sraghuram RW_EXIT(&vswp->if_lockrw);
42785373Sraghuram
42795373Sraghuram ldcp->lane_out.lstate |= VSW_ATTR_INFO_SENT;
42805373Sraghuram
42815373Sraghuram DUMP_TAG(attr_msg.tag);
42825373Sraghuram
42835373Sraghuram (void) vsw_send_msg(ldcp, &attr_msg, sizeof (vnet_attr_msg_t), B_TRUE);
42845373Sraghuram
42855373Sraghuram D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id);
42865373Sraghuram }
42875373Sraghuram
42885373Sraghuram static void
vsw_send_dring_info(vsw_ldc_t * ldcp)42895373Sraghuram vsw_send_dring_info(vsw_ldc_t *ldcp)
42905373Sraghuram {
429112011SSriharsha.Basavapatna@Sun.COM int msgsize;
429212011SSriharsha.Basavapatna@Sun.COM void *msg;
429312011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
429412011SSriharsha.Basavapatna@Sun.COM vsw_port_t *port = ldcp->ldc_port;
429512011SSriharsha.Basavapatna@Sun.COM lane_t *lp = &ldcp->lane_out;
429612011SSriharsha.Basavapatna@Sun.COM vgen_stats_t *statsp = &ldcp->ldc_stats;
42975373Sraghuram
42985373Sraghuram D1(vswp, "%s: (%ld) enter", __func__, ldcp->ldc_id);
42995373Sraghuram
430012011SSriharsha.Basavapatna@Sun.COM /* dring mode has been negotiated in attr phase; save in stats */
430112011SSriharsha.Basavapatna@Sun.COM statsp->dring_mode = lp->dring_mode;
430212011SSriharsha.Basavapatna@Sun.COM
430312011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
430412011SSriharsha.Basavapatna@Sun.COM /*
430512011SSriharsha.Basavapatna@Sun.COM * Change the transmit routine for RxDringData mode.
430612011SSriharsha.Basavapatna@Sun.COM */
430712011SSriharsha.Basavapatna@Sun.COM port->transmit = vsw_dringsend_shm;
430812011SSriharsha.Basavapatna@Sun.COM msg = (void *) vsw_create_rx_dring_info(ldcp);
430912011SSriharsha.Basavapatna@Sun.COM if (msg == NULL) {
431012011SSriharsha.Basavapatna@Sun.COM return;
431112011SSriharsha.Basavapatna@Sun.COM }
431212011SSriharsha.Basavapatna@Sun.COM msgsize =
431312011SSriharsha.Basavapatna@Sun.COM VNET_DRING_REG_EXT_MSG_SIZE(lp->dringp->data_ncookies);
431412011SSriharsha.Basavapatna@Sun.COM ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
431512011SSriharsha.Basavapatna@Sun.COM vsw_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
431612011SSriharsha.Basavapatna@Sun.COM ldcp->rx_dringdata = vsw_process_dringdata_shm;
431712011SSriharsha.Basavapatna@Sun.COM } else {
431812011SSriharsha.Basavapatna@Sun.COM msg = (void *) vsw_create_tx_dring_info(ldcp);
431912011SSriharsha.Basavapatna@Sun.COM if (msg == NULL) {
432012011SSriharsha.Basavapatna@Sun.COM return;
432112011SSriharsha.Basavapatna@Sun.COM }
432212011SSriharsha.Basavapatna@Sun.COM msgsize = sizeof (vio_dring_reg_msg_t);
432312011SSriharsha.Basavapatna@Sun.COM ldcp->msg_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
432412011SSriharsha.Basavapatna@Sun.COM vsw_ldc_msg_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri);
432512011SSriharsha.Basavapatna@Sun.COM ldcp->rx_dringdata = vsw_process_dringdata;
43265373Sraghuram }
43275373Sraghuram
432812011SSriharsha.Basavapatna@Sun.COM lp->lstate |= VSW_DRING_INFO_SENT;
432912011SSriharsha.Basavapatna@Sun.COM DUMP_TAG_PTR((vio_msg_tag_t *)msg);
433012011SSriharsha.Basavapatna@Sun.COM (void) vsw_send_msg(ldcp, msg, msgsize, B_TRUE);
433112011SSriharsha.Basavapatna@Sun.COM kmem_free(msg, msgsize);
43325373Sraghuram
43335373Sraghuram D1(vswp, "%s: (%ld) exit", __func__, ldcp->ldc_id);
43345373Sraghuram }
43355373Sraghuram
43365373Sraghuram static void
vsw_send_rdx(vsw_ldc_t * ldcp)43375373Sraghuram vsw_send_rdx(vsw_ldc_t *ldcp)
43385373Sraghuram {
43395373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
43405373Sraghuram vio_rdx_msg_t rdx_msg;
43415373Sraghuram
43425373Sraghuram D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id);
43435373Sraghuram
43445373Sraghuram rdx_msg.tag.vio_msgtype = VIO_TYPE_CTRL;
43455373Sraghuram rdx_msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
43465373Sraghuram rdx_msg.tag.vio_subtype_env = VIO_RDX;
43475373Sraghuram rdx_msg.tag.vio_sid = ldcp->local_session;
43485373Sraghuram
43495373Sraghuram ldcp->lane_in.lstate |= VSW_RDX_INFO_SENT;
43505373Sraghuram
43515373Sraghuram DUMP_TAG(rdx_msg.tag);
43525373Sraghuram
43535373Sraghuram (void) vsw_send_msg(ldcp, &rdx_msg, sizeof (vio_rdx_msg_t), B_TRUE);
43545373Sraghuram
43555373Sraghuram D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id);
43565373Sraghuram }
43575373Sraghuram
43585373Sraghuram /*
43595373Sraghuram * Remove the specified address from the list of address maintained
43605373Sraghuram * in this port node.
43615373Sraghuram */
43625373Sraghuram mcst_addr_t *
vsw_del_addr(uint8_t devtype,void * arg,uint64_t addr)43635373Sraghuram vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr)
43645373Sraghuram {
43655373Sraghuram vsw_t *vswp = NULL;
43665373Sraghuram vsw_port_t *port = NULL;
43675373Sraghuram mcst_addr_t *prev_p = NULL;
43685373Sraghuram mcst_addr_t *curr_p = NULL;
43695373Sraghuram
43705373Sraghuram D1(NULL, "%s: enter : devtype %d : addr 0x%llx",
43715373Sraghuram __func__, devtype, addr);
43725373Sraghuram
43735373Sraghuram if (devtype == VSW_VNETPORT) {
43745373Sraghuram port = (vsw_port_t *)arg;
43755373Sraghuram mutex_enter(&port->mca_lock);
43765373Sraghuram prev_p = curr_p = port->mcap;
43775373Sraghuram } else {
43785373Sraghuram vswp = (vsw_t *)arg;
43795373Sraghuram mutex_enter(&vswp->mca_lock);
43805373Sraghuram prev_p = curr_p = vswp->mcap;
43815373Sraghuram }
43825373Sraghuram
43835373Sraghuram while (curr_p != NULL) {
43845373Sraghuram if (curr_p->addr == addr) {
43855373Sraghuram D2(NULL, "%s: address found", __func__);
43865373Sraghuram /* match found */
43875373Sraghuram if (prev_p == curr_p) {
43885373Sraghuram /* list head */
43895373Sraghuram if (devtype == VSW_VNETPORT)
43905373Sraghuram port->mcap = curr_p->nextp;
43915373Sraghuram else
43925373Sraghuram vswp->mcap = curr_p->nextp;
43935373Sraghuram } else {
43945373Sraghuram prev_p->nextp = curr_p->nextp;
43955373Sraghuram }
43965373Sraghuram break;
43975373Sraghuram } else {
43985373Sraghuram prev_p = curr_p;
43995373Sraghuram curr_p = curr_p->nextp;
44005373Sraghuram }
44015373Sraghuram }
44025373Sraghuram
44035373Sraghuram if (devtype == VSW_VNETPORT)
44045373Sraghuram mutex_exit(&port->mca_lock);
44055373Sraghuram else
44065373Sraghuram mutex_exit(&vswp->mca_lock);
44075373Sraghuram
44085373Sraghuram D1(NULL, "%s: exit", __func__);
44095373Sraghuram
44105373Sraghuram return (curr_p);
44115373Sraghuram }
44125373Sraghuram
44135373Sraghuram /*
44145373Sraghuram * Create a ring consisting of just a private portion and link
44155373Sraghuram * it into the list of rings for the outbound lane.
44165373Sraghuram *
44175373Sraghuram * These type of rings are used primarily for temporary data
44185373Sraghuram * storage (i.e. as data buffers).
44195373Sraghuram */
44205373Sraghuram void
vsw_create_privring(vsw_ldc_t * ldcp)44215373Sraghuram vsw_create_privring(vsw_ldc_t *ldcp)
44225373Sraghuram {
442312011SSriharsha.Basavapatna@Sun.COM dring_info_t *dp;
44245373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
44255373Sraghuram
44265373Sraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
44275373Sraghuram
44285373Sraghuram dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
44295373Sraghuram mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL);
443012011SSriharsha.Basavapatna@Sun.COM mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL);
443112011SSriharsha.Basavapatna@Sun.COM ldcp->lane_out.dringp = dp;
44325373Sraghuram
44335373Sraghuram /* no public section */
44345373Sraghuram dp->pub_addr = NULL;
44355373Sraghuram dp->priv_addr = kmem_zalloc(
443612011SSriharsha.Basavapatna@Sun.COM (sizeof (vsw_private_desc_t) * vsw_num_descriptors), KM_SLEEP);
443712011SSriharsha.Basavapatna@Sun.COM dp->num_descriptors = vsw_num_descriptors;
443812011SSriharsha.Basavapatna@Sun.COM
443912011SSriharsha.Basavapatna@Sun.COM if (vsw_setup_tx_dring(ldcp, dp)) {
44405373Sraghuram DERR(vswp, "%s: setup of ring failed", __func__);
444112011SSriharsha.Basavapatna@Sun.COM vsw_destroy_tx_dring(ldcp);
44425373Sraghuram return;
44435373Sraghuram }
44445373Sraghuram
44455373Sraghuram /* haven't used any descriptors yet */
44465373Sraghuram dp->end_idx = 0;
44475373Sraghuram dp->restart_reqd = B_TRUE;
44485373Sraghuram
44495373Sraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
44505373Sraghuram }
44515373Sraghuram
44525373Sraghuram /*
44535373Sraghuram * Set the default lane attributes. These are copied into
44545373Sraghuram * the attr msg we send to our peer. If they are not acceptable
44555373Sraghuram * then (currently) the handshake ends.
44565373Sraghuram */
44575373Sraghuram static void
vsw_set_lane_attr(vsw_t * vswp,lane_t * lp)44585373Sraghuram vsw_set_lane_attr(vsw_t *vswp, lane_t *lp)
44595373Sraghuram {
44605373Sraghuram bzero(lp, sizeof (lane_t));
44615373Sraghuram
44625373Sraghuram READ_ENTER(&vswp->if_lockrw);
44635373Sraghuram ether_copy(&(vswp->if_addr), &(lp->addr));
44645373Sraghuram RW_EXIT(&vswp->if_lockrw);
44655373Sraghuram
44666419Ssb155480 lp->mtu = vswp->max_frame_size;
44675373Sraghuram lp->addr_type = ADDR_TYPE_MAC;
44685935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0;
44695373Sraghuram lp->ack_freq = 0; /* for shared mode */
44705935Ssb155480 lp->seq_num = VNET_ISS;
44715373Sraghuram }
44725373Sraghuram
44735373Sraghuram /*
447412011SSriharsha.Basavapatna@Sun.COM * Map the descriptor ring exported by the peer.
44755373Sraghuram */
447612011SSriharsha.Basavapatna@Sun.COM static dring_info_t *
vsw_map_dring(vsw_ldc_t * ldcp,void * pkt)447712011SSriharsha.Basavapatna@Sun.COM vsw_map_dring(vsw_ldc_t *ldcp, void *pkt)
44785373Sraghuram {
447912011SSriharsha.Basavapatna@Sun.COM dring_info_t *dp = NULL;
448012011SSriharsha.Basavapatna@Sun.COM lane_t *lp = &ldcp->lane_out;
448112011SSriharsha.Basavapatna@Sun.COM
448212011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
448312011SSriharsha.Basavapatna@Sun.COM /*
448412011SSriharsha.Basavapatna@Sun.COM * In RxDringData mode, dring that we map in
448512011SSriharsha.Basavapatna@Sun.COM * becomes our transmit descriptor ring.
448612011SSriharsha.Basavapatna@Sun.COM */
448712011SSriharsha.Basavapatna@Sun.COM dp = vsw_map_tx_dring(ldcp, pkt);
448812011SSriharsha.Basavapatna@Sun.COM } else {
448912011SSriharsha.Basavapatna@Sun.COM /*
449012011SSriharsha.Basavapatna@Sun.COM * In TxDring mode, dring that we map in
449112011SSriharsha.Basavapatna@Sun.COM * becomes our receive descriptor ring.
449212011SSriharsha.Basavapatna@Sun.COM */
449312011SSriharsha.Basavapatna@Sun.COM dp = vsw_map_rx_dring(ldcp, pkt);
44945373Sraghuram }
449512011SSriharsha.Basavapatna@Sun.COM return (dp);
44965373Sraghuram }
44975373Sraghuram
44985373Sraghuram /*
449912011SSriharsha.Basavapatna@Sun.COM * Common dring mapping function used in both TxDring and RxDringData modes.
45005373Sraghuram */
450112011SSriharsha.Basavapatna@Sun.COM dring_info_t *
vsw_map_dring_cmn(vsw_ldc_t * ldcp,vio_dring_reg_msg_t * dring_pkt)450212011SSriharsha.Basavapatna@Sun.COM vsw_map_dring_cmn(vsw_ldc_t *ldcp, vio_dring_reg_msg_t *dring_pkt)
45035373Sraghuram {
450412011SSriharsha.Basavapatna@Sun.COM int rv;
450512011SSriharsha.Basavapatna@Sun.COM dring_info_t *dp;
450612011SSriharsha.Basavapatna@Sun.COM ldc_mem_info_t minfo;
450712011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
450812011SSriharsha.Basavapatna@Sun.COM
450912011SSriharsha.Basavapatna@Sun.COM /*
451012011SSriharsha.Basavapatna@Sun.COM * If the dring params are unacceptable then we NACK back.
451112011SSriharsha.Basavapatna@Sun.COM */
451212011SSriharsha.Basavapatna@Sun.COM if ((dring_pkt->num_descriptors == 0) ||
451312011SSriharsha.Basavapatna@Sun.COM (dring_pkt->descriptor_size == 0) ||
451412011SSriharsha.Basavapatna@Sun.COM (dring_pkt->ncookies != 1)) {
451512011SSriharsha.Basavapatna@Sun.COM DERR(vswp, "%s (%lld): invalid dring info",
451612011SSriharsha.Basavapatna@Sun.COM __func__, ldcp->ldc_id);
451712011SSriharsha.Basavapatna@Sun.COM return (NULL);
45185373Sraghuram }
45195373Sraghuram
452012011SSriharsha.Basavapatna@Sun.COM dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
452112011SSriharsha.Basavapatna@Sun.COM
452212011SSriharsha.Basavapatna@Sun.COM dp->num_descriptors = dring_pkt->num_descriptors;
452312011SSriharsha.Basavapatna@Sun.COM dp->descriptor_size = dring_pkt->descriptor_size;
452412011SSriharsha.Basavapatna@Sun.COM dp->options = dring_pkt->options;
452512011SSriharsha.Basavapatna@Sun.COM dp->dring_ncookies = dring_pkt->ncookies;
452612011SSriharsha.Basavapatna@Sun.COM
452712011SSriharsha.Basavapatna@Sun.COM /*
452812011SSriharsha.Basavapatna@Sun.COM * Note: should only get one cookie. Enforced in
452912011SSriharsha.Basavapatna@Sun.COM * the ldc layer.
453012011SSriharsha.Basavapatna@Sun.COM */
453112011SSriharsha.Basavapatna@Sun.COM bcopy(&dring_pkt->cookie[0], &dp->dring_cookie[0],
453212011SSriharsha.Basavapatna@Sun.COM sizeof (ldc_mem_cookie_t));
453312011SSriharsha.Basavapatna@Sun.COM
453412011SSriharsha.Basavapatna@Sun.COM rv = ldc_mem_dring_map(ldcp->ldc_handle, &dp->dring_cookie[0],
453512011SSriharsha.Basavapatna@Sun.COM dp->dring_ncookies, dp->num_descriptors, dp->descriptor_size,
453612011SSriharsha.Basavapatna@Sun.COM LDC_DIRECT_MAP, &(dp->dring_handle));
453712011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
453812011SSriharsha.Basavapatna@Sun.COM goto fail;
453912011SSriharsha.Basavapatna@Sun.COM }
454012011SSriharsha.Basavapatna@Sun.COM
454112011SSriharsha.Basavapatna@Sun.COM rv = ldc_mem_dring_info(dp->dring_handle, &minfo);
454212011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
454312011SSriharsha.Basavapatna@Sun.COM goto fail;
454412011SSriharsha.Basavapatna@Sun.COM }
454512011SSriharsha.Basavapatna@Sun.COM /* store the address of the ring */
454612011SSriharsha.Basavapatna@Sun.COM dp->pub_addr = minfo.vaddr;
454712011SSriharsha.Basavapatna@Sun.COM
454812011SSriharsha.Basavapatna@Sun.COM /* cache the dring mtype */
454912011SSriharsha.Basavapatna@Sun.COM dp->dring_mtype = minfo.mtype;
455012011SSriharsha.Basavapatna@Sun.COM
455112011SSriharsha.Basavapatna@Sun.COM /* no private section as we are importing */
455212011SSriharsha.Basavapatna@Sun.COM dp->priv_addr = NULL;
455312011SSriharsha.Basavapatna@Sun.COM
455412011SSriharsha.Basavapatna@Sun.COM /*
455512011SSriharsha.Basavapatna@Sun.COM * Using simple mono increasing int for ident at the moment.
455612011SSriharsha.Basavapatna@Sun.COM */
455712011SSriharsha.Basavapatna@Sun.COM dp->ident = ldcp->next_ident;
455812011SSriharsha.Basavapatna@Sun.COM ldcp->next_ident++;
455912011SSriharsha.Basavapatna@Sun.COM
456012011SSriharsha.Basavapatna@Sun.COM /*
456112011SSriharsha.Basavapatna@Sun.COM * Acknowledge it; we send back a unique dring identifier that
456212011SSriharsha.Basavapatna@Sun.COM * the sending side will use in future to refer to this
456312011SSriharsha.Basavapatna@Sun.COM * descriptor ring.
456412011SSriharsha.Basavapatna@Sun.COM */
456512011SSriharsha.Basavapatna@Sun.COM dring_pkt->dring_ident = dp->ident;
456612011SSriharsha.Basavapatna@Sun.COM
456712011SSriharsha.Basavapatna@Sun.COM return (dp);
456812011SSriharsha.Basavapatna@Sun.COM fail:
456912011SSriharsha.Basavapatna@Sun.COM if (dp->dring_handle != NULL) {
457012011SSriharsha.Basavapatna@Sun.COM (void) ldc_mem_dring_unmap(dp->dring_handle);
457112011SSriharsha.Basavapatna@Sun.COM }
457212011SSriharsha.Basavapatna@Sun.COM kmem_free(dp, sizeof (*dp));
457312011SSriharsha.Basavapatna@Sun.COM return (NULL);
45745373Sraghuram }
45755373Sraghuram
45765373Sraghuram /*
457712011SSriharsha.Basavapatna@Sun.COM * Unmap the descriptor ring exported by the peer.
45785373Sraghuram */
457912011SSriharsha.Basavapatna@Sun.COM static void
vsw_unmap_dring(vsw_ldc_t * ldcp)458012011SSriharsha.Basavapatna@Sun.COM vsw_unmap_dring(vsw_ldc_t *ldcp)
45815373Sraghuram {
458212011SSriharsha.Basavapatna@Sun.COM lane_t *lane_out = &ldcp->lane_out;
458312011SSriharsha.Basavapatna@Sun.COM
458412011SSriharsha.Basavapatna@Sun.COM if (lane_out->dring_mode == VIO_RX_DRING_DATA) {
458512011SSriharsha.Basavapatna@Sun.COM vsw_unmap_tx_dring(ldcp);
45865373Sraghuram } else {
458712011SSriharsha.Basavapatna@Sun.COM vsw_unmap_rx_dring(ldcp);
45885373Sraghuram }
45895373Sraghuram }
45905373Sraghuram
45915373Sraghuram /*
459212011SSriharsha.Basavapatna@Sun.COM * Map the shared memory data buffer area exported by the peer.
459312011SSriharsha.Basavapatna@Sun.COM * Used in RxDringData mode only.
45945373Sraghuram */
45955373Sraghuram static int
vsw_map_data(vsw_ldc_t * ldcp,dring_info_t * dp,void * pkt)459612011SSriharsha.Basavapatna@Sun.COM vsw_map_data(vsw_ldc_t *ldcp, dring_info_t *dp, void *pkt)
45975373Sraghuram {
459812011SSriharsha.Basavapatna@Sun.COM int rv;
459912011SSriharsha.Basavapatna@Sun.COM vio_dring_reg_ext_msg_t *emsg;
460012011SSriharsha.Basavapatna@Sun.COM vio_dring_reg_msg_t *msg = pkt;
460112011SSriharsha.Basavapatna@Sun.COM uint8_t *buf = (uint8_t *)msg->cookie;
460212011SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
4603*13098SWentao.Yang@Sun.COM ldc_mem_info_t minfo;
460412011SSriharsha.Basavapatna@Sun.COM
460512011SSriharsha.Basavapatna@Sun.COM /* skip over dring cookies */
460612011SSriharsha.Basavapatna@Sun.COM ASSERT(msg->ncookies == 1);
460712011SSriharsha.Basavapatna@Sun.COM buf += (msg->ncookies * sizeof (ldc_mem_cookie_t));
460812011SSriharsha.Basavapatna@Sun.COM
460912011SSriharsha.Basavapatna@Sun.COM emsg = (vio_dring_reg_ext_msg_t *)buf;
461012011SSriharsha.Basavapatna@Sun.COM if (emsg->data_ncookies > VNET_DATA_AREA_COOKIES) {
46115373Sraghuram return (1);
46125373Sraghuram }
46135373Sraghuram
461412011SSriharsha.Basavapatna@Sun.COM /* save # of data area cookies */
461512011SSriharsha.Basavapatna@Sun.COM dp->data_ncookies = emsg->data_ncookies;
461612011SSriharsha.Basavapatna@Sun.COM
461712011SSriharsha.Basavapatna@Sun.COM /* save data area size */
461812011SSriharsha.Basavapatna@Sun.COM dp->data_sz = emsg->data_area_size;
461912011SSriharsha.Basavapatna@Sun.COM
462012011SSriharsha.Basavapatna@Sun.COM /* allocate ldc mem handle for data area */
462112011SSriharsha.Basavapatna@Sun.COM rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &dp->data_handle);
462212011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
462312011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, "ldc_mem_alloc_handle failed\n");
462412011SSriharsha.Basavapatna@Sun.COM DWARN(vswp, "%s (%lld) ldc_mem_alloc_handle() failed: %d\n",
462512011SSriharsha.Basavapatna@Sun.COM __func__, ldcp->ldc_id, rv);
462612011SSriharsha.Basavapatna@Sun.COM return (1);
462712011SSriharsha.Basavapatna@Sun.COM }
462812011SSriharsha.Basavapatna@Sun.COM
462912011SSriharsha.Basavapatna@Sun.COM /* map the data area */
463012011SSriharsha.Basavapatna@Sun.COM rv = ldc_mem_map(dp->data_handle, emsg->data_cookie,
463112011SSriharsha.Basavapatna@Sun.COM emsg->data_ncookies, LDC_DIRECT_MAP, LDC_MEM_R,
463212011SSriharsha.Basavapatna@Sun.COM (caddr_t *)&dp->data_addr, NULL);
463312011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
463412011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, "ldc_mem_map failed\n");
463512011SSriharsha.Basavapatna@Sun.COM DWARN(vswp, "%s (%lld) ldc_mem_map() failed: %d\n",
463612011SSriharsha.Basavapatna@Sun.COM __func__, ldcp->ldc_id, rv);
463712011SSriharsha.Basavapatna@Sun.COM return (1);
463812011SSriharsha.Basavapatna@Sun.COM }
463912011SSriharsha.Basavapatna@Sun.COM
4640*13098SWentao.Yang@Sun.COM /* get the map info */
4641*13098SWentao.Yang@Sun.COM rv = ldc_mem_info(dp->data_handle, &minfo);
4642*13098SWentao.Yang@Sun.COM if (rv != 0) {
4643*13098SWentao.Yang@Sun.COM cmn_err(CE_WARN, "ldc_mem_info failed\n");
4644*13098SWentao.Yang@Sun.COM DWARN(vswp, "%s (%lld) ldc_mem_info() failed: %d\n",
4645*13098SWentao.Yang@Sun.COM __func__, ldcp->ldc_id, rv);
4646*13098SWentao.Yang@Sun.COM return (1);
4647*13098SWentao.Yang@Sun.COM }
4648*13098SWentao.Yang@Sun.COM
4649*13098SWentao.Yang@Sun.COM if (minfo.mtype != LDC_DIRECT_MAP) {
4650*13098SWentao.Yang@Sun.COM DWARN(vswp, "%s (%lld) mtype(%d) is not direct map\n",
4651*13098SWentao.Yang@Sun.COM __func__, ldcp->ldc_id, minfo.mtype);
4652*13098SWentao.Yang@Sun.COM return (1);
4653*13098SWentao.Yang@Sun.COM }
4654*13098SWentao.Yang@Sun.COM
465512011SSriharsha.Basavapatna@Sun.COM /* allocate memory for data area cookies */
465612011SSriharsha.Basavapatna@Sun.COM dp->data_cookie = kmem_zalloc(emsg->data_ncookies *
465712011SSriharsha.Basavapatna@Sun.COM sizeof (ldc_mem_cookie_t), KM_SLEEP);
465812011SSriharsha.Basavapatna@Sun.COM
465912011SSriharsha.Basavapatna@Sun.COM /* save data area cookies */
466012011SSriharsha.Basavapatna@Sun.COM bcopy(emsg->data_cookie, dp->data_cookie,
466112011SSriharsha.Basavapatna@Sun.COM emsg->data_ncookies * sizeof (ldc_mem_cookie_t));
466212011SSriharsha.Basavapatna@Sun.COM
466312011SSriharsha.Basavapatna@Sun.COM return (0);
46645373Sraghuram }
46655373Sraghuram
46665373Sraghuram /*
466712011SSriharsha.Basavapatna@Sun.COM * Reset and free all the resources associated with the channel.
46685373Sraghuram */
46695373Sraghuram static void
vsw_free_lane_resources(vsw_ldc_t * ldcp,uint64_t dir)46705373Sraghuram vsw_free_lane_resources(vsw_ldc_t *ldcp, uint64_t dir)
46715373Sraghuram {
467212011SSriharsha.Basavapatna@Sun.COM lane_t *lp;
46735373Sraghuram
46745373Sraghuram D1(ldcp->ldc_vswp, "%s (%lld): enter", __func__, ldcp->ldc_id);
46755373Sraghuram
46765373Sraghuram if (dir == INBOUND) {
46775373Sraghuram D2(ldcp->ldc_vswp, "%s: freeing INBOUND lane"
46785373Sraghuram " of channel %lld", __func__, ldcp->ldc_id);
46795373Sraghuram lp = &ldcp->lane_in;
46805373Sraghuram } else {
46815373Sraghuram D2(ldcp->ldc_vswp, "%s: freeing OUTBOUND lane"
46825373Sraghuram " of channel %lld", __func__, ldcp->ldc_id);
46835373Sraghuram lp = &ldcp->lane_out;
46845373Sraghuram }
46855373Sraghuram
46865373Sraghuram lp->lstate = VSW_LANE_INACTIV;
46875935Ssb155480 lp->seq_num = VNET_ISS;
46885373Sraghuram
468912011SSriharsha.Basavapatna@Sun.COM if (dir == INBOUND) {
469012011SSriharsha.Basavapatna@Sun.COM /* Unmap the remote dring which is imported from the peer */
469112011SSriharsha.Basavapatna@Sun.COM vsw_unmap_dring(ldcp);
469212011SSriharsha.Basavapatna@Sun.COM } else {
469312011SSriharsha.Basavapatna@Sun.COM /* Destroy the local dring which is exported to the peer */
469412011SSriharsha.Basavapatna@Sun.COM vsw_destroy_dring(ldcp);
46955373Sraghuram }
46965373Sraghuram
46975373Sraghuram D1(ldcp->ldc_vswp, "%s (%lld): exit", __func__, ldcp->ldc_id);
46985373Sraghuram }
46995373Sraghuram
47005373Sraghuram /*
470112011SSriharsha.Basavapatna@Sun.COM * Destroy the descriptor ring.
47025373Sraghuram */
47035373Sraghuram static void
vsw_destroy_dring(vsw_ldc_t * ldcp)470412011SSriharsha.Basavapatna@Sun.COM vsw_destroy_dring(vsw_ldc_t *ldcp)
47055373Sraghuram {
470612011SSriharsha.Basavapatna@Sun.COM lane_t *lp = &ldcp->lane_out;
470712011SSriharsha.Basavapatna@Sun.COM
470812011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
470912011SSriharsha.Basavapatna@Sun.COM vsw_destroy_rx_dring(ldcp);
471012011SSriharsha.Basavapatna@Sun.COM } else {
471112011SSriharsha.Basavapatna@Sun.COM vsw_destroy_tx_dring(ldcp);
47125373Sraghuram }
47135373Sraghuram }
47145373Sraghuram
47155373Sraghuram /*
47165373Sraghuram * vsw_ldc_tx_worker -- A per LDC worker thread to transmit data.
47175373Sraghuram * This thread is woken up by the vsw_portsend to transmit
47185373Sraghuram * packets.
47195373Sraghuram */
47205373Sraghuram static void
vsw_ldc_tx_worker(void * arg)47215373Sraghuram vsw_ldc_tx_worker(void *arg)
47225373Sraghuram {
47235373Sraghuram callb_cpr_t cprinfo;
47245373Sraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
47255373Sraghuram vsw_t *vswp = ldcp->ldc_vswp;
47265373Sraghuram mblk_t *mp;
47275373Sraghuram mblk_t *tmp;
47285373Sraghuram
47295373Sraghuram D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
47305373Sraghuram CALLB_CPR_INIT(&cprinfo, &ldcp->tx_thr_lock, callb_generic_cpr,
47315373Sraghuram "vnet_tx_thread");
47325373Sraghuram mutex_enter(&ldcp->tx_thr_lock);
47335373Sraghuram while (!(ldcp->tx_thr_flags & VSW_WTHR_STOP)) {
47345373Sraghuram
47355373Sraghuram CALLB_CPR_SAFE_BEGIN(&cprinfo);
47365373Sraghuram /*
47375373Sraghuram * Wait until the data is received or a stop
47385373Sraghuram * request is received.
47395373Sraghuram */
47405373Sraghuram while (!(ldcp->tx_thr_flags & VSW_WTHR_STOP) &&
47415373Sraghuram (ldcp->tx_mhead == NULL)) {
47425373Sraghuram cv_wait(&ldcp->tx_thr_cv, &ldcp->tx_thr_lock);
47435373Sraghuram }
47445373Sraghuram CALLB_CPR_SAFE_END(&cprinfo, &ldcp->tx_thr_lock)
47455373Sraghuram
47465373Sraghuram /*
47475373Sraghuram * First process the stop request.
47485373Sraghuram */
47495373Sraghuram if (ldcp->tx_thr_flags & VSW_WTHR_STOP) {
47505373Sraghuram D2(vswp, "%s(%lld):tx thread stopped\n",
47515373Sraghuram __func__, ldcp->ldc_id);
47525373Sraghuram break;
47535373Sraghuram }
47545373Sraghuram mp = ldcp->tx_mhead;
47555373Sraghuram ldcp->tx_mhead = ldcp->tx_mtail = NULL;
47565935Ssb155480 ldcp->tx_cnt = 0;
47575373Sraghuram mutex_exit(&ldcp->tx_thr_lock);
47585373Sraghuram D2(vswp, "%s(%lld):calling vsw_ldcsend\n",
47595373Sraghuram __func__, ldcp->ldc_id);
47605373Sraghuram while (mp != NULL) {
47615373Sraghuram tmp = mp->b_next;
47625373Sraghuram mp->b_next = mp->b_prev = NULL;
47635373Sraghuram (void) vsw_ldcsend(ldcp, mp, vsw_ldc_tx_retries);
47645373Sraghuram mp = tmp;
47655373Sraghuram }
47665373Sraghuram mutex_enter(&ldcp->tx_thr_lock);
47675373Sraghuram }
47685373Sraghuram
47695373Sraghuram /*
47705373Sraghuram * Update the run status and wakeup the thread that
47715373Sraghuram * has sent the stop request.
47725373Sraghuram */
47739217SWentao.Yang@Sun.COM ldcp->tx_thr_flags &= ~VSW_WTHR_STOP;
47749217SWentao.Yang@Sun.COM ldcp->tx_thread = NULL;
47755373Sraghuram CALLB_CPR_EXIT(&cprinfo);
47765373Sraghuram D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
47775373Sraghuram thread_exit();
47785373Sraghuram }
47795373Sraghuram
47805373Sraghuram /* vsw_stop_tx_thread -- Co-ordinate with receive thread to stop it */
47815373Sraghuram static void
vsw_stop_tx_thread(vsw_ldc_t * ldcp)47825373Sraghuram vsw_stop_tx_thread(vsw_ldc_t *ldcp)
47835373Sraghuram {
47849217SWentao.Yang@Sun.COM kt_did_t tid = 0;
47859217SWentao.Yang@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
47865373Sraghuram
47875373Sraghuram D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
47885373Sraghuram /*
47895373Sraghuram * Send a stop request by setting the stop flag and
47905373Sraghuram * wait until the receive thread stops.
47915373Sraghuram */
47925373Sraghuram mutex_enter(&ldcp->tx_thr_lock);
47939217SWentao.Yang@Sun.COM if (ldcp->tx_thread != NULL) {
47949217SWentao.Yang@Sun.COM tid = ldcp->tx_thread->t_did;
47955373Sraghuram ldcp->tx_thr_flags |= VSW_WTHR_STOP;
47965373Sraghuram cv_signal(&ldcp->tx_thr_cv);
47975373Sraghuram }
47985373Sraghuram mutex_exit(&ldcp->tx_thr_lock);
47999217SWentao.Yang@Sun.COM
48009217SWentao.Yang@Sun.COM if (tid != 0) {
48019217SWentao.Yang@Sun.COM thread_join(tid);
48029217SWentao.Yang@Sun.COM }
48039217SWentao.Yang@Sun.COM
48045373Sraghuram D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
48055373Sraghuram }
48065373Sraghuram
4807*13098SWentao.Yang@Sun.COM static int
vsw_mapin_avail(vsw_ldc_t * ldcp)4808*13098SWentao.Yang@Sun.COM vsw_mapin_avail(vsw_ldc_t *ldcp)
4809*13098SWentao.Yang@Sun.COM {
4810*13098SWentao.Yang@Sun.COM int rv;
4811*13098SWentao.Yang@Sun.COM ldc_info_t info;
4812*13098SWentao.Yang@Sun.COM uint64_t mapin_sz_req;
4813*13098SWentao.Yang@Sun.COM uint64_t dblk_sz;
4814*13098SWentao.Yang@Sun.COM vsw_t *vswp = ldcp->ldc_vswp;
4815*13098SWentao.Yang@Sun.COM
4816*13098SWentao.Yang@Sun.COM rv = ldc_info(ldcp->ldc_handle, &info);
4817*13098SWentao.Yang@Sun.COM if (rv != 0) {
4818*13098SWentao.Yang@Sun.COM return (B_FALSE);
4819*13098SWentao.Yang@Sun.COM }
4820*13098SWentao.Yang@Sun.COM
4821*13098SWentao.Yang@Sun.COM dblk_sz = RXDRING_DBLK_SZ(vswp->max_frame_size);
4822*13098SWentao.Yang@Sun.COM mapin_sz_req = (VSW_RXDRING_NRBUFS * dblk_sz);
4823*13098SWentao.Yang@Sun.COM
4824*13098SWentao.Yang@Sun.COM if (info.direct_map_size_max >= mapin_sz_req) {
4825*13098SWentao.Yang@Sun.COM return (B_TRUE);
4826*13098SWentao.Yang@Sun.COM }
4827*13098SWentao.Yang@Sun.COM
4828*13098SWentao.Yang@Sun.COM return (B_FALSE);
4829*13098SWentao.Yang@Sun.COM }
4830*13098SWentao.Yang@Sun.COM
48315373Sraghuram /*
48325373Sraghuram * Debugging routines
48335373Sraghuram */
48345373Sraghuram static void
display_state(void)48355373Sraghuram display_state(void)
48365373Sraghuram {
48375373Sraghuram vsw_t *vswp;
48385373Sraghuram vsw_port_list_t *plist;
48395373Sraghuram vsw_port_t *port;
48405373Sraghuram vsw_ldc_t *ldcp;
48415373Sraghuram extern vsw_t *vsw_head;
48425373Sraghuram
48435373Sraghuram cmn_err(CE_NOTE, "***** system state *****");
48445373Sraghuram
48455373Sraghuram for (vswp = vsw_head; vswp; vswp = vswp->next) {
48465373Sraghuram plist = &vswp->plist;
48475373Sraghuram READ_ENTER(&plist->lockrw);
48485373Sraghuram cmn_err(CE_CONT, "vsw instance %d has %d ports attached\n",
48495373Sraghuram vswp->instance, plist->num_ports);
48505373Sraghuram
48515373Sraghuram for (port = plist->head; port != NULL; port = port->p_next) {
48525373Sraghuram cmn_err(CE_CONT, "port %d : %d ldcs attached\n",
48536419Ssb155480 port->p_instance, port->num_ldcs);
485412011SSriharsha.Basavapatna@Sun.COM ldcp = port->ldcp;
485512011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "chan %lu : dev %d : "
485612011SSriharsha.Basavapatna@Sun.COM "status %d : phase %u\n",
485712011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_id, ldcp->dev_class,
485812011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_status, ldcp->hphase);
485912011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "chan %lu : lsession %lu : "
486012011SSriharsha.Basavapatna@Sun.COM "psession %lu\n", ldcp->ldc_id,
486112011SSriharsha.Basavapatna@Sun.COM ldcp->local_session, ldcp->peer_session);
486212011SSriharsha.Basavapatna@Sun.COM
486312011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "Inbound lane:\n");
486412011SSriharsha.Basavapatna@Sun.COM display_lane(&ldcp->lane_in);
486512011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "Outbound lane:\n");
486612011SSriharsha.Basavapatna@Sun.COM display_lane(&ldcp->lane_out);
48675373Sraghuram }
48685373Sraghuram RW_EXIT(&plist->lockrw);
48695373Sraghuram }
48705373Sraghuram cmn_err(CE_NOTE, "***** system state *****");
48715373Sraghuram }
48725373Sraghuram
48735373Sraghuram static void
display_lane(lane_t * lp)48745373Sraghuram display_lane(lane_t *lp)
48755373Sraghuram {
487612011SSriharsha.Basavapatna@Sun.COM dring_info_t *drp = lp->dringp;
48775373Sraghuram
48785373Sraghuram cmn_err(CE_CONT, "ver 0x%x:0x%x : state %lx : mtu 0x%lx\n",
48795373Sraghuram lp->ver_major, lp->ver_minor, lp->lstate, lp->mtu);
48805373Sraghuram cmn_err(CE_CONT, "addr_type %d : addr 0x%lx : xmode %d\n",
48815373Sraghuram lp->addr_type, lp->addr, lp->xfer_mode);
48825373Sraghuram cmn_err(CE_CONT, "dringp 0x%lx\n", (uint64_t)lp->dringp);
48835373Sraghuram
48845373Sraghuram cmn_err(CE_CONT, "Dring info:\n");
488512011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "\tnum_desc %u : dsize %u\n",
488612011SSriharsha.Basavapatna@Sun.COM drp->num_descriptors, drp->descriptor_size);
488712011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "\thandle 0x%lx\n", drp->dring_handle);
488812011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "\tpub_addr 0x%lx : priv_addr 0x%lx\n",
488912011SSriharsha.Basavapatna@Sun.COM (uint64_t)drp->pub_addr, (uint64_t)drp->priv_addr);
489012011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "\tident 0x%lx : end_idx %lu\n",
489112011SSriharsha.Basavapatna@Sun.COM drp->ident, drp->end_idx);
489212011SSriharsha.Basavapatna@Sun.COM display_ring(drp);
48935373Sraghuram }
48945373Sraghuram
48955373Sraghuram static void
display_ring(dring_info_t * dringp)48965373Sraghuram display_ring(dring_info_t *dringp)
48975373Sraghuram {
48985373Sraghuram uint64_t i;
48995373Sraghuram uint64_t priv_count = 0;
49005373Sraghuram uint64_t pub_count = 0;
49015373Sraghuram vnet_public_desc_t *pub_addr = NULL;
49025373Sraghuram vsw_private_desc_t *priv_addr = NULL;
49035373Sraghuram
490412011SSriharsha.Basavapatna@Sun.COM for (i = 0; i < vsw_num_descriptors; i++) {
49055373Sraghuram if (dringp->pub_addr != NULL) {
49065373Sraghuram pub_addr = (vnet_public_desc_t *)dringp->pub_addr + i;
49075373Sraghuram
49085373Sraghuram if (pub_addr->hdr.dstate == VIO_DESC_FREE)
49095373Sraghuram pub_count++;
49105373Sraghuram }
49115373Sraghuram
49125373Sraghuram if (dringp->priv_addr != NULL) {
49135373Sraghuram priv_addr = (vsw_private_desc_t *)dringp->priv_addr + i;
49145373Sraghuram
49155373Sraghuram if (priv_addr->dstate == VIO_DESC_FREE)
49165373Sraghuram priv_count++;
49175373Sraghuram }
49185373Sraghuram }
49195373Sraghuram cmn_err(CE_CONT, "\t%lu elements: %lu priv free: %lu pub free\n",
49205373Sraghuram i, priv_count, pub_count);
49215373Sraghuram }
49225373Sraghuram
49235373Sraghuram static void
dump_flags(uint64_t state)49245373Sraghuram dump_flags(uint64_t state)
49255373Sraghuram {
49265373Sraghuram int i;
49275373Sraghuram
49285373Sraghuram typedef struct flag_name {
49295373Sraghuram int flag_val;
49305373Sraghuram char *flag_name;
49315373Sraghuram } flag_name_t;
49325373Sraghuram
49335373Sraghuram flag_name_t flags[] = {
49345373Sraghuram VSW_VER_INFO_SENT, "VSW_VER_INFO_SENT",
49355373Sraghuram VSW_VER_INFO_RECV, "VSW_VER_INFO_RECV",
49365373Sraghuram VSW_VER_ACK_RECV, "VSW_VER_ACK_RECV",
49375373Sraghuram VSW_VER_ACK_SENT, "VSW_VER_ACK_SENT",
49385373Sraghuram VSW_VER_NACK_RECV, "VSW_VER_NACK_RECV",
49395373Sraghuram VSW_VER_NACK_SENT, "VSW_VER_NACK_SENT",
49405373Sraghuram VSW_ATTR_INFO_SENT, "VSW_ATTR_INFO_SENT",
49415373Sraghuram VSW_ATTR_INFO_RECV, "VSW_ATTR_INFO_RECV",
49425373Sraghuram VSW_ATTR_ACK_SENT, "VSW_ATTR_ACK_SENT",
49435373Sraghuram VSW_ATTR_ACK_RECV, "VSW_ATTR_ACK_RECV",
49445373Sraghuram VSW_ATTR_NACK_SENT, "VSW_ATTR_NACK_SENT",
49455373Sraghuram VSW_ATTR_NACK_RECV, "VSW_ATTR_NACK_RECV",
49465373Sraghuram VSW_DRING_INFO_SENT, "VSW_DRING_INFO_SENT",
49475373Sraghuram VSW_DRING_INFO_RECV, "VSW_DRING_INFO_RECV",
49485373Sraghuram VSW_DRING_ACK_SENT, "VSW_DRING_ACK_SENT",
49495373Sraghuram VSW_DRING_ACK_RECV, "VSW_DRING_ACK_RECV",
49505373Sraghuram VSW_DRING_NACK_SENT, "VSW_DRING_NACK_SENT",
49515373Sraghuram VSW_DRING_NACK_RECV, "VSW_DRING_NACK_RECV",
49525373Sraghuram VSW_RDX_INFO_SENT, "VSW_RDX_INFO_SENT",
49535373Sraghuram VSW_RDX_INFO_RECV, "VSW_RDX_INFO_RECV",
49545373Sraghuram VSW_RDX_ACK_SENT, "VSW_RDX_ACK_SENT",
49555373Sraghuram VSW_RDX_ACK_RECV, "VSW_RDX_ACK_RECV",
49565373Sraghuram VSW_RDX_NACK_SENT, "VSW_RDX_NACK_SENT",
49575373Sraghuram VSW_RDX_NACK_RECV, "VSW_RDX_NACK_RECV",
49585373Sraghuram VSW_MCST_INFO_SENT, "VSW_MCST_INFO_SENT",
49595373Sraghuram VSW_MCST_INFO_RECV, "VSW_MCST_INFO_RECV",
49605373Sraghuram VSW_MCST_ACK_SENT, "VSW_MCST_ACK_SENT",
49615373Sraghuram VSW_MCST_ACK_RECV, "VSW_MCST_ACK_RECV",
49625373Sraghuram VSW_MCST_NACK_SENT, "VSW_MCST_NACK_SENT",
49635373Sraghuram VSW_MCST_NACK_RECV, "VSW_MCST_NACK_RECV",
49645373Sraghuram VSW_LANE_ACTIVE, "VSW_LANE_ACTIVE"};
49655373Sraghuram
49665373Sraghuram DERR(NULL, "DUMP_FLAGS: %llx\n", state);
49675373Sraghuram for (i = 0; i < sizeof (flags)/sizeof (flag_name_t); i++) {
49685373Sraghuram if (state & flags[i].flag_val)
49695373Sraghuram DERR(NULL, "DUMP_FLAGS %s", flags[i].flag_name);
49705373Sraghuram }
49715373Sraghuram }
4972