11991Sheppo /*
21991Sheppo * CDDL HEADER START
31991Sheppo *
41991Sheppo * The contents of this file are subject to the terms of the
51991Sheppo * Common Development and Distribution License (the "License").
61991Sheppo * You may not use this file except in compliance with the License.
71991Sheppo *
81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo * or http://www.opensolaris.org/os/licensing.
101991Sheppo * See the License for the specific language governing permissions
111991Sheppo * and limitations under the License.
121991Sheppo *
131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo *
191991Sheppo * CDDL HEADER END
201991Sheppo */
211991Sheppo
221991Sheppo /*
2312300SSriharsha.Basavapatna@Sun.COM * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241991Sheppo */
251991Sheppo
261991Sheppo #include <sys/types.h>
271991Sheppo #include <sys/errno.h>
287529SSriharsha.Basavapatna@Sun.COM #include <sys/sysmacros.h>
291991Sheppo #include <sys/param.h>
3012011SSriharsha.Basavapatna@Sun.COM #include <sys/machsystm.h>
311991Sheppo #include <sys/stream.h>
324647Sraghuram #include <sys/strsubr.h>
331991Sheppo #include <sys/kmem.h>
341991Sheppo #include <sys/conf.h>
351991Sheppo #include <sys/devops.h>
361991Sheppo #include <sys/ksynch.h>
371991Sheppo #include <sys/stat.h>
381991Sheppo #include <sys/modctl.h>
391991Sheppo #include <sys/debug.h>
401991Sheppo #include <sys/ethernet.h>
411991Sheppo #include <sys/ddi.h>
421991Sheppo #include <sys/sunddi.h>
431991Sheppo #include <sys/strsun.h>
441991Sheppo #include <sys/note.h>
458275SEric Cheng #include <sys/mac_provider.h>
462311Sseb #include <sys/mac_ether.h>
471991Sheppo #include <sys/ldc.h>
481991Sheppo #include <sys/mach_descrip.h>
491991Sheppo #include <sys/mdeg.h>
504647Sraghuram #include <net/if.h>
514647Sraghuram #include <sys/vnet.h>
521991Sheppo #include <sys/vio_mailbox.h>
531991Sheppo #include <sys/vio_common.h>
541991Sheppo #include <sys/vnet_common.h>
552336Snarayan #include <sys/vnet_mailbox.h>
562336Snarayan #include <sys/vio_util.h>
571991Sheppo #include <sys/vnet_gen.h>
585935Ssb155480 #include <sys/atomic.h>
594647Sraghuram #include <sys/callb.h>
604647Sraghuram #include <sys/sdt.h>
614647Sraghuram #include <sys/intr.h>
624647Sraghuram #include <sys/pattr.h>
636419Ssb155480 #include <sys/vlan.h>
641991Sheppo
651991Sheppo /*
6612011SSriharsha.Basavapatna@Sun.COM * Implementation of the mac provider functionality for vnet using the
671991Sheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC).
681991Sheppo */
691991Sheppo
7012011SSriharsha.Basavapatna@Sun.COM /* Entry Points */
716495Sspeer int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
726495Sspeer const uint8_t *macaddr, void **vgenhdl);
7310309SSriharsha.Basavapatna@Sun.COM int vgen_init_mdeg(void *arg);
749235SWentao.Yang@Sun.COM void vgen_uninit(void *arg);
756495Sspeer int vgen_dds_tx(void *arg, void *dmsg);
7610309SSriharsha.Basavapatna@Sun.COM int vgen_enable_intr(void *arg);
7710309SSriharsha.Basavapatna@Sun.COM int vgen_disable_intr(void *arg);
7812011SSriharsha.Basavapatna@Sun.COM mblk_t *vgen_rx_poll(void *arg, int bytes_to_pickup);
791991Sheppo static int vgen_start(void *arg);
801991Sheppo static void vgen_stop(void *arg);
811991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp);
821991Sheppo static int vgen_multicst(void *arg, boolean_t add,
831991Sheppo const uint8_t *mca);
841991Sheppo static int vgen_promisc(void *arg, boolean_t on);
851991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca);
862311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val);
879336SSriharsha.Basavapatna@Sun.COM static void vgen_ioctl(void *arg, queue_t *q, mblk_t *mp);
889336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG
899336SSriharsha.Basavapatna@Sun.COM static int vgen_force_link_state(vgen_port_t *portp, int link_state);
909336SSriharsha.Basavapatna@Sun.COM #endif
911991Sheppo
9212011SSriharsha.Basavapatna@Sun.COM /* Port/LDC Configuration */
936419Ssb155480 static int vgen_read_mdprops(vgen_t *vgenp);
946419Ssb155480 static void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
956419Ssb155480 static void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp,
966419Ssb155480 mde_cookie_t node);
977529SSriharsha.Basavapatna@Sun.COM static void vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
987529SSriharsha.Basavapatna@Sun.COM uint32_t *mtu);
999336SSriharsha.Basavapatna@Sun.COM static void vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
1009336SSriharsha.Basavapatna@Sun.COM boolean_t *pls);
1011991Sheppo static void vgen_detach_ports(vgen_t *vgenp);
1021991Sheppo static void vgen_port_detach(vgen_port_t *portp);
1031991Sheppo static void vgen_port_list_insert(vgen_port_t *portp);
1041991Sheppo static void vgen_port_list_remove(vgen_port_t *portp);
1051991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp,
1061991Sheppo int port_num);
1071991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp);
1081991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp);
1091991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp);
1106419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
1111991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1126419Ssb155480 static int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
1136419Ssb155480 mde_cookie_t mdex);
1141991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex);
1156419Ssb155480 static int vgen_port_attach(vgen_port_t *portp);
1166419Ssb155480 static void vgen_port_detach_mdeg(vgen_port_t *portp);
1171991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp,
1181991Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex);
1192311Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat);
1209336SSriharsha.Basavapatna@Sun.COM static void vgen_port_reset(vgen_port_t *portp);
1219336SSriharsha.Basavapatna@Sun.COM static void vgen_reset_vsw_port(vgen_t *vgenp);
12212011SSriharsha.Basavapatna@Sun.COM static int vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller);
12312011SSriharsha.Basavapatna@Sun.COM static void vgen_ldc_up(vgen_ldc_t *ldcp);
1241991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id);
1251991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp);
1261991Sheppo static void vgen_port_init(vgen_port_t *portp);
1271991Sheppo static void vgen_port_uninit(vgen_port_t *portp);
1281991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp);
1291991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp);
1302311Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat);
13112011SSriharsha.Basavapatna@Sun.COM
13212011SSriharsha.Basavapatna@Sun.COM /* I/O Processing */
1331991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp);
1345935Ssb155480 static int vgen_ldcsend(void *arg, mblk_t *mp);
1355935Ssb155480 static void vgen_ldcsend_pkt(void *arg, mblk_t *mp);
13612011SSriharsha.Basavapatna@Sun.COM static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg);
13712011SSriharsha.Basavapatna@Sun.COM static void vgen_tx_watchdog(void *arg);
13812011SSriharsha.Basavapatna@Sun.COM
13912011SSriharsha.Basavapatna@Sun.COM /* Dring Configuration */
14012011SSriharsha.Basavapatna@Sun.COM static int vgen_create_dring(vgen_ldc_t *ldcp);
14112011SSriharsha.Basavapatna@Sun.COM static void vgen_destroy_dring(vgen_ldc_t *ldcp);
14212011SSriharsha.Basavapatna@Sun.COM static int vgen_map_dring(vgen_ldc_t *ldcp, void *pkt);
14312011SSriharsha.Basavapatna@Sun.COM static void vgen_unmap_dring(vgen_ldc_t *ldcp);
144*13098SWentao.Yang@Sun.COM static int vgen_mapin_avail(vgen_ldc_t *ldcp);
14512011SSriharsha.Basavapatna@Sun.COM
14612011SSriharsha.Basavapatna@Sun.COM /* VIO Message Processing */
14712011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake(vgen_ldc_t *ldcp);
14812011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake_done(vgen_ldc_t *ldcp);
1491991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp);
15012011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake_phase2(vgen_ldc_t *ldcp);
15112011SSriharsha.Basavapatna@Sun.COM static int vgen_handshake_phase3(vgen_ldc_t *ldcp);
15212011SSriharsha.Basavapatna@Sun.COM static void vgen_setup_handshake_params(vgen_ldc_t *ldcp);
1531991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp);
1541991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp);
15512011SSriharsha.Basavapatna@Sun.COM static int vgen_send_rx_dring_reg(vgen_ldc_t *ldcp);
15612011SSriharsha.Basavapatna@Sun.COM static int vgen_send_tx_dring_reg(vgen_ldc_t *ldcp);
15712011SSriharsha.Basavapatna@Sun.COM static void vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg,
15812011SSriharsha.Basavapatna@Sun.COM uint8_t option);
1591991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp);
16012011SSriharsha.Basavapatna@Sun.COM static int vgen_send_dringdata(vgen_ldc_t *ldcp, uint32_t start, int32_t end);
1611991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp);
1622793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp,
1631991Sheppo vio_msg_tag_t *tagp);
16412011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
16512011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg);
16612011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg);
1672793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
16812011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
16912011SSriharsha.Basavapatna@Sun.COM static int vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1702793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1712793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1722793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1735935Ssb155480 static void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen);
1745935Ssb155480 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
1755935Ssb155480 uint32_t msglen);
1761991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
17712011SSriharsha.Basavapatna@Sun.COM static int vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1786495Sspeer static void vgen_handle_evt_up(vgen_ldc_t *ldcp);
17912011SSriharsha.Basavapatna@Sun.COM static int vgen_process_reset(vgen_ldc_t *ldcp, int flags);
1801991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
1811991Sheppo static void vgen_hwatchdog(void *arg);
1825935Ssb155480 static void vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp);
1835935Ssb155480 static void vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp);
1849336SSriharsha.Basavapatna@Sun.COM static void vgen_link_update(vgen_t *vgenp, link_state_t link_state);
1851991Sheppo
18612011SSriharsha.Basavapatna@Sun.COM /* VLANs */
1876419Ssb155480 static void vgen_vlan_read_ids(void *arg, int type, md_t *mdp,
1886419Ssb155480 mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp,
1896419Ssb155480 uint16_t *nvidsp, uint16_t *default_idp);
1906419Ssb155480 static void vgen_vlan_create_hash(vgen_port_t *portp);
1916419Ssb155480 static void vgen_vlan_destroy_hash(vgen_port_t *portp);
1926419Ssb155480 static void vgen_vlan_add_ids(vgen_port_t *portp);
1936419Ssb155480 static void vgen_vlan_remove_ids(vgen_port_t *portp);
1946419Ssb155480 static boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid);
1956419Ssb155480 static boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp,
1966419Ssb155480 uint16_t *vidp);
1976419Ssb155480 static mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp,
1986419Ssb155480 boolean_t is_tagged, uint16_t vid);
1996419Ssb155480 static void vgen_vlan_unaware_port_reset(vgen_port_t *portp);
2006419Ssb155480 static void vgen_reset_vlan_unaware_ports(vgen_t *vgenp);
20112011SSriharsha.Basavapatna@Sun.COM
20212011SSriharsha.Basavapatna@Sun.COM /* Exported functions */
20312011SSriharsha.Basavapatna@Sun.COM int vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller);
20412011SSriharsha.Basavapatna@Sun.COM int vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller);
20512011SSriharsha.Basavapatna@Sun.COM void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen);
20612011SSriharsha.Basavapatna@Sun.COM void vgen_destroy_rxpools(void *arg);
20712011SSriharsha.Basavapatna@Sun.COM
20812011SSriharsha.Basavapatna@Sun.COM /* Externs */
2096495Sspeer extern void vnet_dds_rx(void *arg, void *dmsg);
2109647SWentao.Yang@Sun.COM extern void vnet_dds_cleanup_hio(vnet_t *vnetp);
2117529SSriharsha.Basavapatna@Sun.COM extern int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu);
2129336SSriharsha.Basavapatna@Sun.COM extern void vnet_link_update(vnet_t *vnetp, link_state_t link_state);
21312011SSriharsha.Basavapatna@Sun.COM extern int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen,
21412011SSriharsha.Basavapatna@Sun.COM boolean_t caller_holds_lock);
21512011SSriharsha.Basavapatna@Sun.COM extern void vgen_stop_msg_thread(vgen_ldc_t *ldcp);
21612011SSriharsha.Basavapatna@Sun.COM extern int vgen_create_tx_dring(vgen_ldc_t *ldcp);
21712011SSriharsha.Basavapatna@Sun.COM extern void vgen_destroy_tx_dring(vgen_ldc_t *ldcp);
21812011SSriharsha.Basavapatna@Sun.COM extern int vgen_map_rx_dring(vgen_ldc_t *ldcp, void *pkt);
21912011SSriharsha.Basavapatna@Sun.COM extern void vgen_unmap_rx_dring(vgen_ldc_t *ldcp);
22012011SSriharsha.Basavapatna@Sun.COM extern int vgen_create_rx_dring(vgen_ldc_t *ldcp);
22112011SSriharsha.Basavapatna@Sun.COM extern void vgen_destroy_rx_dring(vgen_ldc_t *ldcp);
22212011SSriharsha.Basavapatna@Sun.COM extern int vgen_map_tx_dring(vgen_ldc_t *ldcp, void *pkt);
22312011SSriharsha.Basavapatna@Sun.COM extern void vgen_unmap_tx_dring(vgen_ldc_t *ldcp);
22412011SSriharsha.Basavapatna@Sun.COM extern int vgen_map_data(vgen_ldc_t *ldcp, void *pkt);
22512011SSriharsha.Basavapatna@Sun.COM extern int vgen_handle_dringdata_shm(void *arg1, void *arg2);
22612011SSriharsha.Basavapatna@Sun.COM extern int vgen_handle_dringdata(void *arg1, void *arg2);
22712011SSriharsha.Basavapatna@Sun.COM extern int vgen_dringsend_shm(void *arg, mblk_t *mp);
22812011SSriharsha.Basavapatna@Sun.COM extern int vgen_dringsend(void *arg, mblk_t *mp);
22912011SSriharsha.Basavapatna@Sun.COM extern void vgen_ldc_msg_worker(void *arg);
23012011SSriharsha.Basavapatna@Sun.COM extern int vgen_send_dringack_shm(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp,
23112011SSriharsha.Basavapatna@Sun.COM uint32_t start, int32_t end, uint8_t pstate);
23212011SSriharsha.Basavapatna@Sun.COM extern mblk_t *vgen_poll_rcv_shm(vgen_ldc_t *ldcp, int bytes_to_pickup);
23312011SSriharsha.Basavapatna@Sun.COM extern mblk_t *vgen_poll_rcv(vgen_ldc_t *ldcp, int bytes_to_pickup);
23412011SSriharsha.Basavapatna@Sun.COM extern int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp);
2351991Sheppo
2365935Ssb155480 #define VGEN_PRI_ETH_DEFINED(vgenp) ((vgenp)->pri_num_types != 0)
2375935Ssb155480
2381991Sheppo #define LDC_LOCK(ldcp) \
2391991Sheppo mutex_enter(&((ldcp)->cblock));\
2404647Sraghuram mutex_enter(&((ldcp)->rxlock));\
2414647Sraghuram mutex_enter(&((ldcp)->wrlock));\
2421991Sheppo mutex_enter(&((ldcp)->txlock));\
2431991Sheppo mutex_enter(&((ldcp)->tclock));
2441991Sheppo #define LDC_UNLOCK(ldcp) \
2451991Sheppo mutex_exit(&((ldcp)->tclock));\
2461991Sheppo mutex_exit(&((ldcp)->txlock));\
2474647Sraghuram mutex_exit(&((ldcp)->wrlock));\
2484647Sraghuram mutex_exit(&((ldcp)->rxlock));\
2491991Sheppo mutex_exit(&((ldcp)->cblock));
2501991Sheppo
2516419Ssb155480 #define VGEN_VER_EQ(ldcp, major, minor) \
2526419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \
2536419Ssb155480 (ldcp)->local_hparams.ver_minor == (minor))
2546419Ssb155480
2556419Ssb155480 #define VGEN_VER_LT(ldcp, major, minor) \
2566419Ssb155480 (((ldcp)->local_hparams.ver_major < (major)) || \
2576419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \
2586419Ssb155480 (ldcp)->local_hparams.ver_minor < (minor)))
2596419Ssb155480
2606419Ssb155480 #define VGEN_VER_GTEQ(ldcp, major, minor) \
2616419Ssb155480 (((ldcp)->local_hparams.ver_major > (major)) || \
2626419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \
2636419Ssb155480 (ldcp)->local_hparams.ver_minor >= (minor)))
2646419Ssb155480
2651991Sheppo /*
2661991Sheppo * Property names
2671991Sheppo */
2681991Sheppo static char macaddr_propname[] = "mac-address";
2691991Sheppo static char rmacaddr_propname[] = "remote-mac-address";
2701991Sheppo static char channel_propname[] = "channel-endpoint";
2711991Sheppo static char reg_propname[] = "reg";
2721991Sheppo static char port_propname[] = "port";
2731991Sheppo static char swport_propname[] = "switch-port";
2741991Sheppo static char id_propname[] = "id";
2755935Ssb155480 static char vdev_propname[] = "virtual-device";
2765935Ssb155480 static char vnet_propname[] = "network";
2775935Ssb155480 static char pri_types_propname[] = "priority-ether-types";
2786419Ssb155480 static char vgen_pvid_propname[] = "port-vlan-id";
2796419Ssb155480 static char vgen_vid_propname[] = "vlan-id";
2806419Ssb155480 static char vgen_dvid_propname[] = "default-vlan-id";
2816419Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id";
2826419Ssb155480 static char port_vid_propname[] = "remote-vlan-id";
2837529SSriharsha.Basavapatna@Sun.COM static char vgen_mtu_propname[] = "mtu";
2849336SSriharsha.Basavapatna@Sun.COM static char vgen_linkprop_propname[] = "linkprop";
2859336SSriharsha.Basavapatna@Sun.COM
2869336SSriharsha.Basavapatna@Sun.COM /*
2879336SSriharsha.Basavapatna@Sun.COM * VIO Protocol Version Info:
2889336SSriharsha.Basavapatna@Sun.COM *
2899336SSriharsha.Basavapatna@Sun.COM * The version specified below represents the version of protocol currently
2909336SSriharsha.Basavapatna@Sun.COM * supported in the driver. It means the driver can negotiate with peers with
2919336SSriharsha.Basavapatna@Sun.COM * versions <= this version. Here is a summary of the feature(s) that are
2929336SSriharsha.Basavapatna@Sun.COM * supported at each version of the protocol:
2939336SSriharsha.Basavapatna@Sun.COM *
2949336SSriharsha.Basavapatna@Sun.COM * 1.0 Basic VIO protocol.
2959336SSriharsha.Basavapatna@Sun.COM * 1.1 vDisk protocol update (no virtual network update).
2969336SSriharsha.Basavapatna@Sun.COM * 1.2 Support for priority frames (priority-ether-types).
2979336SSriharsha.Basavapatna@Sun.COM * 1.3 VLAN and HybridIO support.
2989336SSriharsha.Basavapatna@Sun.COM * 1.4 Jumbo Frame support.
2999336SSriharsha.Basavapatna@Sun.COM * 1.5 Link State Notification support with optional support
3009336SSriharsha.Basavapatna@Sun.COM * for Physical Link information.
30112011SSriharsha.Basavapatna@Sun.COM * 1.6 Support for RxDringData mode.
3029336SSriharsha.Basavapatna@Sun.COM */
30312011SSriharsha.Basavapatna@Sun.COM static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 6} };
3041991Sheppo
3051991Sheppo /* Tunables */
3065171Ssb155480 uint32_t vgen_hwd_interval = 5; /* handshake watchdog freq in sec */
3071991Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */
3082109Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */
3098623SSriharsha.Basavapatna@Sun.COM uint32_t vgen_ldccl_retries = 5; /* max # of ldc_close() retries */
3105022Sraghuram uint32_t vgen_tx_delay = 0x30; /* delay when tx descr not available */
31112011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_ldc_mtu = VGEN_LDC_MTU; /* ldc mtu */
31212011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_txwd_interval = VGEN_TXWD_INTERVAL; /* watchdog freq in msec */
31312011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_txwd_timeout = VGEN_TXWD_TIMEOUT; /* tx timeout in msec */
31412011SSriharsha.Basavapatna@Sun.COM
31512011SSriharsha.Basavapatna@Sun.COM /*
31612011SSriharsha.Basavapatna@Sun.COM * Max # of channel resets allowed during handshake.
31712011SSriharsha.Basavapatna@Sun.COM */
31812011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_ldc_max_resets = 5;
31912011SSriharsha.Basavapatna@Sun.COM
32012011SSriharsha.Basavapatna@Sun.COM /*
32112011SSriharsha.Basavapatna@Sun.COM * See comments in vsw.c for details on the dring modes supported.
32212011SSriharsha.Basavapatna@Sun.COM * In RxDringData mode, # of buffers is determined by multiplying the # of
32312011SSriharsha.Basavapatna@Sun.COM * descriptors with the factor below. Note that the factor must be > 1; i.e,
32412011SSriharsha.Basavapatna@Sun.COM * the # of buffers must always be > # of descriptors. This is needed because,
32512011SSriharsha.Basavapatna@Sun.COM * while the shared memory buffers are sent up the stack on the receiver, the
32612011SSriharsha.Basavapatna@Sun.COM * sender needs additional buffers that can be used for further transmits.
32712011SSriharsha.Basavapatna@Sun.COM * See vgen_create_rx_dring() for details.
32812011SSriharsha.Basavapatna@Sun.COM */
32912011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_nrbufs_factor = 2;
33012011SSriharsha.Basavapatna@Sun.COM
33112011SSriharsha.Basavapatna@Sun.COM /*
33212011SSriharsha.Basavapatna@Sun.COM * Retry delay used while destroying rx mblk pools. Used in both Dring modes.
33312011SSriharsha.Basavapatna@Sun.COM */
33412011SSriharsha.Basavapatna@Sun.COM int vgen_rxpool_cleanup_delay = 100000; /* 100ms */
33512011SSriharsha.Basavapatna@Sun.COM
33612011SSriharsha.Basavapatna@Sun.COM /*
33712011SSriharsha.Basavapatna@Sun.COM * Delay when rx descr not ready; used in TxDring mode only.
33812011SSriharsha.Basavapatna@Sun.COM */
33912011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_recv_delay = 1;
34012011SSriharsha.Basavapatna@Sun.COM
34112011SSriharsha.Basavapatna@Sun.COM /*
34212011SSriharsha.Basavapatna@Sun.COM * Retry when rx descr not ready; used in TxDring mode only.
34312011SSriharsha.Basavapatna@Sun.COM */
34412011SSriharsha.Basavapatna@Sun.COM uint32_t vgen_recv_retries = 10;
34512011SSriharsha.Basavapatna@Sun.COM
34612011SSriharsha.Basavapatna@Sun.COM /*
34712011SSriharsha.Basavapatna@Sun.COM * Max # of packets accumulated prior to sending them up. It is best
34812011SSriharsha.Basavapatna@Sun.COM * to keep this at 60% of the number of receive buffers. Used in TxDring mode
34912011SSriharsha.Basavapatna@Sun.COM * by the msg worker thread. Used in RxDringData mode while in interrupt mode
35012011SSriharsha.Basavapatna@Sun.COM * (not used in polled mode).
3514647Sraghuram */
3524647Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6);
3534647Sraghuram
3544647Sraghuram /*
3557529SSriharsha.Basavapatna@Sun.COM * Internal tunables for receive buffer pools, that is, the size and number of
3567529SSriharsha.Basavapatna@Sun.COM * mblks for each pool. At least 3 sizes must be specified if these are used.
3577529SSriharsha.Basavapatna@Sun.COM * The sizes must be specified in increasing order. Non-zero value of the first
3587529SSriharsha.Basavapatna@Sun.COM * size will be used as a hint to use these values instead of the algorithm
35912011SSriharsha.Basavapatna@Sun.COM * that determines the sizes based on MTU. Used in TxDring mode only.
3604647Sraghuram */
3617529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz1 = 0;
3627529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz2 = 0;
3637529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz3 = 0;
3647529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz4 = 0;
3654647Sraghuram
3664647Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS;
3674647Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS;
3684647Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS;
3697529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_nrbufs4 = VGEN_NRBUFS;
3704647Sraghuram
3715935Ssb155480 /*
3725935Ssb155480 * In the absence of "priority-ether-types" property in MD, the following
3735935Ssb155480 * internal tunable can be set to specify a single priority ethertype.
3745935Ssb155480 */
3755935Ssb155480 uint64_t vgen_pri_eth_type = 0;
3765935Ssb155480
3775935Ssb155480 /*
3785935Ssb155480 * Number of transmit priority buffers that are preallocated per device.
3795935Ssb155480 * This number is chosen to be a small value to throttle transmission
3805935Ssb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks().
3815935Ssb155480 */
3825935Ssb155480 uint32_t vgen_pri_tx_nmblks = 64;
3835935Ssb155480
3846419Ssb155480 uint32_t vgen_vlan_nchains = 4; /* # of chains in vlan id hash table */
3856419Ssb155480
3866419Ssb155480 /*
3876419Ssb155480 * Matching criteria passed to the MDEG to register interest
3886419Ssb155480 * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified
3896419Ssb155480 * by their 'name' and 'cfg-handle' properties.
3906419Ssb155480 */
3916419Ssb155480 static md_prop_match_t vdev_prop_match[] = {
3926419Ssb155480 { MDET_PROP_STR, "name" },
3936419Ssb155480 { MDET_PROP_VAL, "cfg-handle" },
3946419Ssb155480 { MDET_LIST_END, NULL }
3956419Ssb155480 };
3966419Ssb155480
3976419Ssb155480 static mdeg_node_match_t vdev_match = { "virtual-device",
3986419Ssb155480 vdev_prop_match };
3996419Ssb155480
4001991Sheppo /* MD update matching structure */
4011991Sheppo static md_prop_match_t vport_prop_match[] = {
4021991Sheppo { MDET_PROP_VAL, "id" },
4031991Sheppo { MDET_LIST_END, NULL }
4041991Sheppo };
4051991Sheppo
4061991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port",
4071991Sheppo vport_prop_match };
4081991Sheppo
40912011SSriharsha.Basavapatna@Sun.COM /* Template for matching a particular vnet instance */
4101991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = {
4111991Sheppo { MDET_PROP_STR, "name", "network" },
4121991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL },
4131991Sheppo { MDET_LIST_END, NULL, NULL }
4141991Sheppo };
4151991Sheppo
4161991Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val)
4171991Sheppo
4186419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp);
4191991Sheppo
4209336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG
4219336SSriharsha.Basavapatna@Sun.COM #define VGEN_M_CALLBACK_FLAGS (MC_IOCTL)
4229336SSriharsha.Basavapatna@Sun.COM #else
4239336SSriharsha.Basavapatna@Sun.COM #define VGEN_M_CALLBACK_FLAGS (0)
4249336SSriharsha.Basavapatna@Sun.COM #endif
4259336SSriharsha.Basavapatna@Sun.COM
4262311Sseb static mac_callbacks_t vgen_m_callbacks = {
4279336SSriharsha.Basavapatna@Sun.COM VGEN_M_CALLBACK_FLAGS,
4282311Sseb vgen_stat,
4292311Sseb vgen_start,
4302311Sseb vgen_stop,
4312311Sseb vgen_promisc,
4322311Sseb vgen_multicst,
4332311Sseb vgen_unicst,
4342311Sseb vgen_tx,
43511878SVenu.Iyer@Sun.COM NULL,
4369336SSriharsha.Basavapatna@Sun.COM vgen_ioctl,
4372311Sseb NULL,
4382311Sseb NULL
4392311Sseb };
4402311Sseb
44112011SSriharsha.Basavapatna@Sun.COM /* Externs */
4424647Sraghuram extern pri_t maxclsyspri;
4434647Sraghuram extern proc_t p0;
4446419Ssb155480 extern uint32_t vnet_ethermtu;
4456419Ssb155480 extern uint16_t vnet_default_vlan_id;
446*13098SWentao.Yang@Sun.COM extern uint32_t vnet_num_descriptors;
4471991Sheppo
4481991Sheppo #ifdef DEBUG
4491991Sheppo
45012011SSriharsha.Basavapatna@Sun.COM #define DEBUG_PRINTF vgen_debug_printf
45112011SSriharsha.Basavapatna@Sun.COM
4524647Sraghuram extern int vnet_dbglevel;
45312011SSriharsha.Basavapatna@Sun.COM
45412011SSriharsha.Basavapatna@Sun.COM void vgen_debug_printf(const char *fname, vgen_t *vgenp,
4554647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...);
4564647Sraghuram
4574647Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */
4584647Sraghuram int vgendbg_ldcid = -1;
4591991Sheppo
46012011SSriharsha.Basavapatna@Sun.COM /* Flags to simulate error conditions for debugging */
46112011SSriharsha.Basavapatna@Sun.COM int vgen_inject_err_flag = 0;
46212011SSriharsha.Basavapatna@Sun.COM
46312011SSriharsha.Basavapatna@Sun.COM
46412011SSriharsha.Basavapatna@Sun.COM boolean_t
vgen_inject_error(vgen_ldc_t * ldcp,int error)46512011SSriharsha.Basavapatna@Sun.COM vgen_inject_error(vgen_ldc_t *ldcp, int error)
46612011SSriharsha.Basavapatna@Sun.COM {
46712011SSriharsha.Basavapatna@Sun.COM if ((vgendbg_ldcid == ldcp->ldc_id) &&
46812011SSriharsha.Basavapatna@Sun.COM (vgen_inject_err_flag & error)) {
46912011SSriharsha.Basavapatna@Sun.COM return (B_TRUE);
47012011SSriharsha.Basavapatna@Sun.COM }
47112011SSriharsha.Basavapatna@Sun.COM return (B_FALSE);
47212011SSriharsha.Basavapatna@Sun.COM }
4731991Sheppo
4741991Sheppo #endif
4751991Sheppo
4761991Sheppo /*
4771991Sheppo * vgen_init() is called by an instance of vnet driver to initialize the
47812011SSriharsha.Basavapatna@Sun.COM * corresponding generic transport layer. This layer uses Logical Domain
47912011SSriharsha.Basavapatna@Sun.COM * Channels (LDCs) to communicate with the virtual switch in the service domain
48012011SSriharsha.Basavapatna@Sun.COM * and also with peer vnets in other guest domains in the system.
48112011SSriharsha.Basavapatna@Sun.COM *
48212011SSriharsha.Basavapatna@Sun.COM * Arguments:
48312011SSriharsha.Basavapatna@Sun.COM * vnetp: an opaque pointer to the vnet instance
48412011SSriharsha.Basavapatna@Sun.COM * regprop: frame to be transmitted
48512011SSriharsha.Basavapatna@Sun.COM * vnetdip: dip of the vnet device
48612011SSriharsha.Basavapatna@Sun.COM * macaddr: mac address of the vnet device
48712011SSriharsha.Basavapatna@Sun.COM *
48812011SSriharsha.Basavapatna@Sun.COM * Returns:
48912011SSriharsha.Basavapatna@Sun.COM * Sucess: a handle to the vgen instance (vgen_t)
49012011SSriharsha.Basavapatna@Sun.COM * Failure: NULL
4911991Sheppo */
4921991Sheppo int
vgen_init(void * vnetp,uint64_t regprop,dev_info_t * vnetdip,const uint8_t * macaddr,void ** vgenhdl)4936495Sspeer vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip,
4946495Sspeer const uint8_t *macaddr, void **vgenhdl)
4951991Sheppo {
49612011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp;
49712011SSriharsha.Basavapatna@Sun.COM int instance;
49812011SSriharsha.Basavapatna@Sun.COM int rv;
49912011SSriharsha.Basavapatna@Sun.COM char qname[TASKQ_NAMELEN];
5001991Sheppo
5012311Sseb if ((vnetp == NULL) || (vnetdip == NULL))
5021991Sheppo return (DDI_FAILURE);
5031991Sheppo
5041991Sheppo instance = ddi_get_instance(vnetdip);
5051991Sheppo
5065373Sraghuram DBG1(NULL, NULL, "vnet(%d): enter\n", instance);
5071991Sheppo
5081991Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP);
5091991Sheppo
5101991Sheppo vgenp->vnetp = vnetp;
5116495Sspeer vgenp->instance = instance;
5126495Sspeer vgenp->regprop = regprop;
5131991Sheppo vgenp->vnetdip = vnetdip;
5141991Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL);
5159336SSriharsha.Basavapatna@Sun.COM vgenp->phys_link_state = LINK_STATE_UNKNOWN;
5161991Sheppo
5171991Sheppo /* allocate multicast table */
5181991Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE *
5191991Sheppo sizeof (struct ether_addr), KM_SLEEP);
5201991Sheppo vgenp->mccount = 0;
5211991Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE;
5221991Sheppo
5231991Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL);
5245641Swentaoy rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL);
5251991Sheppo
52612011SSriharsha.Basavapatna@Sun.COM (void) snprintf(qname, TASKQ_NAMELEN, "rxpool_taskq%d",
52712011SSriharsha.Basavapatna@Sun.COM instance);
52812011SSriharsha.Basavapatna@Sun.COM if ((vgenp->rxp_taskq = ddi_taskq_create(vnetdip, qname, 1,
52912011SSriharsha.Basavapatna@Sun.COM TASKQ_DEFAULTPRI, 0)) == NULL) {
53012011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, "!vnet%d: Unable to create rx pool task queue",
53112011SSriharsha.Basavapatna@Sun.COM instance);
53212011SSriharsha.Basavapatna@Sun.COM goto vgen_init_fail;
53312011SSriharsha.Basavapatna@Sun.COM }
53412011SSriharsha.Basavapatna@Sun.COM
5355935Ssb155480 rv = vgen_read_mdprops(vgenp);
5365935Ssb155480 if (rv != 0) {
5375935Ssb155480 goto vgen_init_fail;
5385935Ssb155480 }
5396495Sspeer *vgenhdl = (void *)vgenp;
5401991Sheppo
5415373Sraghuram DBG1(NULL, NULL, "vnet(%d): exit\n", instance);
5421991Sheppo return (DDI_SUCCESS);
5435935Ssb155480
5445935Ssb155480 vgen_init_fail:
5455935Ssb155480 rw_destroy(&vgenp->vgenports.rwlock);
5465935Ssb155480 mutex_destroy(&vgenp->lock);
5475935Ssb155480 kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE *
5485935Ssb155480 sizeof (struct ether_addr));
5495935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) {
5505935Ssb155480 kmem_free(vgenp->pri_types,
5515935Ssb155480 sizeof (uint16_t) * vgenp->pri_num_types);
5525935Ssb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp);
5535935Ssb155480 }
55412011SSriharsha.Basavapatna@Sun.COM if (vgenp->rxp_taskq != NULL) {
55512011SSriharsha.Basavapatna@Sun.COM ddi_taskq_destroy(vgenp->rxp_taskq);
55612011SSriharsha.Basavapatna@Sun.COM vgenp->rxp_taskq = NULL;
55712011SSriharsha.Basavapatna@Sun.COM }
5585935Ssb155480 KMEM_FREE(vgenp);
5595935Ssb155480 return (DDI_FAILURE);
5601991Sheppo }
5611991Sheppo
56210309SSriharsha.Basavapatna@Sun.COM int
vgen_init_mdeg(void * arg)56310309SSriharsha.Basavapatna@Sun.COM vgen_init_mdeg(void *arg)
56410309SSriharsha.Basavapatna@Sun.COM {
56510309SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = (vgen_t *)arg;
56610309SSriharsha.Basavapatna@Sun.COM
56710309SSriharsha.Basavapatna@Sun.COM /* register with MD event generator */
56810309SSriharsha.Basavapatna@Sun.COM return (vgen_mdeg_reg(vgenp));
56910309SSriharsha.Basavapatna@Sun.COM }
57010309SSriharsha.Basavapatna@Sun.COM
5711991Sheppo /*
5721991Sheppo * Called by vnet to undo the initializations done by vgen_init().
5731991Sheppo * The handle provided by generic transport during vgen_init() is the argument.
5741991Sheppo */
5759235SWentao.Yang@Sun.COM void
vgen_uninit(void * arg)5761991Sheppo vgen_uninit(void *arg)
5771991Sheppo {
57812011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = (vgen_t *)arg;
5792336Snarayan
5802336Snarayan if (vgenp == NULL) {
5819235SWentao.Yang@Sun.COM return;
5822336Snarayan }
5831991Sheppo
5844647Sraghuram DBG1(vgenp, NULL, "enter\n");
5851991Sheppo
58612011SSriharsha.Basavapatna@Sun.COM /* Unregister with MD event generator */
5871991Sheppo vgen_mdeg_unreg(vgenp);
5881991Sheppo
5891991Sheppo mutex_enter(&vgenp->lock);
5901991Sheppo
59112011SSriharsha.Basavapatna@Sun.COM /*
59212011SSriharsha.Basavapatna@Sun.COM * Detach all ports from the device; note that the device should have
59312011SSriharsha.Basavapatna@Sun.COM * been unplumbed by this time (See vnet_unattach() for the sequence)
59412011SSriharsha.Basavapatna@Sun.COM * and thus vgen_stop() has already been invoked on all the ports.
59512011SSriharsha.Basavapatna@Sun.COM */
5961991Sheppo vgen_detach_ports(vgenp);
5971991Sheppo
5982336Snarayan /*
59912011SSriharsha.Basavapatna@Sun.COM * We now destroy the taskq used to clean up rx mblk pools that
60012011SSriharsha.Basavapatna@Sun.COM * couldn't be destroyed when the ports/channels were detached.
60112011SSriharsha.Basavapatna@Sun.COM * We implicitly wait for those tasks to complete in
60212011SSriharsha.Basavapatna@Sun.COM * ddi_taskq_destroy().
6032336Snarayan */
60412011SSriharsha.Basavapatna@Sun.COM if (vgenp->rxp_taskq != NULL) {
60512011SSriharsha.Basavapatna@Sun.COM ddi_taskq_destroy(vgenp->rxp_taskq);
60612011SSriharsha.Basavapatna@Sun.COM vgenp->rxp_taskq = NULL;
60712011SSriharsha.Basavapatna@Sun.COM }
60812011SSriharsha.Basavapatna@Sun.COM
60912011SSriharsha.Basavapatna@Sun.COM /* Free multicast table */
6101991Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr));
6111991Sheppo
61212011SSriharsha.Basavapatna@Sun.COM /* Free pri_types table */
6135935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) {
6145935Ssb155480 kmem_free(vgenp->pri_types,
6155935Ssb155480 sizeof (uint16_t) * vgenp->pri_num_types);
6165935Ssb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp);
6175935Ssb155480 }
6185935Ssb155480
6191991Sheppo mutex_exit(&vgenp->lock);
6205641Swentaoy rw_destroy(&vgenp->vgenports.rwlock);
6211991Sheppo mutex_destroy(&vgenp->lock);
6221991Sheppo
6237572SWentao.Yang@Sun.COM DBG1(vgenp, NULL, "exit\n");
6241991Sheppo KMEM_FREE(vgenp);
6251991Sheppo }
6261991Sheppo
6271991Sheppo /* enable transmit/receive for the device */
6282311Sseb int
vgen_start(void * arg)6291991Sheppo vgen_start(void *arg)
6301991Sheppo {
6316495Sspeer vgen_port_t *portp = (vgen_port_t *)arg;
6326495Sspeer vgen_t *vgenp = portp->vgenp;
6331991Sheppo
6344647Sraghuram DBG1(vgenp, NULL, "enter\n");
6356495Sspeer mutex_enter(&portp->lock);
6366495Sspeer vgen_port_init(portp);
6376495Sspeer portp->flags |= VGEN_STARTED;
6386495Sspeer mutex_exit(&portp->lock);
6394647Sraghuram DBG1(vgenp, NULL, "exit\n");
6406495Sspeer
6411991Sheppo return (DDI_SUCCESS);
6421991Sheppo }
6431991Sheppo
6441991Sheppo /* stop transmit/receive */
6452311Sseb void
vgen_stop(void * arg)6461991Sheppo vgen_stop(void *arg)
6471991Sheppo {
6486495Sspeer vgen_port_t *portp = (vgen_port_t *)arg;
6496495Sspeer vgen_t *vgenp = portp->vgenp;
6501991Sheppo
6514647Sraghuram DBG1(vgenp, NULL, "enter\n");
6521991Sheppo
6536495Sspeer mutex_enter(&portp->lock);
65411543SWentao.Yang@Sun.COM if (portp->flags & VGEN_STARTED) {
65511543SWentao.Yang@Sun.COM vgen_port_uninit(portp);
65611543SWentao.Yang@Sun.COM portp->flags &= ~(VGEN_STARTED);
65711543SWentao.Yang@Sun.COM }
6586495Sspeer mutex_exit(&portp->lock);
6594647Sraghuram DBG1(vgenp, NULL, "exit\n");
6606495Sspeer
6611991Sheppo }
6621991Sheppo
6631991Sheppo /* vgen transmit function */
6641991Sheppo static mblk_t *
vgen_tx(void * arg,mblk_t * mp)6651991Sheppo vgen_tx(void *arg, mblk_t *mp)
6661991Sheppo {
66712011SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp;
66812011SSriharsha.Basavapatna@Sun.COM int status;
6691991Sheppo
6701991Sheppo portp = (vgen_port_t *)arg;
67112011SSriharsha.Basavapatna@Sun.COM status = vgen_portsend(portp, mp);
6721991Sheppo if (status != VGEN_SUCCESS) {
6731991Sheppo /* failure */
6741991Sheppo return (mp);
6751991Sheppo }
6761991Sheppo /* success */
6771991Sheppo return (NULL);
6781991Sheppo }
6791991Sheppo
6806419Ssb155480 /*
6816419Ssb155480 * This function provides any necessary tagging/untagging of the frames
6826419Ssb155480 * that are being transmitted over the port. It first verifies the vlan
6836419Ssb155480 * membership of the destination(port) and drops the packet if the
6846419Ssb155480 * destination doesn't belong to the given vlan.
6856419Ssb155480 *
6866419Ssb155480 * Arguments:
6876419Ssb155480 * portp: port over which the frames should be transmitted
6886419Ssb155480 * mp: frame to be transmitted
6896419Ssb155480 * is_tagged:
6906419Ssb155480 * B_TRUE: indicates frame header contains the vlan tag already.
6916419Ssb155480 * B_FALSE: indicates frame is untagged.
6926419Ssb155480 * vid: vlan in which the frame should be transmitted.
6936419Ssb155480 *
6946419Ssb155480 * Returns:
6956419Ssb155480 * Sucess: frame(mblk_t *) after doing the necessary tag/untag.
6966419Ssb155480 * Failure: NULL
6976419Ssb155480 */
6986419Ssb155480 static mblk_t *
vgen_vlan_frame_fixtag(vgen_port_t * portp,mblk_t * mp,boolean_t is_tagged,uint16_t vid)6996419Ssb155480 vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged,
7006419Ssb155480 uint16_t vid)
7016419Ssb155480 {
70212011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp;
70312011SSriharsha.Basavapatna@Sun.COM boolean_t dst_tagged;
70412011SSriharsha.Basavapatna@Sun.COM int rv;
7056419Ssb155480
7066419Ssb155480 vgenp = portp->vgenp;
7076419Ssb155480
7086419Ssb155480 /*
7096419Ssb155480 * If the packet is going to a vnet:
7106419Ssb155480 * Check if the destination vnet is in the same vlan.
7116419Ssb155480 * Check the frame header if tag or untag is needed.
7126419Ssb155480 *
7136419Ssb155480 * We do not check the above conditions if the packet is going to vsw:
7146419Ssb155480 * vsw must be present implicitly in all the vlans that a vnet device
7156419Ssb155480 * is configured into; even if vsw itself is not assigned to those
7166419Ssb155480 * vlans as an interface. For instance, the packet might be destined
7176419Ssb155480 * to another vnet(indirectly through vsw) or to an external host
7186419Ssb155480 * which is in the same vlan as this vnet and vsw itself may not be
7196419Ssb155480 * present in that vlan. Similarly packets going to vsw must be
7206419Ssb155480 * always tagged(unless in the default-vlan) if not already tagged,
7216419Ssb155480 * as we do not know the final destination. This is needed because
7226419Ssb155480 * vsw must always invoke its switching function only after tagging
7236419Ssb155480 * the packet; otherwise after switching function determines the
7246419Ssb155480 * destination we cannot figure out if the destination belongs to the
7256419Ssb155480 * the same vlan that the frame originated from and if it needs tag/
7266419Ssb155480 * untag. Note that vsw will tag the packet itself when it receives
7276419Ssb155480 * it over the channel from a client if needed. However, that is
7286419Ssb155480 * needed only in the case of vlan unaware clients such as obp or
7296419Ssb155480 * earlier versions of vnet.
7306419Ssb155480 *
7316419Ssb155480 */
7326419Ssb155480 if (portp != vgenp->vsw_portp) {
7336419Ssb155480 /*
7346419Ssb155480 * Packet going to a vnet. Check if the destination vnet is in
7356419Ssb155480 * the same vlan. Then check the frame header if tag/untag is
7366419Ssb155480 * needed.
7376419Ssb155480 */
7386419Ssb155480 rv = vgen_vlan_lookup(portp->vlan_hashp, vid);
7396419Ssb155480 if (rv == B_FALSE) {
7406419Ssb155480 /* drop the packet */
7416419Ssb155480 freemsg(mp);
7426419Ssb155480 return (NULL);
7436419Ssb155480 }
7446419Ssb155480
7456419Ssb155480 /* is the destination tagged or untagged in this vlan? */
7466419Ssb155480 (vid == portp->pvid) ? (dst_tagged = B_FALSE) :
7476419Ssb155480 (dst_tagged = B_TRUE);
7486419Ssb155480
7496419Ssb155480 if (is_tagged == dst_tagged) {
7506419Ssb155480 /* no tagging/untagging needed */
7516419Ssb155480 return (mp);
7526419Ssb155480 }
7536419Ssb155480
7546419Ssb155480 if (is_tagged == B_TRUE) {
7556419Ssb155480 /* frame is tagged; destination needs untagged */
7566419Ssb155480 mp = vnet_vlan_remove_tag(mp);
7576419Ssb155480 return (mp);
7586419Ssb155480 }
7596419Ssb155480
7606419Ssb155480 /* (is_tagged == B_FALSE): fallthru to tag tx packet: */
7616419Ssb155480 }
7626419Ssb155480
7636419Ssb155480 /*
7646419Ssb155480 * Packet going to a vnet needs tagging.
7656419Ssb155480 * OR
7666419Ssb155480 * If the packet is going to vsw, then it must be tagged in all cases:
7676419Ssb155480 * unknown unicast, broadcast/multicast or to vsw interface.
7686419Ssb155480 */
7696419Ssb155480
7706419Ssb155480 if (is_tagged == B_FALSE) {
7716419Ssb155480 mp = vnet_vlan_insert_tag(mp, vid);
7726419Ssb155480 }
7736419Ssb155480
7746419Ssb155480 return (mp);
7756419Ssb155480 }
7766419Ssb155480
7771991Sheppo /* transmit packets over the given port */
7781991Sheppo static int
vgen_portsend(vgen_port_t * portp,mblk_t * mp)7791991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp)
7801991Sheppo {
7816419Ssb155480 vgen_ldc_t *ldcp;
7826419Ssb155480 int status;
7836419Ssb155480 int rv = VGEN_SUCCESS;
7846495Sspeer vgen_t *vgenp = portp->vgenp;
7856495Sspeer vnet_t *vnetp = vgenp->vnetp;
7866419Ssb155480 boolean_t is_tagged;
7876495Sspeer boolean_t dec_refcnt = B_FALSE;
7886419Ssb155480 uint16_t vlan_id;
7896419Ssb155480 struct ether_header *ehp;
7906419Ssb155480
79112011SSriharsha.Basavapatna@Sun.COM if (portp == NULL) {
79212011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
79312011SSriharsha.Basavapatna@Sun.COM }
79412011SSriharsha.Basavapatna@Sun.COM
7956495Sspeer if (portp->use_vsw_port) {
7966495Sspeer (void) atomic_inc_32(&vgenp->vsw_port_refcnt);
7976495Sspeer portp = portp->vgenp->vsw_portp;
79812011SSriharsha.Basavapatna@Sun.COM ASSERT(portp != NULL);
7996495Sspeer dec_refcnt = B_TRUE;
8006495Sspeer }
8016419Ssb155480
8026419Ssb155480 /*
8036419Ssb155480 * Determine the vlan id that the frame belongs to.
8046419Ssb155480 */
8056419Ssb155480 ehp = (struct ether_header *)mp->b_rptr;
8066419Ssb155480 is_tagged = vgen_frame_lookup_vid(vnetp, ehp, &vlan_id);
8076419Ssb155480
8086419Ssb155480 if (vlan_id == vnetp->default_vlan_id) {
8096419Ssb155480
8106419Ssb155480 /* Frames in default vlan must be untagged */
8116419Ssb155480 ASSERT(is_tagged == B_FALSE);
8126419Ssb155480
8136419Ssb155480 /*
8146419Ssb155480 * If the destination is a vnet-port verify it belongs to the
8156419Ssb155480 * default vlan; otherwise drop the packet. We do not need
8166419Ssb155480 * this check for vsw-port, as it should implicitly belong to
8176419Ssb155480 * this vlan; see comments in vgen_vlan_frame_fixtag().
8186419Ssb155480 */
8196419Ssb155480 if (portp != vgenp->vsw_portp &&
8206419Ssb155480 portp->pvid != vnetp->default_vlan_id) {
8216419Ssb155480 freemsg(mp);
8226495Sspeer goto portsend_ret;
8236419Ssb155480 }
8246419Ssb155480
8256419Ssb155480 } else { /* frame not in default-vlan */
8266419Ssb155480
8276419Ssb155480 mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id);
8286419Ssb155480 if (mp == NULL) {
8296495Sspeer goto portsend_ret;
8306419Ssb155480 }
8316419Ssb155480
8326419Ssb155480 }
8331991Sheppo
83412011SSriharsha.Basavapatna@Sun.COM ldcp = portp->ldcp;
8355935Ssb155480 status = ldcp->tx(ldcp, mp);
8365022Sraghuram
8375022Sraghuram if (status != VGEN_TX_SUCCESS) {
8385022Sraghuram rv = VGEN_FAILURE;
8395022Sraghuram }
8406495Sspeer
8416495Sspeer portsend_ret:
8426495Sspeer if (dec_refcnt == B_TRUE) {
8436495Sspeer (void) atomic_dec_32(&vgenp->vsw_port_refcnt);
8446495Sspeer }
8455022Sraghuram return (rv);
8461991Sheppo }
8471991Sheppo
8485935Ssb155480 /*
8495935Ssb155480 * Wrapper function to transmit normal and/or priority frames over the channel.
8505935Ssb155480 */
8511991Sheppo static int
vgen_ldcsend(void * arg,mblk_t * mp)8525935Ssb155480 vgen_ldcsend(void *arg, mblk_t *mp)
8535935Ssb155480 {
8545935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
8555935Ssb155480 int status;
8565935Ssb155480 struct ether_header *ehp;
8575935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
8585935Ssb155480 uint32_t num_types;
8595935Ssb155480 uint16_t *types;
8605935Ssb155480 int i;
8615935Ssb155480
8625935Ssb155480 ASSERT(VGEN_PRI_ETH_DEFINED(vgenp));
8635935Ssb155480
8645935Ssb155480 num_types = vgenp->pri_num_types;
8655935Ssb155480 types = vgenp->pri_types;
8665935Ssb155480 ehp = (struct ether_header *)mp->b_rptr;
8675935Ssb155480
8685935Ssb155480 for (i = 0; i < num_types; i++) {
8695935Ssb155480
8705935Ssb155480 if (ehp->ether_type == types[i]) {
8715935Ssb155480 /* priority frame, use pri tx function */
8725935Ssb155480 vgen_ldcsend_pkt(ldcp, mp);
8735935Ssb155480 return (VGEN_SUCCESS);
8745935Ssb155480 }
8755935Ssb155480
8765935Ssb155480 }
8775935Ssb155480
87812011SSriharsha.Basavapatna@Sun.COM if (ldcp->tx_dringdata == NULL) {
87912011SSriharsha.Basavapatna@Sun.COM freemsg(mp);
88012011SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
88112011SSriharsha.Basavapatna@Sun.COM }
88212011SSriharsha.Basavapatna@Sun.COM
88312011SSriharsha.Basavapatna@Sun.COM status = ldcp->tx_dringdata(ldcp, mp);
8845935Ssb155480 return (status);
8855935Ssb155480 }
8865935Ssb155480
8875935Ssb155480 /*
8885935Ssb155480 * This function transmits the frame in the payload of a raw data
8895935Ssb155480 * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
8905935Ssb155480 * send special frames with high priorities, without going through
8915935Ssb155480 * the normal data path which uses descriptor ring mechanism.
8925935Ssb155480 */
8935935Ssb155480 static void
vgen_ldcsend_pkt(void * arg,mblk_t * mp)8945935Ssb155480 vgen_ldcsend_pkt(void *arg, mblk_t *mp)
8951991Sheppo {
8965935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
8975935Ssb155480 vio_raw_data_msg_t *pkt;
8985935Ssb155480 mblk_t *bp;
8995935Ssb155480 mblk_t *nmp = NULL;
90012011SSriharsha.Basavapatna@Sun.COM vio_mblk_t *vmp;
9015935Ssb155480 caddr_t dst;
9025935Ssb155480 uint32_t mblksz;
9035935Ssb155480 uint32_t size;
9045935Ssb155480 uint32_t nbytes;
9055935Ssb155480 int rv;
9065935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
9075935Ssb155480 vgen_stats_t *statsp = &ldcp->stats;
9085935Ssb155480
9095935Ssb155480 /* drop the packet if ldc is not up or handshake is not done */
9105935Ssb155480 if (ldcp->ldc_status != LDC_UP) {
9115935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
9125935Ssb155480 DWARN(vgenp, ldcp, "status(%d), dropping packet\n",
9135935Ssb155480 ldcp->ldc_status);
9145935Ssb155480 goto send_pkt_exit;
9155935Ssb155480 }
9165935Ssb155480
9175935Ssb155480 if (ldcp->hphase != VH_DONE) {
9185935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
9195935Ssb155480 DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n",
9205935Ssb155480 ldcp->hphase);
9215935Ssb155480 goto send_pkt_exit;
9225935Ssb155480 }
9235935Ssb155480
9245935Ssb155480 size = msgsize(mp);
9255935Ssb155480
9265935Ssb155480 /* frame size bigger than available payload len of raw data msg ? */
9275935Ssb155480 if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
9285935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
9295935Ssb155480 DWARN(vgenp, ldcp, "invalid size(%d)\n", size);
9305935Ssb155480 goto send_pkt_exit;
9315935Ssb155480 }
9325935Ssb155480
9335935Ssb155480 if (size < ETHERMIN)
9345935Ssb155480 size = ETHERMIN;
9355935Ssb155480
9365935Ssb155480 /* alloc space for a raw data message */
93712011SSriharsha.Basavapatna@Sun.COM vmp = vio_allocb(vgenp->pri_tx_vmp);
93812011SSriharsha.Basavapatna@Sun.COM if (vmp == NULL) {
9395935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
9405935Ssb155480 DWARN(vgenp, ldcp, "vio_allocb failed\n");
9415935Ssb155480 goto send_pkt_exit;
94212011SSriharsha.Basavapatna@Sun.COM } else {
94312011SSriharsha.Basavapatna@Sun.COM nmp = vmp->mp;
9445935Ssb155480 }
9455935Ssb155480 pkt = (vio_raw_data_msg_t *)nmp->b_rptr;
9465935Ssb155480
9475935Ssb155480 /* copy frame into the payload of raw data message */
9485935Ssb155480 dst = (caddr_t)pkt->data;
9495935Ssb155480 for (bp = mp; bp != NULL; bp = bp->b_cont) {
9505935Ssb155480 mblksz = MBLKL(bp);
9515935Ssb155480 bcopy(bp->b_rptr, dst, mblksz);
9525935Ssb155480 dst += mblksz;
9535935Ssb155480 }
9545935Ssb155480
95512011SSriharsha.Basavapatna@Sun.COM vmp->state = VIO_MBLK_HAS_DATA;
95612011SSriharsha.Basavapatna@Sun.COM
9575935Ssb155480 /* setup the raw data msg */
9585935Ssb155480 pkt->tag.vio_msgtype = VIO_TYPE_DATA;
9595935Ssb155480 pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
9605935Ssb155480 pkt->tag.vio_subtype_env = VIO_PKT_DATA;
9615935Ssb155480 pkt->tag.vio_sid = ldcp->local_sid;
9625935Ssb155480 nbytes = VIO_PKT_DATA_HDRSIZE + size;
9635935Ssb155480
9645935Ssb155480 /* send the msg over ldc */
9655935Ssb155480 rv = vgen_sendmsg(ldcp, (caddr_t)pkt, nbytes, B_FALSE);
9665935Ssb155480 if (rv != VGEN_SUCCESS) {
9675935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail);
9685935Ssb155480 DWARN(vgenp, ldcp, "Error sending priority frame\n");
9695935Ssb155480 if (rv == ECONNRESET) {
97012011SSriharsha.Basavapatna@Sun.COM (void) vgen_handle_evt_reset(ldcp, VGEN_OTHER);
9715935Ssb155480 }
9725935Ssb155480 goto send_pkt_exit;
9735935Ssb155480 }
9745935Ssb155480
9755935Ssb155480 /* update stats */
9765935Ssb155480 (void) atomic_inc_64(&statsp->tx_pri_packets);
9775935Ssb155480 (void) atomic_add_64(&statsp->tx_pri_bytes, size);
9785935Ssb155480
9795935Ssb155480 send_pkt_exit:
9805935Ssb155480 if (nmp != NULL)
9815935Ssb155480 freemsg(nmp);
9825935Ssb155480 freemsg(mp);
9835935Ssb155480 }
9845935Ssb155480
9855935Ssb155480 /*
98611543SWentao.Yang@Sun.COM * enable/disable a multicast address
98711543SWentao.Yang@Sun.COM * note that the cblock of the ldc channel connected to the vsw is used for
98811543SWentao.Yang@Sun.COM * synchronization of the mctab.
98911543SWentao.Yang@Sun.COM */
9902311Sseb int
vgen_multicst(void * arg,boolean_t add,const uint8_t * mca)9911991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca)
9921991Sheppo {
9931991Sheppo vgen_t *vgenp;
9941991Sheppo vnet_mcast_msg_t mcastmsg;
9951991Sheppo vio_msg_tag_t *tagp;
9961991Sheppo vgen_port_t *portp;
9971991Sheppo vgen_ldc_t *ldcp;
9981991Sheppo struct ether_addr *addrp;
9993653Snarayan int rv = DDI_FAILURE;
10001991Sheppo uint32_t i;
10011991Sheppo
10026495Sspeer portp = (vgen_port_t *)arg;
10036495Sspeer vgenp = portp->vgenp;
10046495Sspeer
100511543SWentao.Yang@Sun.COM if (portp->is_vsw_port != B_TRUE) {
10066495Sspeer return (DDI_SUCCESS);
10076495Sspeer }
10086495Sspeer
10091991Sheppo addrp = (struct ether_addr *)mca;
10101991Sheppo tagp = &mcastmsg.tag;
10111991Sheppo bzero(&mcastmsg, sizeof (mcastmsg));
10121991Sheppo
101312011SSriharsha.Basavapatna@Sun.COM ldcp = portp->ldcp;
101411543SWentao.Yang@Sun.COM if (ldcp == NULL) {
101511543SWentao.Yang@Sun.COM return (DDI_FAILURE);
101611543SWentao.Yang@Sun.COM }
10171991Sheppo
10181991Sheppo mutex_enter(&ldcp->cblock);
10191991Sheppo
10201991Sheppo if (ldcp->hphase == VH_DONE) {
10211991Sheppo /*
10221991Sheppo * If handshake is done, send a msg to vsw to add/remove
10235171Ssb155480 * the multicast address. Otherwise, we just update this
10245171Ssb155480 * mcast address in our table and the table will be sync'd
10255171Ssb155480 * with vsw when handshake completes.
10261991Sheppo */
10271991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
10281991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
10291991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO;
10301991Sheppo tagp->vio_sid = ldcp->local_sid;
10311991Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL);
10321991Sheppo mcastmsg.set = add;
10331991Sheppo mcastmsg.count = 1;
10343653Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg),
10353653Snarayan B_FALSE) != VGEN_SUCCESS) {
10364647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
103711543SWentao.Yang@Sun.COM rv = DDI_FAILURE;
10383653Snarayan goto vgen_mcast_exit;
10391991Sheppo }
10401991Sheppo }
10411991Sheppo
10421991Sheppo if (add) {
10431991Sheppo
10441991Sheppo /* expand multicast table if necessary */
10451991Sheppo if (vgenp->mccount >= vgenp->mcsize) {
10461991Sheppo struct ether_addr *newtab;
10471991Sheppo uint32_t newsize;
10481991Sheppo
10491991Sheppo
10501991Sheppo newsize = vgenp->mcsize * 2;
10511991Sheppo
10521991Sheppo newtab = kmem_zalloc(newsize *
10531991Sheppo sizeof (struct ether_addr), KM_NOSLEEP);
10543653Snarayan if (newtab == NULL)
10553653Snarayan goto vgen_mcast_exit;
10561991Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize *
10571991Sheppo sizeof (struct ether_addr));
10581991Sheppo kmem_free(vgenp->mctab,
10591991Sheppo vgenp->mcsize * sizeof (struct ether_addr));
10601991Sheppo
10611991Sheppo vgenp->mctab = newtab;
10621991Sheppo vgenp->mcsize = newsize;
10631991Sheppo }
10641991Sheppo
10651991Sheppo /* add address to the table */
10661991Sheppo vgenp->mctab[vgenp->mccount++] = *addrp;
10671991Sheppo
10681991Sheppo } else {
10691991Sheppo
10701991Sheppo /* delete address from the table */
10711991Sheppo for (i = 0; i < vgenp->mccount; i++) {
10721991Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) {
10731991Sheppo
10741991Sheppo /*
10751991Sheppo * If there's more than one address in this
10761991Sheppo * table, delete the unwanted one by moving
10771991Sheppo * the last one in the list over top of it;
10781991Sheppo * otherwise, just remove it.
10791991Sheppo */
10801991Sheppo if (vgenp->mccount > 1) {
10811991Sheppo vgenp->mctab[i] =
10824650Sraghuram vgenp->mctab[vgenp->mccount-1];
10831991Sheppo }
10841991Sheppo vgenp->mccount--;
10851991Sheppo break;
10861991Sheppo }
10871991Sheppo }
10881991Sheppo }
10891991Sheppo
10903653Snarayan rv = DDI_SUCCESS;
10913653Snarayan
10923653Snarayan vgen_mcast_exit:
109312011SSriharsha.Basavapatna@Sun.COM
109411543SWentao.Yang@Sun.COM mutex_exit(&ldcp->cblock);
10953653Snarayan return (rv);
10961991Sheppo }
10971991Sheppo
10981991Sheppo /* set or clear promiscuous mode on the device */
10991991Sheppo static int
vgen_promisc(void * arg,boolean_t on)11001991Sheppo vgen_promisc(void *arg, boolean_t on)
11011991Sheppo {
11021991Sheppo _NOTE(ARGUNUSED(arg, on))
11031991Sheppo return (DDI_SUCCESS);
11041991Sheppo }
11051991Sheppo
11061991Sheppo /* set the unicast mac address of the device */
11071991Sheppo static int
vgen_unicst(void * arg,const uint8_t * mca)11081991Sheppo vgen_unicst(void *arg, const uint8_t *mca)
11091991Sheppo {
11101991Sheppo _NOTE(ARGUNUSED(arg, mca))
11111991Sheppo return (DDI_SUCCESS);
11121991Sheppo }
11131991Sheppo
11141991Sheppo /* get device statistics */
11152311Sseb int
vgen_stat(void * arg,uint_t stat,uint64_t * val)11162311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val)
11171991Sheppo {
11186495Sspeer vgen_port_t *portp = (vgen_port_t *)arg;
11196495Sspeer
11206495Sspeer *val = vgen_port_stat(portp, stat);
11212311Sseb return (0);
11221991Sheppo }
11231991Sheppo
11241991Sheppo /* vgen internal functions */
11251991Sheppo /* detach all ports from the device */
11261991Sheppo static void
vgen_detach_ports(vgen_t * vgenp)11271991Sheppo vgen_detach_ports(vgen_t *vgenp)
11281991Sheppo {
11291991Sheppo vgen_port_t *portp;
11301991Sheppo vgen_portlist_t *plistp;
11311991Sheppo
11321991Sheppo plistp = &(vgenp->vgenports);
11331991Sheppo WRITE_ENTER(&plistp->rwlock);
11341991Sheppo while ((portp = plistp->headp) != NULL) {
11351991Sheppo vgen_port_detach(portp);
11361991Sheppo }
11371991Sheppo RW_EXIT(&plistp->rwlock);
11381991Sheppo }
11391991Sheppo
11401991Sheppo /*
11411991Sheppo * detach the given port.
11421991Sheppo */
11431991Sheppo static void
vgen_port_detach(vgen_port_t * portp)11441991Sheppo vgen_port_detach(vgen_port_t *portp)
11451991Sheppo {
11461991Sheppo vgen_t *vgenp;
11471991Sheppo int port_num;
11481991Sheppo
11491991Sheppo vgenp = portp->vgenp;
11501991Sheppo port_num = portp->port_num;
11511991Sheppo
11524647Sraghuram DBG1(vgenp, NULL, "port(%d):enter\n", port_num);
11531991Sheppo
11546495Sspeer /*
11556495Sspeer * If this port is connected to the vswitch, then
11566495Sspeer * potentially there could be ports that may be using
11576495Sspeer * this port to transmit packets. To address this do
11586495Sspeer * the following:
11596495Sspeer * - First set vgenp->vsw_portp to NULL, so that
11606495Sspeer * its not used after that.
11616495Sspeer * - Then wait for the refcnt to go down to 0.
11626495Sspeer * - Now we can safely detach this port.
11636495Sspeer */
11646495Sspeer if (vgenp->vsw_portp == portp) {
11656495Sspeer vgenp->vsw_portp = NULL;
11666495Sspeer while (vgenp->vsw_port_refcnt > 0) {
11676495Sspeer delay(drv_usectohz(vgen_tx_delay));
11686495Sspeer }
11696495Sspeer (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0);
11706495Sspeer }
11716495Sspeer
11726495Sspeer if (portp->vhp != NULL) {
11736495Sspeer vio_net_resource_unreg(portp->vhp);
11746495Sspeer portp->vhp = NULL;
11756495Sspeer }
11766495Sspeer
11776419Ssb155480 vgen_vlan_destroy_hash(portp);
11786419Ssb155480
11791991Sheppo /* remove it from port list */
11801991Sheppo vgen_port_list_remove(portp);
11811991Sheppo
11821991Sheppo /* detach channels from this port */
118312011SSriharsha.Basavapatna@Sun.COM vgen_ldc_detach(portp->ldcp);
11841991Sheppo
11856419Ssb155480 if (portp->num_ldcs != 0) {
11866419Ssb155480 kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t));
11876419Ssb155480 portp->num_ldcs = 0;
11886419Ssb155480 }
11896419Ssb155480
11906495Sspeer mutex_destroy(&portp->lock);
11911991Sheppo KMEM_FREE(portp);
11921991Sheppo
11934647Sraghuram DBG1(vgenp, NULL, "port(%d):exit\n", port_num);
11941991Sheppo }
11951991Sheppo
11961991Sheppo /* add a port to port list */
11971991Sheppo static void
vgen_port_list_insert(vgen_port_t * portp)11981991Sheppo vgen_port_list_insert(vgen_port_t *portp)
11991991Sheppo {
120012011SSriharsha.Basavapatna@Sun.COM vgen_portlist_t *plistp;
120112011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp;
12021991Sheppo
12031991Sheppo vgenp = portp->vgenp;
12041991Sheppo plistp = &(vgenp->vgenports);
12051991Sheppo
12061991Sheppo if (plistp->headp == NULL) {
12071991Sheppo plistp->headp = portp;
12081991Sheppo } else {
12091991Sheppo plistp->tailp->nextp = portp;
12101991Sheppo }
12111991Sheppo plistp->tailp = portp;
12121991Sheppo portp->nextp = NULL;
12131991Sheppo }
12141991Sheppo
12151991Sheppo /* remove a port from port list */
12161991Sheppo static void
vgen_port_list_remove(vgen_port_t * portp)12171991Sheppo vgen_port_list_remove(vgen_port_t *portp)
12181991Sheppo {
121912011SSriharsha.Basavapatna@Sun.COM vgen_port_t *prevp;
122012011SSriharsha.Basavapatna@Sun.COM vgen_port_t *nextp;
122112011SSriharsha.Basavapatna@Sun.COM vgen_portlist_t *plistp;
122212011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp;
12231991Sheppo
12241991Sheppo vgenp = portp->vgenp;
12251991Sheppo
12261991Sheppo plistp = &(vgenp->vgenports);
12271991Sheppo
12281991Sheppo if (plistp->headp == NULL)
12291991Sheppo return;
12301991Sheppo
12311991Sheppo if (portp == plistp->headp) {
12321991Sheppo plistp->headp = portp->nextp;
12331991Sheppo if (portp == plistp->tailp)
12341991Sheppo plistp->tailp = plistp->headp;
12351991Sheppo } else {
12364650Sraghuram for (prevp = plistp->headp;
12374650Sraghuram ((nextp = prevp->nextp) != NULL) && (nextp != portp);
12384650Sraghuram prevp = nextp)
12394650Sraghuram ;
12401991Sheppo if (nextp == portp) {
12411991Sheppo prevp->nextp = portp->nextp;
12421991Sheppo }
12431991Sheppo if (portp == plistp->tailp)
12441991Sheppo plistp->tailp = prevp;
12451991Sheppo }
12461991Sheppo }
12471991Sheppo
12481991Sheppo /* lookup a port in the list based on port_num */
12491991Sheppo static vgen_port_t *
vgen_port_lookup(vgen_portlist_t * plistp,int port_num)12501991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num)
12511991Sheppo {
12521991Sheppo vgen_port_t *portp = NULL;
12531991Sheppo
12541991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
12551991Sheppo if (portp->port_num == port_num) {
12561991Sheppo break;
12571991Sheppo }
12581991Sheppo }
12591991Sheppo
12601991Sheppo return (portp);
12611991Sheppo }
12621991Sheppo
12631991Sheppo static void
vgen_port_init(vgen_port_t * portp)12641991Sheppo vgen_port_init(vgen_port_t *portp)
12651991Sheppo {
12666419Ssb155480 /* Add the port to the specified vlans */
12676419Ssb155480 vgen_vlan_add_ids(portp);
12681991Sheppo
126912011SSriharsha.Basavapatna@Sun.COM /* Bring up the channel */
127012011SSriharsha.Basavapatna@Sun.COM (void) vgen_ldc_init(portp->ldcp);
12711991Sheppo }
12721991Sheppo
12731991Sheppo static void
vgen_port_uninit(vgen_port_t * portp)12741991Sheppo vgen_port_uninit(vgen_port_t *portp)
12751991Sheppo {
127612011SSriharsha.Basavapatna@Sun.COM vgen_ldc_uninit(portp->ldcp);
12776419Ssb155480
12786419Ssb155480 /* remove the port from vlans it has been assigned to */
12796419Ssb155480 vgen_vlan_remove_ids(portp);
12801991Sheppo }
12811991Sheppo
12825935Ssb155480 /*
12835935Ssb155480 * Scan the machine description for this instance of vnet
12845935Ssb155480 * and read its properties. Called only from vgen_init().
12855935Ssb155480 * Returns: 0 on success, 1 on failure.
12865935Ssb155480 */
12875935Ssb155480 static int
vgen_read_mdprops(vgen_t * vgenp)12885935Ssb155480 vgen_read_mdprops(vgen_t *vgenp)
12895935Ssb155480 {
12906419Ssb155480 vnet_t *vnetp = vgenp->vnetp;
12915935Ssb155480 md_t *mdp = NULL;
12925935Ssb155480 mde_cookie_t rootnode;
12935935Ssb155480 mde_cookie_t *listp = NULL;
12945935Ssb155480 uint64_t cfgh;
12955935Ssb155480 char *name;
12965935Ssb155480 int rv = 1;
12975935Ssb155480 int num_nodes = 0;
12985935Ssb155480 int num_devs = 0;
12995935Ssb155480 int listsz = 0;
13005935Ssb155480 int i;
13015935Ssb155480
13025935Ssb155480 if ((mdp = md_get_handle()) == NULL) {
13035935Ssb155480 return (rv);
13045935Ssb155480 }
13055935Ssb155480
13065935Ssb155480 num_nodes = md_node_count(mdp);
13075935Ssb155480 ASSERT(num_nodes > 0);
13085935Ssb155480
13095935Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t);
13105935Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);
13115935Ssb155480
13125935Ssb155480 rootnode = md_root_node(mdp);
13135935Ssb155480
13145935Ssb155480 /* search for all "virtual_device" nodes */
13155935Ssb155480 num_devs = md_scan_dag(mdp, rootnode,
13165935Ssb155480 md_find_name(mdp, vdev_propname),
13175935Ssb155480 md_find_name(mdp, "fwd"), listp);
13185935Ssb155480 if (num_devs <= 0) {
13195935Ssb155480 goto vgen_readmd_exit;
13205935Ssb155480 }
13215935Ssb155480
13225935Ssb155480 /*
13235935Ssb155480 * Now loop through the list of virtual-devices looking for
13245935Ssb155480 * devices with name "network" and for each such device compare
13255935Ssb155480 * its instance with what we have from the 'reg' property to
13265935Ssb155480 * find the right node in MD and then read all its properties.
13275935Ssb155480 */
13285935Ssb155480 for (i = 0; i < num_devs; i++) {
13295935Ssb155480
13305935Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) {
13315935Ssb155480 goto vgen_readmd_exit;
13325935Ssb155480 }
13335935Ssb155480
13345935Ssb155480 /* is this a "network" device? */
13355935Ssb155480 if (strcmp(name, vnet_propname) != 0)
13365935Ssb155480 continue;
13375935Ssb155480
13385935Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) {
13395935Ssb155480 goto vgen_readmd_exit;
13405935Ssb155480 }
13415935Ssb155480
13425935Ssb155480 /* is this the required instance of vnet? */
13436495Sspeer if (vgenp->regprop != cfgh)
13445935Ssb155480 continue;
13455935Ssb155480
13467529SSriharsha.Basavapatna@Sun.COM /*
13479336SSriharsha.Basavapatna@Sun.COM * Read the 'linkprop' property to know if this vnet
13489336SSriharsha.Basavapatna@Sun.COM * device should get physical link updates from vswitch.
13499336SSriharsha.Basavapatna@Sun.COM */
13509336SSriharsha.Basavapatna@Sun.COM vgen_linkprop_read(vgenp, mdp, listp[i],
13519336SSriharsha.Basavapatna@Sun.COM &vnetp->pls_update);
13529336SSriharsha.Basavapatna@Sun.COM
13539336SSriharsha.Basavapatna@Sun.COM /*
13547529SSriharsha.Basavapatna@Sun.COM * Read the mtu. Note that we set the mtu of vnet device within
13557529SSriharsha.Basavapatna@Sun.COM * this routine itself, after validating the range.
13567529SSriharsha.Basavapatna@Sun.COM */
13577529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgenp, mdp, listp[i], &vnetp->mtu);
13587529SSriharsha.Basavapatna@Sun.COM if (vnetp->mtu < ETHERMTU || vnetp->mtu > VNET_MAX_MTU) {
13597529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = ETHERMTU;
13607529SSriharsha.Basavapatna@Sun.COM }
13617529SSriharsha.Basavapatna@Sun.COM vgenp->max_frame_size = vnetp->mtu +
13627529SSriharsha.Basavapatna@Sun.COM sizeof (struct ether_header) + VLAN_TAGSZ;
13637529SSriharsha.Basavapatna@Sun.COM
13647529SSriharsha.Basavapatna@Sun.COM /* read priority ether types */
13655935Ssb155480 vgen_read_pri_eth_types(vgenp, mdp, listp[i]);
13666419Ssb155480
13676419Ssb155480 /* read vlan id properties of this vnet instance */
13686419Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, listp[i],
13696419Ssb155480 &vnetp->pvid, &vnetp->vids, &vnetp->nvids,
13706419Ssb155480 &vnetp->default_vlan_id);
13716419Ssb155480
13725935Ssb155480 rv = 0;
13735935Ssb155480 break;
13745935Ssb155480 }
13755935Ssb155480
13765935Ssb155480 vgen_readmd_exit:
13775935Ssb155480
13785935Ssb155480 kmem_free(listp, listsz);
13795935Ssb155480 (void) md_fini_handle(mdp);
13805935Ssb155480 return (rv);
13815935Ssb155480 }
13825935Ssb155480
13835935Ssb155480 /*
13846419Ssb155480 * Read vlan id properties of the given MD node.
13856419Ssb155480 * Arguments:
13866419Ssb155480 * arg: device argument(vnet device or a port)
13876419Ssb155480 * type: type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port)
13886419Ssb155480 * mdp: machine description
13896419Ssb155480 * node: md node cookie
13906419Ssb155480 *
13916419Ssb155480 * Returns:
13926419Ssb155480 * pvidp: port-vlan-id of the node
13936419Ssb155480 * vidspp: list of vlan-ids of the node
13946419Ssb155480 * nvidsp: # of vlan-ids in the list
13956419Ssb155480 * default_idp: default-vlan-id of the node(if node is vnet device)
13966419Ssb155480 */
13976419Ssb155480 static void
vgen_vlan_read_ids(void * arg,int type,md_t * mdp,mde_cookie_t node,uint16_t * pvidp,uint16_t ** vidspp,uint16_t * nvidsp,uint16_t * default_idp)13986419Ssb155480 vgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node,
13996419Ssb155480 uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp,
14006419Ssb155480 uint16_t *default_idp)
14016419Ssb155480 {
14026419Ssb155480 vgen_t *vgenp;
14036419Ssb155480 vnet_t *vnetp;
14046419Ssb155480 vgen_port_t *portp;
14056419Ssb155480 char *pvid_propname;
14066419Ssb155480 char *vid_propname;
14076419Ssb155480 uint_t nvids;
14086419Ssb155480 uint32_t vids_size;
14096419Ssb155480 int rv;
14106419Ssb155480 int i;
14116419Ssb155480 uint64_t *data;
14126419Ssb155480 uint64_t val;
14136419Ssb155480 int size;
14146419Ssb155480 int inst;
14156419Ssb155480
14166419Ssb155480 if (type == VGEN_LOCAL) {
14176419Ssb155480
14186419Ssb155480 vgenp = (vgen_t *)arg;
14196419Ssb155480 vnetp = vgenp->vnetp;
14206419Ssb155480 pvid_propname = vgen_pvid_propname;
14216419Ssb155480 vid_propname = vgen_vid_propname;
14226419Ssb155480 inst = vnetp->instance;
14236419Ssb155480
14246419Ssb155480 } else if (type == VGEN_PEER) {
14256419Ssb155480
14266419Ssb155480 portp = (vgen_port_t *)arg;
14276419Ssb155480 vgenp = portp->vgenp;
14286419Ssb155480 vnetp = vgenp->vnetp;
14296419Ssb155480 pvid_propname = port_pvid_propname;
14306419Ssb155480 vid_propname = port_vid_propname;
14316419Ssb155480 inst = portp->port_num;
14326419Ssb155480
14336419Ssb155480 } else {
14346419Ssb155480 return;
14356419Ssb155480 }
14366419Ssb155480
14376419Ssb155480 if (type == VGEN_LOCAL && default_idp != NULL) {
14386419Ssb155480 rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val);
14396419Ssb155480 if (rv != 0) {
14406419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found",
14416419Ssb155480 vgen_dvid_propname);
14426419Ssb155480
14436419Ssb155480 *default_idp = vnet_default_vlan_id;
14446419Ssb155480 } else {
14456419Ssb155480 *default_idp = val & 0xFFF;
14466419Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", vgen_dvid_propname,
14476419Ssb155480 inst, *default_idp);
14486419Ssb155480 }
14496419Ssb155480 }
14506419Ssb155480
14516419Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val);
14526419Ssb155480 if (rv != 0) {
14536419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", pvid_propname);
14546419Ssb155480 *pvidp = vnet_default_vlan_id;
14556419Ssb155480 } else {
14566419Ssb155480
14576419Ssb155480 *pvidp = val & 0xFFF;
14586419Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n",
14596419Ssb155480 pvid_propname, inst, *pvidp);
14606419Ssb155480 }
14616419Ssb155480
14626419Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data,
14636419Ssb155480 &size);
14646419Ssb155480 if (rv != 0) {
14656419Ssb155480 DBG2(vgenp, NULL, "prop(%s) not found", vid_propname);
14666419Ssb155480 size = 0;
14676419Ssb155480 } else {
14686419Ssb155480 size /= sizeof (uint64_t);
14696419Ssb155480 }
14706419Ssb155480 nvids = size;
14716419Ssb155480
14726419Ssb155480 if (nvids != 0) {
14736419Ssb155480 DBG2(vgenp, NULL, "%s(%d): ", vid_propname, inst);
14746419Ssb155480 vids_size = sizeof (uint16_t) * nvids;
14756419Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP);
14766419Ssb155480 for (i = 0; i < nvids; i++) {
14776419Ssb155480 (*vidspp)[i] = data[i] & 0xFFFF;
14786419Ssb155480 DBG2(vgenp, NULL, " %d ", (*vidspp)[i]);
14796419Ssb155480 }
14806419Ssb155480 DBG2(vgenp, NULL, "\n");
14816419Ssb155480 }
14826419Ssb155480
14836419Ssb155480 *nvidsp = nvids;
14846419Ssb155480 }
14856419Ssb155480
14866419Ssb155480 /*
14876419Ssb155480 * Create a vlan id hash table for the given port.
14886419Ssb155480 */
14896419Ssb155480 static void
vgen_vlan_create_hash(vgen_port_t * portp)14906419Ssb155480 vgen_vlan_create_hash(vgen_port_t *portp)
14916419Ssb155480 {
14926419Ssb155480 char hashname[MAXNAMELEN];
14936419Ssb155480
14946419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash",
14956419Ssb155480 portp->port_num);
14966419Ssb155480
14976419Ssb155480 portp->vlan_nchains = vgen_vlan_nchains;
14986419Ssb155480 portp->vlan_hashp = mod_hash_create_idhash(hashname,
14996419Ssb155480 portp->vlan_nchains, mod_hash_null_valdtor);
15006419Ssb155480 }
15016419Ssb155480
15026419Ssb155480 /*
15036419Ssb155480 * Destroy the vlan id hash table in the given port.
15046419Ssb155480 */
15056419Ssb155480 static void
vgen_vlan_destroy_hash(vgen_port_t * portp)15066419Ssb155480 vgen_vlan_destroy_hash(vgen_port_t *portp)
15076419Ssb155480 {
15086419Ssb155480 if (portp->vlan_hashp != NULL) {
15096419Ssb155480 mod_hash_destroy_hash(portp->vlan_hashp);
15106419Ssb155480 portp->vlan_hashp = NULL;
15116419Ssb155480 portp->vlan_nchains = 0;
15126419Ssb155480 }
15136419Ssb155480 }
15146419Ssb155480
15156419Ssb155480 /*
15166419Ssb155480 * Add a port to the vlans specified in its port properites.
15176419Ssb155480 */
15186419Ssb155480 static void
vgen_vlan_add_ids(vgen_port_t * portp)15196419Ssb155480 vgen_vlan_add_ids(vgen_port_t *portp)
15206419Ssb155480 {
15216419Ssb155480 int rv;
15226419Ssb155480 int i;
15236419Ssb155480
15246419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp,
15256419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
15266419Ssb155480 (mod_hash_val_t)B_TRUE);
15276419Ssb155480 ASSERT(rv == 0);
15286419Ssb155480
15296419Ssb155480 for (i = 0; i < portp->nvids; i++) {
15306419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp,
15316419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
15326419Ssb155480 (mod_hash_val_t)B_TRUE);
15336419Ssb155480 ASSERT(rv == 0);
15346419Ssb155480 }
15356419Ssb155480 }
15366419Ssb155480
15376419Ssb155480 /*
15386419Ssb155480 * Remove a port from the vlans it has been assigned to.
15396419Ssb155480 */
15406419Ssb155480 static void
vgen_vlan_remove_ids(vgen_port_t * portp)15416419Ssb155480 vgen_vlan_remove_ids(vgen_port_t *portp)
15426419Ssb155480 {
15436419Ssb155480 int rv;
15446419Ssb155480 int i;
15456419Ssb155480 mod_hash_val_t vp;
15466419Ssb155480
15476419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp,
15486419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid),
15496419Ssb155480 (mod_hash_val_t *)&vp);
15506419Ssb155480 ASSERT(rv == 0);
15516419Ssb155480
15526419Ssb155480 for (i = 0; i < portp->nvids; i++) {
15536419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp,
15546419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]),
15556419Ssb155480 (mod_hash_val_t *)&vp);
15566419Ssb155480 ASSERT(rv == 0);
15576419Ssb155480 }
15586419Ssb155480 }
15596419Ssb155480
15606419Ssb155480 /*
15616419Ssb155480 * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame,
15626419Ssb155480 * then the vlan-id is available in the tag; otherwise, its vlan id is
15636419Ssb155480 * implicitly obtained from the port-vlan-id of the vnet device.
15646419Ssb155480 * The vlan id determined is returned in vidp.
15656419Ssb155480 * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged.
15666419Ssb155480 */
15676419Ssb155480 static boolean_t
vgen_frame_lookup_vid(vnet_t * vnetp,struct ether_header * ehp,uint16_t * vidp)15686419Ssb155480 vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp)
15696419Ssb155480 {
15706419Ssb155480 struct ether_vlan_header *evhp;
15716419Ssb155480
15726419Ssb155480 /* If it's a tagged frame, get the vlan id from vlan header */
15736419Ssb155480 if (ehp->ether_type == ETHERTYPE_VLAN) {
15746419Ssb155480
15756419Ssb155480 evhp = (struct ether_vlan_header *)ehp;
15766419Ssb155480 *vidp = VLAN_ID(ntohs(evhp->ether_tci));
15776419Ssb155480 return (B_TRUE);
15786419Ssb155480 }
15796419Ssb155480
15806419Ssb155480 /* Untagged frame, vlan-id is the pvid of vnet device */
15816419Ssb155480 *vidp = vnetp->pvid;
15826419Ssb155480 return (B_FALSE);
15836419Ssb155480 }
15846419Ssb155480
15856419Ssb155480 /*
15866419Ssb155480 * Find the given vlan id in the hash table.
15876419Ssb155480 * Return: B_TRUE if the id is found; B_FALSE if not found.
15886419Ssb155480 */
15896419Ssb155480 static boolean_t
vgen_vlan_lookup(mod_hash_t * vlan_hashp,uint16_t vid)15906419Ssb155480 vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid)
15916419Ssb155480 {
15926419Ssb155480 int rv;
15936419Ssb155480 mod_hash_val_t vp;
15946419Ssb155480
15956419Ssb155480 rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp);
15966419Ssb155480
15976419Ssb155480 if (rv != 0)
15986419Ssb155480 return (B_FALSE);
15996419Ssb155480
16006419Ssb155480 return (B_TRUE);
16016419Ssb155480 }
16026419Ssb155480
16036419Ssb155480 /*
16045935Ssb155480 * This function reads "priority-ether-types" property from md. This property
16055935Ssb155480 * is used to enable support for priority frames. Applications which need
16065935Ssb155480 * guaranteed and timely delivery of certain high priority frames to/from
16075935Ssb155480 * a vnet or vsw within ldoms, should configure this property by providing
16085935Ssb155480 * the ether type(s) for which the priority facility is needed.
16095935Ssb155480 * Normal data frames are delivered over a ldc channel using the descriptor
16105935Ssb155480 * ring mechanism which is constrained by factors such as descriptor ring size,
16115935Ssb155480 * the rate at which the ring is processed at the peer ldc end point, etc.
16125935Ssb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames
16135935Ssb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the
16145935Ssb155480 * descriptor ring path and enables a more reliable and timely delivery of
16155935Ssb155480 * frames to the peer.
16165935Ssb155480 */
16175935Ssb155480 static void
vgen_read_pri_eth_types(vgen_t * vgenp,md_t * mdp,mde_cookie_t node)16185935Ssb155480 vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node)
16195935Ssb155480 {
16205935Ssb155480 int rv;
16215935Ssb155480 uint16_t *types;
16225935Ssb155480 uint64_t *data;
16235935Ssb155480 int size;
16245935Ssb155480 int i;
16255935Ssb155480 size_t mblk_sz;
16265935Ssb155480
16275935Ssb155480 rv = md_get_prop_data(mdp, node, pri_types_propname,
16285935Ssb155480 (uint8_t **)&data, &size);
16295935Ssb155480 if (rv != 0) {
16305935Ssb155480 /*
16315935Ssb155480 * Property may not exist if we are running pre-ldoms1.1 f/w.
16325935Ssb155480 * Check if 'vgen_pri_eth_type' has been set in that case.
16335935Ssb155480 */
16345935Ssb155480 if (vgen_pri_eth_type != 0) {
16355935Ssb155480 size = sizeof (vgen_pri_eth_type);
16365935Ssb155480 data = &vgen_pri_eth_type;
16375935Ssb155480 } else {
16386495Sspeer DBG2(vgenp, NULL,
16395935Ssb155480 "prop(%s) not found", pri_types_propname);
16405935Ssb155480 size = 0;
16415935Ssb155480 }
16425935Ssb155480 }
16435935Ssb155480
16445935Ssb155480 if (size == 0) {
16455935Ssb155480 vgenp->pri_num_types = 0;
16465935Ssb155480 return;
16475935Ssb155480 }
16485935Ssb155480
16495935Ssb155480 /*
16505935Ssb155480 * we have some priority-ether-types defined;
16515935Ssb155480 * allocate a table of these types and also
16525935Ssb155480 * allocate a pool of mblks to transmit these
16535935Ssb155480 * priority packets.
16545935Ssb155480 */
16555935Ssb155480 size /= sizeof (uint64_t);
16565935Ssb155480 vgenp->pri_num_types = size;
16575935Ssb155480 vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP);
16585935Ssb155480 for (i = 0, types = vgenp->pri_types; i < size; i++) {
16595935Ssb155480 types[i] = data[i] & 0xFFFF;
16605935Ssb155480 }
16616419Ssb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7;
166212011SSriharsha.Basavapatna@Sun.COM (void) vio_create_mblks(vgen_pri_tx_nmblks, mblk_sz, NULL,
16635935Ssb155480 &vgenp->pri_tx_vmp);
16645935Ssb155480 }
16655935Ssb155480
16667529SSriharsha.Basavapatna@Sun.COM static void
vgen_mtu_read(vgen_t * vgenp,md_t * mdp,mde_cookie_t node,uint32_t * mtu)16677529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, uint32_t *mtu)
16687529SSriharsha.Basavapatna@Sun.COM {
16697529SSriharsha.Basavapatna@Sun.COM int rv;
16707529SSriharsha.Basavapatna@Sun.COM uint64_t val;
16717529SSriharsha.Basavapatna@Sun.COM char *mtu_propname;
16727529SSriharsha.Basavapatna@Sun.COM
16737529SSriharsha.Basavapatna@Sun.COM mtu_propname = vgen_mtu_propname;
16747529SSriharsha.Basavapatna@Sun.COM
16757529SSriharsha.Basavapatna@Sun.COM rv = md_get_prop_val(mdp, node, mtu_propname, &val);
16767529SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
16777529SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, NULL, "prop(%s) not found", mtu_propname);
16787529SSriharsha.Basavapatna@Sun.COM *mtu = vnet_ethermtu;
16797529SSriharsha.Basavapatna@Sun.COM } else {
16807529SSriharsha.Basavapatna@Sun.COM
16817529SSriharsha.Basavapatna@Sun.COM *mtu = val & 0xFFFF;
16827529SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "%s(%d): (%d)\n", mtu_propname,
16837529SSriharsha.Basavapatna@Sun.COM vgenp->instance, *mtu);
16847529SSriharsha.Basavapatna@Sun.COM }
16857529SSriharsha.Basavapatna@Sun.COM }
16867529SSriharsha.Basavapatna@Sun.COM
16879336SSriharsha.Basavapatna@Sun.COM static void
vgen_linkprop_read(vgen_t * vgenp,md_t * mdp,mde_cookie_t node,boolean_t * pls)16889336SSriharsha.Basavapatna@Sun.COM vgen_linkprop_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node,
16899336SSriharsha.Basavapatna@Sun.COM boolean_t *pls)
16909336SSriharsha.Basavapatna@Sun.COM {
16919336SSriharsha.Basavapatna@Sun.COM int rv;
16929336SSriharsha.Basavapatna@Sun.COM uint64_t val;
16939336SSriharsha.Basavapatna@Sun.COM char *linkpropname;
16949336SSriharsha.Basavapatna@Sun.COM
16959336SSriharsha.Basavapatna@Sun.COM linkpropname = vgen_linkprop_propname;
16969336SSriharsha.Basavapatna@Sun.COM
16979336SSriharsha.Basavapatna@Sun.COM rv = md_get_prop_val(mdp, node, linkpropname, &val);
16989336SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
16999336SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, NULL, "prop(%s) not found", linkpropname);
17009336SSriharsha.Basavapatna@Sun.COM *pls = B_FALSE;
17019336SSriharsha.Basavapatna@Sun.COM } else {
17029336SSriharsha.Basavapatna@Sun.COM
17039336SSriharsha.Basavapatna@Sun.COM *pls = (val & 0x1) ? B_TRUE : B_FALSE;
17049336SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "%s(%d): (%d)\n", linkpropname,
17059336SSriharsha.Basavapatna@Sun.COM vgenp->instance, *pls);
17069336SSriharsha.Basavapatna@Sun.COM }
17079336SSriharsha.Basavapatna@Sun.COM }
17089336SSriharsha.Basavapatna@Sun.COM
17091991Sheppo /* register with MD event generator */
17101991Sheppo static int
vgen_mdeg_reg(vgen_t * vgenp)17111991Sheppo vgen_mdeg_reg(vgen_t *vgenp)
17121991Sheppo {
17131991Sheppo mdeg_prop_spec_t *pspecp;
17141991Sheppo mdeg_node_spec_t *parentp;
17151991Sheppo uint_t templatesz;
17161991Sheppo int rv;
17176419Ssb155480 mdeg_handle_t dev_hdl = NULL;
17186419Ssb155480 mdeg_handle_t port_hdl = NULL;
17196419Ssb155480
17201991Sheppo templatesz = sizeof (vgen_prop_template);
17211991Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP);
17221991Sheppo if (pspecp == NULL) {
17231991Sheppo return (DDI_FAILURE);
17241991Sheppo }
17251991Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP);
17261991Sheppo if (parentp == NULL) {
17271991Sheppo kmem_free(pspecp, templatesz);
17281991Sheppo return (DDI_FAILURE);
17291991Sheppo }
17301991Sheppo
17311991Sheppo bcopy(vgen_prop_template, pspecp, templatesz);
17321991Sheppo
17331991Sheppo /*
17341991Sheppo * NOTE: The instance here refers to the value of "reg" property and
17351991Sheppo * not the dev_info instance (ddi_get_instance()) of vnet.
17361991Sheppo */
17376419Ssb155480 VGEN_SET_MDEG_PROP_INST(pspecp, vgenp->regprop);
17381991Sheppo
17391991Sheppo parentp->namep = "virtual-device";
17401991Sheppo parentp->specp = pspecp;
17411991Sheppo
17421991Sheppo /* save parentp in vgen_t */
17431991Sheppo vgenp->mdeg_parentp = parentp;
17441991Sheppo
17456419Ssb155480 /*
17466419Ssb155480 * Register an interest in 'virtual-device' nodes with a
17476419Ssb155480 * 'name' property of 'network'
17486419Ssb155480 */
17496419Ssb155480 rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl);
17501991Sheppo if (rv != MDEG_SUCCESS) {
17514647Sraghuram DERR(vgenp, NULL, "mdeg_register failed\n");
17526419Ssb155480 goto mdeg_reg_fail;
17536419Ssb155480 }
17546419Ssb155480
17556419Ssb155480 /* Register an interest in 'port' nodes */
17566419Ssb155480 rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp,
17576419Ssb155480 &port_hdl);
17586419Ssb155480 if (rv != MDEG_SUCCESS) {
17596419Ssb155480 DERR(vgenp, NULL, "mdeg_register failed\n");
17606419Ssb155480 goto mdeg_reg_fail;
17611991Sheppo }
17621991Sheppo
17631991Sheppo /* save mdeg handle in vgen_t */
17646419Ssb155480 vgenp->mdeg_dev_hdl = dev_hdl;
17656419Ssb155480 vgenp->mdeg_port_hdl = port_hdl;
17661991Sheppo
17671991Sheppo return (DDI_SUCCESS);
17686419Ssb155480
17696419Ssb155480 mdeg_reg_fail:
17706419Ssb155480 if (dev_hdl != NULL) {
17716419Ssb155480 (void) mdeg_unregister(dev_hdl);
17726419Ssb155480 }
17736419Ssb155480 KMEM_FREE(parentp);
17746419Ssb155480 kmem_free(pspecp, templatesz);
17756419Ssb155480 vgenp->mdeg_parentp = NULL;
17766419Ssb155480 return (DDI_FAILURE);
17771991Sheppo }
17781991Sheppo
17791991Sheppo /* unregister with MD event generator */
17801991Sheppo static void
vgen_mdeg_unreg(vgen_t * vgenp)17811991Sheppo vgen_mdeg_unreg(vgen_t *vgenp)
17821991Sheppo {
178310309SSriharsha.Basavapatna@Sun.COM if (vgenp->mdeg_dev_hdl != NULL) {
178410309SSriharsha.Basavapatna@Sun.COM (void) mdeg_unregister(vgenp->mdeg_dev_hdl);
178510309SSriharsha.Basavapatna@Sun.COM vgenp->mdeg_dev_hdl = NULL;
178610309SSriharsha.Basavapatna@Sun.COM }
178710309SSriharsha.Basavapatna@Sun.COM if (vgenp->mdeg_port_hdl != NULL) {
178810309SSriharsha.Basavapatna@Sun.COM (void) mdeg_unregister(vgenp->mdeg_port_hdl);
178910309SSriharsha.Basavapatna@Sun.COM vgenp->mdeg_port_hdl = NULL;
179010309SSriharsha.Basavapatna@Sun.COM }
179110309SSriharsha.Basavapatna@Sun.COM
179210309SSriharsha.Basavapatna@Sun.COM if (vgenp->mdeg_parentp != NULL) {
179310309SSriharsha.Basavapatna@Sun.COM kmem_free(vgenp->mdeg_parentp->specp,
179410309SSriharsha.Basavapatna@Sun.COM sizeof (vgen_prop_template));
179510309SSriharsha.Basavapatna@Sun.COM KMEM_FREE(vgenp->mdeg_parentp);
179610309SSriharsha.Basavapatna@Sun.COM vgenp->mdeg_parentp = NULL;
179710309SSriharsha.Basavapatna@Sun.COM }
17981991Sheppo }
17991991Sheppo
18006419Ssb155480 /* mdeg callback function for the port node */
18011991Sheppo static int
vgen_mdeg_port_cb(void * cb_argp,mdeg_result_t * resp)18026419Ssb155480 vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp)
18031991Sheppo {
180412011SSriharsha.Basavapatna@Sun.COM int idx;
180512011SSriharsha.Basavapatna@Sun.COM int vsw_idx = -1;
180612011SSriharsha.Basavapatna@Sun.COM uint64_t val;
180712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp;
18081991Sheppo
18091991Sheppo if ((resp == NULL) || (cb_argp == NULL)) {
18101991Sheppo return (MDEG_FAILURE);
18111991Sheppo }
18121991Sheppo
18131991Sheppo vgenp = (vgen_t *)cb_argp;
18144647Sraghuram DBG1(vgenp, NULL, "enter\n");
18151991Sheppo
18161991Sheppo mutex_enter(&vgenp->lock);
18171991Sheppo
18184647Sraghuram DBG1(vgenp, NULL, "ports: removed(%x), "
18194647Sraghuram "added(%x), updated(%x)\n", resp->removed.nelem,
18204647Sraghuram resp->added.nelem, resp->match_curr.nelem);
18211991Sheppo
18221991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) {
18231991Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp,
18241991Sheppo resp->removed.mdep[idx]);
18251991Sheppo }
18261991Sheppo
18271991Sheppo if (vgenp->vsw_portp == NULL) {
18281991Sheppo /*
18291991Sheppo * find vsw_port and add it first, because other ports need
18301991Sheppo * this when adding fdb entry (see vgen_port_init()).
18311991Sheppo */
18321991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) {
18331991Sheppo if (!(md_get_prop_val(resp->added.mdp,
18341991Sheppo resp->added.mdep[idx], swport_propname, &val))) {
18351991Sheppo if (val == 0) {
18361991Sheppo /*
18371991Sheppo * This port is connected to the
18386419Ssb155480 * vsw on service domain.
18391991Sheppo */
18401991Sheppo vsw_idx = idx;
18414663Szk194757 if (vgen_add_port(vgenp,
18421991Sheppo resp->added.mdp,
18434663Szk194757 resp->added.mdep[idx]) !=
18444663Szk194757 DDI_SUCCESS) {
18454663Szk194757 cmn_err(CE_NOTE, "vnet%d Could "
18464663Szk194757 "not initialize virtual "
18474663Szk194757 "switch port.",
18486495Sspeer vgenp->instance);
18494663Szk194757 mutex_exit(&vgenp->lock);
18504663Szk194757 return (MDEG_FAILURE);
18514663Szk194757 }
18521991Sheppo break;
18531991Sheppo }
18541991Sheppo }
18551991Sheppo }
18564666Szk194757 if (vsw_idx == -1) {
18574647Sraghuram DWARN(vgenp, NULL, "can't find vsw_port\n");
18584663Szk194757 mutex_exit(&vgenp->lock);
18591991Sheppo return (MDEG_FAILURE);
18601991Sheppo }
18611991Sheppo }
18621991Sheppo
18631991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) {
18641991Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */
18651991Sheppo continue;
18664663Szk194757
18674663Szk194757 /* If this port can't be added just skip it. */
18681991Sheppo (void) vgen_add_port(vgenp, resp->added.mdp,
18691991Sheppo resp->added.mdep[idx]);
18701991Sheppo }
18711991Sheppo
18721991Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) {
18731991Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp,
18741991Sheppo resp->match_curr.mdep[idx],
18751991Sheppo resp->match_prev.mdp,
18761991Sheppo resp->match_prev.mdep[idx]);
18771991Sheppo }
18781991Sheppo
18791991Sheppo mutex_exit(&vgenp->lock);
18804647Sraghuram DBG1(vgenp, NULL, "exit\n");
18811991Sheppo return (MDEG_SUCCESS);
18821991Sheppo }
18831991Sheppo
18846419Ssb155480 /* mdeg callback function for the vnet node */
18856419Ssb155480 static int
vgen_mdeg_cb(void * cb_argp,mdeg_result_t * resp)18866419Ssb155480 vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp)
18876419Ssb155480 {
18886419Ssb155480 vgen_t *vgenp;
18896419Ssb155480 vnet_t *vnetp;
18906419Ssb155480 md_t *mdp;
18916419Ssb155480 mde_cookie_t node;
18926419Ssb155480 uint64_t inst;
18936419Ssb155480 char *node_name = NULL;
18946419Ssb155480
18956419Ssb155480 if ((resp == NULL) || (cb_argp == NULL)) {
18966419Ssb155480 return (MDEG_FAILURE);
18976419Ssb155480 }
18986419Ssb155480
18996419Ssb155480 vgenp = (vgen_t *)cb_argp;
19006419Ssb155480 vnetp = vgenp->vnetp;
19016419Ssb155480
19027572SWentao.Yang@Sun.COM DBG1(vgenp, NULL, "added %d : removed %d : curr matched %d"
19036419Ssb155480 " : prev matched %d", resp->added.nelem, resp->removed.nelem,
19046419Ssb155480 resp->match_curr.nelem, resp->match_prev.nelem);
19056419Ssb155480
19066419Ssb155480 mutex_enter(&vgenp->lock);
19076419Ssb155480
19086419Ssb155480 /*
19096419Ssb155480 * We get an initial callback for this node as 'added' after
19106419Ssb155480 * registering with mdeg. Note that we would have already gathered
19116419Ssb155480 * information about this vnet node by walking MD earlier during attach
19126419Ssb155480 * (in vgen_read_mdprops()). So, there is a window where the properties
19136419Ssb155480 * of this node might have changed when we get this initial 'added'
19146419Ssb155480 * callback. We handle this as if an update occured and invoke the same
19156419Ssb155480 * function which handles updates to the properties of this vnet-node
19166419Ssb155480 * if any. A non-zero 'match' value indicates that the MD has been
19176419Ssb155480 * updated and that a 'network' node is present which may or may not
19186419Ssb155480 * have been updated. It is up to the clients to examine their own
19196419Ssb155480 * nodes and determine if they have changed.
19206419Ssb155480 */
19216419Ssb155480 if (resp->added.nelem != 0) {
19226419Ssb155480
19236419Ssb155480 if (resp->added.nelem != 1) {
19246419Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes added "
19256419Ssb155480 "invalid: %d\n", vnetp->instance,
19266419Ssb155480 resp->added.nelem);
19276419Ssb155480 goto vgen_mdeg_cb_err;
19286419Ssb155480 }
19296419Ssb155480
19306419Ssb155480 mdp = resp->added.mdp;
19316419Ssb155480 node = resp->added.mdep[0];
19326419Ssb155480
19336419Ssb155480 } else if (resp->match_curr.nelem != 0) {
19346419Ssb155480
19356419Ssb155480 if (resp->match_curr.nelem != 1) {
19366419Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes updated "
19376419Ssb155480 "invalid: %d\n", vnetp->instance,
19386419Ssb155480 resp->match_curr.nelem);
19396419Ssb155480 goto vgen_mdeg_cb_err;
19406419Ssb155480 }
19416419Ssb155480
19426419Ssb155480 mdp = resp->match_curr.mdp;
19436419Ssb155480 node = resp->match_curr.mdep[0];
19446419Ssb155480
19456419Ssb155480 } else {
19466419Ssb155480 goto vgen_mdeg_cb_err;
19476419Ssb155480 }
19486419Ssb155480
19496419Ssb155480 /* Validate name and instance */
19506419Ssb155480 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) {
19516419Ssb155480 DERR(vgenp, NULL, "unable to get node name\n");
19526419Ssb155480 goto vgen_mdeg_cb_err;
19536419Ssb155480 }
19546419Ssb155480
19556419Ssb155480 /* is this a virtual-network device? */
19566419Ssb155480 if (strcmp(node_name, vnet_propname) != 0) {
19576419Ssb155480 DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name);
19586419Ssb155480 goto vgen_mdeg_cb_err;
19596419Ssb155480 }
19606419Ssb155480
19616419Ssb155480 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) {
19626419Ssb155480 DERR(vgenp, NULL, "prop(cfg-handle) not found\n");
19636419Ssb155480 goto vgen_mdeg_cb_err;
19646419Ssb155480 }
19656419Ssb155480
19666495Sspeer /* is this the right instance of vnet? */
19676419Ssb155480 if (inst != vgenp->regprop) {
19686419Ssb155480 DERR(vgenp, NULL, "Invalid cfg-handle: %lx\n", inst);
19696419Ssb155480 goto vgen_mdeg_cb_err;
19706419Ssb155480 }
19716419Ssb155480
19726419Ssb155480 vgen_update_md_prop(vgenp, mdp, node);
19736419Ssb155480
19746419Ssb155480 mutex_exit(&vgenp->lock);
19756419Ssb155480 return (MDEG_SUCCESS);
19766419Ssb155480
19776419Ssb155480 vgen_mdeg_cb_err:
19786419Ssb155480 mutex_exit(&vgenp->lock);
19796419Ssb155480 return (MDEG_FAILURE);
19806419Ssb155480 }
19816419Ssb155480
19826419Ssb155480 /*
19836419Ssb155480 * Check to see if the relevant properties in the specified node have
19846419Ssb155480 * changed, and if so take the appropriate action.
19856419Ssb155480 */
19866419Ssb155480 static void
vgen_update_md_prop(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)19876419Ssb155480 vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
19886419Ssb155480 {
19896419Ssb155480 uint16_t pvid;
19906419Ssb155480 uint16_t *vids;
19916419Ssb155480 uint16_t nvids;
19926419Ssb155480 vnet_t *vnetp = vgenp->vnetp;
19937529SSriharsha.Basavapatna@Sun.COM uint32_t mtu;
19949336SSriharsha.Basavapatna@Sun.COM boolean_t pls_update;
19957529SSriharsha.Basavapatna@Sun.COM enum { MD_init = 0x1,
19967529SSriharsha.Basavapatna@Sun.COM MD_vlans = 0x2,
19979336SSriharsha.Basavapatna@Sun.COM MD_mtu = 0x4,
19989336SSriharsha.Basavapatna@Sun.COM MD_pls = 0x8 } updated;
19997529SSriharsha.Basavapatna@Sun.COM int rv;
20007529SSriharsha.Basavapatna@Sun.COM
20017529SSriharsha.Basavapatna@Sun.COM updated = MD_init;
20026419Ssb155480
20036419Ssb155480 /* Read the vlan ids */
20046419Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids,
20056419Ssb155480 &nvids, NULL);
20066419Ssb155480
20076419Ssb155480 /* Determine if there are any vlan id updates */
20086419Ssb155480 if ((pvid != vnetp->pvid) || /* pvid changed? */
20096419Ssb155480 (nvids != vnetp->nvids) || /* # of vids changed? */
20106419Ssb155480 ((nvids != 0) && (vnetp->nvids != 0) && /* vids changed? */
20116419Ssb155480 bcmp(vids, vnetp->vids, sizeof (uint16_t) * nvids))) {
20127529SSriharsha.Basavapatna@Sun.COM updated |= MD_vlans;
20137529SSriharsha.Basavapatna@Sun.COM }
20147529SSriharsha.Basavapatna@Sun.COM
20157529SSriharsha.Basavapatna@Sun.COM /* Read mtu */
20167529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgenp, mdp, mdex, &mtu);
20177529SSriharsha.Basavapatna@Sun.COM if (mtu != vnetp->mtu) {
20187529SSriharsha.Basavapatna@Sun.COM if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) {
20197529SSriharsha.Basavapatna@Sun.COM updated |= MD_mtu;
20207529SSriharsha.Basavapatna@Sun.COM } else {
20217529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu update"
20227529SSriharsha.Basavapatna@Sun.COM " as the specified value:%d is invalid\n",
20237529SSriharsha.Basavapatna@Sun.COM vnetp->instance, mtu);
20247529SSriharsha.Basavapatna@Sun.COM }
20257529SSriharsha.Basavapatna@Sun.COM }
20267529SSriharsha.Basavapatna@Sun.COM
20279336SSriharsha.Basavapatna@Sun.COM /*
20289336SSriharsha.Basavapatna@Sun.COM * Read the 'linkprop' property.
20299336SSriharsha.Basavapatna@Sun.COM */
20309336SSriharsha.Basavapatna@Sun.COM vgen_linkprop_read(vgenp, mdp, mdex, &pls_update);
20319336SSriharsha.Basavapatna@Sun.COM if (pls_update != vnetp->pls_update) {
20329336SSriharsha.Basavapatna@Sun.COM updated |= MD_pls;
20339336SSriharsha.Basavapatna@Sun.COM }
20349336SSriharsha.Basavapatna@Sun.COM
20357529SSriharsha.Basavapatna@Sun.COM /* Now process the updated props */
20367529SSriharsha.Basavapatna@Sun.COM
20377529SSriharsha.Basavapatna@Sun.COM if (updated & MD_vlans) {
20387529SSriharsha.Basavapatna@Sun.COM
20397529SSriharsha.Basavapatna@Sun.COM /* save the new vlan ids */
20407529SSriharsha.Basavapatna@Sun.COM vnetp->pvid = pvid;
20417529SSriharsha.Basavapatna@Sun.COM if (vnetp->nvids != 0) {
20427529SSriharsha.Basavapatna@Sun.COM kmem_free(vnetp->vids,
20437529SSriharsha.Basavapatna@Sun.COM sizeof (uint16_t) * vnetp->nvids);
20447529SSriharsha.Basavapatna@Sun.COM vnetp->nvids = 0;
20457529SSriharsha.Basavapatna@Sun.COM }
20467529SSriharsha.Basavapatna@Sun.COM if (nvids != 0) {
20477529SSriharsha.Basavapatna@Sun.COM vnetp->nvids = nvids;
20487529SSriharsha.Basavapatna@Sun.COM vnetp->vids = vids;
20497529SSriharsha.Basavapatna@Sun.COM }
20507529SSriharsha.Basavapatna@Sun.COM
20517529SSriharsha.Basavapatna@Sun.COM /* reset vlan-unaware peers (ver < 1.3) and restart handshake */
20527529SSriharsha.Basavapatna@Sun.COM vgen_reset_vlan_unaware_ports(vgenp);
20537529SSriharsha.Basavapatna@Sun.COM
20547529SSriharsha.Basavapatna@Sun.COM } else {
20557529SSriharsha.Basavapatna@Sun.COM
20566419Ssb155480 if (nvids != 0) {
20576419Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids);
20586419Ssb155480 }
20597529SSriharsha.Basavapatna@Sun.COM }
20607529SSriharsha.Basavapatna@Sun.COM
20617529SSriharsha.Basavapatna@Sun.COM if (updated & MD_mtu) {
20627529SSriharsha.Basavapatna@Sun.COM
20637529SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "curr_mtu(%d) new_mtu(%d)\n",
20647529SSriharsha.Basavapatna@Sun.COM vnetp->mtu, mtu);
20657529SSriharsha.Basavapatna@Sun.COM
20667529SSriharsha.Basavapatna@Sun.COM rv = vnet_mtu_update(vnetp, mtu);
20677529SSriharsha.Basavapatna@Sun.COM if (rv == 0) {
20687529SSriharsha.Basavapatna@Sun.COM vgenp->max_frame_size = mtu +
20697529SSriharsha.Basavapatna@Sun.COM sizeof (struct ether_header) + VLAN_TAGSZ;
20707529SSriharsha.Basavapatna@Sun.COM }
20717529SSriharsha.Basavapatna@Sun.COM }
20729336SSriharsha.Basavapatna@Sun.COM
20739336SSriharsha.Basavapatna@Sun.COM if (updated & MD_pls) {
20749336SSriharsha.Basavapatna@Sun.COM /* enable/disable physical link state updates */
20759336SSriharsha.Basavapatna@Sun.COM vnetp->pls_update = pls_update;
20769647SWentao.Yang@Sun.COM mutex_exit(&vgenp->lock);
20779336SSriharsha.Basavapatna@Sun.COM
20789336SSriharsha.Basavapatna@Sun.COM /* reset vsw-port to re-negotiate with the updated prop. */
20799336SSriharsha.Basavapatna@Sun.COM vgen_reset_vsw_port(vgenp);
20809647SWentao.Yang@Sun.COM
20819647SWentao.Yang@Sun.COM mutex_enter(&vgenp->lock);
20829336SSriharsha.Basavapatna@Sun.COM }
20836419Ssb155480 }
20846419Ssb155480
20851991Sheppo /* add a new port to the device */
20861991Sheppo static int
vgen_add_port(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)20871991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
20881991Sheppo {
20896419Ssb155480 vgen_port_t *portp;
20906419Ssb155480 int rv;
20916419Ssb155480
20926419Ssb155480 portp = kmem_zalloc(sizeof (vgen_port_t), KM_SLEEP);
20936419Ssb155480
20946419Ssb155480 rv = vgen_port_read_props(portp, vgenp, mdp, mdex);
20956419Ssb155480 if (rv != DDI_SUCCESS) {
20966419Ssb155480 KMEM_FREE(portp);
20976419Ssb155480 return (DDI_FAILURE);
20986419Ssb155480 }
20996419Ssb155480
21006419Ssb155480 rv = vgen_port_attach(portp);
21016419Ssb155480 if (rv != DDI_SUCCESS) {
21026419Ssb155480 return (DDI_FAILURE);
21036419Ssb155480 }
21046419Ssb155480
21056419Ssb155480 return (DDI_SUCCESS);
21066419Ssb155480 }
21076419Ssb155480
21086419Ssb155480 /* read properties of the port from its md node */
21096419Ssb155480 static int
vgen_port_read_props(vgen_port_t * portp,vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)21106419Ssb155480 vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp,
21116419Ssb155480 mde_cookie_t mdex)
21126419Ssb155480 {
21136419Ssb155480 uint64_t port_num;
21146419Ssb155480 uint64_t *ldc_ids;
21156419Ssb155480 uint64_t macaddr;
21166419Ssb155480 uint64_t val;
21176419Ssb155480 int num_ldcs;
21186419Ssb155480 int i;
21196419Ssb155480 int addrsz;
21206419Ssb155480 int num_nodes = 0;
21216419Ssb155480 int listsz = 0;
21226419Ssb155480 mde_cookie_t *listp = NULL;
21236419Ssb155480 uint8_t *addrp;
21241991Sheppo struct ether_addr ea;
21251991Sheppo
21261991Sheppo /* read "id" property to get the port number */
21271991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
21284647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
21291991Sheppo return (DDI_FAILURE);
21301991Sheppo }
21311991Sheppo
21321991Sheppo /*
21331991Sheppo * Find the channel endpoint node(s) under this port node.
21341991Sheppo */
21351991Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) {
21364647Sraghuram DWARN(vgenp, NULL, "invalid number of nodes found (%d)",
21374647Sraghuram num_nodes);
21381991Sheppo return (DDI_FAILURE);
21391991Sheppo }
21401991Sheppo
21411991Sheppo /* allocate space for node list */
21421991Sheppo listsz = num_nodes * sizeof (mde_cookie_t);
21431991Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP);
21441991Sheppo if (listp == NULL)
21451991Sheppo return (DDI_FAILURE);
21461991Sheppo
21471991Sheppo num_ldcs = md_scan_dag(mdp, mdex,
21484650Sraghuram md_find_name(mdp, channel_propname),
21494650Sraghuram md_find_name(mdp, "fwd"), listp);
21501991Sheppo
21511991Sheppo if (num_ldcs <= 0) {
21524647Sraghuram DWARN(vgenp, NULL, "can't find %s nodes", channel_propname);
21531991Sheppo kmem_free(listp, listsz);
21541991Sheppo return (DDI_FAILURE);
21551991Sheppo }
21561991Sheppo
215712011SSriharsha.Basavapatna@Sun.COM if (num_ldcs > 1) {
215812011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, NULL, "Port %d: Number of channels %d > 1\n",
215912011SSriharsha.Basavapatna@Sun.COM port_num, num_ldcs);
216012011SSriharsha.Basavapatna@Sun.COM }
21611991Sheppo
21621991Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP);
21631991Sheppo if (ldc_ids == NULL) {
21641991Sheppo kmem_free(listp, listsz);
21651991Sheppo return (DDI_FAILURE);
21661991Sheppo }
21671991Sheppo
21681991Sheppo for (i = 0; i < num_ldcs; i++) {
21691991Sheppo /* read channel ids */
21701991Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) {
21714647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n",
21724647Sraghuram id_propname);
21731991Sheppo kmem_free(listp, listsz);
21741991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21751991Sheppo return (DDI_FAILURE);
21761991Sheppo }
21774647Sraghuram DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]);
21781991Sheppo }
21791991Sheppo
21801991Sheppo kmem_free(listp, listsz);
21811991Sheppo
21821991Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp,
21831991Sheppo &addrsz)) {
21844647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname);
21851991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21861991Sheppo return (DDI_FAILURE);
21871991Sheppo }
21881991Sheppo
21891991Sheppo if (addrsz < ETHERADDRL) {
21904647Sraghuram DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz);
21911991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
21921991Sheppo return (DDI_FAILURE);
21931991Sheppo }
21941991Sheppo
21951991Sheppo macaddr = *((uint64_t *)addrp);
21961991Sheppo
21974647Sraghuram DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr);
21981991Sheppo
21991991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) {
22001991Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF;
22011991Sheppo macaddr >>= 8;
22021991Sheppo }
22031991Sheppo
22049336SSriharsha.Basavapatna@Sun.COM if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) {
22059336SSriharsha.Basavapatna@Sun.COM if (val == 0) {
22069336SSriharsha.Basavapatna@Sun.COM /* This port is connected to the vswitch */
22079336SSriharsha.Basavapatna@Sun.COM portp->is_vsw_port = B_TRUE;
22089336SSriharsha.Basavapatna@Sun.COM } else {
22099336SSriharsha.Basavapatna@Sun.COM portp->is_vsw_port = B_FALSE;
22101991Sheppo }
22111991Sheppo }
22126419Ssb155480
22136419Ssb155480 /* now update all properties into the port */
22146419Ssb155480 portp->vgenp = vgenp;
22156419Ssb155480 portp->port_num = port_num;
22166419Ssb155480 ether_copy(&ea, &portp->macaddr);
22176419Ssb155480 portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP);
22186419Ssb155480 bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs);
22196419Ssb155480 portp->num_ldcs = num_ldcs;
22206419Ssb155480
22216419Ssb155480 /* read vlan id properties of this port node */
22226419Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid,
22236419Ssb155480 &portp->vids, &portp->nvids, NULL);
22241991Sheppo
22251991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t));
22261991Sheppo
22276419Ssb155480 return (DDI_SUCCESS);
22281991Sheppo }
22291991Sheppo
22301991Sheppo /* remove a port from the device */
22311991Sheppo static int
vgen_remove_port(vgen_t * vgenp,md_t * mdp,mde_cookie_t mdex)22321991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex)
22331991Sheppo {
22341991Sheppo uint64_t port_num;
22351991Sheppo vgen_port_t *portp;
22361991Sheppo vgen_portlist_t *plistp;
22371991Sheppo
22381991Sheppo /* read "id" property to get the port number */
22391991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) {
22404647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
22411991Sheppo return (DDI_FAILURE);
22421991Sheppo }
22431991Sheppo
22441991Sheppo plistp = &(vgenp->vgenports);
22451991Sheppo
22461991Sheppo WRITE_ENTER(&plistp->rwlock);
22471991Sheppo portp = vgen_port_lookup(plistp, (int)port_num);
22481991Sheppo if (portp == NULL) {
22494647Sraghuram DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num);
22501991Sheppo RW_EXIT(&plistp->rwlock);
22511991Sheppo return (DDI_FAILURE);
22521991Sheppo }
22531991Sheppo
22541991Sheppo vgen_port_detach_mdeg(portp);
22551991Sheppo RW_EXIT(&plistp->rwlock);
22561991Sheppo
22571991Sheppo return (DDI_SUCCESS);
22581991Sheppo }
22591991Sheppo
22601991Sheppo /* attach a port to the device based on mdeg data */
22611991Sheppo static int
vgen_port_attach(vgen_port_t * portp)22626419Ssb155480 vgen_port_attach(vgen_port_t *portp)
22631991Sheppo {
22646419Ssb155480 vgen_portlist_t *plistp;
22656419Ssb155480 vgen_t *vgenp;
22666419Ssb155480 uint64_t *ldcids;
22676495Sspeer mac_register_t *macp;
22686495Sspeer vio_net_res_type_t type;
22696495Sspeer int rv;
22706419Ssb155480
22716419Ssb155480 ASSERT(portp != NULL);
22726419Ssb155480 vgenp = portp->vgenp;
22736419Ssb155480 ldcids = portp->ldc_ids;
227412011SSriharsha.Basavapatna@Sun.COM
227512011SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "port_num(%d), ldcid(%lx)\n",
227612011SSriharsha.Basavapatna@Sun.COM portp->port_num, ldcids[0]);
22771991Sheppo
22786495Sspeer mutex_init(&portp->lock, NULL, MUTEX_DRIVER, NULL);
227912011SSriharsha.Basavapatna@Sun.COM
228012011SSriharsha.Basavapatna@Sun.COM /*
228112011SSriharsha.Basavapatna@Sun.COM * attach the channel under the port using its channel id;
228212011SSriharsha.Basavapatna@Sun.COM * note that we only support one channel per port for now.
228312011SSriharsha.Basavapatna@Sun.COM */
228412011SSriharsha.Basavapatna@Sun.COM if (vgen_ldc_attach(portp, ldcids[0]) == DDI_FAILURE) {
228512011SSriharsha.Basavapatna@Sun.COM vgen_port_detach(portp);
228612011SSriharsha.Basavapatna@Sun.COM return (DDI_FAILURE);
22871991Sheppo }
22881991Sheppo
22896419Ssb155480 /* create vlan id hash table */
22906419Ssb155480 vgen_vlan_create_hash(portp);
22916419Ssb155480
22929336SSriharsha.Basavapatna@Sun.COM if (portp->is_vsw_port == B_TRUE) {
22936495Sspeer /* This port is connected to the switch port */
22946495Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_FALSE);
22956495Sspeer type = VIO_NET_RES_LDC_SERVICE;
22966495Sspeer } else {
22976495Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE);
22986495Sspeer type = VIO_NET_RES_LDC_GUEST;
22996495Sspeer }
23006495Sspeer
23016495Sspeer if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
23026495Sspeer vgen_port_detach(portp);
23036495Sspeer return (DDI_FAILURE);
23046495Sspeer }
23056495Sspeer macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
23066495Sspeer macp->m_driver = portp;
23076495Sspeer macp->m_dip = vgenp->vnetdip;
23086495Sspeer macp->m_src_addr = (uint8_t *)&(vgenp->macaddr);
23096495Sspeer macp->m_callbacks = &vgen_m_callbacks;
23106495Sspeer macp->m_min_sdu = 0;
23116495Sspeer macp->m_max_sdu = ETHERMTU;
23126495Sspeer
23136495Sspeer mutex_enter(&portp->lock);
23146495Sspeer rv = vio_net_resource_reg(macp, type, vgenp->macaddr,
23156495Sspeer portp->macaddr, &portp->vhp, &portp->vcb);
23166495Sspeer mutex_exit(&portp->lock);
23176495Sspeer mac_free(macp);
23186495Sspeer
23196495Sspeer if (rv == 0) {
23206495Sspeer /* link it into the list of ports */
23216495Sspeer plistp = &(vgenp->vgenports);
23226495Sspeer WRITE_ENTER(&plistp->rwlock);
23236495Sspeer vgen_port_list_insert(portp);
23246495Sspeer RW_EXIT(&plistp->rwlock);
23259336SSriharsha.Basavapatna@Sun.COM
23269336SSriharsha.Basavapatna@Sun.COM if (portp->is_vsw_port == B_TRUE) {
23279336SSriharsha.Basavapatna@Sun.COM /* We now have the vswitch port attached */
23289336SSriharsha.Basavapatna@Sun.COM vgenp->vsw_portp = portp;
23299336SSriharsha.Basavapatna@Sun.COM (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0);
23309336SSriharsha.Basavapatna@Sun.COM }
23316495Sspeer } else {
23326495Sspeer DERR(vgenp, NULL, "vio_net_resource_reg failed for portp=0x%p",
23336495Sspeer portp);
23346495Sspeer vgen_port_detach(portp);
23351991Sheppo }
23361991Sheppo
23374647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
23381991Sheppo return (DDI_SUCCESS);
23391991Sheppo }
23401991Sheppo
23411991Sheppo /* detach a port from the device based on mdeg data */
23421991Sheppo static void
vgen_port_detach_mdeg(vgen_port_t * portp)23431991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp)
23441991Sheppo {
23451991Sheppo vgen_t *vgenp = portp->vgenp;
23461991Sheppo
23474647Sraghuram DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num);
23486495Sspeer
23496495Sspeer mutex_enter(&portp->lock);
23506495Sspeer
23511991Sheppo /* stop the port if needed */
23526495Sspeer if (portp->flags & VGEN_STARTED) {
23531991Sheppo vgen_port_uninit(portp);
235411543SWentao.Yang@Sun.COM portp->flags &= ~(VGEN_STARTED);
23551991Sheppo }
23566495Sspeer
23576495Sspeer mutex_exit(&portp->lock);
23581991Sheppo vgen_port_detach(portp);
23591991Sheppo
23604647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num);
23611991Sheppo }
23621991Sheppo
23631991Sheppo static int
vgen_update_port(vgen_t * vgenp,md_t * curr_mdp,mde_cookie_t curr_mdex,md_t * prev_mdp,mde_cookie_t prev_mdex)23641991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex,
23651991Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex)
23661991Sheppo {
23676419Ssb155480 uint64_t cport_num;
23686419Ssb155480 uint64_t pport_num;
23696419Ssb155480 vgen_portlist_t *plistp;
23706419Ssb155480 vgen_port_t *portp;
23716419Ssb155480 boolean_t updated_vlans = B_FALSE;
23726419Ssb155480 uint16_t pvid;
23736419Ssb155480 uint16_t *vids;
23746419Ssb155480 uint16_t nvids;
23756419Ssb155480
23766419Ssb155480 /*
23776419Ssb155480 * For now, we get port updates only if vlan ids changed.
23786419Ssb155480 * We read the port num and do some sanity check.
23796419Ssb155480 */
23806419Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) {
23816419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
23826419Ssb155480 return (DDI_FAILURE);
23836419Ssb155480 }
23846419Ssb155480
23856419Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) {
23866419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname);
23876419Ssb155480 return (DDI_FAILURE);
23886419Ssb155480 }
23896419Ssb155480 if (cport_num != pport_num)
23906419Ssb155480 return (DDI_FAILURE);
23916419Ssb155480
23926419Ssb155480 plistp = &(vgenp->vgenports);
23936419Ssb155480
23946419Ssb155480 READ_ENTER(&plistp->rwlock);
23956419Ssb155480
23966419Ssb155480 portp = vgen_port_lookup(plistp, (int)cport_num);
23976419Ssb155480 if (portp == NULL) {
23986419Ssb155480 DWARN(vgenp, NULL, "can't find port(%lx)\n", cport_num);
23996419Ssb155480 RW_EXIT(&plistp->rwlock);
24006419Ssb155480 return (DDI_FAILURE);
24016419Ssb155480 }
24026419Ssb155480
24036419Ssb155480 /* Read the vlan ids */
24046419Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids,
24056419Ssb155480 &nvids, NULL);
24066419Ssb155480
24076419Ssb155480 /* Determine if there are any vlan id updates */
24086419Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */
24096419Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */
24106419Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */
24116419Ssb155480 bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) {
24126419Ssb155480 updated_vlans = B_TRUE;
24136419Ssb155480 }
24146419Ssb155480
24156419Ssb155480 if (updated_vlans == B_FALSE) {
24166419Ssb155480 RW_EXIT(&plistp->rwlock);
24176419Ssb155480 return (DDI_FAILURE);
24186419Ssb155480 }
24196419Ssb155480
24206419Ssb155480 /* remove the port from vlans it has been assigned to */
24216419Ssb155480 vgen_vlan_remove_ids(portp);
24226419Ssb155480
24236419Ssb155480 /* save the new vlan ids */
24246419Ssb155480 portp->pvid = pvid;
24256419Ssb155480 if (portp->nvids != 0) {
24266419Ssb155480 kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids);
24276419Ssb155480 portp->nvids = 0;
24286419Ssb155480 }
24296419Ssb155480 if (nvids != 0) {
24306419Ssb155480 portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP);
24316419Ssb155480 bcopy(vids, portp->vids, sizeof (uint16_t) * nvids);
24326419Ssb155480 portp->nvids = nvids;
24336419Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids);
24346419Ssb155480 }
24356419Ssb155480
24366419Ssb155480 /* add port to the new vlans */
24376419Ssb155480 vgen_vlan_add_ids(portp);
24386419Ssb155480
24396419Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */
24406419Ssb155480 vgen_vlan_unaware_port_reset(portp);
24416419Ssb155480
24426419Ssb155480 RW_EXIT(&plistp->rwlock);
24436419Ssb155480
24441991Sheppo return (DDI_SUCCESS);
24451991Sheppo }
24461991Sheppo
24471991Sheppo static uint64_t
vgen_port_stat(vgen_port_t * portp,uint_t stat)24482311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat)
24491991Sheppo {
245012011SSriharsha.Basavapatna@Sun.COM return (vgen_ldc_stat(portp->ldcp, stat));
24517529SSriharsha.Basavapatna@Sun.COM }
24527529SSriharsha.Basavapatna@Sun.COM
24531991Sheppo /* attach the channel corresponding to the given ldc_id to the port */
24541991Sheppo static int
vgen_ldc_attach(vgen_port_t * portp,uint64_t ldc_id)24551991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id)
24561991Sheppo {
24571991Sheppo vgen_t *vgenp;
245812011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp;
24591991Sheppo ldc_attr_t attr;
24601991Sheppo int status;
24611991Sheppo ldc_status_t istatus;
24625373Sraghuram char kname[MAXNAMELEN];
24635373Sraghuram int instance;
24644647Sraghuram enum {AST_init = 0x0, AST_ldc_alloc = 0x1,
24654647Sraghuram AST_mutex_init = 0x2, AST_ldc_init = 0x4,
246612011SSriharsha.Basavapatna@Sun.COM AST_ldc_reg_cb = 0x8 } attach_state;
24671991Sheppo
24681991Sheppo attach_state = AST_init;
24691991Sheppo vgenp = portp->vgenp;
24701991Sheppo
24711991Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP);
24721991Sheppo if (ldcp == NULL) {
24731991Sheppo goto ldc_attach_failed;
24741991Sheppo }
24751991Sheppo ldcp->ldc_id = ldc_id;
24761991Sheppo ldcp->portp = portp;
24771991Sheppo
24781991Sheppo attach_state |= AST_ldc_alloc;
24791991Sheppo
24801991Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL);
24811991Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL);
24821991Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL);
24834647Sraghuram mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL);
24844647Sraghuram mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL);
248510309SSriharsha.Basavapatna@Sun.COM mutex_init(&ldcp->pollq_lock, NULL, MUTEX_DRIVER, NULL);
248612011SSriharsha.Basavapatna@Sun.COM mutex_init(&ldcp->msg_thr_lock, NULL, MUTEX_DRIVER, NULL);
248712011SSriharsha.Basavapatna@Sun.COM cv_init(&ldcp->msg_thr_cv, NULL, CV_DRIVER, NULL);
24881991Sheppo
24891991Sheppo attach_state |= AST_mutex_init;
24901991Sheppo
24911991Sheppo attr.devclass = LDC_DEV_NT;
24926495Sspeer attr.instance = vgenp->instance;
24931991Sheppo attr.mode = LDC_MODE_UNRELIABLE;
249412011SSriharsha.Basavapatna@Sun.COM attr.mtu = vgen_ldc_mtu;
24951991Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle);
24961991Sheppo if (status != 0) {
24974647Sraghuram DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status);
24981991Sheppo goto ldc_attach_failed;
24991991Sheppo }
25001991Sheppo attach_state |= AST_ldc_init;
25011991Sheppo
25021991Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp);
25031991Sheppo if (status != 0) {
25044647Sraghuram DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n",
25054647Sraghuram status);
25061991Sheppo goto ldc_attach_failed;
25071991Sheppo }
25085935Ssb155480 /*
25095935Ssb155480 * allocate a message for ldc_read()s, big enough to hold ctrl and
25105935Ssb155480 * data msgs, including raw data msgs used to recv priority frames.
25115935Ssb155480 */
25126419Ssb155480 ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size;
25135935Ssb155480 ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP);
25141991Sheppo attach_state |= AST_ldc_reg_cb;
25151991Sheppo
25161991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus);
25171991Sheppo ASSERT(istatus == LDC_INIT);
25181991Sheppo ldcp->ldc_status = istatus;
25191991Sheppo
25201991Sheppo /* Setup kstats for the channel */
25216495Sspeer instance = vgenp->instance;
25225373Sraghuram (void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id);
25235373Sraghuram ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats);
25245373Sraghuram if (ldcp->ksp == NULL) {
25251991Sheppo goto ldc_attach_failed;
25261991Sheppo }
25271991Sheppo
25281991Sheppo /* initialize vgen_versions supported */
25291991Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions));
25305935Ssb155480 vgen_reset_vnet_proto_ops(ldcp);
25311991Sheppo
253212011SSriharsha.Basavapatna@Sun.COM /* Link this channel to the port */
253312011SSriharsha.Basavapatna@Sun.COM portp->ldcp = ldcp;
25341991Sheppo
25359336SSriharsha.Basavapatna@Sun.COM ldcp->link_state = LINK_STATE_UNKNOWN;
25369336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG
25379336SSriharsha.Basavapatna@Sun.COM ldcp->link_down_forced = B_FALSE;
25389336SSriharsha.Basavapatna@Sun.COM #endif
25391991Sheppo ldcp->flags |= CHANNEL_ATTACHED;
25401991Sheppo return (DDI_SUCCESS);
25411991Sheppo
25421991Sheppo ldc_attach_failed:
25434647Sraghuram if (attach_state & AST_ldc_reg_cb) {
25444647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle);
25455935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen);
25464647Sraghuram }
254712011SSriharsha.Basavapatna@Sun.COM
25481991Sheppo if (attach_state & AST_ldc_init) {
25491991Sheppo (void) ldc_fini(ldcp->ldc_handle);
25501991Sheppo }
25511991Sheppo if (attach_state & AST_mutex_init) {
25521991Sheppo mutex_destroy(&ldcp->tclock);
25531991Sheppo mutex_destroy(&ldcp->txlock);
25541991Sheppo mutex_destroy(&ldcp->cblock);
25554647Sraghuram mutex_destroy(&ldcp->wrlock);
25564647Sraghuram mutex_destroy(&ldcp->rxlock);
255710309SSriharsha.Basavapatna@Sun.COM mutex_destroy(&ldcp->pollq_lock);
25581991Sheppo }
25591991Sheppo if (attach_state & AST_ldc_alloc) {
25601991Sheppo KMEM_FREE(ldcp);
25611991Sheppo }
25621991Sheppo return (DDI_FAILURE);
25631991Sheppo }
25641991Sheppo
25651991Sheppo /* detach a channel from the port */
25661991Sheppo static void
vgen_ldc_detach(vgen_ldc_t * ldcp)25671991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp)
25681991Sheppo {
25691991Sheppo vgen_port_t *portp;
25701991Sheppo vgen_t *vgenp;
257112011SSriharsha.Basavapatna@Sun.COM
257212011SSriharsha.Basavapatna@Sun.COM ASSERT(ldcp != NULL);
25731991Sheppo
25741991Sheppo portp = ldcp->portp;
25751991Sheppo vgenp = portp->vgenp;
25761991Sheppo
25771991Sheppo if (ldcp->ldc_status != LDC_INIT) {
25784647Sraghuram DWARN(vgenp, ldcp, "ldc_status is not INIT\n");
25791991Sheppo }
25801991Sheppo
25811991Sheppo if (ldcp->flags & CHANNEL_ATTACHED) {
25821991Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED);
25831991Sheppo
25844647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle);
258512011SSriharsha.Basavapatna@Sun.COM (void) ldc_fini(ldcp->ldc_handle);
258612011SSriharsha.Basavapatna@Sun.COM
25875935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen);
25885373Sraghuram vgen_destroy_kstats(ldcp->ksp);
25895373Sraghuram ldcp->ksp = NULL;
25901991Sheppo mutex_destroy(&ldcp->tclock);
25911991Sheppo mutex_destroy(&ldcp->txlock);
25921991Sheppo mutex_destroy(&ldcp->cblock);
25934647Sraghuram mutex_destroy(&ldcp->wrlock);
25944647Sraghuram mutex_destroy(&ldcp->rxlock);
259510309SSriharsha.Basavapatna@Sun.COM mutex_destroy(&ldcp->pollq_lock);
259612011SSriharsha.Basavapatna@Sun.COM mutex_destroy(&ldcp->msg_thr_lock);
259712011SSriharsha.Basavapatna@Sun.COM cv_destroy(&ldcp->msg_thr_cv);
259812011SSriharsha.Basavapatna@Sun.COM
25991991Sheppo KMEM_FREE(ldcp);
26001991Sheppo }
26011991Sheppo }
26021991Sheppo
26031991Sheppo /* enable transmit/receive on the channel */
26041991Sheppo static int
vgen_ldc_init(vgen_ldc_t * ldcp)26051991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp)
26061991Sheppo {
260712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
26081991Sheppo ldc_status_t istatus;
26091991Sheppo int rv;
261012011SSriharsha.Basavapatna@Sun.COM enum { ST_init = 0x0, ST_ldc_open = 0x1,
261112011SSriharsha.Basavapatna@Sun.COM ST_cb_enable = 0x2} init_state;
261212011SSriharsha.Basavapatna@Sun.COM int flag = 0;
261312011SSriharsha.Basavapatna@Sun.COM
26141991Sheppo init_state = ST_init;
26151991Sheppo
26164647Sraghuram DBG1(vgenp, ldcp, "enter\n");
26171991Sheppo LDC_LOCK(ldcp);
26181991Sheppo
26191991Sheppo rv = ldc_open(ldcp->ldc_handle);
26201991Sheppo if (rv != 0) {
26214647Sraghuram DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv);
26221991Sheppo goto ldcinit_failed;
26231991Sheppo }
26241991Sheppo init_state |= ST_ldc_open;
26251991Sheppo
26261991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus);
26271991Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) {
26284647Sraghuram DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus);
26291991Sheppo goto ldcinit_failed;
26301991Sheppo }
26311991Sheppo ldcp->ldc_status = istatus;
26321991Sheppo
26332748Slm66018 rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE);
26342748Slm66018 if (rv != 0) {
26354647Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv);
26362748Slm66018 goto ldcinit_failed;
26372748Slm66018 }
26382748Slm66018
26392748Slm66018 init_state |= ST_cb_enable;
26402748Slm66018
264112011SSriharsha.Basavapatna@Sun.COM vgen_ldc_up(ldcp);
26421991Sheppo
26431991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus);
26442793Slm66018 if (istatus == LDC_UP) {
26454647Sraghuram DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus);
26461991Sheppo }
26472793Slm66018
26481991Sheppo ldcp->ldc_status = istatus;
26491991Sheppo
265012011SSriharsha.Basavapatna@Sun.COM ldcp->hphase = VH_PHASE0;
265112011SSriharsha.Basavapatna@Sun.COM ldcp->hstate = 0;
26521991Sheppo ldcp->flags |= CHANNEL_STARTED;
26531991Sheppo
265412011SSriharsha.Basavapatna@Sun.COM vgen_setup_handshake_params(ldcp);
265512011SSriharsha.Basavapatna@Sun.COM
26562793Slm66018 /* if channel is already UP - start handshake */
26572793Slm66018 if (istatus == LDC_UP) {
26582793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
26592793Slm66018 if (ldcp->portp != vgenp->vsw_portp) {
26602793Slm66018 /*
26616495Sspeer * As the channel is up, use this port from now on.
26622793Slm66018 */
26636495Sspeer (void) atomic_swap_32(
26646495Sspeer &ldcp->portp->use_vsw_port, B_FALSE);
26652793Slm66018 }
26662793Slm66018
26672793Slm66018 /* Initialize local session id */
26682793Slm66018 ldcp->local_sid = ddi_get_lbolt();
26692793Slm66018
26702793Slm66018 /* clear peer session id */
26712793Slm66018 ldcp->peer_sid = 0;
26722793Slm66018
26732793Slm66018 mutex_exit(&ldcp->tclock);
26742793Slm66018 mutex_exit(&ldcp->txlock);
26754647Sraghuram mutex_exit(&ldcp->wrlock);
26765708Sraghuram mutex_exit(&ldcp->rxlock);
267712011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
26782793Slm66018 mutex_exit(&ldcp->cblock);
267912011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
268012011SSriharsha.Basavapatna@Sun.COM flag = (rv == ECONNRESET) ? VGEN_FLAG_EVT_RESET :
268112011SSriharsha.Basavapatna@Sun.COM VGEN_FLAG_NEED_LDCRESET;
268212011SSriharsha.Basavapatna@Sun.COM (void) vgen_process_reset(ldcp, flag);
268312011SSriharsha.Basavapatna@Sun.COM }
26842793Slm66018 } else {
26852793Slm66018 LDC_UNLOCK(ldcp);
26862793Slm66018 }
26872793Slm66018
26881991Sheppo return (DDI_SUCCESS);
26891991Sheppo
26901991Sheppo ldcinit_failed:
26912748Slm66018 if (init_state & ST_cb_enable) {
26922748Slm66018 (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
26932748Slm66018 }
26941991Sheppo if (init_state & ST_ldc_open) {
26951991Sheppo (void) ldc_close(ldcp->ldc_handle);
26961991Sheppo }
26971991Sheppo LDC_UNLOCK(ldcp);
26984647Sraghuram DBG1(vgenp, ldcp, "exit\n");
26991991Sheppo return (DDI_FAILURE);
27001991Sheppo }
27011991Sheppo
27021991Sheppo /* stop transmit/receive on the channel */
27031991Sheppo static void
vgen_ldc_uninit(vgen_ldc_t * ldcp)27041991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp)
27051991Sheppo {
27064647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
27071991Sheppo
27084647Sraghuram DBG1(vgenp, ldcp, "enter\n");
270912011SSriharsha.Basavapatna@Sun.COM
27101991Sheppo LDC_LOCK(ldcp);
27111991Sheppo
27121991Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) {
27131991Sheppo LDC_UNLOCK(ldcp);
27144647Sraghuram DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n");
27151991Sheppo return;
27161991Sheppo }
27171991Sheppo
27181991Sheppo LDC_UNLOCK(ldcp);
27193653Snarayan
272012011SSriharsha.Basavapatna@Sun.COM while (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
272112011SSriharsha.Basavapatna@Sun.COM delay(drv_usectohz(VGEN_LDC_UNINIT_DELAY));
272212011SSriharsha.Basavapatna@Sun.COM }
272312011SSriharsha.Basavapatna@Sun.COM
272412011SSriharsha.Basavapatna@Sun.COM (void) vgen_process_reset(ldcp, VGEN_FLAG_UNINIT);
27251991Sheppo
27264647Sraghuram DBG1(vgenp, ldcp, "exit\n");
27271991Sheppo }
27281991Sheppo
272912011SSriharsha.Basavapatna@Sun.COM /*
273012011SSriharsha.Basavapatna@Sun.COM * Create a descriptor ring, that will be exported to the peer for mapping.
273112011SSriharsha.Basavapatna@Sun.COM */
27321991Sheppo static int
vgen_create_dring(vgen_ldc_t * ldcp)273312011SSriharsha.Basavapatna@Sun.COM vgen_create_dring(vgen_ldc_t *ldcp)
27341991Sheppo {
273512011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
273612011SSriharsha.Basavapatna@Sun.COM int rv;
273712011SSriharsha.Basavapatna@Sun.COM
273812011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
273912011SSriharsha.Basavapatna@Sun.COM rv = vgen_create_rx_dring(ldcp);
27407529SSriharsha.Basavapatna@Sun.COM } else {
274112011SSriharsha.Basavapatna@Sun.COM rv = vgen_create_tx_dring(ldcp);
274212011SSriharsha.Basavapatna@Sun.COM }
274312011SSriharsha.Basavapatna@Sun.COM
274412011SSriharsha.Basavapatna@Sun.COM return (rv);
274512011SSriharsha.Basavapatna@Sun.COM }
274612011SSriharsha.Basavapatna@Sun.COM
274712011SSriharsha.Basavapatna@Sun.COM /*
274812011SSriharsha.Basavapatna@Sun.COM * Destroy the descriptor ring.
274912011SSriharsha.Basavapatna@Sun.COM */
275012011SSriharsha.Basavapatna@Sun.COM static void
vgen_destroy_dring(vgen_ldc_t * ldcp)275112011SSriharsha.Basavapatna@Sun.COM vgen_destroy_dring(vgen_ldc_t *ldcp)
275212011SSriharsha.Basavapatna@Sun.COM {
275312011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
275412011SSriharsha.Basavapatna@Sun.COM
275512011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
275612011SSriharsha.Basavapatna@Sun.COM vgen_destroy_rx_dring(ldcp);
275712011SSriharsha.Basavapatna@Sun.COM } else {
275812011SSriharsha.Basavapatna@Sun.COM vgen_destroy_tx_dring(ldcp);
275912011SSriharsha.Basavapatna@Sun.COM }
276012011SSriharsha.Basavapatna@Sun.COM }
276112011SSriharsha.Basavapatna@Sun.COM
276212011SSriharsha.Basavapatna@Sun.COM /*
276312011SSriharsha.Basavapatna@Sun.COM * Map the descriptor ring exported by the peer.
276412011SSriharsha.Basavapatna@Sun.COM */
276512011SSriharsha.Basavapatna@Sun.COM static int
vgen_map_dring(vgen_ldc_t * ldcp,void * pkt)276612011SSriharsha.Basavapatna@Sun.COM vgen_map_dring(vgen_ldc_t *ldcp, void *pkt)
276712011SSriharsha.Basavapatna@Sun.COM {
276812011SSriharsha.Basavapatna@Sun.COM int rv;
276912011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
277012011SSriharsha.Basavapatna@Sun.COM
277112011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
27722109Slm66018 /*
277312011SSriharsha.Basavapatna@Sun.COM * In RxDringData mode, dring that we map in
277412011SSriharsha.Basavapatna@Sun.COM * becomes our transmit descriptor ring.
27752109Slm66018 */
277612011SSriharsha.Basavapatna@Sun.COM rv = vgen_map_tx_dring(ldcp, pkt);
277712011SSriharsha.Basavapatna@Sun.COM } else {
27782109Slm66018
27792109Slm66018 /*
278012011SSriharsha.Basavapatna@Sun.COM * In TxDring mode, dring that we map in
278112011SSriharsha.Basavapatna@Sun.COM * becomes our receive descriptor ring.
27822109Slm66018 */
278312011SSriharsha.Basavapatna@Sun.COM rv = vgen_map_rx_dring(ldcp, pkt);
278412011SSriharsha.Basavapatna@Sun.COM }
278512011SSriharsha.Basavapatna@Sun.COM
278612011SSriharsha.Basavapatna@Sun.COM return (rv);
27871991Sheppo }
27881991Sheppo
278912011SSriharsha.Basavapatna@Sun.COM /*
279012011SSriharsha.Basavapatna@Sun.COM * Unmap the descriptor ring exported by the peer.
279112011SSriharsha.Basavapatna@Sun.COM */
27921991Sheppo static void
vgen_unmap_dring(vgen_ldc_t * ldcp)279312011SSriharsha.Basavapatna@Sun.COM vgen_unmap_dring(vgen_ldc_t *ldcp)
27941991Sheppo {
279512011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
279612011SSriharsha.Basavapatna@Sun.COM
279712011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
279812011SSriharsha.Basavapatna@Sun.COM vgen_unmap_tx_dring(ldcp);
279912011SSriharsha.Basavapatna@Sun.COM } else {
280012011SSriharsha.Basavapatna@Sun.COM vgen_unmap_rx_dring(ldcp);
280112011SSriharsha.Basavapatna@Sun.COM }
28021991Sheppo }
28031991Sheppo
280412011SSriharsha.Basavapatna@Sun.COM void
vgen_destroy_rxpools(void * arg)280512011SSriharsha.Basavapatna@Sun.COM vgen_destroy_rxpools(void *arg)
28061991Sheppo {
280712011SSriharsha.Basavapatna@Sun.COM vio_mblk_pool_t *poolp = (vio_mblk_pool_t *)arg;
280812011SSriharsha.Basavapatna@Sun.COM vio_mblk_pool_t *npoolp;
280912011SSriharsha.Basavapatna@Sun.COM
281012011SSriharsha.Basavapatna@Sun.COM while (poolp != NULL) {
281112011SSriharsha.Basavapatna@Sun.COM npoolp = poolp->nextp;
281212011SSriharsha.Basavapatna@Sun.COM while (vio_destroy_mblks(poolp) != 0) {
281312300SSriharsha.Basavapatna@Sun.COM delay(drv_usectohz(vgen_rxpool_cleanup_delay));
281412011SSriharsha.Basavapatna@Sun.COM }
281512011SSriharsha.Basavapatna@Sun.COM poolp = npoolp;
281612011SSriharsha.Basavapatna@Sun.COM }
28171991Sheppo }
28181991Sheppo
28191991Sheppo /* get channel statistics */
28201991Sheppo static uint64_t
vgen_ldc_stat(vgen_ldc_t * ldcp,uint_t stat)28212311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat)
28221991Sheppo {
282312011SSriharsha.Basavapatna@Sun.COM vgen_stats_t *statsp;
282412011SSriharsha.Basavapatna@Sun.COM uint64_t val;
28251991Sheppo
28261991Sheppo val = 0;
28275373Sraghuram statsp = &ldcp->stats;
28281991Sheppo switch (stat) {
28291991Sheppo
28301991Sheppo case MAC_STAT_MULTIRCV:
28311991Sheppo val = statsp->multircv;
28321991Sheppo break;
28331991Sheppo
28341991Sheppo case MAC_STAT_BRDCSTRCV:
28351991Sheppo val = statsp->brdcstrcv;
28361991Sheppo break;
28371991Sheppo
28381991Sheppo case MAC_STAT_MULTIXMT:
28391991Sheppo val = statsp->multixmt;
28401991Sheppo break;
28411991Sheppo
28421991Sheppo case MAC_STAT_BRDCSTXMT:
28431991Sheppo val = statsp->brdcstxmt;
28441991Sheppo break;
28451991Sheppo
28461991Sheppo case MAC_STAT_NORCVBUF:
28471991Sheppo val = statsp->norcvbuf;
28481991Sheppo break;
28491991Sheppo
28501991Sheppo case MAC_STAT_IERRORS:
28511991Sheppo val = statsp->ierrors;
28521991Sheppo break;
28531991Sheppo
28541991Sheppo case MAC_STAT_NOXMTBUF:
28551991Sheppo val = statsp->noxmtbuf;
28561991Sheppo break;
28571991Sheppo
28581991Sheppo case MAC_STAT_OERRORS:
28591991Sheppo val = statsp->oerrors;
28601991Sheppo break;
28611991Sheppo
28621991Sheppo case MAC_STAT_COLLISIONS:
28631991Sheppo break;
28641991Sheppo
28651991Sheppo case MAC_STAT_RBYTES:
28661991Sheppo val = statsp->rbytes;
28671991Sheppo break;
28681991Sheppo
28691991Sheppo case MAC_STAT_IPACKETS:
28701991Sheppo val = statsp->ipackets;
28711991Sheppo break;
28721991Sheppo
28731991Sheppo case MAC_STAT_OBYTES:
28741991Sheppo val = statsp->obytes;
28751991Sheppo break;
28761991Sheppo
28771991Sheppo case MAC_STAT_OPACKETS:
28781991Sheppo val = statsp->opackets;
28791991Sheppo break;
28801991Sheppo
28811991Sheppo /* stats not relevant to ldc, return 0 */
28821991Sheppo case MAC_STAT_IFSPEED:
28832311Sseb case ETHER_STAT_ALIGN_ERRORS:
28842311Sseb case ETHER_STAT_FCS_ERRORS:
28852311Sseb case ETHER_STAT_FIRST_COLLISIONS:
28862311Sseb case ETHER_STAT_MULTI_COLLISIONS:
28872311Sseb case ETHER_STAT_DEFER_XMTS:
28882311Sseb case ETHER_STAT_TX_LATE_COLLISIONS:
28892311Sseb case ETHER_STAT_EX_COLLISIONS:
28902311Sseb case ETHER_STAT_MACXMT_ERRORS:
28912311Sseb case ETHER_STAT_CARRIER_ERRORS:
28922311Sseb case ETHER_STAT_TOOLONG_ERRORS:
28932311Sseb case ETHER_STAT_XCVR_ADDR:
28942311Sseb case ETHER_STAT_XCVR_ID:
28952311Sseb case ETHER_STAT_XCVR_INUSE:
28962311Sseb case ETHER_STAT_CAP_1000FDX:
28972311Sseb case ETHER_STAT_CAP_1000HDX:
28982311Sseb case ETHER_STAT_CAP_100FDX:
28992311Sseb case ETHER_STAT_CAP_100HDX:
29002311Sseb case ETHER_STAT_CAP_10FDX:
29012311Sseb case ETHER_STAT_CAP_10HDX:
29022311Sseb case ETHER_STAT_CAP_ASMPAUSE:
29032311Sseb case ETHER_STAT_CAP_PAUSE:
29042311Sseb case ETHER_STAT_CAP_AUTONEG:
29052311Sseb case ETHER_STAT_ADV_CAP_1000FDX:
29062311Sseb case ETHER_STAT_ADV_CAP_1000HDX:
29072311Sseb case ETHER_STAT_ADV_CAP_100FDX:
29082311Sseb case ETHER_STAT_ADV_CAP_100HDX:
29092311Sseb case ETHER_STAT_ADV_CAP_10FDX:
29102311Sseb case ETHER_STAT_ADV_CAP_10HDX:
29112311Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE:
29122311Sseb case ETHER_STAT_ADV_CAP_PAUSE:
29132311Sseb case ETHER_STAT_ADV_CAP_AUTONEG:
29142311Sseb case ETHER_STAT_LP_CAP_1000FDX:
29152311Sseb case ETHER_STAT_LP_CAP_1000HDX:
29162311Sseb case ETHER_STAT_LP_CAP_100FDX:
29172311Sseb case ETHER_STAT_LP_CAP_100HDX:
29182311Sseb case ETHER_STAT_LP_CAP_10FDX:
29192311Sseb case ETHER_STAT_LP_CAP_10HDX:
29202311Sseb case ETHER_STAT_LP_CAP_ASMPAUSE:
29212311Sseb case ETHER_STAT_LP_CAP_PAUSE:
29222311Sseb case ETHER_STAT_LP_CAP_AUTONEG:
29232311Sseb case ETHER_STAT_LINK_ASMPAUSE:
29242311Sseb case ETHER_STAT_LINK_PAUSE:
29252311Sseb case ETHER_STAT_LINK_AUTONEG:
29262311Sseb case ETHER_STAT_LINK_DUPLEX:
29271991Sheppo default:
29281991Sheppo val = 0;
29291991Sheppo break;
29301991Sheppo
29311991Sheppo }
29321991Sheppo return (val);
29331991Sheppo }
29341991Sheppo
29352793Slm66018 /*
29366495Sspeer * LDC channel is UP, start handshake process with peer.
29372793Slm66018 */
29382793Slm66018 static void
vgen_handle_evt_up(vgen_ldc_t * ldcp)29396495Sspeer vgen_handle_evt_up(vgen_ldc_t *ldcp)
29402793Slm66018 {
29412793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
29424647Sraghuram
29434647Sraghuram DBG1(vgenp, ldcp, "enter\n");
29442793Slm66018
29452793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock));
29462793Slm66018
29472793Slm66018 if (ldcp->portp != vgenp->vsw_portp) {
29482793Slm66018 /*
29496495Sspeer * As the channel is up, use this port from now on.
29502793Slm66018 */
29516495Sspeer (void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_FALSE);
29522793Slm66018 }
29532793Slm66018
29542793Slm66018 /* Initialize local session id */
29552793Slm66018 ldcp->local_sid = ddi_get_lbolt();
29562793Slm66018
29572793Slm66018 /* clear peer session id */
29582793Slm66018 ldcp->peer_sid = 0;
29592793Slm66018
29602793Slm66018 /* Initiate Handshake process with peer ldc endpoint */
296112011SSriharsha.Basavapatna@Sun.COM (void) vgen_handshake(vh_nextphase(ldcp));
29622793Slm66018
29634647Sraghuram DBG1(vgenp, ldcp, "exit\n");
29642793Slm66018 }
29652793Slm66018
29662793Slm66018 /*
29672793Slm66018 * LDC channel is Reset, terminate connection with peer and try to
29682793Slm66018 * bring the channel up again.
29692793Slm66018 */
297012011SSriharsha.Basavapatna@Sun.COM int
vgen_handle_evt_reset(vgen_ldc_t * ldcp,vgen_caller_t caller)297112011SSriharsha.Basavapatna@Sun.COM vgen_handle_evt_reset(vgen_ldc_t *ldcp, vgen_caller_t caller)
29722793Slm66018 {
297312011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
297412011SSriharsha.Basavapatna@Sun.COM ASSERT(MUTEX_HELD(&ldcp->cblock));
297512011SSriharsha.Basavapatna@Sun.COM }
297612011SSriharsha.Basavapatna@Sun.COM
297712011SSriharsha.Basavapatna@Sun.COM /* Set the flag to indicate reset is in progress */
297812011SSriharsha.Basavapatna@Sun.COM if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
297912011SSriharsha.Basavapatna@Sun.COM /* another thread is already in the process of resetting */
298012011SSriharsha.Basavapatna@Sun.COM return (EBUSY);
298112011SSriharsha.Basavapatna@Sun.COM }
298212011SSriharsha.Basavapatna@Sun.COM
298312011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
298412011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
298512011SSriharsha.Basavapatna@Sun.COM }
298612011SSriharsha.Basavapatna@Sun.COM
298712011SSriharsha.Basavapatna@Sun.COM (void) vgen_process_reset(ldcp, VGEN_FLAG_EVT_RESET);
298812011SSriharsha.Basavapatna@Sun.COM
298912011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
299012011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
299112011SSriharsha.Basavapatna@Sun.COM }
299212011SSriharsha.Basavapatna@Sun.COM
299312011SSriharsha.Basavapatna@Sun.COM return (0);
29942793Slm66018 }
29952793Slm66018
29961991Sheppo /* Interrupt handler for the channel */
29971991Sheppo static uint_t
vgen_ldc_cb(uint64_t event,caddr_t arg)29981991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg)
29991991Sheppo {
30001991Sheppo _NOTE(ARGUNUSED(event))
30011991Sheppo vgen_ldc_t *ldcp;
30021991Sheppo vgen_t *vgenp;
30031991Sheppo ldc_status_t istatus;
30041991Sheppo vgen_stats_t *statsp;
30057572SWentao.Yang@Sun.COM uint_t ret = LDC_SUCCESS;
30061991Sheppo
30071991Sheppo ldcp = (vgen_ldc_t *)arg;
30081991Sheppo vgenp = LDC_TO_VGEN(ldcp);
30095373Sraghuram statsp = &ldcp->stats;
30101991Sheppo
30114647Sraghuram DBG1(vgenp, ldcp, "enter\n");
30121991Sheppo
30131991Sheppo mutex_enter(&ldcp->cblock);
30141991Sheppo statsp->callbacks++;
30151991Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) {
30164647Sraghuram DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n",
30174647Sraghuram ldcp->ldc_status);
30181991Sheppo mutex_exit(&ldcp->cblock);
30191991Sheppo return (LDC_SUCCESS);
30201991Sheppo }
30211991Sheppo
30222793Slm66018 /*
30232793Slm66018 * NOTE: not using switch() as event could be triggered by
30242793Slm66018 * a state change and a read request. Also the ordering of the
30252793Slm66018 * check for the event types is deliberate.
30262793Slm66018 */
30272793Slm66018 if (event & LDC_EVT_UP) {
30282793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
30294647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n");
30305708Sraghuram /* status couldn't be determined */
30317572SWentao.Yang@Sun.COM ret = LDC_FAILURE;
30327572SWentao.Yang@Sun.COM goto ldc_cb_ret;
30332793Slm66018 }
30345708Sraghuram ldcp->ldc_status = istatus;
30355708Sraghuram if (ldcp->ldc_status != LDC_UP) {
30365708Sraghuram DWARN(vgenp, ldcp, "LDC_EVT_UP received "
30375708Sraghuram " but ldc status is not UP(0x%x)\n",
30385708Sraghuram ldcp->ldc_status);
30395708Sraghuram /* spurious interrupt, return success */
30407572SWentao.Yang@Sun.COM goto ldc_cb_ret;
30415708Sraghuram }
30424647Sraghuram DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n",
30434647Sraghuram event, ldcp->ldc_status);
30442793Slm66018
30456495Sspeer vgen_handle_evt_up(ldcp);
30462793Slm66018
30472793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
30482793Slm66018 }
30492793Slm66018
30505708Sraghuram /* Handle RESET/DOWN before READ event */
30515708Sraghuram if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) {
30525708Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
30535708Sraghuram DWARN(vgenp, ldcp, "ldc_status error\n");
30545708Sraghuram /* status couldn't be determined */
30557572SWentao.Yang@Sun.COM ret = LDC_FAILURE;
30567572SWentao.Yang@Sun.COM goto ldc_cb_ret;
30575708Sraghuram }
30585708Sraghuram ldcp->ldc_status = istatus;
30595708Sraghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n",
30605708Sraghuram event, ldcp->ldc_status);
30615708Sraghuram
306212011SSriharsha.Basavapatna@Sun.COM (void) vgen_handle_evt_reset(ldcp, VGEN_LDC_CB);
30635708Sraghuram
30645708Sraghuram /*
30655708Sraghuram * As the channel is down/reset, ignore READ event
30665708Sraghuram * but print a debug warning message.
30675708Sraghuram */
30685708Sraghuram if (event & LDC_EVT_READ) {
30695708Sraghuram DWARN(vgenp, ldcp,
30705708Sraghuram "LDC_EVT_READ set along with RESET/DOWN\n");
30715708Sraghuram event &= ~LDC_EVT_READ;
30725708Sraghuram }
30735708Sraghuram }
30745708Sraghuram
30752793Slm66018 if (event & LDC_EVT_READ) {
30764647Sraghuram DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n",
30774647Sraghuram event, ldcp->ldc_status);
30782793Slm66018
30792793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
30804647Sraghuram
308112011SSriharsha.Basavapatna@Sun.COM if (ldcp->msg_thread != NULL) {
30824647Sraghuram /*
30834647Sraghuram * If the receive thread is enabled, then
30844647Sraghuram * wakeup the receive thread to process the
30854647Sraghuram * LDC messages.
30864647Sraghuram */
30874647Sraghuram mutex_exit(&ldcp->cblock);
308812011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->msg_thr_lock);
308912011SSriharsha.Basavapatna@Sun.COM if (!(ldcp->msg_thr_flags & VGEN_WTHR_DATARCVD)) {
309012011SSriharsha.Basavapatna@Sun.COM ldcp->msg_thr_flags |= VGEN_WTHR_DATARCVD;
309112011SSriharsha.Basavapatna@Sun.COM cv_signal(&ldcp->msg_thr_cv);
30924647Sraghuram }
309312011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->msg_thr_lock);
30944647Sraghuram mutex_enter(&ldcp->cblock);
30954647Sraghuram } else {
309612011SSriharsha.Basavapatna@Sun.COM (void) vgen_handle_evt_read(ldcp, VGEN_LDC_CB);
30974647Sraghuram }
30982793Slm66018 }
30997572SWentao.Yang@Sun.COM
31007572SWentao.Yang@Sun.COM ldc_cb_ret:
31012793Slm66018 mutex_exit(&ldcp->cblock);
31024647Sraghuram DBG1(vgenp, ldcp, "exit\n");
31037572SWentao.Yang@Sun.COM return (ret);
31044647Sraghuram }
31054647Sraghuram
310612011SSriharsha.Basavapatna@Sun.COM int
vgen_handle_evt_read(vgen_ldc_t * ldcp,vgen_caller_t caller)310712011SSriharsha.Basavapatna@Sun.COM vgen_handle_evt_read(vgen_ldc_t *ldcp, vgen_caller_t caller)
31084647Sraghuram {
31094647Sraghuram int rv;
31105935Ssb155480 uint64_t *ldcmsg;
31114647Sraghuram size_t msglen;
31124647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
31134647Sraghuram vio_msg_tag_t *tagp;
31144647Sraghuram ldc_status_t istatus;
31154647Sraghuram boolean_t has_data;
31164647Sraghuram
31174647Sraghuram DBG1(vgenp, ldcp, "enter\n");
31184647Sraghuram
311912011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_LDC_CB) {
312012011SSriharsha.Basavapatna@Sun.COM ASSERT(MUTEX_HELD(&ldcp->cblock));
312112011SSriharsha.Basavapatna@Sun.COM } else if (caller == VGEN_MSG_THR) {
31224647Sraghuram mutex_enter(&ldcp->cblock);
31234647Sraghuram } else {
312412011SSriharsha.Basavapatna@Sun.COM return (EINVAL);
312512011SSriharsha.Basavapatna@Sun.COM }
312612011SSriharsha.Basavapatna@Sun.COM
312712011SSriharsha.Basavapatna@Sun.COM ldcmsg = ldcp->ldcmsg;
312812011SSriharsha.Basavapatna@Sun.COM
312912011SSriharsha.Basavapatna@Sun.COM vgen_evtread:
31301991Sheppo do {
31315935Ssb155480 msglen = ldcp->msglen;
31325935Ssb155480 rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen);
31331991Sheppo
31341991Sheppo if (rv != 0) {
313512011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ldc_read() failed "
313612011SSriharsha.Basavapatna@Sun.COM "rv(%d) len(%d)\n", rv, msglen);
31372793Slm66018 if (rv == ECONNRESET)
31384647Sraghuram goto vgen_evtread_error;
31391991Sheppo break;
31401991Sheppo }
31411991Sheppo if (msglen == 0) {
31424647Sraghuram DBG2(vgenp, ldcp, "ldc_read NODATA");
31431991Sheppo break;
31441991Sheppo }
31454647Sraghuram DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen);
31461991Sheppo
31471991Sheppo tagp = (vio_msg_tag_t *)ldcmsg;
31481991Sheppo
31491991Sheppo if (ldcp->peer_sid) {
31501991Sheppo /*
31511991Sheppo * check sid only after we have received peer's sid
31521991Sheppo * in the version negotiate msg.
31531991Sheppo */
31541991Sheppo #ifdef DEBUG
315512011SSriharsha.Basavapatna@Sun.COM if (vgen_inject_error(ldcp, VGEN_ERR_HSID)) {
31561991Sheppo /* simulate bad sid condition */
31571991Sheppo tagp->vio_sid = 0;
315812011SSriharsha.Basavapatna@Sun.COM vgen_inject_err_flag &= ~(VGEN_ERR_HSID);
31591991Sheppo }
31601991Sheppo #endif
31612793Slm66018 rv = vgen_check_sid(ldcp, tagp);
31622793Slm66018 if (rv != VGEN_SUCCESS) {
31631991Sheppo /*
31641991Sheppo * If sid mismatch is detected,
31651991Sheppo * reset the channel.
31661991Sheppo */
316712011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "vgen_check_sid() failed\n");
31684647Sraghuram goto vgen_evtread_error;
31691991Sheppo }
31701991Sheppo }
31711991Sheppo
31721991Sheppo switch (tagp->vio_msgtype) {
31731991Sheppo case VIO_TYPE_CTRL:
31742793Slm66018 rv = vgen_handle_ctrlmsg(ldcp, tagp);
317512011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
317612011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "vgen_handle_ctrlmsg()"
317712011SSriharsha.Basavapatna@Sun.COM " failed rv(%d)\n", rv);
317812011SSriharsha.Basavapatna@Sun.COM }
31791991Sheppo break;
31801991Sheppo
31811991Sheppo case VIO_TYPE_DATA:
31825935Ssb155480 rv = vgen_handle_datamsg(ldcp, tagp, msglen);
318312011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
318412011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "vgen_handle_datamsg()"
318512011SSriharsha.Basavapatna@Sun.COM " failed rv(%d)\n", rv);
318612011SSriharsha.Basavapatna@Sun.COM }
31871991Sheppo break;
31881991Sheppo
31891991Sheppo case VIO_TYPE_ERR:
31901991Sheppo vgen_handle_errmsg(ldcp, tagp);
31911991Sheppo break;
31921991Sheppo
31931991Sheppo default:
31944647Sraghuram DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n",
31954647Sraghuram tagp->vio_msgtype);
31961991Sheppo break;
31971991Sheppo }
31981991Sheppo
31994647Sraghuram /*
32004647Sraghuram * If an error is encountered, stop processing and
32014647Sraghuram * handle the error.
32024647Sraghuram */
32034647Sraghuram if (rv != 0) {
32044647Sraghuram goto vgen_evtread_error;
32052793Slm66018 }
32062793Slm66018
32071991Sheppo } while (msglen);
32081991Sheppo
32094647Sraghuram /* check once more before exiting */
32104647Sraghuram rv = ldc_chkq(ldcp->ldc_handle, &has_data);
32114647Sraghuram if ((rv == 0) && (has_data == B_TRUE)) {
321212011SSriharsha.Basavapatna@Sun.COM DTRACE_PROBE1(vgen_chkq, vgen_ldc_t *, ldcp);
321312011SSriharsha.Basavapatna@Sun.COM goto vgen_evtread;
32144647Sraghuram }
32154647Sraghuram
32164647Sraghuram vgen_evtread_error:
321712011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
321812011SSriharsha.Basavapatna@Sun.COM /*
321912011SSriharsha.Basavapatna@Sun.COM * We handle the error and then return the error value. If we
322012011SSriharsha.Basavapatna@Sun.COM * are running in the context of the msg worker, the error
322112011SSriharsha.Basavapatna@Sun.COM * tells the worker thread to exit, as the channel would have
322212011SSriharsha.Basavapatna@Sun.COM * been reset.
322312011SSriharsha.Basavapatna@Sun.COM */
322412011SSriharsha.Basavapatna@Sun.COM if (rv == ECONNRESET) {
322512011SSriharsha.Basavapatna@Sun.COM if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
322612011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ldc_status err\n");
322712011SSriharsha.Basavapatna@Sun.COM } else {
322812011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_status = istatus;
322912011SSriharsha.Basavapatna@Sun.COM }
323012011SSriharsha.Basavapatna@Sun.COM (void) vgen_handle_evt_reset(ldcp, caller);
32314647Sraghuram } else {
323212011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "Calling vgen_ldc_reset()...\n");
323312011SSriharsha.Basavapatna@Sun.COM (void) vgen_ldc_reset(ldcp, caller);
32344647Sraghuram }
323512011SSriharsha.Basavapatna@Sun.COM }
323612011SSriharsha.Basavapatna@Sun.COM
323712011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_MSG_THR) {
32384647Sraghuram mutex_exit(&ldcp->cblock);
32394647Sraghuram }
32404647Sraghuram
32414647Sraghuram DBG1(vgenp, ldcp, "exit\n");
324212011SSriharsha.Basavapatna@Sun.COM return (rv);
32431991Sheppo }
32441991Sheppo
32451991Sheppo /* vgen handshake functions */
32461991Sheppo
32471991Sheppo /* change the hphase for the channel to the next phase */
32481991Sheppo static vgen_ldc_t *
vh_nextphase(vgen_ldc_t * ldcp)32491991Sheppo vh_nextphase(vgen_ldc_t *ldcp)
32501991Sheppo {
325112011SSriharsha.Basavapatna@Sun.COM if (ldcp->hphase == VH_PHASE4) {
32521991Sheppo ldcp->hphase = VH_DONE;
32531991Sheppo } else {
32541991Sheppo ldcp->hphase++;
32551991Sheppo }
32561991Sheppo return (ldcp);
32571991Sheppo }
32581991Sheppo
32591991Sheppo /* send version negotiate message to the peer over ldc */
32601991Sheppo static int
vgen_send_version_negotiate(vgen_ldc_t * ldcp)32611991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp)
32621991Sheppo {
32634647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
32641991Sheppo vio_ver_msg_t vermsg;
32651991Sheppo vio_msg_tag_t *tagp = &vermsg.tag;
32661991Sheppo int rv;
32671991Sheppo
32681991Sheppo bzero(&vermsg, sizeof (vermsg));
32691991Sheppo
32701991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
32711991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
32721991Sheppo tagp->vio_subtype_env = VIO_VER_INFO;
32731991Sheppo tagp->vio_sid = ldcp->local_sid;
32741991Sheppo
32751991Sheppo /* get version msg payload from ldcp->local */
32761991Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major;
32771991Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor;
32781991Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class;
32791991Sheppo
32801991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE);
32811991Sheppo if (rv != VGEN_SUCCESS) {
32824647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
32832793Slm66018 return (rv);
32841991Sheppo }
32851991Sheppo
32861991Sheppo ldcp->hstate |= VER_INFO_SENT;
32874647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n",
32884647Sraghuram vermsg.ver_major, vermsg.ver_minor);
32891991Sheppo
32901991Sheppo return (VGEN_SUCCESS);
32911991Sheppo }
32921991Sheppo
32931991Sheppo /* send attr info message to the peer over ldc */
32941991Sheppo static int
vgen_send_attr_info(vgen_ldc_t * ldcp)32951991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp)
32961991Sheppo {
32974647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
32981991Sheppo vnet_attr_msg_t attrmsg;
32991991Sheppo vio_msg_tag_t *tagp = &attrmsg.tag;
33001991Sheppo int rv;
33011991Sheppo
33021991Sheppo bzero(&attrmsg, sizeof (attrmsg));
33031991Sheppo
33041991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
33051991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
33061991Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO;
33071991Sheppo tagp->vio_sid = ldcp->local_sid;
33081991Sheppo
33091991Sheppo /* get attr msg payload from ldcp->local */
33101991Sheppo attrmsg.mtu = ldcp->local_hparams.mtu;
33111991Sheppo attrmsg.addr = ldcp->local_hparams.addr;
33121991Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type;
33131991Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode;
33141991Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq;
33159336SSriharsha.Basavapatna@Sun.COM attrmsg.physlink_update = ldcp->local_hparams.physlink_update;
331612011SSriharsha.Basavapatna@Sun.COM attrmsg.options = ldcp->local_hparams.dring_mode;
33171991Sheppo
33181991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE);
33191991Sheppo if (rv != VGEN_SUCCESS) {
33204647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
33212793Slm66018 return (rv);
33221991Sheppo }
33231991Sheppo
33241991Sheppo ldcp->hstate |= ATTR_INFO_SENT;
33254647Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n");
33261991Sheppo
33271991Sheppo return (VGEN_SUCCESS);
33281991Sheppo }
33291991Sheppo
333012011SSriharsha.Basavapatna@Sun.COM /*
333112011SSriharsha.Basavapatna@Sun.COM * Send descriptor ring register message to the peer over ldc.
333212011SSriharsha.Basavapatna@Sun.COM * Invoked in RxDringData mode.
333312011SSriharsha.Basavapatna@Sun.COM */
33341991Sheppo static int
vgen_send_rx_dring_reg(vgen_ldc_t * ldcp)333512011SSriharsha.Basavapatna@Sun.COM vgen_send_rx_dring_reg(vgen_ldc_t *ldcp)
333612011SSriharsha.Basavapatna@Sun.COM {
333712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
333812011SSriharsha.Basavapatna@Sun.COM vio_dring_reg_msg_t *msg;
333912011SSriharsha.Basavapatna@Sun.COM vio_dring_reg_ext_msg_t *emsg;
334012011SSriharsha.Basavapatna@Sun.COM int rv;
334112011SSriharsha.Basavapatna@Sun.COM uint8_t *buf;
334212011SSriharsha.Basavapatna@Sun.COM uint_t msgsize;
334312011SSriharsha.Basavapatna@Sun.COM
334412011SSriharsha.Basavapatna@Sun.COM msgsize = VNET_DRING_REG_EXT_MSG_SIZE(ldcp->rx_data_ncookies);
334512011SSriharsha.Basavapatna@Sun.COM msg = kmem_zalloc(msgsize, KM_SLEEP);
334612011SSriharsha.Basavapatna@Sun.COM
334712011SSriharsha.Basavapatna@Sun.COM /* Initialize the common part of dring reg msg */
334812011SSriharsha.Basavapatna@Sun.COM vgen_init_dring_reg_msg(ldcp, msg, VIO_RX_DRING_DATA);
334912011SSriharsha.Basavapatna@Sun.COM
335012011SSriharsha.Basavapatna@Sun.COM /* skip over dring cookies at the tail of common section */
335112011SSriharsha.Basavapatna@Sun.COM buf = (uint8_t *)msg->cookie;
335212011SSriharsha.Basavapatna@Sun.COM ASSERT(msg->ncookies == 1);
335312011SSriharsha.Basavapatna@Sun.COM buf += (msg->ncookies * sizeof (ldc_mem_cookie_t));
335412011SSriharsha.Basavapatna@Sun.COM
335512011SSriharsha.Basavapatna@Sun.COM /* Now setup the extended part, specific to RxDringData mode */
335612011SSriharsha.Basavapatna@Sun.COM emsg = (vio_dring_reg_ext_msg_t *)buf;
335712011SSriharsha.Basavapatna@Sun.COM
335812011SSriharsha.Basavapatna@Sun.COM /* copy data_ncookies in the msg */
335912011SSriharsha.Basavapatna@Sun.COM emsg->data_ncookies = ldcp->rx_data_ncookies;
336012011SSriharsha.Basavapatna@Sun.COM
336112011SSriharsha.Basavapatna@Sun.COM /* copy data area size in the msg */
336212011SSriharsha.Basavapatna@Sun.COM emsg->data_area_size = ldcp->rx_data_sz;
336312011SSriharsha.Basavapatna@Sun.COM
336412011SSriharsha.Basavapatna@Sun.COM /* copy data area cookies in the msg */
336512011SSriharsha.Basavapatna@Sun.COM bcopy(ldcp->rx_data_cookie, (ldc_mem_cookie_t *)emsg->data_cookie,
336612011SSriharsha.Basavapatna@Sun.COM sizeof (ldc_mem_cookie_t) * ldcp->rx_data_ncookies);
336712011SSriharsha.Basavapatna@Sun.COM
336812011SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)msg, msgsize, B_FALSE);
336912011SSriharsha.Basavapatna@Sun.COM if (rv != VGEN_SUCCESS) {
337012011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
337112011SSriharsha.Basavapatna@Sun.COM kmem_free(msg, msgsize);
337212011SSriharsha.Basavapatna@Sun.COM return (rv);
337312011SSriharsha.Basavapatna@Sun.COM }
337412011SSriharsha.Basavapatna@Sun.COM
337512011SSriharsha.Basavapatna@Sun.COM ldcp->hstate |= DRING_INFO_SENT;
337612011SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
337712011SSriharsha.Basavapatna@Sun.COM
337812011SSriharsha.Basavapatna@Sun.COM kmem_free(msg, msgsize);
337912011SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
338012011SSriharsha.Basavapatna@Sun.COM }
338112011SSriharsha.Basavapatna@Sun.COM
338212011SSriharsha.Basavapatna@Sun.COM /*
338312011SSriharsha.Basavapatna@Sun.COM * Send descriptor ring register message to the peer over ldc.
338412011SSriharsha.Basavapatna@Sun.COM * Invoked in TxDring mode.
338512011SSriharsha.Basavapatna@Sun.COM */
338612011SSriharsha.Basavapatna@Sun.COM static int
vgen_send_tx_dring_reg(vgen_ldc_t * ldcp)338712011SSriharsha.Basavapatna@Sun.COM vgen_send_tx_dring_reg(vgen_ldc_t *ldcp)
33881991Sheppo {
33894647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
33901991Sheppo vio_dring_reg_msg_t msg;
339112011SSriharsha.Basavapatna@Sun.COM int rv;
33921991Sheppo
33931991Sheppo bzero(&msg, sizeof (msg));
33941991Sheppo
33951991Sheppo /*
339612011SSriharsha.Basavapatna@Sun.COM * Initialize only the common part of dring reg msg in TxDring mode.
33971991Sheppo */
339812011SSriharsha.Basavapatna@Sun.COM vgen_init_dring_reg_msg(ldcp, &msg, VIO_TX_DRING);
339912011SSriharsha.Basavapatna@Sun.COM
340012011SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)&msg, sizeof (msg), B_FALSE);
34011991Sheppo if (rv != VGEN_SUCCESS) {
34024647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
34032793Slm66018 return (rv);
34041991Sheppo }
34051991Sheppo
34061991Sheppo ldcp->hstate |= DRING_INFO_SENT;
34074647Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_SENT \n");
34081991Sheppo
34091991Sheppo return (VGEN_SUCCESS);
34101991Sheppo }
34111991Sheppo
34121991Sheppo static int
vgen_send_rdx_info(vgen_ldc_t * ldcp)34131991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp)
34141991Sheppo {
34154647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
34161991Sheppo vio_rdx_msg_t rdxmsg;
34171991Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag;
34181991Sheppo int rv;
34191991Sheppo
34201991Sheppo bzero(&rdxmsg, sizeof (rdxmsg));
34211991Sheppo
34221991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
34231991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
34241991Sheppo tagp->vio_subtype_env = VIO_RDX;
34251991Sheppo tagp->vio_sid = ldcp->local_sid;
34261991Sheppo
34271991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE);
34281991Sheppo if (rv != VGEN_SUCCESS) {
34294647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n");
34302793Slm66018 return (rv);
34311991Sheppo }
34321991Sheppo
34331991Sheppo ldcp->hstate |= RDX_INFO_SENT;
34344647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_SENT\n");
34351991Sheppo
34361991Sheppo return (VGEN_SUCCESS);
34371991Sheppo }
34381991Sheppo
34391991Sheppo /* send multicast addr info message to vsw */
34401991Sheppo static int
vgen_send_mcast_info(vgen_ldc_t * ldcp)34411991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp)
34421991Sheppo {
34431991Sheppo vnet_mcast_msg_t mcastmsg;
34441991Sheppo vnet_mcast_msg_t *msgp;
34451991Sheppo vio_msg_tag_t *tagp;
34461991Sheppo vgen_t *vgenp;
34471991Sheppo struct ether_addr *mca;
34481991Sheppo int rv;
34491991Sheppo int i;
34501991Sheppo uint32_t size;
34511991Sheppo uint32_t mccount;
34521991Sheppo uint32_t n;
34531991Sheppo
34541991Sheppo msgp = &mcastmsg;
34551991Sheppo tagp = &msgp->tag;
34561991Sheppo vgenp = LDC_TO_VGEN(ldcp);
34571991Sheppo
34581991Sheppo mccount = vgenp->mccount;
34591991Sheppo i = 0;
34601991Sheppo
34611991Sheppo do {
34621991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL;
34631991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO;
34641991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO;
34651991Sheppo tagp->vio_sid = ldcp->local_sid;
34661991Sheppo
34671991Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount);
34681991Sheppo size = n * sizeof (struct ether_addr);
34691991Sheppo
34701991Sheppo mca = &(vgenp->mctab[i]);
34711991Sheppo bcopy(mca, (msgp->mca), size);
34721991Sheppo msgp->set = B_TRUE;
34731991Sheppo msgp->count = n;
34741991Sheppo
34751991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp),
34761991Sheppo B_FALSE);
34771991Sheppo if (rv != VGEN_SUCCESS) {
34784647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv);
34792793Slm66018 return (rv);
34801991Sheppo }
34811991Sheppo
34821991Sheppo mccount -= n;
34831991Sheppo i += n;
34841991Sheppo
34851991Sheppo } while (mccount);
34861991Sheppo
34871991Sheppo return (VGEN_SUCCESS);
34881991Sheppo }
34891991Sheppo
349012011SSriharsha.Basavapatna@Sun.COM /*
349112011SSriharsha.Basavapatna@Sun.COM * vgen_dds_rx -- post DDS messages to vnet.
349212011SSriharsha.Basavapatna@Sun.COM */
349312011SSriharsha.Basavapatna@Sun.COM static int
vgen_dds_rx(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)349412011SSriharsha.Basavapatna@Sun.COM vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
349512011SSriharsha.Basavapatna@Sun.COM {
349612011SSriharsha.Basavapatna@Sun.COM vio_dds_msg_t *dmsg = (vio_dds_msg_t *)tagp;
349712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
349812011SSriharsha.Basavapatna@Sun.COM
349912011SSriharsha.Basavapatna@Sun.COM if (dmsg->dds_class != DDS_VNET_NIU) {
350012011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "Unknown DDS class, dropping");
350112011SSriharsha.Basavapatna@Sun.COM return (EBADMSG);
350212011SSriharsha.Basavapatna@Sun.COM }
350312011SSriharsha.Basavapatna@Sun.COM vnet_dds_rx(vgenp->vnetp, dmsg);
350412011SSriharsha.Basavapatna@Sun.COM return (0);
350512011SSriharsha.Basavapatna@Sun.COM }
350612011SSriharsha.Basavapatna@Sun.COM
350712011SSriharsha.Basavapatna@Sun.COM /*
350812011SSriharsha.Basavapatna@Sun.COM * vgen_dds_tx -- an interface called by vnet to send DDS messages.
350912011SSriharsha.Basavapatna@Sun.COM */
351012011SSriharsha.Basavapatna@Sun.COM int
vgen_dds_tx(void * arg,void * msg)351112011SSriharsha.Basavapatna@Sun.COM vgen_dds_tx(void *arg, void *msg)
351212011SSriharsha.Basavapatna@Sun.COM {
351312011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = arg;
351412011SSriharsha.Basavapatna@Sun.COM vio_dds_msg_t *dmsg = msg;
351512011SSriharsha.Basavapatna@Sun.COM vgen_portlist_t *plistp = &vgenp->vgenports;
351612011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp;
351712011SSriharsha.Basavapatna@Sun.COM int rv = EIO;
351812011SSriharsha.Basavapatna@Sun.COM
351912011SSriharsha.Basavapatna@Sun.COM READ_ENTER(&plistp->rwlock);
352012011SSriharsha.Basavapatna@Sun.COM ldcp = vgenp->vsw_portp->ldcp;
352112011SSriharsha.Basavapatna@Sun.COM if ((ldcp == NULL) || (ldcp->hphase != VH_DONE)) {
352212011SSriharsha.Basavapatna@Sun.COM goto vgen_dsend_exit;
352312011SSriharsha.Basavapatna@Sun.COM }
352412011SSriharsha.Basavapatna@Sun.COM
352512011SSriharsha.Basavapatna@Sun.COM dmsg->tag.vio_sid = ldcp->local_sid;
352612011SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)dmsg, sizeof (vio_dds_msg_t), B_FALSE);
352712011SSriharsha.Basavapatna@Sun.COM if (rv != VGEN_SUCCESS) {
352812011SSriharsha.Basavapatna@Sun.COM rv = EIO;
352912011SSriharsha.Basavapatna@Sun.COM } else {
353012011SSriharsha.Basavapatna@Sun.COM rv = 0;
353112011SSriharsha.Basavapatna@Sun.COM }
353212011SSriharsha.Basavapatna@Sun.COM
353312011SSriharsha.Basavapatna@Sun.COM vgen_dsend_exit:
353412011SSriharsha.Basavapatna@Sun.COM RW_EXIT(&plistp->rwlock);
353512011SSriharsha.Basavapatna@Sun.COM return (rv);
353612011SSriharsha.Basavapatna@Sun.COM
353712011SSriharsha.Basavapatna@Sun.COM }
353812011SSriharsha.Basavapatna@Sun.COM
35391991Sheppo /* Initiate Phase 2 of handshake */
35401991Sheppo static int
vgen_handshake_phase2(vgen_ldc_t * ldcp)35411991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp)
35421991Sheppo {
354312011SSriharsha.Basavapatna@Sun.COM int rv;
35444647Sraghuram
35451991Sheppo #ifdef DEBUG
354612011SSriharsha.Basavapatna@Sun.COM if (vgen_inject_error(ldcp, VGEN_ERR_HSTATE)) {
35471991Sheppo /* simulate out of state condition */
354812011SSriharsha.Basavapatna@Sun.COM vgen_inject_err_flag &= ~(VGEN_ERR_HSTATE);
35491991Sheppo rv = vgen_send_rdx_info(ldcp);
35501991Sheppo return (rv);
35511991Sheppo }
355212011SSriharsha.Basavapatna@Sun.COM if (vgen_inject_error(ldcp, VGEN_ERR_HTIMEOUT)) {
35531991Sheppo /* simulate timeout condition */
355412011SSriharsha.Basavapatna@Sun.COM vgen_inject_err_flag &= ~(VGEN_ERR_HTIMEOUT);
35551991Sheppo return (VGEN_SUCCESS);
35561991Sheppo }
35571991Sheppo #endif
35582793Slm66018 rv = vgen_send_attr_info(ldcp);
35592793Slm66018 if (rv != VGEN_SUCCESS) {
35601991Sheppo return (rv);
35611991Sheppo }
35622793Slm66018
356312011SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
356412011SSriharsha.Basavapatna@Sun.COM }
356512011SSriharsha.Basavapatna@Sun.COM
356612011SSriharsha.Basavapatna@Sun.COM static int
vgen_handshake_phase3(vgen_ldc_t * ldcp)356712011SSriharsha.Basavapatna@Sun.COM vgen_handshake_phase3(vgen_ldc_t *ldcp)
356812011SSriharsha.Basavapatna@Sun.COM {
356912011SSriharsha.Basavapatna@Sun.COM int rv;
357012011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
357112011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
357212011SSriharsha.Basavapatna@Sun.COM vgen_stats_t *statsp = &ldcp->stats;
357312011SSriharsha.Basavapatna@Sun.COM
357412011SSriharsha.Basavapatna@Sun.COM /* dring mode has been negotiated in attr phase; save in stats */
357512011SSriharsha.Basavapatna@Sun.COM statsp->dring_mode = lp->dring_mode;
357612011SSriharsha.Basavapatna@Sun.COM
357712011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) { /* RxDringData mode */
357812011SSriharsha.Basavapatna@Sun.COM ldcp->rx_dringdata = vgen_handle_dringdata_shm;
357912011SSriharsha.Basavapatna@Sun.COM ldcp->tx_dringdata = vgen_dringsend_shm;
358012011SSriharsha.Basavapatna@Sun.COM if (!VGEN_PRI_ETH_DEFINED(vgenp)) {
358112011SSriharsha.Basavapatna@Sun.COM /*
358212011SSriharsha.Basavapatna@Sun.COM * If priority frames are not in use, we don't need a
358312011SSriharsha.Basavapatna@Sun.COM * separate wrapper function for 'tx', so we set it to
358412011SSriharsha.Basavapatna@Sun.COM * 'tx_dringdata'. If priority frames are configured,
358512011SSriharsha.Basavapatna@Sun.COM * we leave the 'tx' pointer as is (initialized in
358612011SSriharsha.Basavapatna@Sun.COM * vgen_set_vnet_proto_ops()).
358712011SSriharsha.Basavapatna@Sun.COM */
358812011SSriharsha.Basavapatna@Sun.COM ldcp->tx = ldcp->tx_dringdata;
35892793Slm66018 }
359012011SSriharsha.Basavapatna@Sun.COM } else { /* TxDring mode */
359112011SSriharsha.Basavapatna@Sun.COM ldcp->msg_thread = thread_create(NULL,
359212011SSriharsha.Basavapatna@Sun.COM 2 * DEFAULTSTKSZ, vgen_ldc_msg_worker, ldcp, 0,
359312011SSriharsha.Basavapatna@Sun.COM &p0, TS_RUN, maxclsyspri);
359412011SSriharsha.Basavapatna@Sun.COM }
359512011SSriharsha.Basavapatna@Sun.COM
359612011SSriharsha.Basavapatna@Sun.COM rv = vgen_create_dring(ldcp);
359712011SSriharsha.Basavapatna@Sun.COM if (rv != VGEN_SUCCESS) {
359812011SSriharsha.Basavapatna@Sun.COM return (rv);
35992793Slm66018 }
36002793Slm66018
36012793Slm66018 /* update local dring_info params */
360212011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
360312011SSriharsha.Basavapatna@Sun.COM bcopy(&(ldcp->rx_dring_cookie),
360412011SSriharsha.Basavapatna@Sun.COM &(ldcp->local_hparams.dring_cookie),
360512011SSriharsha.Basavapatna@Sun.COM sizeof (ldc_mem_cookie_t));
360612011SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.dring_ncookies = ldcp->rx_dring_ncookies;
360712011SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.num_desc = ldcp->num_rxds;
360812011SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.desc_size =
360912011SSriharsha.Basavapatna@Sun.COM sizeof (vnet_rx_dringdata_desc_t);
361012011SSriharsha.Basavapatna@Sun.COM rv = vgen_send_rx_dring_reg(ldcp);
361112011SSriharsha.Basavapatna@Sun.COM } else {
361212011SSriharsha.Basavapatna@Sun.COM bcopy(&(ldcp->tx_dring_cookie),
361312011SSriharsha.Basavapatna@Sun.COM &(ldcp->local_hparams.dring_cookie),
361412011SSriharsha.Basavapatna@Sun.COM sizeof (ldc_mem_cookie_t));
361512011SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.dring_ncookies = ldcp->tx_dring_ncookies;
361612011SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.num_desc = ldcp->num_txds;
361712011SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t);
361812011SSriharsha.Basavapatna@Sun.COM rv = vgen_send_tx_dring_reg(ldcp);
361912011SSriharsha.Basavapatna@Sun.COM }
362012011SSriharsha.Basavapatna@Sun.COM
36212793Slm66018 if (rv != VGEN_SUCCESS) {
36221991Sheppo return (rv);
36231991Sheppo }
36241991Sheppo
36251991Sheppo return (VGEN_SUCCESS);
36261991Sheppo }
36271991Sheppo
36281991Sheppo /*
36295935Ssb155480 * Set vnet-protocol-version dependent functions based on version.
36305935Ssb155480 */
36315935Ssb155480 static void
vgen_set_vnet_proto_ops(vgen_ldc_t * ldcp)36325935Ssb155480 vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp)
36335935Ssb155480 {
36345935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams;
36355935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp);
36365935Ssb155480
363712011SSriharsha.Basavapatna@Sun.COM /*
363812011SSriharsha.Basavapatna@Sun.COM * Setup the appropriate dring data processing routine and any
363912011SSriharsha.Basavapatna@Sun.COM * associated thread based on the version.
364012011SSriharsha.Basavapatna@Sun.COM *
364112011SSriharsha.Basavapatna@Sun.COM * In versions < 1.6, we only support TxDring mode. In this mode, the
364212011SSriharsha.Basavapatna@Sun.COM * msg worker thread processes all types of VIO msgs (ctrl and data).
364312011SSriharsha.Basavapatna@Sun.COM *
364412011SSriharsha.Basavapatna@Sun.COM * In versions >= 1.6, we also support RxDringData mode. In this mode,
364512011SSriharsha.Basavapatna@Sun.COM * all msgs including dring data messages are handled directly by the
364612011SSriharsha.Basavapatna@Sun.COM * callback (intr) thread. The dring data msgs (msgtype: VIO_TYPE_DATA,
364712011SSriharsha.Basavapatna@Sun.COM * subtype: VIO_SUBTYPE_INFO, subtype_env: VIO_DRING_DATA) can also be
364812011SSriharsha.Basavapatna@Sun.COM * disabled while the polling thread is active, in which case the
364912011SSriharsha.Basavapatna@Sun.COM * polling thread processes the rcv descriptor ring.
365012011SSriharsha.Basavapatna@Sun.COM *
365112011SSriharsha.Basavapatna@Sun.COM * However, for versions >= 1.6, we can force to only use TxDring mode.
365212011SSriharsha.Basavapatna@Sun.COM * This could happen if RxDringData mode has been disabled (see
3653*13098SWentao.Yang@Sun.COM * below) on this guest or on the peer guest. This info is determined
3654*13098SWentao.Yang@Sun.COM * as part of attr exchange phase of handshake. Hence, we setup these
3655*13098SWentao.Yang@Sun.COM * pointers for v1.6 after attr msg phase completes during handshake.
365612011SSriharsha.Basavapatna@Sun.COM */
365712011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 6)) { /* Ver >= 1.6 */
365812011SSriharsha.Basavapatna@Sun.COM /*
365912011SSriharsha.Basavapatna@Sun.COM * Set data dring mode for vgen_send_attr_info().
366012011SSriharsha.Basavapatna@Sun.COM */
3661*13098SWentao.Yang@Sun.COM if (vgen_mapin_avail(ldcp) == B_TRUE) {
366212011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = (VIO_RX_DRING_DATA | VIO_TX_DRING);
366312011SSriharsha.Basavapatna@Sun.COM } else {
366412011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = VIO_TX_DRING;
366512011SSriharsha.Basavapatna@Sun.COM }
366612011SSriharsha.Basavapatna@Sun.COM } else { /* Ver <= 1.5 */
366712011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = VIO_TX_DRING;
366812011SSriharsha.Basavapatna@Sun.COM }
366912011SSriharsha.Basavapatna@Sun.COM
36709336SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 5)) {
36719336SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp = ldcp->portp;
36729336SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vgenp->vnetp;
36739336SSriharsha.Basavapatna@Sun.COM /*
36749336SSriharsha.Basavapatna@Sun.COM * If the version negotiated with vswitch is >= 1.5 (link
36759336SSriharsha.Basavapatna@Sun.COM * status update support), set the required bits in our
36769336SSriharsha.Basavapatna@Sun.COM * attributes if this vnet device has been configured to get
36779336SSriharsha.Basavapatna@Sun.COM * physical link state updates.
36789336SSriharsha.Basavapatna@Sun.COM */
36799336SSriharsha.Basavapatna@Sun.COM if (portp == vgenp->vsw_portp && vnetp->pls_update == B_TRUE) {
36809336SSriharsha.Basavapatna@Sun.COM lp->physlink_update = PHYSLINK_UPDATE_STATE;
36819336SSriharsha.Basavapatna@Sun.COM } else {
36829336SSriharsha.Basavapatna@Sun.COM lp->physlink_update = PHYSLINK_UPDATE_NONE;
36839336SSriharsha.Basavapatna@Sun.COM }
36849336SSriharsha.Basavapatna@Sun.COM }
36859336SSriharsha.Basavapatna@Sun.COM
36867529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
36876419Ssb155480 /*
36887529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is >= 1.4(Jumbo Frame
36897529SSriharsha.Basavapatna@Sun.COM * Support), set the mtu in our attributes to max_frame_size.
36906419Ssb155480 */
36916419Ssb155480 lp->mtu = vgenp->max_frame_size;
36927529SSriharsha.Basavapatna@Sun.COM } else if (VGEN_VER_EQ(ldcp, 1, 3)) {
36937529SSriharsha.Basavapatna@Sun.COM /*
36947529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is == 1.3 (Vlan Tag
36957529SSriharsha.Basavapatna@Sun.COM * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ.
36967529SSriharsha.Basavapatna@Sun.COM */
36977529SSriharsha.Basavapatna@Sun.COM lp->mtu = ETHERMAX + VLAN_TAGSZ;
36986419Ssb155480 } else {
36996419Ssb155480 vgen_port_t *portp = ldcp->portp;
37006419Ssb155480 vnet_t *vnetp = vgenp->vnetp;
37016419Ssb155480 /*
37026419Ssb155480 * Pre-1.3 peers expect max frame size of ETHERMAX.
37036419Ssb155480 * We can negotiate that size with those peers provided the
37046419Ssb155480 * following conditions are true:
37056419Ssb155480 * - Only pvid is defined for our peer and there are no vids.
37066419Ssb155480 * - pvids are equal.
37076419Ssb155480 * If the above conditions are true, then we can send/recv only
37086419Ssb155480 * untagged frames of max size ETHERMAX.
37096419Ssb155480 */
37107529SSriharsha.Basavapatna@Sun.COM if (portp->nvids == 0 && portp->pvid == vnetp->pvid) {
37116419Ssb155480 lp->mtu = ETHERMAX;
37126419Ssb155480 }
37136419Ssb155480 }
37146419Ssb155480
371512011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 2)) { /* Versions >= 1.2 */
371612011SSriharsha.Basavapatna@Sun.COM /*
371712011SSriharsha.Basavapatna@Sun.COM * Starting v1.2 we support priority frames; so set the
371812011SSriharsha.Basavapatna@Sun.COM * dring processing routines and xfer modes based on the
371912011SSriharsha.Basavapatna@Sun.COM * version. Note that the dring routines could be changed after
372012011SSriharsha.Basavapatna@Sun.COM * attribute handshake phase for versions >= 1.6 (See
372112011SSriharsha.Basavapatna@Sun.COM * vgen_handshake_phase3())
372212011SSriharsha.Basavapatna@Sun.COM */
372312011SSriharsha.Basavapatna@Sun.COM ldcp->tx_dringdata = vgen_dringsend;
372412011SSriharsha.Basavapatna@Sun.COM ldcp->rx_dringdata = vgen_handle_dringdata;
37255935Ssb155480
37265935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) {
37275935Ssb155480 /*
372812011SSriharsha.Basavapatna@Sun.COM * Enable priority routines and pkt mode only if
37295935Ssb155480 * at least one pri-eth-type is specified in MD.
37305935Ssb155480 */
37315935Ssb155480 ldcp->tx = vgen_ldcsend;
37325935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data;
37335935Ssb155480
37345935Ssb155480 /* set xfer mode for vgen_send_attr_info() */
37355935Ssb155480 lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2;
37365935Ssb155480 } else {
373712011SSriharsha.Basavapatna@Sun.COM /* No priority eth types defined in MD */
373812011SSriharsha.Basavapatna@Sun.COM ldcp->tx = ldcp->tx_dringdata;
37395935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
37405935Ssb155480
374112011SSriharsha.Basavapatna@Sun.COM /* Set xfer mode for vgen_send_attr_info() */
37425935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_2;
37435935Ssb155480 }
374412011SSriharsha.Basavapatna@Sun.COM } else { /* Versions prior to 1.2 */
37455935Ssb155480 vgen_reset_vnet_proto_ops(ldcp);
37465935Ssb155480 }
37475935Ssb155480 }
37485935Ssb155480
37495935Ssb155480 /*
37505935Ssb155480 * Reset vnet-protocol-version dependent functions to pre-v1.2.
37515935Ssb155480 */
37525935Ssb155480 static void
vgen_reset_vnet_proto_ops(vgen_ldc_t * ldcp)37535935Ssb155480 vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp)
37545935Ssb155480 {
37555935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams;
37565935Ssb155480
375712011SSriharsha.Basavapatna@Sun.COM ldcp->tx = ldcp->tx_dringdata = vgen_dringsend;
375812011SSriharsha.Basavapatna@Sun.COM ldcp->rx_dringdata = vgen_handle_dringdata;
37595935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop;
37605935Ssb155480
37615935Ssb155480 /* set xfer mode for vgen_send_attr_info() */
37625935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0;
37635935Ssb155480 }
37645935Ssb155480
37656419Ssb155480 static void
vgen_vlan_unaware_port_reset(vgen_port_t * portp)37666419Ssb155480 vgen_vlan_unaware_port_reset(vgen_port_t *portp)
37676419Ssb155480 {
376812011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp = portp->ldcp;
37696419Ssb155480 vgen_t *vgenp = portp->vgenp;
37706419Ssb155480 vnet_t *vnetp = vgenp->vnetp;
377112011SSriharsha.Basavapatna@Sun.COM boolean_t need_reset = B_FALSE;
37726419Ssb155480
37736419Ssb155480 mutex_enter(&ldcp->cblock);
37746419Ssb155480
37756419Ssb155480 /*
37766419Ssb155480 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
37776419Ssb155480 * the connection. See comments in vgen_set_vnet_proto_ops().
37786419Ssb155480 */
37796419Ssb155480 if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) &&
37806419Ssb155480 (portp->nvids != 0 || portp->pvid != vnetp->pvid)) {
378112011SSriharsha.Basavapatna@Sun.COM need_reset = B_TRUE;
378212011SSriharsha.Basavapatna@Sun.COM }
37836419Ssb155480 mutex_exit(&ldcp->cblock);
37846419Ssb155480
378512011SSriharsha.Basavapatna@Sun.COM if (need_reset == B_TRUE) {
378612011SSriharsha.Basavapatna@Sun.COM (void) vgen_ldc_reset(ldcp, VGEN_OTHER);
378712011SSriharsha.Basavapatna@Sun.COM }
37886419Ssb155480 }
37896419Ssb155480
37906419Ssb155480 static void
vgen_port_reset(vgen_port_t * portp)37919336SSriharsha.Basavapatna@Sun.COM vgen_port_reset(vgen_port_t *portp)
37929336SSriharsha.Basavapatna@Sun.COM {
379312011SSriharsha.Basavapatna@Sun.COM (void) vgen_ldc_reset(portp->ldcp, VGEN_OTHER);
37949336SSriharsha.Basavapatna@Sun.COM }
37959336SSriharsha.Basavapatna@Sun.COM
37969336SSriharsha.Basavapatna@Sun.COM static void
vgen_reset_vlan_unaware_ports(vgen_t * vgenp)37976419Ssb155480 vgen_reset_vlan_unaware_ports(vgen_t *vgenp)
37986419Ssb155480 {
37996419Ssb155480 vgen_port_t *portp;
38006419Ssb155480 vgen_portlist_t *plistp;
38016419Ssb155480
38026419Ssb155480 plistp = &(vgenp->vgenports);
38036419Ssb155480 READ_ENTER(&plistp->rwlock);
38046419Ssb155480
38056419Ssb155480 for (portp = plistp->headp; portp != NULL; portp = portp->nextp) {
38066419Ssb155480
38076419Ssb155480 vgen_vlan_unaware_port_reset(portp);
38086419Ssb155480
38096419Ssb155480 }
38106419Ssb155480
38116419Ssb155480 RW_EXIT(&plistp->rwlock);
38126419Ssb155480 }
38136419Ssb155480
38149336SSriharsha.Basavapatna@Sun.COM static void
vgen_reset_vsw_port(vgen_t * vgenp)38159336SSriharsha.Basavapatna@Sun.COM vgen_reset_vsw_port(vgen_t *vgenp)
38169336SSriharsha.Basavapatna@Sun.COM {
38179336SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp;
38189336SSriharsha.Basavapatna@Sun.COM
38199336SSriharsha.Basavapatna@Sun.COM if ((portp = vgenp->vsw_portp) != NULL) {
38209336SSriharsha.Basavapatna@Sun.COM vgen_port_reset(portp);
38219336SSriharsha.Basavapatna@Sun.COM }
38229336SSriharsha.Basavapatna@Sun.COM }
38239336SSriharsha.Basavapatna@Sun.COM
38241991Sheppo static void
vgen_setup_handshake_params(vgen_ldc_t * ldcp)382512011SSriharsha.Basavapatna@Sun.COM vgen_setup_handshake_params(vgen_ldc_t *ldcp)
38261991Sheppo {
382712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
38281991Sheppo
38291991Sheppo /*
38301991Sheppo * clear local handshake params and initialize.
38311991Sheppo */
38321991Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams));
38331991Sheppo
38341991Sheppo /* set version to the highest version supported */
38351991Sheppo ldcp->local_hparams.ver_major =
38364650Sraghuram ldcp->vgen_versions[0].ver_major;
38371991Sheppo ldcp->local_hparams.ver_minor =
38384650Sraghuram ldcp->vgen_versions[0].ver_minor;
38391991Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK;
38401991Sheppo
38411991Sheppo /* set attr_info params */
38426419Ssb155480 ldcp->local_hparams.mtu = vgenp->max_frame_size;
38431991Sheppo ldcp->local_hparams.addr =
38445462Swentaoy vnet_macaddr_strtoul(vgenp->macaddr);
38451991Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC;
38465935Ssb155480 ldcp->local_hparams.xfer_mode = VIO_DRING_MODE_V1_0;
38471991Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */
38489336SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.physlink_update = PHYSLINK_UPDATE_NONE;
38491991Sheppo
385012011SSriharsha.Basavapatna@Sun.COM /* reset protocol version specific function pointers */
385112011SSriharsha.Basavapatna@Sun.COM vgen_reset_vnet_proto_ops(ldcp);
38521991Sheppo ldcp->local_hparams.dring_ident = 0;
385312011SSriharsha.Basavapatna@Sun.COM ldcp->local_hparams.dring_ready = B_FALSE;
38541991Sheppo
38551991Sheppo /* clear peer_hparams */
38561991Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams));
385712011SSriharsha.Basavapatna@Sun.COM ldcp->peer_hparams.dring_ready = B_FALSE;
385812011SSriharsha.Basavapatna@Sun.COM }
385912011SSriharsha.Basavapatna@Sun.COM
386012011SSriharsha.Basavapatna@Sun.COM /*
386112011SSriharsha.Basavapatna@Sun.COM * Process Channel Reset. We tear down the resources (timers, threads,
386212011SSriharsha.Basavapatna@Sun.COM * descriptor rings etc) associated with the channel and reinitialize the
386312011SSriharsha.Basavapatna@Sun.COM * channel based on the flags.
386412011SSriharsha.Basavapatna@Sun.COM *
386512011SSriharsha.Basavapatna@Sun.COM * Arguments:
386612011SSriharsha.Basavapatna@Sun.COM * ldcp: The channel being processed.
386712011SSriharsha.Basavapatna@Sun.COM *
386812011SSriharsha.Basavapatna@Sun.COM * flags:
386912011SSriharsha.Basavapatna@Sun.COM * VGEN_FLAG_EVT_RESET:
387012011SSriharsha.Basavapatna@Sun.COM * A ECONNRESET error occured while doing ldc operations such as
387112011SSriharsha.Basavapatna@Sun.COM * ldc_read() or ldc_write(); the channel is already reset and it
387212011SSriharsha.Basavapatna@Sun.COM * needs to be handled.
387312011SSriharsha.Basavapatna@Sun.COM * VGEN_FLAG_NEED_LDCRESET:
387412011SSriharsha.Basavapatna@Sun.COM * Some other errors occured and the error handling code needs to
387512011SSriharsha.Basavapatna@Sun.COM * explicitly reset the channel and restart handshake with the
387612011SSriharsha.Basavapatna@Sun.COM * peer. The error could be either in ldc operations or other
387712011SSriharsha.Basavapatna@Sun.COM * parts of the code such as timeouts or mdeg events etc.
387812011SSriharsha.Basavapatna@Sun.COM * VGEN_FLAG_UNINIT:
387912011SSriharsha.Basavapatna@Sun.COM * The channel is being torn down; no need to bring up the channel
388012011SSriharsha.Basavapatna@Sun.COM * after resetting.
388112011SSriharsha.Basavapatna@Sun.COM */
388212011SSriharsha.Basavapatna@Sun.COM static int
vgen_process_reset(vgen_ldc_t * ldcp,int flags)388312011SSriharsha.Basavapatna@Sun.COM vgen_process_reset(vgen_ldc_t *ldcp, int flags)
388412011SSriharsha.Basavapatna@Sun.COM {
388512011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
388612011SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp = ldcp->portp;
388712011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
388812011SSriharsha.Basavapatna@Sun.COM boolean_t is_vsw_port = B_FALSE;
388912011SSriharsha.Basavapatna@Sun.COM boolean_t link_update = B_FALSE;
389012011SSriharsha.Basavapatna@Sun.COM ldc_status_t istatus;
389112011SSriharsha.Basavapatna@Sun.COM int rv;
389212011SSriharsha.Basavapatna@Sun.COM uint_t retries = 0;
389312011SSriharsha.Basavapatna@Sun.COM timeout_id_t htid = 0;
389412011SSriharsha.Basavapatna@Sun.COM timeout_id_t wd_tid = 0;
389512011SSriharsha.Basavapatna@Sun.COM
389612011SSriharsha.Basavapatna@Sun.COM if (portp == vgenp->vsw_portp) { /* vswitch port ? */
389712011SSriharsha.Basavapatna@Sun.COM is_vsw_port = B_TRUE;
389812011SSriharsha.Basavapatna@Sun.COM }
389912011SSriharsha.Basavapatna@Sun.COM
390012011SSriharsha.Basavapatna@Sun.COM /*
390112011SSriharsha.Basavapatna@Sun.COM * Report that the channel is being reset; it ensures that any HybridIO
390212011SSriharsha.Basavapatna@Sun.COM * configuration is torn down before we reset the channel if it is not
390312011SSriharsha.Basavapatna@Sun.COM * already reset (flags == VGEN_FLAG_NEED_LDCRESET).
390412011SSriharsha.Basavapatna@Sun.COM */
390512011SSriharsha.Basavapatna@Sun.COM if (is_vsw_port == B_TRUE) {
390612011SSriharsha.Basavapatna@Sun.COM vio_net_report_err_t rep_err = portp->vcb.vio_net_report_err;
390712011SSriharsha.Basavapatna@Sun.COM rep_err(portp->vhp, VIO_NET_RES_DOWN);
390812011SSriharsha.Basavapatna@Sun.COM }
390912011SSriharsha.Basavapatna@Sun.COM
391012011SSriharsha.Basavapatna@Sun.COM again:
391112011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
391212011SSriharsha.Basavapatna@Sun.COM
391312011SSriharsha.Basavapatna@Sun.COM /* Clear hstate and hphase */
391412011SSriharsha.Basavapatna@Sun.COM ldcp->hstate = 0;
391512011SSriharsha.Basavapatna@Sun.COM ldcp->hphase = VH_PHASE0;
391612011SSriharsha.Basavapatna@Sun.COM if (flags == VGEN_FLAG_NEED_LDCRESET || flags == VGEN_FLAG_UNINIT) {
39174647Sraghuram DWARN(vgenp, ldcp, "Doing Channel Reset...\n");
39182410Slm66018 (void) ldc_down(ldcp->ldc_handle);
39191991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus);
392012011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "Reset Done, ldc_status(%d)\n", istatus);
39211991Sheppo ldcp->ldc_status = istatus;
39222793Slm66018
392312011SSriharsha.Basavapatna@Sun.COM if (flags == VGEN_FLAG_UNINIT) {
392412011SSriharsha.Basavapatna@Sun.COM /* disable further callbacks */
392512011SSriharsha.Basavapatna@Sun.COM rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE);
392612011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
392712011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n");
392812011SSriharsha.Basavapatna@Sun.COM }
39292793Slm66018 }
393012011SSriharsha.Basavapatna@Sun.COM
393112011SSriharsha.Basavapatna@Sun.COM } else {
393212011SSriharsha.Basavapatna@Sun.COM /* flags == VGEN_FLAG_EVT_RESET */
393312011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ldc status(%d)\n", ldcp->ldc_status);
393412011SSriharsha.Basavapatna@Sun.COM }
39359336SSriharsha.Basavapatna@Sun.COM
39369336SSriharsha.Basavapatna@Sun.COM /*
39379336SSriharsha.Basavapatna@Sun.COM * As the connection is now reset, mark the channel
39389336SSriharsha.Basavapatna@Sun.COM * link_state as 'down' and notify the stack if needed.
39399336SSriharsha.Basavapatna@Sun.COM */
39409336SSriharsha.Basavapatna@Sun.COM if (ldcp->link_state != LINK_STATE_DOWN) {
39419336SSriharsha.Basavapatna@Sun.COM ldcp->link_state = LINK_STATE_DOWN;
39429336SSriharsha.Basavapatna@Sun.COM
394312011SSriharsha.Basavapatna@Sun.COM if (is_vsw_port == B_TRUE) { /* vswitch port ? */
39449336SSriharsha.Basavapatna@Sun.COM /*
39459336SSriharsha.Basavapatna@Sun.COM * As the channel link is down, mark physical link also
39469336SSriharsha.Basavapatna@Sun.COM * as down. After the channel comes back up and
39479336SSriharsha.Basavapatna@Sun.COM * handshake completes, we will get an update on the
39489336SSriharsha.Basavapatna@Sun.COM * physlink state from vswitch (if this device has been
39499336SSriharsha.Basavapatna@Sun.COM * configured to get phys link updates).
39509336SSriharsha.Basavapatna@Sun.COM */
39519336SSriharsha.Basavapatna@Sun.COM vgenp->phys_link_state = LINK_STATE_DOWN;
395212011SSriharsha.Basavapatna@Sun.COM link_update = B_TRUE;
395312011SSriharsha.Basavapatna@Sun.COM
395412011SSriharsha.Basavapatna@Sun.COM }
395512011SSriharsha.Basavapatna@Sun.COM }
395612011SSriharsha.Basavapatna@Sun.COM
395712011SSriharsha.Basavapatna@Sun.COM if (ldcp->htid != 0) {
395812011SSriharsha.Basavapatna@Sun.COM htid = ldcp->htid;
395912011SSriharsha.Basavapatna@Sun.COM ldcp->htid = 0;
396012011SSriharsha.Basavapatna@Sun.COM }
396112011SSriharsha.Basavapatna@Sun.COM
396212011SSriharsha.Basavapatna@Sun.COM if (ldcp->wd_tid != 0) {
396312011SSriharsha.Basavapatna@Sun.COM wd_tid = ldcp->wd_tid;
396412011SSriharsha.Basavapatna@Sun.COM ldcp->wd_tid = 0;
396512011SSriharsha.Basavapatna@Sun.COM }
396612011SSriharsha.Basavapatna@Sun.COM
396712011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
396812011SSriharsha.Basavapatna@Sun.COM
396912011SSriharsha.Basavapatna@Sun.COM /* Update link state to the stack */
397012011SSriharsha.Basavapatna@Sun.COM if (link_update == B_TRUE) {
397112011SSriharsha.Basavapatna@Sun.COM vgen_link_update(vgenp, ldcp->link_state);
397212011SSriharsha.Basavapatna@Sun.COM }
397312011SSriharsha.Basavapatna@Sun.COM
397412011SSriharsha.Basavapatna@Sun.COM /*
397512011SSriharsha.Basavapatna@Sun.COM * As the channel is being reset, redirect traffic to the peer through
397612011SSriharsha.Basavapatna@Sun.COM * vswitch, until the channel becomes ready to be used again.
397712011SSriharsha.Basavapatna@Sun.COM */
397812011SSriharsha.Basavapatna@Sun.COM if (is_vsw_port == B_FALSE && vgenp->vsw_portp != NULL) {
397912011SSriharsha.Basavapatna@Sun.COM (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE);
398012011SSriharsha.Basavapatna@Sun.COM }
398112011SSriharsha.Basavapatna@Sun.COM
398212011SSriharsha.Basavapatna@Sun.COM /* Cancel handshake watchdog timeout */
398312011SSriharsha.Basavapatna@Sun.COM if (htid) {
398412011SSriharsha.Basavapatna@Sun.COM (void) untimeout(htid);
398512011SSriharsha.Basavapatna@Sun.COM }
398612011SSriharsha.Basavapatna@Sun.COM
398712011SSriharsha.Basavapatna@Sun.COM /* Cancel transmit watchdog timeout */
398812011SSriharsha.Basavapatna@Sun.COM if (wd_tid) {
398912011SSriharsha.Basavapatna@Sun.COM (void) untimeout(wd_tid);
399012011SSriharsha.Basavapatna@Sun.COM }
399112011SSriharsha.Basavapatna@Sun.COM
399212011SSriharsha.Basavapatna@Sun.COM /* Stop the msg worker thread */
399312011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_TX_DRING && curthread != ldcp->msg_thread) {
399412011SSriharsha.Basavapatna@Sun.COM vgen_stop_msg_thread(ldcp);
399512011SSriharsha.Basavapatna@Sun.COM }
399612011SSriharsha.Basavapatna@Sun.COM
399712011SSriharsha.Basavapatna@Sun.COM /* Grab all locks while we tear down tx/rx resources */
399812011SSriharsha.Basavapatna@Sun.COM LDC_LOCK(ldcp);
399912011SSriharsha.Basavapatna@Sun.COM
400012011SSriharsha.Basavapatna@Sun.COM /* Destroy the local dring which is exported to the peer */
400112011SSriharsha.Basavapatna@Sun.COM vgen_destroy_dring(ldcp);
400212011SSriharsha.Basavapatna@Sun.COM
400312011SSriharsha.Basavapatna@Sun.COM /* Unmap the remote dring which is imported from the peer */
400412011SSriharsha.Basavapatna@Sun.COM vgen_unmap_dring(ldcp);
400512011SSriharsha.Basavapatna@Sun.COM
400612011SSriharsha.Basavapatna@Sun.COM /*
400712011SSriharsha.Basavapatna@Sun.COM * Bring up the channel and restart handshake
400812011SSriharsha.Basavapatna@Sun.COM * only if the channel is not being torn down.
400912011SSriharsha.Basavapatna@Sun.COM */
401012011SSriharsha.Basavapatna@Sun.COM if (flags != VGEN_FLAG_UNINIT) {
401112011SSriharsha.Basavapatna@Sun.COM
401212011SSriharsha.Basavapatna@Sun.COM /* Setup handshake parameters to restart a new handshake */
401312011SSriharsha.Basavapatna@Sun.COM vgen_setup_handshake_params(ldcp);
401412011SSriharsha.Basavapatna@Sun.COM
401512011SSriharsha.Basavapatna@Sun.COM /* Bring the channel up */
401612011SSriharsha.Basavapatna@Sun.COM vgen_ldc_up(ldcp);
401712011SSriharsha.Basavapatna@Sun.COM
401812011SSriharsha.Basavapatna@Sun.COM if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
401912011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ldc_status err\n");
402012011SSriharsha.Basavapatna@Sun.COM } else {
402112011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_status = istatus;
402212011SSriharsha.Basavapatna@Sun.COM }
402312011SSriharsha.Basavapatna@Sun.COM
402412011SSriharsha.Basavapatna@Sun.COM /* If the channel is UP, start handshake */
402512011SSriharsha.Basavapatna@Sun.COM if (ldcp->ldc_status == LDC_UP) {
402612011SSriharsha.Basavapatna@Sun.COM
402712011SSriharsha.Basavapatna@Sun.COM if (is_vsw_port == B_FALSE) {
402812011SSriharsha.Basavapatna@Sun.COM /*
402912011SSriharsha.Basavapatna@Sun.COM * Channel is up; use this port from now on.
403012011SSriharsha.Basavapatna@Sun.COM */
403112011SSriharsha.Basavapatna@Sun.COM (void) atomic_swap_32(&portp->use_vsw_port,
403212011SSriharsha.Basavapatna@Sun.COM B_FALSE);
403312011SSriharsha.Basavapatna@Sun.COM }
403412011SSriharsha.Basavapatna@Sun.COM
403512011SSriharsha.Basavapatna@Sun.COM /* Initialize local session id */
403612011SSriharsha.Basavapatna@Sun.COM ldcp->local_sid = ddi_get_lbolt();
403712011SSriharsha.Basavapatna@Sun.COM
403812011SSriharsha.Basavapatna@Sun.COM /* clear peer session id */
403912011SSriharsha.Basavapatna@Sun.COM ldcp->peer_sid = 0;
404012011SSriharsha.Basavapatna@Sun.COM
404112011SSriharsha.Basavapatna@Sun.COM /*
404212011SSriharsha.Basavapatna@Sun.COM * Initiate Handshake process with peer ldc endpoint by
404312011SSriharsha.Basavapatna@Sun.COM * sending version info vio message. If that fails we
404412011SSriharsha.Basavapatna@Sun.COM * go back to the top of this function to process the
404512011SSriharsha.Basavapatna@Sun.COM * error again. Note that we can be in this loop for
404612011SSriharsha.Basavapatna@Sun.COM * 'vgen_ldc_max_resets' times, after which the channel
404712011SSriharsha.Basavapatna@Sun.COM * is not brought up.
404812011SSriharsha.Basavapatna@Sun.COM */
404912011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->tclock);
405012011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->txlock);
405112011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->wrlock);
405212011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->rxlock);
405312011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
40549336SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
405512011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
405612011SSriharsha.Basavapatna@Sun.COM if (rv == ECONNRESET) {
405712011SSriharsha.Basavapatna@Sun.COM flags = VGEN_FLAG_EVT_RESET;
405812011SSriharsha.Basavapatna@Sun.COM } else {
405912011SSriharsha.Basavapatna@Sun.COM flags = VGEN_FLAG_NEED_LDCRESET;
406012011SSriharsha.Basavapatna@Sun.COM }
406112011SSriharsha.Basavapatna@Sun.COM
406212011SSriharsha.Basavapatna@Sun.COM /*
406312011SSriharsha.Basavapatna@Sun.COM * We still hold 'reset_in_progress'; so we can
406412011SSriharsha.Basavapatna@Sun.COM * just loop back to the top to restart error
406512011SSriharsha.Basavapatna@Sun.COM * processing.
406612011SSriharsha.Basavapatna@Sun.COM */
406712011SSriharsha.Basavapatna@Sun.COM goto again;
406812011SSriharsha.Basavapatna@Sun.COM }
406912011SSriharsha.Basavapatna@Sun.COM } else {
407012011SSriharsha.Basavapatna@Sun.COM LDC_UNLOCK(ldcp);
40719336SSriharsha.Basavapatna@Sun.COM }
407212011SSriharsha.Basavapatna@Sun.COM
407312011SSriharsha.Basavapatna@Sun.COM } else { /* flags == VGEN_FLAG_UNINIT */
407412011SSriharsha.Basavapatna@Sun.COM
407512011SSriharsha.Basavapatna@Sun.COM /* Close the channel - retry on EAGAIN */
407612011SSriharsha.Basavapatna@Sun.COM while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) {
407712011SSriharsha.Basavapatna@Sun.COM if (++retries > vgen_ldccl_retries) {
407812011SSriharsha.Basavapatna@Sun.COM break;
407912011SSriharsha.Basavapatna@Sun.COM }
408012011SSriharsha.Basavapatna@Sun.COM drv_usecwait(VGEN_LDC_CLOSE_DELAY);
408112011SSriharsha.Basavapatna@Sun.COM }
408212011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
408312011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE,
408412011SSriharsha.Basavapatna@Sun.COM "!vnet%d: Error(%d) closing the channel(0x%lx)\n",
408512011SSriharsha.Basavapatna@Sun.COM vgenp->instance, rv, ldcp->ldc_id);
408612011SSriharsha.Basavapatna@Sun.COM }
408712011SSriharsha.Basavapatna@Sun.COM
408812011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_reset_count = 0;
408912011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_status = LDC_INIT;
409012011SSriharsha.Basavapatna@Sun.COM ldcp->flags &= ~(CHANNEL_STARTED);
409112011SSriharsha.Basavapatna@Sun.COM
409212011SSriharsha.Basavapatna@Sun.COM LDC_UNLOCK(ldcp);
409312011SSriharsha.Basavapatna@Sun.COM }
409412011SSriharsha.Basavapatna@Sun.COM
409512011SSriharsha.Basavapatna@Sun.COM /* Done processing channel reset; clear the atomic flag */
409612011SSriharsha.Basavapatna@Sun.COM ldcp->reset_in_progress = 0;
409712011SSriharsha.Basavapatna@Sun.COM return (0);
40981991Sheppo }
40991991Sheppo
41001991Sheppo /*
41011991Sheppo * Initiate handshake with the peer by sending various messages
41021991Sheppo * based on the handshake-phase that the channel is currently in.
41031991Sheppo */
410412011SSriharsha.Basavapatna@Sun.COM static int
vgen_handshake(vgen_ldc_t * ldcp)41051991Sheppo vgen_handshake(vgen_ldc_t *ldcp)
41061991Sheppo {
41079336SSriharsha.Basavapatna@Sun.COM uint32_t hphase = ldcp->hphase;
41089336SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
41099336SSriharsha.Basavapatna@Sun.COM int rv = 0;
411012011SSriharsha.Basavapatna@Sun.COM timeout_id_t htid;
41111991Sheppo
41121991Sheppo switch (hphase) {
41131991Sheppo
41141991Sheppo case VH_PHASE1:
41151991Sheppo
41161991Sheppo /*
41171991Sheppo * start timer, for entire handshake process, turn this timer
41181991Sheppo * off if all phases of handshake complete successfully and
411912011SSriharsha.Basavapatna@Sun.COM * hphase goes to VH_DONE(below) or channel is reset due to
412012011SSriharsha.Basavapatna@Sun.COM * errors or vgen_ldc_uninit() is invoked(vgen_stop).
41211991Sheppo */
41227572SWentao.Yang@Sun.COM ASSERT(ldcp->htid == 0);
41231991Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp,
41245171Ssb155480 drv_usectohz(vgen_hwd_interval * MICROSEC));
41251991Sheppo
41261991Sheppo /* Phase 1 involves negotiating the version */
41272793Slm66018 rv = vgen_send_version_negotiate(ldcp);
41281991Sheppo break;
41291991Sheppo
41301991Sheppo case VH_PHASE2:
41312793Slm66018 rv = vgen_handshake_phase2(ldcp);
41321991Sheppo break;
41331991Sheppo
41341991Sheppo case VH_PHASE3:
413512011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake_phase3(ldcp);
413612011SSriharsha.Basavapatna@Sun.COM break;
413712011SSriharsha.Basavapatna@Sun.COM
413812011SSriharsha.Basavapatna@Sun.COM case VH_PHASE4:
41392793Slm66018 rv = vgen_send_rdx_info(ldcp);
41401991Sheppo break;
41411991Sheppo
41421991Sheppo case VH_DONE:
414312011SSriharsha.Basavapatna@Sun.COM
414412011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_reset_count = 0;
414512011SSriharsha.Basavapatna@Sun.COM
41464647Sraghuram DBG1(vgenp, ldcp, "Handshake Done\n");
41471991Sheppo
41489336SSriharsha.Basavapatna@Sun.COM /*
41499336SSriharsha.Basavapatna@Sun.COM * The channel is up and handshake is done successfully. Now we
41509336SSriharsha.Basavapatna@Sun.COM * can mark the channel link_state as 'up'. We also notify the
41519336SSriharsha.Basavapatna@Sun.COM * stack if the channel is connected to vswitch.
41529336SSriharsha.Basavapatna@Sun.COM */
41539336SSriharsha.Basavapatna@Sun.COM ldcp->link_state = LINK_STATE_UP;
41549336SSriharsha.Basavapatna@Sun.COM
41555171Ssb155480 if (ldcp->portp == vgenp->vsw_portp) {
41565171Ssb155480 /*
41575171Ssb155480 * If this channel(port) is connected to vsw,
41585171Ssb155480 * need to sync multicast table with vsw.
41595171Ssb155480 */
41602793Slm66018 rv = vgen_send_mcast_info(ldcp);
416112011SSriharsha.Basavapatna@Sun.COM if (rv != VGEN_SUCCESS)
416211543SWentao.Yang@Sun.COM break;
41631991Sheppo
41649336SSriharsha.Basavapatna@Sun.COM if (vgenp->pls_negotiated == B_FALSE) {
41659336SSriharsha.Basavapatna@Sun.COM /*
41669336SSriharsha.Basavapatna@Sun.COM * We haven't negotiated with vswitch to get
41679336SSriharsha.Basavapatna@Sun.COM * physical link state updates. We can update
41689336SSriharsha.Basavapatna@Sun.COM * update the stack at this point as the
41699336SSriharsha.Basavapatna@Sun.COM * channel to vswitch is up and the handshake
41709336SSriharsha.Basavapatna@Sun.COM * is done successfully.
41719336SSriharsha.Basavapatna@Sun.COM *
41729336SSriharsha.Basavapatna@Sun.COM * If we have negotiated to get physical link
41739336SSriharsha.Basavapatna@Sun.COM * state updates, then we won't notify the
41749336SSriharsha.Basavapatna@Sun.COM * the stack here; we do that as soon as
41759336SSriharsha.Basavapatna@Sun.COM * vswitch sends us the initial phys link state
41769336SSriharsha.Basavapatna@Sun.COM * (see vgen_handle_physlink_info()).
41779336SSriharsha.Basavapatna@Sun.COM */
417811543SWentao.Yang@Sun.COM mutex_exit(&ldcp->cblock);
41799336SSriharsha.Basavapatna@Sun.COM vgen_link_update(vgenp, ldcp->link_state);
418011543SWentao.Yang@Sun.COM mutex_enter(&ldcp->cblock);
41819336SSriharsha.Basavapatna@Sun.COM }
418212011SSriharsha.Basavapatna@Sun.COM }
418312011SSriharsha.Basavapatna@Sun.COM
418412011SSriharsha.Basavapatna@Sun.COM if (ldcp->htid != 0) {
418512011SSriharsha.Basavapatna@Sun.COM htid = ldcp->htid;
418612011SSriharsha.Basavapatna@Sun.COM ldcp->htid = 0;
418712011SSriharsha.Basavapatna@Sun.COM
418812011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
418912011SSriharsha.Basavapatna@Sun.COM (void) untimeout(htid);
419012011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
41911991Sheppo }
41922793Slm66018
41932793Slm66018 /*
41942793Slm66018 * Check if mac layer should be notified to restart
41952793Slm66018 * transmissions. This can happen if the channel got
419612011SSriharsha.Basavapatna@Sun.COM * reset and while tx_blocked is set.
41972793Slm66018 */
41982793Slm66018 mutex_enter(&ldcp->tclock);
419912011SSriharsha.Basavapatna@Sun.COM if (ldcp->tx_blocked) {
42006495Sspeer vio_net_tx_update_t vtx_update =
42016495Sspeer ldcp->portp->vcb.vio_net_tx_update;
42026495Sspeer
420312011SSriharsha.Basavapatna@Sun.COM ldcp->tx_blocked = B_FALSE;
42046495Sspeer vtx_update(ldcp->portp->vhp);
42052793Slm66018 }
42062793Slm66018 mutex_exit(&ldcp->tclock);
42072793Slm66018
420812011SSriharsha.Basavapatna@Sun.COM /* start transmit watchdog timer */
420912011SSriharsha.Basavapatna@Sun.COM ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp,
421012011SSriharsha.Basavapatna@Sun.COM drv_usectohz(vgen_txwd_interval * 1000));
421112011SSriharsha.Basavapatna@Sun.COM
42121991Sheppo break;
42131991Sheppo
42141991Sheppo default:
42151991Sheppo break;
42161991Sheppo }
42172793Slm66018
421812011SSriharsha.Basavapatna@Sun.COM return (rv);
42191991Sheppo }
42201991Sheppo
42211991Sheppo /*
42221991Sheppo * Check if the current handshake phase has completed successfully and
42231991Sheppo * return the status.
42241991Sheppo */
42251991Sheppo static int
vgen_handshake_done(vgen_ldc_t * ldcp)42261991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp)
42271991Sheppo {
42284647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
42291991Sheppo uint32_t hphase = ldcp->hphase;
42301991Sheppo int status = 0;
42311991Sheppo
42321991Sheppo switch (hphase) {
42331991Sheppo
42341991Sheppo case VH_PHASE1:
42351991Sheppo /*
42361991Sheppo * Phase1 is done, if version negotiation
42371991Sheppo * completed successfully.
42381991Sheppo */
42391991Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) ==
42404650Sraghuram VER_NEGOTIATED);
42411991Sheppo break;
42421991Sheppo
42431991Sheppo case VH_PHASE2:
42441991Sheppo /*
424512011SSriharsha.Basavapatna@Sun.COM * Phase 2 is done, if attr info
424612011SSriharsha.Basavapatna@Sun.COM * has been exchanged successfully.
42471991Sheppo */
424812011SSriharsha.Basavapatna@Sun.COM status = ((ldcp->hstate & ATTR_INFO_EXCHANGED) ==
424912011SSriharsha.Basavapatna@Sun.COM ATTR_INFO_EXCHANGED);
42501991Sheppo break;
42511991Sheppo
42521991Sheppo case VH_PHASE3:
425312011SSriharsha.Basavapatna@Sun.COM /*
425412011SSriharsha.Basavapatna@Sun.COM * Phase 3 is done, if dring registration
425512011SSriharsha.Basavapatna@Sun.COM * has been exchanged successfully.
425612011SSriharsha.Basavapatna@Sun.COM */
425712011SSriharsha.Basavapatna@Sun.COM status = ((ldcp->hstate & DRING_INFO_EXCHANGED) ==
425812011SSriharsha.Basavapatna@Sun.COM DRING_INFO_EXCHANGED);
425912011SSriharsha.Basavapatna@Sun.COM break;
426012011SSriharsha.Basavapatna@Sun.COM
426112011SSriharsha.Basavapatna@Sun.COM case VH_PHASE4:
426212011SSriharsha.Basavapatna@Sun.COM /* Phase 4 is done, if rdx msg has been exchanged */
42631991Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) ==
42644650Sraghuram RDX_EXCHANGED);
42651991Sheppo break;
42661991Sheppo
42671991Sheppo default:
42681991Sheppo break;
42691991Sheppo }
42701991Sheppo
42711991Sheppo if (status == 0) {
42721991Sheppo return (VGEN_FAILURE);
42731991Sheppo }
42744647Sraghuram DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase);
42751991Sheppo return (VGEN_SUCCESS);
42761991Sheppo }
42771991Sheppo
42789336SSriharsha.Basavapatna@Sun.COM /*
42799336SSriharsha.Basavapatna@Sun.COM * Link State Update Notes:
42809336SSriharsha.Basavapatna@Sun.COM * The link state of the channel connected to vswitch is reported as the link
42819336SSriharsha.Basavapatna@Sun.COM * state of the vnet device, by default. If the channel is down or reset, then
42829336SSriharsha.Basavapatna@Sun.COM * the link state is marked 'down'. If the channel is 'up' *and* handshake
42839336SSriharsha.Basavapatna@Sun.COM * between the vnet and vswitch is successful, then the link state is marked
42849336SSriharsha.Basavapatna@Sun.COM * 'up'. If physical network link state is desired, then the vnet device must
42859336SSriharsha.Basavapatna@Sun.COM * be configured to get physical link updates and the 'linkprop' property
42869336SSriharsha.Basavapatna@Sun.COM * in the virtual-device MD node indicates this. As part of attribute exchange
42879336SSriharsha.Basavapatna@Sun.COM * the vnet device negotiates with the vswitch to obtain physical link state
42889336SSriharsha.Basavapatna@Sun.COM * updates. If it successfully negotiates, vswitch sends an initial physlink
42899336SSriharsha.Basavapatna@Sun.COM * msg once the handshake is done and further whenever the physical link state
42909336SSriharsha.Basavapatna@Sun.COM * changes. Currently we don't have mac layer interfaces to report two distinct
42919336SSriharsha.Basavapatna@Sun.COM * link states - virtual and physical. Thus, if the vnet has been configured to
42929336SSriharsha.Basavapatna@Sun.COM * get physical link updates, then the link status will be reported as 'up'
42939336SSriharsha.Basavapatna@Sun.COM * only when both the virtual and physical links are up.
42949336SSriharsha.Basavapatna@Sun.COM */
42959336SSriharsha.Basavapatna@Sun.COM static void
vgen_link_update(vgen_t * vgenp,link_state_t link_state)42969336SSriharsha.Basavapatna@Sun.COM vgen_link_update(vgen_t *vgenp, link_state_t link_state)
42979336SSriharsha.Basavapatna@Sun.COM {
42989336SSriharsha.Basavapatna@Sun.COM vnet_link_update(vgenp->vnetp, link_state);
42999336SSriharsha.Basavapatna@Sun.COM }
43009336SSriharsha.Basavapatna@Sun.COM
43011991Sheppo /*
43021991Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer
43031991Sheppo * to a version info msg that we sent.
43041991Sheppo */
43052793Slm66018 static int
vgen_handle_version_negotiate(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)43061991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
43071991Sheppo {
43084647Sraghuram vgen_t *vgenp;
43091991Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp;
43101991Sheppo int ack = 0;
43111991Sheppo int failed = 0;
43121991Sheppo int idx;
43131991Sheppo vgen_ver_t *versions = ldcp->vgen_versions;
43142793Slm66018 int rv = 0;
43151991Sheppo
43164647Sraghuram vgenp = LDC_TO_VGEN(ldcp);
43174647Sraghuram DBG1(vgenp, ldcp, "enter\n");
43181991Sheppo switch (tagp->vio_subtype) {
43191991Sheppo case VIO_SUBTYPE_INFO:
43201991Sheppo
43211991Sheppo /* Cache sid of peer if this is the first time */
43221991Sheppo if (ldcp->peer_sid == 0) {
43234647Sraghuram DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n",
43244647Sraghuram tagp->vio_sid);
43251991Sheppo ldcp->peer_sid = tagp->vio_sid;
43261991Sheppo }
43271991Sheppo
43281991Sheppo if (ldcp->hphase != VH_PHASE1) {
43291991Sheppo /*
43301991Sheppo * If we are not already in VH_PHASE1, reset to
43311991Sheppo * pre-handshake state, and initiate handshake
43321991Sheppo * to the peer too.
43331991Sheppo */
433412011SSriharsha.Basavapatna@Sun.COM return (EINVAL);
43351991Sheppo }
433612011SSriharsha.Basavapatna@Sun.COM
43371991Sheppo ldcp->hstate |= VER_INFO_RCVD;
43381991Sheppo
43391991Sheppo /* save peer's requested values */
43401991Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major;
43411991Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor;
43421991Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class;
43431991Sheppo
43441991Sheppo if ((vermsg->dev_class != VDEV_NETWORK) &&
43451991Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) {
43461991Sheppo /* unsupported dev_class, send NACK */
43471991Sheppo
43484647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
43492793Slm66018
43501991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK;
43511991Sheppo tagp->vio_sid = ldcp->local_sid;
43521991Sheppo /* send reply msg back to peer */
43532793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
43541991Sheppo sizeof (*vermsg), B_FALSE);
43552793Slm66018 if (rv != VGEN_SUCCESS) {
43562793Slm66018 return (rv);
43572793Slm66018 }
43582793Slm66018 return (VGEN_FAILURE);
43591991Sheppo }
43601991Sheppo
43614647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n",
43624647Sraghuram vermsg->ver_major, vermsg->ver_minor);
43631991Sheppo
43641991Sheppo idx = 0;
43651991Sheppo
43661991Sheppo for (;;) {
43671991Sheppo
43681991Sheppo if (vermsg->ver_major > versions[idx].ver_major) {
43691991Sheppo
43701991Sheppo /* nack with next lower version */
43711991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK;
43721991Sheppo vermsg->ver_major = versions[idx].ver_major;
43731991Sheppo vermsg->ver_minor = versions[idx].ver_minor;
43741991Sheppo break;
43751991Sheppo }
43761991Sheppo
43771991Sheppo if (vermsg->ver_major == versions[idx].ver_major) {
43781991Sheppo
43791991Sheppo /* major version match - ACK version */
43801991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK;
43811991Sheppo ack = 1;
43821991Sheppo
43831991Sheppo /*
43841991Sheppo * lower minor version to the one this endpt
43851991Sheppo * supports, if necessary
43861991Sheppo */
43871991Sheppo if (vermsg->ver_minor >
43881991Sheppo versions[idx].ver_minor) {
43891991Sheppo vermsg->ver_minor =
43904650Sraghuram versions[idx].ver_minor;
43911991Sheppo ldcp->peer_hparams.ver_minor =
43924650Sraghuram versions[idx].ver_minor;
43931991Sheppo }
43941991Sheppo break;
43951991Sheppo }
43961991Sheppo
43971991Sheppo idx++;
43981991Sheppo
43991991Sheppo if (idx == VGEN_NUM_VER) {
44001991Sheppo
44011991Sheppo /* no version match - send NACK */
44021991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK;
44031991Sheppo vermsg->ver_major = 0;
44041991Sheppo vermsg->ver_minor = 0;
44051991Sheppo failed = 1;
44061991Sheppo break;
44071991Sheppo }
44081991Sheppo
44091991Sheppo }
44101991Sheppo
44111991Sheppo tagp->vio_sid = ldcp->local_sid;
44121991Sheppo
44131991Sheppo /* send reply msg back to peer */
44142793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg),
44152793Slm66018 B_FALSE);
44162793Slm66018 if (rv != VGEN_SUCCESS) {
44172793Slm66018 return (rv);
44181991Sheppo }
44191991Sheppo
44201991Sheppo if (ack) {
44211991Sheppo ldcp->hstate |= VER_ACK_SENT;
44224647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n",
44234647Sraghuram vermsg->ver_major, vermsg->ver_minor);
44241991Sheppo }
44251991Sheppo if (failed) {
44264647Sraghuram DWARN(vgenp, ldcp, "Negotiation Failed\n");
44272793Slm66018 return (VGEN_FAILURE);
44281991Sheppo }
44291991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
44301991Sheppo
44311991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */
44321991Sheppo
44331991Sheppo /* local and peer versions match? */
44341991Sheppo ASSERT((ldcp->local_hparams.ver_major ==
44354650Sraghuram ldcp->peer_hparams.ver_major) &&
44364650Sraghuram (ldcp->local_hparams.ver_minor ==
44374650Sraghuram ldcp->peer_hparams.ver_minor));
44381991Sheppo
44395935Ssb155480 vgen_set_vnet_proto_ops(ldcp);
44405935Ssb155480
44411991Sheppo /* move to the next phase */
444212011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
444312011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
444412011SSriharsha.Basavapatna@Sun.COM return (rv);
444512011SSriharsha.Basavapatna@Sun.COM }
44461991Sheppo }
44471991Sheppo
44481991Sheppo break;
44491991Sheppo
44501991Sheppo case VIO_SUBTYPE_ACK:
44511991Sheppo
44521991Sheppo if (ldcp->hphase != VH_PHASE1) {
44531991Sheppo /* This should not happen. */
44544647Sraghuram DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase);
44552793Slm66018 return (VGEN_FAILURE);
44561991Sheppo }
44571991Sheppo
44581991Sheppo /* SUCCESS - we have agreed on a version */
44591991Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major;
44601991Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor;
44611991Sheppo ldcp->hstate |= VER_ACK_RCVD;
44621991Sheppo
44634647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n",
44644647Sraghuram vermsg->ver_major, vermsg->ver_minor);
44651991Sheppo
44661991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
44671991Sheppo
44681991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */
44691991Sheppo
44701991Sheppo /* local and peer versions match? */
44711991Sheppo ASSERT((ldcp->local_hparams.ver_major ==
44724650Sraghuram ldcp->peer_hparams.ver_major) &&
44734650Sraghuram (ldcp->local_hparams.ver_minor ==
44744650Sraghuram ldcp->peer_hparams.ver_minor));
44751991Sheppo
44765935Ssb155480 vgen_set_vnet_proto_ops(ldcp);
44775935Ssb155480
44781991Sheppo /* move to the next phase */
447912011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
448012011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
448112011SSriharsha.Basavapatna@Sun.COM return (rv);
448212011SSriharsha.Basavapatna@Sun.COM }
44831991Sheppo }
44841991Sheppo break;
44851991Sheppo
44861991Sheppo case VIO_SUBTYPE_NACK:
44871991Sheppo
44881991Sheppo if (ldcp->hphase != VH_PHASE1) {
44891991Sheppo /* This should not happen. */
44904647Sraghuram DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid "
44914647Sraghuram "Phase(%u)\n", ldcp->hphase);
44922793Slm66018 return (VGEN_FAILURE);
44931991Sheppo }
44941991Sheppo
44954647Sraghuram DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n",
44964647Sraghuram vermsg->ver_major, vermsg->ver_minor);
44971991Sheppo
44981991Sheppo /* check if version in NACK is zero */
44991991Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) {
45001991Sheppo /*
45011991Sheppo * Version Negotiation has failed.
45021991Sheppo */
45034647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n");
45042793Slm66018 return (VGEN_FAILURE);
45051991Sheppo }
45061991Sheppo
45071991Sheppo idx = 0;
45081991Sheppo
45091991Sheppo for (;;) {
45101991Sheppo
45111991Sheppo if (vermsg->ver_major > versions[idx].ver_major) {
45121991Sheppo /* select next lower version */
45131991Sheppo
45141991Sheppo ldcp->local_hparams.ver_major =
45154650Sraghuram versions[idx].ver_major;
45161991Sheppo ldcp->local_hparams.ver_minor =
45174650Sraghuram versions[idx].ver_minor;
45181991Sheppo break;
45191991Sheppo }
45201991Sheppo
45211991Sheppo if (vermsg->ver_major == versions[idx].ver_major) {
45221991Sheppo /* major version match */
45231991Sheppo
45241991Sheppo ldcp->local_hparams.ver_major =
45254650Sraghuram versions[idx].ver_major;
45261991Sheppo
45271991Sheppo ldcp->local_hparams.ver_minor =
45284650Sraghuram versions[idx].ver_minor;
45291991Sheppo break;
45301991Sheppo }
45311991Sheppo
45321991Sheppo idx++;
45331991Sheppo
45341991Sheppo if (idx == VGEN_NUM_VER) {
45351991Sheppo /*
45361991Sheppo * no version match.
45371991Sheppo * Version Negotiation has failed.
45381991Sheppo */
45394647Sraghuram DWARN(vgenp, ldcp,
45404647Sraghuram "Version Negotiation Failed\n");
45412793Slm66018 return (VGEN_FAILURE);
45421991Sheppo }
45431991Sheppo
45441991Sheppo }
45451991Sheppo
45462793Slm66018 rv = vgen_send_version_negotiate(ldcp);
45472793Slm66018 if (rv != VGEN_SUCCESS) {
45482793Slm66018 return (rv);
45491991Sheppo }
45501991Sheppo
45511991Sheppo break;
45521991Sheppo }
45532793Slm66018
45544647Sraghuram DBG1(vgenp, ldcp, "exit\n");
45552793Slm66018 return (VGEN_SUCCESS);
45561991Sheppo }
45571991Sheppo
45581991Sheppo static int
vgen_handle_attr_info(vgen_ldc_t * ldcp,vnet_attr_msg_t * msg)455912011SSriharsha.Basavapatna@Sun.COM vgen_handle_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
45601991Sheppo {
456112011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
45625935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams;
456312011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *rp = &ldcp->peer_hparams;
456412011SSriharsha.Basavapatna@Sun.COM uint32_t mtu;
456512011SSriharsha.Basavapatna@Sun.COM uint8_t dring_mode;
456612011SSriharsha.Basavapatna@Sun.COM
456712011SSriharsha.Basavapatna@Sun.COM ldcp->hstate |= ATTR_INFO_RCVD;
456812011SSriharsha.Basavapatna@Sun.COM
456912011SSriharsha.Basavapatna@Sun.COM /* save peer's values */
457012011SSriharsha.Basavapatna@Sun.COM rp->mtu = msg->mtu;
457112011SSriharsha.Basavapatna@Sun.COM rp->addr = msg->addr;
457212011SSriharsha.Basavapatna@Sun.COM rp->addr_type = msg->addr_type;
457312011SSriharsha.Basavapatna@Sun.COM rp->xfer_mode = msg->xfer_mode;
457412011SSriharsha.Basavapatna@Sun.COM rp->ack_freq = msg->ack_freq;
457512011SSriharsha.Basavapatna@Sun.COM rp->dring_mode = msg->options;
457612011SSriharsha.Basavapatna@Sun.COM
457712011SSriharsha.Basavapatna@Sun.COM /*
457812011SSriharsha.Basavapatna@Sun.COM * Process address type, ack frequency and transfer mode attributes.
457912011SSriharsha.Basavapatna@Sun.COM */
45807529SSriharsha.Basavapatna@Sun.COM if ((msg->addr_type != ADDR_TYPE_MAC) ||
45815935Ssb155480 (msg->ack_freq > 64) ||
45825935Ssb155480 (msg->xfer_mode != lp->xfer_mode)) {
45831991Sheppo return (VGEN_FAILURE);
45841991Sheppo }
45851991Sheppo
458612011SSriharsha.Basavapatna@Sun.COM /*
458712011SSriharsha.Basavapatna@Sun.COM * Process dring mode attribute.
458812011SSriharsha.Basavapatna@Sun.COM */
458912011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 6)) {
459012011SSriharsha.Basavapatna@Sun.COM /*
459112011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.6:
459212011SSriharsha.Basavapatna@Sun.COM * Though we are operating in v1.6 mode, it is possible that
459312011SSriharsha.Basavapatna@Sun.COM * RxDringData mode has been disabled either on this guest or
459412011SSriharsha.Basavapatna@Sun.COM * on the peer guest. If so, we revert to pre v1.6 behavior of
459512011SSriharsha.Basavapatna@Sun.COM * TxDring mode. But this must be agreed upon in both
459612011SSriharsha.Basavapatna@Sun.COM * directions of attr exchange. We first determine the mode
459712011SSriharsha.Basavapatna@Sun.COM * that can be negotiated.
459812011SSriharsha.Basavapatna@Sun.COM */
459912011SSriharsha.Basavapatna@Sun.COM if ((msg->options & VIO_RX_DRING_DATA) != 0 &&
4600*13098SWentao.Yang@Sun.COM vgen_mapin_avail(ldcp) == B_TRUE) {
460112011SSriharsha.Basavapatna@Sun.COM /*
460212011SSriharsha.Basavapatna@Sun.COM * We are capable of handling RxDringData AND the peer
460312011SSriharsha.Basavapatna@Sun.COM * is also capable of it; we enable RxDringData mode on
460412011SSriharsha.Basavapatna@Sun.COM * this channel.
460512011SSriharsha.Basavapatna@Sun.COM */
460612011SSriharsha.Basavapatna@Sun.COM dring_mode = VIO_RX_DRING_DATA;
460712011SSriharsha.Basavapatna@Sun.COM } else if ((msg->options & VIO_TX_DRING) != 0) {
460812011SSriharsha.Basavapatna@Sun.COM /*
460912011SSriharsha.Basavapatna@Sun.COM * If the peer is capable of TxDring mode, we
461012011SSriharsha.Basavapatna@Sun.COM * negotiate TxDring mode on this channel.
461112011SSriharsha.Basavapatna@Sun.COM */
461212011SSriharsha.Basavapatna@Sun.COM dring_mode = VIO_TX_DRING;
461312011SSriharsha.Basavapatna@Sun.COM } else {
461412011SSriharsha.Basavapatna@Sun.COM /*
461512011SSriharsha.Basavapatna@Sun.COM * We support only VIO_TX_DRING and VIO_RX_DRING_DATA
461612011SSriharsha.Basavapatna@Sun.COM * modes. We don't support VIO_RX_DRING mode.
461712011SSriharsha.Basavapatna@Sun.COM */
461812011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
461912011SSriharsha.Basavapatna@Sun.COM }
462012011SSriharsha.Basavapatna@Sun.COM
462112011SSriharsha.Basavapatna@Sun.COM /*
462212011SSriharsha.Basavapatna@Sun.COM * If we have received an ack for the attr info that we sent,
462312011SSriharsha.Basavapatna@Sun.COM * then check if the dring mode matches what the peer had ack'd
462412011SSriharsha.Basavapatna@Sun.COM * (saved in local hparams). If they don't match, we fail the
462512011SSriharsha.Basavapatna@Sun.COM * handshake.
462612011SSriharsha.Basavapatna@Sun.COM */
462712011SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_RCVD) {
462812011SSriharsha.Basavapatna@Sun.COM if (msg->options != lp->dring_mode) {
462912011SSriharsha.Basavapatna@Sun.COM /* send NACK */
463012011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
463112011SSriharsha.Basavapatna@Sun.COM }
463212011SSriharsha.Basavapatna@Sun.COM } else {
463312011SSriharsha.Basavapatna@Sun.COM /*
463412011SSriharsha.Basavapatna@Sun.COM * Save the negotiated dring mode in our attr
463512011SSriharsha.Basavapatna@Sun.COM * parameters, so it gets sent in the attr info from us
463612011SSriharsha.Basavapatna@Sun.COM * to the peer.
463712011SSriharsha.Basavapatna@Sun.COM */
463812011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = dring_mode;
463912011SSriharsha.Basavapatna@Sun.COM }
464012011SSriharsha.Basavapatna@Sun.COM
464112011SSriharsha.Basavapatna@Sun.COM /* save the negotiated dring mode in the msg to be replied */
464212011SSriharsha.Basavapatna@Sun.COM msg->options = dring_mode;
464312011SSriharsha.Basavapatna@Sun.COM }
464412011SSriharsha.Basavapatna@Sun.COM
464512011SSriharsha.Basavapatna@Sun.COM /*
464612011SSriharsha.Basavapatna@Sun.COM * Process MTU attribute.
464712011SSriharsha.Basavapatna@Sun.COM */
464812011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
464912011SSriharsha.Basavapatna@Sun.COM /*
465012011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4:
465112011SSriharsha.Basavapatna@Sun.COM * Validate mtu of the peer is at least ETHERMAX. Then, the mtu
465212011SSriharsha.Basavapatna@Sun.COM * is negotiated down to the minimum of our mtu and peer's mtu.
465312011SSriharsha.Basavapatna@Sun.COM */
465412011SSriharsha.Basavapatna@Sun.COM if (msg->mtu < ETHERMAX) {
465512011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
465612011SSriharsha.Basavapatna@Sun.COM }
465712011SSriharsha.Basavapatna@Sun.COM
465812011SSriharsha.Basavapatna@Sun.COM mtu = MIN(msg->mtu, vgenp->max_frame_size);
465912011SSriharsha.Basavapatna@Sun.COM
466012011SSriharsha.Basavapatna@Sun.COM /*
466112011SSriharsha.Basavapatna@Sun.COM * If we have received an ack for the attr info
466212011SSriharsha.Basavapatna@Sun.COM * that we sent, then check if the mtu computed
466312011SSriharsha.Basavapatna@Sun.COM * above matches the mtu that the peer had ack'd
466412011SSriharsha.Basavapatna@Sun.COM * (saved in local hparams). If they don't
466512011SSriharsha.Basavapatna@Sun.COM * match, we fail the handshake.
466612011SSriharsha.Basavapatna@Sun.COM */
466712011SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_RCVD) {
466812011SSriharsha.Basavapatna@Sun.COM if (mtu != lp->mtu) {
466912011SSriharsha.Basavapatna@Sun.COM /* send NACK */
467012011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
467112011SSriharsha.Basavapatna@Sun.COM }
467212011SSriharsha.Basavapatna@Sun.COM } else {
467312011SSriharsha.Basavapatna@Sun.COM /*
467412011SSriharsha.Basavapatna@Sun.COM * Save the mtu computed above in our
467512011SSriharsha.Basavapatna@Sun.COM * attr parameters, so it gets sent in
467612011SSriharsha.Basavapatna@Sun.COM * the attr info from us to the peer.
467712011SSriharsha.Basavapatna@Sun.COM */
467812011SSriharsha.Basavapatna@Sun.COM lp->mtu = mtu;
467912011SSriharsha.Basavapatna@Sun.COM }
468012011SSriharsha.Basavapatna@Sun.COM
468112011SSriharsha.Basavapatna@Sun.COM /* save the MIN mtu in the msg to be replied */
468212011SSriharsha.Basavapatna@Sun.COM msg->mtu = mtu;
468312011SSriharsha.Basavapatna@Sun.COM
468412011SSriharsha.Basavapatna@Sun.COM } else {
46857529SSriharsha.Basavapatna@Sun.COM /* versions < 1.4, mtu must match */
46867529SSriharsha.Basavapatna@Sun.COM if (msg->mtu != lp->mtu) {
46877529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
46887529SSriharsha.Basavapatna@Sun.COM }
46897529SSriharsha.Basavapatna@Sun.COM }
46907529SSriharsha.Basavapatna@Sun.COM
46911991Sheppo return (VGEN_SUCCESS);
46921991Sheppo }
46931991Sheppo
469412011SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_attr_ack(vgen_ldc_t * ldcp,vnet_attr_msg_t * msg)469512011SSriharsha.Basavapatna@Sun.COM vgen_handle_attr_ack(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg)
469612011SSriharsha.Basavapatna@Sun.COM {
469712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
469812011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
469912011SSriharsha.Basavapatna@Sun.COM
470012011SSriharsha.Basavapatna@Sun.COM /*
470112011SSriharsha.Basavapatna@Sun.COM * Process dring mode attribute.
470212011SSriharsha.Basavapatna@Sun.COM */
470312011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 6)) {
470412011SSriharsha.Basavapatna@Sun.COM /*
470512011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.6:
470612011SSriharsha.Basavapatna@Sun.COM * The ack msg sent by the peer contains the negotiated dring
470712011SSriharsha.Basavapatna@Sun.COM * mode between our capability (that we had sent in our attr
470812011SSriharsha.Basavapatna@Sun.COM * info) and the peer's capability.
470912011SSriharsha.Basavapatna@Sun.COM */
471012011SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_SENT) {
471112011SSriharsha.Basavapatna@Sun.COM /*
471212011SSriharsha.Basavapatna@Sun.COM * If we have sent an ack for the attr info msg from
471312011SSriharsha.Basavapatna@Sun.COM * the peer, check if the dring mode that was
471412011SSriharsha.Basavapatna@Sun.COM * negotiated then (saved in local hparams) matches the
471512011SSriharsha.Basavapatna@Sun.COM * mode that the peer has ack'd. If they don't match,
471612011SSriharsha.Basavapatna@Sun.COM * we fail the handshake.
471712011SSriharsha.Basavapatna@Sun.COM */
471812011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode != msg->options) {
471912011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
472012011SSriharsha.Basavapatna@Sun.COM }
472112011SSriharsha.Basavapatna@Sun.COM } else {
472212011SSriharsha.Basavapatna@Sun.COM if ((msg->options & lp->dring_mode) == 0) {
472312011SSriharsha.Basavapatna@Sun.COM /*
472412011SSriharsha.Basavapatna@Sun.COM * Peer ack'd with a mode that we don't
472512011SSriharsha.Basavapatna@Sun.COM * support; we fail the handshake.
472612011SSriharsha.Basavapatna@Sun.COM */
472712011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
472812011SSriharsha.Basavapatna@Sun.COM }
472912011SSriharsha.Basavapatna@Sun.COM if ((msg->options & (VIO_TX_DRING|VIO_RX_DRING_DATA))
473012011SSriharsha.Basavapatna@Sun.COM == (VIO_TX_DRING|VIO_RX_DRING_DATA)) {
473112011SSriharsha.Basavapatna@Sun.COM /*
473212011SSriharsha.Basavapatna@Sun.COM * Peer must ack with only one negotiated mode.
473312011SSriharsha.Basavapatna@Sun.COM * Otherwise fail handshake.
473412011SSriharsha.Basavapatna@Sun.COM */
473512011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
473612011SSriharsha.Basavapatna@Sun.COM }
473712011SSriharsha.Basavapatna@Sun.COM
473812011SSriharsha.Basavapatna@Sun.COM /*
473912011SSriharsha.Basavapatna@Sun.COM * Save the negotiated mode, so we can validate it when
474012011SSriharsha.Basavapatna@Sun.COM * we receive attr info from the peer.
474112011SSriharsha.Basavapatna@Sun.COM */
474212011SSriharsha.Basavapatna@Sun.COM lp->dring_mode = msg->options;
474312011SSriharsha.Basavapatna@Sun.COM }
474412011SSriharsha.Basavapatna@Sun.COM }
474512011SSriharsha.Basavapatna@Sun.COM
474612011SSriharsha.Basavapatna@Sun.COM /*
474712011SSriharsha.Basavapatna@Sun.COM * Process Physical Link Update attribute.
474812011SSriharsha.Basavapatna@Sun.COM */
474912011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 5) &&
475012011SSriharsha.Basavapatna@Sun.COM ldcp->portp == vgenp->vsw_portp) {
475112011SSriharsha.Basavapatna@Sun.COM /*
475212011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.5:
475312011SSriharsha.Basavapatna@Sun.COM * If the vnet device has been configured to get
475412011SSriharsha.Basavapatna@Sun.COM * physical link state updates, check the corresponding
475512011SSriharsha.Basavapatna@Sun.COM * bits in the ack msg, if the peer is vswitch.
475612011SSriharsha.Basavapatna@Sun.COM */
475712011SSriharsha.Basavapatna@Sun.COM if (((lp->physlink_update & PHYSLINK_UPDATE_STATE_MASK) ==
475812011SSriharsha.Basavapatna@Sun.COM PHYSLINK_UPDATE_STATE) &&
475912011SSriharsha.Basavapatna@Sun.COM ((msg->physlink_update & PHYSLINK_UPDATE_STATE_MASK) ==
476012011SSriharsha.Basavapatna@Sun.COM PHYSLINK_UPDATE_STATE_ACK)) {
476112011SSriharsha.Basavapatna@Sun.COM vgenp->pls_negotiated = B_TRUE;
476212011SSriharsha.Basavapatna@Sun.COM } else {
476312011SSriharsha.Basavapatna@Sun.COM vgenp->pls_negotiated = B_FALSE;
476412011SSriharsha.Basavapatna@Sun.COM }
476512011SSriharsha.Basavapatna@Sun.COM }
476612011SSriharsha.Basavapatna@Sun.COM
476712011SSriharsha.Basavapatna@Sun.COM /*
476812011SSriharsha.Basavapatna@Sun.COM * Process MTU attribute.
476912011SSriharsha.Basavapatna@Sun.COM */
477012011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) {
477112011SSriharsha.Basavapatna@Sun.COM /*
477212011SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4:
477312011SSriharsha.Basavapatna@Sun.COM * The ack msg sent by the peer contains the minimum of
477412011SSriharsha.Basavapatna@Sun.COM * our mtu (that we had sent in our attr info) and the
477512011SSriharsha.Basavapatna@Sun.COM * peer's mtu.
477612011SSriharsha.Basavapatna@Sun.COM *
477712011SSriharsha.Basavapatna@Sun.COM * If we have sent an ack for the attr info msg from
477812011SSriharsha.Basavapatna@Sun.COM * the peer, check if the mtu that was computed then
477912011SSriharsha.Basavapatna@Sun.COM * (saved in local hparams) matches the mtu that the
478012011SSriharsha.Basavapatna@Sun.COM * peer has ack'd. If they don't match, we fail the
478112011SSriharsha.Basavapatna@Sun.COM * handshake.
478212011SSriharsha.Basavapatna@Sun.COM */
478312011SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_SENT) {
478412011SSriharsha.Basavapatna@Sun.COM if (lp->mtu != msg->mtu) {
478512011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
478612011SSriharsha.Basavapatna@Sun.COM }
478712011SSriharsha.Basavapatna@Sun.COM } else {
478812011SSriharsha.Basavapatna@Sun.COM /*
478912011SSriharsha.Basavapatna@Sun.COM * If the mtu ack'd by the peer is > our mtu
479012011SSriharsha.Basavapatna@Sun.COM * fail handshake. Otherwise, save the mtu, so
479112011SSriharsha.Basavapatna@Sun.COM * we can validate it when we receive attr info
479212011SSriharsha.Basavapatna@Sun.COM * from our peer.
479312011SSriharsha.Basavapatna@Sun.COM */
479412011SSriharsha.Basavapatna@Sun.COM if (msg->mtu > lp->mtu) {
479512011SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE);
479612011SSriharsha.Basavapatna@Sun.COM }
479712011SSriharsha.Basavapatna@Sun.COM if (msg->mtu <= lp->mtu) {
479812011SSriharsha.Basavapatna@Sun.COM lp->mtu = msg->mtu;
479912011SSriharsha.Basavapatna@Sun.COM }
480012011SSriharsha.Basavapatna@Sun.COM }
480112011SSriharsha.Basavapatna@Sun.COM }
480212011SSriharsha.Basavapatna@Sun.COM
480312011SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
480412011SSriharsha.Basavapatna@Sun.COM }
480512011SSriharsha.Basavapatna@Sun.COM
480612011SSriharsha.Basavapatna@Sun.COM
48071991Sheppo /*
48081991Sheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer
48091991Sheppo * to an attr info msg that we sent.
48101991Sheppo */
48112793Slm66018 static int
vgen_handle_attr_msg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)481212011SSriharsha.Basavapatna@Sun.COM vgen_handle_attr_msg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
48131991Sheppo {
48147529SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
48157529SSriharsha.Basavapatna@Sun.COM vnet_attr_msg_t *msg = (vnet_attr_msg_t *)tagp;
48162793Slm66018 int rv = 0;
48171991Sheppo
48184647Sraghuram DBG1(vgenp, ldcp, "enter\n");
48191991Sheppo if (ldcp->hphase != VH_PHASE2) {
48204647Sraghuram DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d),"
48214647Sraghuram " Invalid Phase(%u)\n",
48224647Sraghuram tagp->vio_subtype, ldcp->hphase);
48232793Slm66018 return (VGEN_FAILURE);
48241991Sheppo }
48251991Sheppo switch (tagp->vio_subtype) {
48261991Sheppo case VIO_SUBTYPE_INFO:
48271991Sheppo
482812011SSriharsha.Basavapatna@Sun.COM rv = vgen_handle_attr_info(ldcp, msg);
482912011SSriharsha.Basavapatna@Sun.COM if (rv == VGEN_SUCCESS) {
48301991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK;
48317529SSriharsha.Basavapatna@Sun.COM } else {
48327529SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_NACK;
48331991Sheppo }
48341991Sheppo tagp->vio_sid = ldcp->local_sid;
48351991Sheppo
48361991Sheppo /* send reply msg back to peer */
48377529SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg),
48382793Slm66018 B_FALSE);
48392793Slm66018 if (rv != VGEN_SUCCESS) {
48402793Slm66018 return (rv);
48411991Sheppo }
48421991Sheppo
484312011SSriharsha.Basavapatna@Sun.COM if (tagp->vio_subtype == VIO_SUBTYPE_NACK) {
484412011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ATTR_NACK_SENT");
484512011SSriharsha.Basavapatna@Sun.COM break;
48461991Sheppo }
48471991Sheppo
484812011SSriharsha.Basavapatna@Sun.COM ldcp->hstate |= ATTR_ACK_SENT;
484912011SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n");
48501991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
485112011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
485212011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
485312011SSriharsha.Basavapatna@Sun.COM return (rv);
485412011SSriharsha.Basavapatna@Sun.COM }
48551991Sheppo }
48561991Sheppo
48571991Sheppo break;
48581991Sheppo
48591991Sheppo case VIO_SUBTYPE_ACK:
48601991Sheppo
486112011SSriharsha.Basavapatna@Sun.COM rv = vgen_handle_attr_ack(ldcp, msg);
486212011SSriharsha.Basavapatna@Sun.COM if (rv == VGEN_FAILURE) {
486312011SSriharsha.Basavapatna@Sun.COM break;
48647529SSriharsha.Basavapatna@Sun.COM }
48657529SSriharsha.Basavapatna@Sun.COM
48661991Sheppo ldcp->hstate |= ATTR_ACK_RCVD;
48674647Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n");
48681991Sheppo
48691991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
487012011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
487112011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
487212011SSriharsha.Basavapatna@Sun.COM return (rv);
487312011SSriharsha.Basavapatna@Sun.COM }
48741991Sheppo }
48751991Sheppo break;
48761991Sheppo
48771991Sheppo case VIO_SUBTYPE_NACK:
48781991Sheppo
48794647Sraghuram DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n");
48802793Slm66018 return (VGEN_FAILURE);
48811991Sheppo }
48824647Sraghuram DBG1(vgenp, ldcp, "exit\n");
48832793Slm66018 return (VGEN_SUCCESS);
48841991Sheppo }
48851991Sheppo
48861991Sheppo static int
vgen_handle_dring_reg_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)488712011SSriharsha.Basavapatna@Sun.COM vgen_handle_dring_reg_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
48881991Sheppo {
488912011SSriharsha.Basavapatna@Sun.COM int rv = 0;
489012011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
489112011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
489212011SSriharsha.Basavapatna@Sun.COM
489312011SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, ldcp, "DRING_INFO_RCVD");
489412011SSriharsha.Basavapatna@Sun.COM ldcp->hstate |= DRING_INFO_RCVD;
489512011SSriharsha.Basavapatna@Sun.COM
489612011SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 6) &&
489712011SSriharsha.Basavapatna@Sun.COM (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) {
489812011SSriharsha.Basavapatna@Sun.COM /*
489912011SSriharsha.Basavapatna@Sun.COM * The earlier version of Solaris vnet driver doesn't set the
490012011SSriharsha.Basavapatna@Sun.COM * option (VIO_TX_DRING in its case) correctly in its dring reg
490112011SSriharsha.Basavapatna@Sun.COM * message. We workaround that here by doing the check only
490212011SSriharsha.Basavapatna@Sun.COM * for versions >= v1.6.
490312011SSriharsha.Basavapatna@Sun.COM */
490412011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp,
490512011SSriharsha.Basavapatna@Sun.COM "Rcvd dring reg option (%d), negotiated mode (%d)\n",
490612011SSriharsha.Basavapatna@Sun.COM ((vio_dring_reg_msg_t *)tagp)->options, lp->dring_mode);
49071991Sheppo return (VGEN_FAILURE);
49081991Sheppo }
490912011SSriharsha.Basavapatna@Sun.COM
491012011SSriharsha.Basavapatna@Sun.COM /*
491112011SSriharsha.Basavapatna@Sun.COM * Map dring exported by the peer.
491212011SSriharsha.Basavapatna@Sun.COM */
491312011SSriharsha.Basavapatna@Sun.COM rv = vgen_map_dring(ldcp, (void *)tagp);
491412011SSriharsha.Basavapatna@Sun.COM if (rv != VGEN_SUCCESS) {
491512011SSriharsha.Basavapatna@Sun.COM return (rv);
491612011SSriharsha.Basavapatna@Sun.COM }
491712011SSriharsha.Basavapatna@Sun.COM
491812011SSriharsha.Basavapatna@Sun.COM /*
491912011SSriharsha.Basavapatna@Sun.COM * Map data buffers exported by the peer if we are in RxDringData mode.
492012011SSriharsha.Basavapatna@Sun.COM */
492112011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
492212011SSriharsha.Basavapatna@Sun.COM rv = vgen_map_data(ldcp, (void *)tagp);
492312011SSriharsha.Basavapatna@Sun.COM if (rv != VGEN_SUCCESS) {
492412011SSriharsha.Basavapatna@Sun.COM vgen_unmap_dring(ldcp);
492512011SSriharsha.Basavapatna@Sun.COM return (rv);
492612011SSriharsha.Basavapatna@Sun.COM }
492712011SSriharsha.Basavapatna@Sun.COM }
492812011SSriharsha.Basavapatna@Sun.COM
492912011SSriharsha.Basavapatna@Sun.COM if (ldcp->peer_hparams.dring_ready == B_FALSE) {
493012011SSriharsha.Basavapatna@Sun.COM ldcp->peer_hparams.dring_ready = B_TRUE;
493112011SSriharsha.Basavapatna@Sun.COM }
493212011SSriharsha.Basavapatna@Sun.COM
493312011SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
493412011SSriharsha.Basavapatna@Sun.COM }
493512011SSriharsha.Basavapatna@Sun.COM
493612011SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_dring_reg_ack(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)493712011SSriharsha.Basavapatna@Sun.COM vgen_handle_dring_reg_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
493812011SSriharsha.Basavapatna@Sun.COM {
493912011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
494012011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
494112011SSriharsha.Basavapatna@Sun.COM
494212011SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, ldcp, "DRING_ACK_RCVD");
494312011SSriharsha.Basavapatna@Sun.COM ldcp->hstate |= DRING_ACK_RCVD;
494412011SSriharsha.Basavapatna@Sun.COM
494512011SSriharsha.Basavapatna@Sun.COM if (lp->dring_ready) {
494612011SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
494712011SSriharsha.Basavapatna@Sun.COM }
494812011SSriharsha.Basavapatna@Sun.COM
494912011SSriharsha.Basavapatna@Sun.COM /* save dring_ident acked by peer */
495012011SSriharsha.Basavapatna@Sun.COM lp->dring_ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident;
495112011SSriharsha.Basavapatna@Sun.COM
495212011SSriharsha.Basavapatna@Sun.COM /* local dring is now ready */
495312011SSriharsha.Basavapatna@Sun.COM lp->dring_ready = B_TRUE;
495412011SSriharsha.Basavapatna@Sun.COM
49551991Sheppo return (VGEN_SUCCESS);
49561991Sheppo }
49571991Sheppo
49581991Sheppo /*
49591991Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from
49601991Sheppo * the peer to a dring register msg that we sent.
49611991Sheppo */
49622793Slm66018 static int
vgen_handle_dring_reg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)49631991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
49641991Sheppo {
496512011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
496612011SSriharsha.Basavapatna@Sun.COM int rv = 0;
496712011SSriharsha.Basavapatna@Sun.COM int msgsize;
496812011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
49691991Sheppo
49704647Sraghuram DBG1(vgenp, ldcp, "enter\n");
49711991Sheppo if (ldcp->hphase < VH_PHASE2) {
49721991Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */
49734647Sraghuram DWARN(vgenp, ldcp,
49744647Sraghuram "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n",
49754650Sraghuram tagp->vio_subtype, ldcp->hphase);
49762793Slm66018 return (VGEN_FAILURE);
49771991Sheppo }
497812011SSriharsha.Basavapatna@Sun.COM
49791991Sheppo switch (tagp->vio_subtype) {
49801991Sheppo case VIO_SUBTYPE_INFO:
49811991Sheppo
498212011SSriharsha.Basavapatna@Sun.COM rv = vgen_handle_dring_reg_info(ldcp, tagp);
498312011SSriharsha.Basavapatna@Sun.COM if (rv == VGEN_SUCCESS) {
498412011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_ACK;
49851991Sheppo } else {
498612011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_NACK;
49871991Sheppo }
498812011SSriharsha.Basavapatna@Sun.COM
49891991Sheppo tagp->vio_sid = ldcp->local_sid;
499012011SSriharsha.Basavapatna@Sun.COM
499112011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
499212011SSriharsha.Basavapatna@Sun.COM msgsize =
499312011SSriharsha.Basavapatna@Sun.COM VNET_DRING_REG_EXT_MSG_SIZE(ldcp->tx_data_ncookies);
499412011SSriharsha.Basavapatna@Sun.COM } else {
499512011SSriharsha.Basavapatna@Sun.COM msgsize = sizeof (vio_dring_reg_msg_t);
499612011SSriharsha.Basavapatna@Sun.COM }
499712011SSriharsha.Basavapatna@Sun.COM
49981991Sheppo /* send reply msg back to peer */
499912011SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)tagp, msgsize,
50002793Slm66018 B_FALSE);
50012793Slm66018 if (rv != VGEN_SUCCESS) {
50022793Slm66018 return (rv);
50031991Sheppo }
50041991Sheppo
500512011SSriharsha.Basavapatna@Sun.COM if (tagp->vio_subtype == VIO_SUBTYPE_NACK) {
50064647Sraghuram DWARN(vgenp, ldcp, "DRING_NACK_SENT");
50072793Slm66018 return (VGEN_FAILURE);
50081991Sheppo }
50091991Sheppo
501012011SSriharsha.Basavapatna@Sun.COM ldcp->hstate |= DRING_ACK_SENT;
501112011SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, ldcp, "DRING_ACK_SENT");
501212011SSriharsha.Basavapatna@Sun.COM
50131991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
501412011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
501512011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
501612011SSriharsha.Basavapatna@Sun.COM return (rv);
501712011SSriharsha.Basavapatna@Sun.COM }
50181991Sheppo }
50191991Sheppo break;
50201991Sheppo
50211991Sheppo case VIO_SUBTYPE_ACK:
50221991Sheppo
502312011SSriharsha.Basavapatna@Sun.COM rv = vgen_handle_dring_reg_ack(ldcp, tagp);
502412011SSriharsha.Basavapatna@Sun.COM if (rv == VGEN_FAILURE) {
502512011SSriharsha.Basavapatna@Sun.COM return (rv);
50261991Sheppo }
50271991Sheppo
50281991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
502912011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
503012011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
503112011SSriharsha.Basavapatna@Sun.COM return (rv);
503212011SSriharsha.Basavapatna@Sun.COM }
50331991Sheppo }
50341991Sheppo
50351991Sheppo break;
50361991Sheppo
50371991Sheppo case VIO_SUBTYPE_NACK:
50381991Sheppo
503912011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "DRING_NACK_RCVD");
50402793Slm66018 return (VGEN_FAILURE);
50411991Sheppo }
50424647Sraghuram DBG1(vgenp, ldcp, "exit\n");
50432793Slm66018 return (VGEN_SUCCESS);
50441991Sheppo }
50451991Sheppo
50461991Sheppo /*
50471991Sheppo * Handle a rdx info msg from the peer or an ACK/NACK
50481991Sheppo * from the peer to a rdx info msg that we sent.
50491991Sheppo */
50502793Slm66018 static int
vgen_handle_rdx_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)50511991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
50521991Sheppo {
505312011SSriharsha.Basavapatna@Sun.COM int rv = 0;
50544647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp);
50554647Sraghuram
50564647Sraghuram DBG1(vgenp, ldcp, "enter\n");
505712011SSriharsha.Basavapatna@Sun.COM if (ldcp->hphase != VH_PHASE4) {
50584647Sraghuram DWARN(vgenp, ldcp,
50594647Sraghuram "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n",
50604650Sraghuram tagp->vio_subtype, ldcp->hphase);
50612793Slm66018 return (VGEN_FAILURE);
50621991Sheppo }
50631991Sheppo switch (tagp->vio_subtype) {
50641991Sheppo case VIO_SUBTYPE_INFO:
50651991Sheppo
50664647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n");
50671991Sheppo ldcp->hstate |= RDX_INFO_RCVD;
50681991Sheppo
50691991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK;
50701991Sheppo tagp->vio_sid = ldcp->local_sid;
50711991Sheppo /* send reply msg back to peer */
50722793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t),
50732793Slm66018 B_FALSE);
50742793Slm66018 if (rv != VGEN_SUCCESS) {
50752793Slm66018 return (rv);
50761991Sheppo }
50771991Sheppo
50781991Sheppo ldcp->hstate |= RDX_ACK_SENT;
50794647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_SENT \n");
50801991Sheppo
50811991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
508212011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
508312011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
508412011SSriharsha.Basavapatna@Sun.COM return (rv);
508512011SSriharsha.Basavapatna@Sun.COM }
50861991Sheppo }
50871991Sheppo
50881991Sheppo break;
50891991Sheppo
50901991Sheppo case VIO_SUBTYPE_ACK:
50911991Sheppo
50921991Sheppo ldcp->hstate |= RDX_ACK_RCVD;
50931991Sheppo
50944647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n");
50951991Sheppo
50961991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) {
509712011SSriharsha.Basavapatna@Sun.COM rv = vgen_handshake(vh_nextphase(ldcp));
509812011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
509912011SSriharsha.Basavapatna@Sun.COM return (rv);
510012011SSriharsha.Basavapatna@Sun.COM }
51011991Sheppo }
51021991Sheppo break;
51031991Sheppo
51041991Sheppo case VIO_SUBTYPE_NACK:
51051991Sheppo
51064647Sraghuram DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n");
51072793Slm66018 return (VGEN_FAILURE);
51081991Sheppo }
51094647Sraghuram DBG1(vgenp, ldcp, "exit\n");
51102793Slm66018 return (VGEN_SUCCESS);
51111991Sheppo }
51121991Sheppo
51131991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */
51142793Slm66018 static int
vgen_handle_mcast_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)51151991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51161991Sheppo {
511712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
511812011SSriharsha.Basavapatna@Sun.COM vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp;
511912011SSriharsha.Basavapatna@Sun.COM struct ether_addr *addrp;
512012011SSriharsha.Basavapatna@Sun.COM int count;
512112011SSriharsha.Basavapatna@Sun.COM int i;
51221991Sheppo
51234647Sraghuram DBG1(vgenp, ldcp, "enter\n");
51241991Sheppo switch (tagp->vio_subtype) {
51251991Sheppo
51261991Sheppo case VIO_SUBTYPE_INFO:
51271991Sheppo
51281991Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */
51294647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n");
51301991Sheppo break;
51311991Sheppo
51321991Sheppo case VIO_SUBTYPE_ACK:
51331991Sheppo
51341991Sheppo /* success adding/removing multicast addr */
51354647Sraghuram DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n");
51361991Sheppo break;
51371991Sheppo
51381991Sheppo case VIO_SUBTYPE_NACK:
51391991Sheppo
51404647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n");
51411991Sheppo if (!(msgp->set)) {
51421991Sheppo /* multicast remove request failed */
51431991Sheppo break;
51441991Sheppo }
51451991Sheppo
51461991Sheppo /* multicast add request failed */
51471991Sheppo for (count = 0; count < msgp->count; count++) {
51481991Sheppo addrp = &(msgp->mca[count]);
51491991Sheppo
51501991Sheppo /* delete address from the table */
51511991Sheppo for (i = 0; i < vgenp->mccount; i++) {
51521991Sheppo if (ether_cmp(addrp,
51531991Sheppo &(vgenp->mctab[i])) == 0) {
51541991Sheppo if (vgenp->mccount > 1) {
51554647Sraghuram int t = vgenp->mccount - 1;
51561991Sheppo vgenp->mctab[i] =
51574650Sraghuram vgenp->mctab[t];
51581991Sheppo }
51591991Sheppo vgenp->mccount--;
51601991Sheppo break;
51611991Sheppo }
51621991Sheppo }
51631991Sheppo }
51641991Sheppo break;
51651991Sheppo
51661991Sheppo }
51674647Sraghuram DBG1(vgenp, ldcp, "exit\n");
51682793Slm66018
51692793Slm66018 return (VGEN_SUCCESS);
51701991Sheppo }
51711991Sheppo
51729336SSriharsha.Basavapatna@Sun.COM /*
51739336SSriharsha.Basavapatna@Sun.COM * Physical link information message from the peer. Only vswitch should send
51749336SSriharsha.Basavapatna@Sun.COM * us this message; if the vnet device has been configured to get physical link
51759336SSriharsha.Basavapatna@Sun.COM * state updates. Note that we must have already negotiated this with the
51769336SSriharsha.Basavapatna@Sun.COM * vswitch during attribute exchange phase of handshake.
51779336SSriharsha.Basavapatna@Sun.COM */
51789336SSriharsha.Basavapatna@Sun.COM static int
vgen_handle_physlink_info(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)51799336SSriharsha.Basavapatna@Sun.COM vgen_handle_physlink_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
51809336SSriharsha.Basavapatna@Sun.COM {
51819336SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
51829336SSriharsha.Basavapatna@Sun.COM vnet_physlink_msg_t *msgp = (vnet_physlink_msg_t *)tagp;
51839336SSriharsha.Basavapatna@Sun.COM link_state_t link_state;
51849336SSriharsha.Basavapatna@Sun.COM int rv;
51859336SSriharsha.Basavapatna@Sun.COM
51869336SSriharsha.Basavapatna@Sun.COM if (ldcp->portp != vgenp->vsw_portp) {
51879336SSriharsha.Basavapatna@Sun.COM /*
51889336SSriharsha.Basavapatna@Sun.COM * drop the message and don't process; as we should
51899336SSriharsha.Basavapatna@Sun.COM * receive physlink_info message from only vswitch.
51909336SSriharsha.Basavapatna@Sun.COM */
51919336SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
51929336SSriharsha.Basavapatna@Sun.COM }
51939336SSriharsha.Basavapatna@Sun.COM
51949336SSriharsha.Basavapatna@Sun.COM if (vgenp->pls_negotiated == B_FALSE) {
51959336SSriharsha.Basavapatna@Sun.COM /*
51969336SSriharsha.Basavapatna@Sun.COM * drop the message and don't process; as we should receive
51979336SSriharsha.Basavapatna@Sun.COM * physlink_info message only if physlink update is enabled for
51989336SSriharsha.Basavapatna@Sun.COM * the device and negotiated with vswitch.
51999336SSriharsha.Basavapatna@Sun.COM */
52009336SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
52019336SSriharsha.Basavapatna@Sun.COM }
52029336SSriharsha.Basavapatna@Sun.COM
52039336SSriharsha.Basavapatna@Sun.COM switch (tagp->vio_subtype) {
52049336SSriharsha.Basavapatna@Sun.COM
52059336SSriharsha.Basavapatna@Sun.COM case VIO_SUBTYPE_INFO:
52069336SSriharsha.Basavapatna@Sun.COM
52079336SSriharsha.Basavapatna@Sun.COM if ((msgp->physlink_info & VNET_PHYSLINK_STATE_MASK) ==
52089336SSriharsha.Basavapatna@Sun.COM VNET_PHYSLINK_STATE_UP) {
52099336SSriharsha.Basavapatna@Sun.COM link_state = LINK_STATE_UP;
52109336SSriharsha.Basavapatna@Sun.COM } else {
52119336SSriharsha.Basavapatna@Sun.COM link_state = LINK_STATE_DOWN;
52129336SSriharsha.Basavapatna@Sun.COM }
52139336SSriharsha.Basavapatna@Sun.COM
52149336SSriharsha.Basavapatna@Sun.COM if (vgenp->phys_link_state != link_state) {
52159336SSriharsha.Basavapatna@Sun.COM vgenp->phys_link_state = link_state;
52169336SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
52179336SSriharsha.Basavapatna@Sun.COM
52189336SSriharsha.Basavapatna@Sun.COM /* Now update the stack */
52199336SSriharsha.Basavapatna@Sun.COM vgen_link_update(vgenp, link_state);
52209336SSriharsha.Basavapatna@Sun.COM
52219336SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
52229336SSriharsha.Basavapatna@Sun.COM }
52239336SSriharsha.Basavapatna@Sun.COM
52249336SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_ACK;
52259336SSriharsha.Basavapatna@Sun.COM tagp->vio_sid = ldcp->local_sid;
52269336SSriharsha.Basavapatna@Sun.COM
52279336SSriharsha.Basavapatna@Sun.COM /* send reply msg back to peer */
52289336SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)tagp,
52299336SSriharsha.Basavapatna@Sun.COM sizeof (vnet_physlink_msg_t), B_FALSE);
52309336SSriharsha.Basavapatna@Sun.COM if (rv != VGEN_SUCCESS) {
52319336SSriharsha.Basavapatna@Sun.COM return (rv);
52329336SSriharsha.Basavapatna@Sun.COM }
52339336SSriharsha.Basavapatna@Sun.COM break;
52349336SSriharsha.Basavapatna@Sun.COM
52359336SSriharsha.Basavapatna@Sun.COM case VIO_SUBTYPE_ACK:
52369336SSriharsha.Basavapatna@Sun.COM
52379336SSriharsha.Basavapatna@Sun.COM /* vnet shouldn't recv physlink acks */
52389336SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "rcvd PHYSLINK_ACK \n");
52399336SSriharsha.Basavapatna@Sun.COM break;
52409336SSriharsha.Basavapatna@Sun.COM
52419336SSriharsha.Basavapatna@Sun.COM case VIO_SUBTYPE_NACK:
52429336SSriharsha.Basavapatna@Sun.COM
52439336SSriharsha.Basavapatna@Sun.COM /* vnet shouldn't recv physlink nacks */
52449336SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "rcvd PHYSLINK_NACK \n");
52459336SSriharsha.Basavapatna@Sun.COM break;
52469336SSriharsha.Basavapatna@Sun.COM
52479336SSriharsha.Basavapatna@Sun.COM }
52489336SSriharsha.Basavapatna@Sun.COM DBG1(vgenp, ldcp, "exit\n");
52499336SSriharsha.Basavapatna@Sun.COM
52509336SSriharsha.Basavapatna@Sun.COM return (VGEN_SUCCESS);
52519336SSriharsha.Basavapatna@Sun.COM }
52529336SSriharsha.Basavapatna@Sun.COM
52531991Sheppo /* handler for control messages received from the peer ldc end-point */
52542793Slm66018 static int
vgen_handle_ctrlmsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)52551991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
52561991Sheppo {
525712011SSriharsha.Basavapatna@Sun.COM int rv = 0;
525812011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
52594647Sraghuram
52604647Sraghuram DBG1(vgenp, ldcp, "enter\n");
52611991Sheppo switch (tagp->vio_subtype_env) {
52621991Sheppo
52631991Sheppo case VIO_VER_INFO:
52642793Slm66018 rv = vgen_handle_version_negotiate(ldcp, tagp);
52651991Sheppo break;
52661991Sheppo
52671991Sheppo case VIO_ATTR_INFO:
526812011SSriharsha.Basavapatna@Sun.COM rv = vgen_handle_attr_msg(ldcp, tagp);
52691991Sheppo break;
52701991Sheppo
52711991Sheppo case VIO_DRING_REG:
52722793Slm66018 rv = vgen_handle_dring_reg(ldcp, tagp);
52731991Sheppo break;
52741991Sheppo
52751991Sheppo case VIO_RDX:
52762793Slm66018 rv = vgen_handle_rdx_info(ldcp, tagp);
52771991Sheppo break;
52781991Sheppo
52791991Sheppo case VNET_MCAST_INFO:
52802793Slm66018 rv = vgen_handle_mcast_info(ldcp, tagp);
52811991Sheppo break;
52821991Sheppo
52836495Sspeer case VIO_DDS_INFO:
52849647SWentao.Yang@Sun.COM /*
52859647SWentao.Yang@Sun.COM * If we are in the process of resetting the vswitch channel,
52869647SWentao.Yang@Sun.COM * drop the dds message. A new handshake will be initiated
52879647SWentao.Yang@Sun.COM * when the channel comes back up after the reset and dds
52889647SWentao.Yang@Sun.COM * negotiation can then continue.
52899647SWentao.Yang@Sun.COM */
529012011SSriharsha.Basavapatna@Sun.COM if (ldcp->reset_in_progress == 1) {
52919647SWentao.Yang@Sun.COM break;
52929647SWentao.Yang@Sun.COM }
52936495Sspeer rv = vgen_dds_rx(ldcp, tagp);
52946495Sspeer break;
52959336SSriharsha.Basavapatna@Sun.COM
52969336SSriharsha.Basavapatna@Sun.COM case VNET_PHYSLINK_INFO:
52979336SSriharsha.Basavapatna@Sun.COM rv = vgen_handle_physlink_info(ldcp, tagp);
52989336SSriharsha.Basavapatna@Sun.COM break;
52991991Sheppo }
53002793Slm66018
53014647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
53022793Slm66018 return (rv);
53031991Sheppo }
53041991Sheppo
530512011SSriharsha.Basavapatna@Sun.COM /* handler for error messages received from the peer ldc end-point */
530612011SSriharsha.Basavapatna@Sun.COM static void
vgen_handle_errmsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)530712011SSriharsha.Basavapatna@Sun.COM vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
530812011SSriharsha.Basavapatna@Sun.COM {
530912011SSriharsha.Basavapatna@Sun.COM _NOTE(ARGUNUSED(ldcp, tagp))
531012011SSriharsha.Basavapatna@Sun.COM }
531112011SSriharsha.Basavapatna@Sun.COM
531212011SSriharsha.Basavapatna@Sun.COM /*
531312011SSriharsha.Basavapatna@Sun.COM * This function handles raw pkt data messages received over the channel.
531412011SSriharsha.Basavapatna@Sun.COM * Currently, only priority-eth-type frames are received through this mechanism.
531512011SSriharsha.Basavapatna@Sun.COM * In this case, the frame(data) is present within the message itself which
531612011SSriharsha.Basavapatna@Sun.COM * is copied into an mblk before sending it up the stack.
531712011SSriharsha.Basavapatna@Sun.COM */
531812011SSriharsha.Basavapatna@Sun.COM void
vgen_handle_pkt_data(void * arg1,void * arg2,uint32_t msglen)531912011SSriharsha.Basavapatna@Sun.COM vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen)
532012011SSriharsha.Basavapatna@Sun.COM {
532112011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp = (vgen_ldc_t *)arg1;
532212011SSriharsha.Basavapatna@Sun.COM vio_raw_data_msg_t *pkt = (vio_raw_data_msg_t *)arg2;
532312011SSriharsha.Basavapatna@Sun.COM uint32_t size;
532412011SSriharsha.Basavapatna@Sun.COM mblk_t *mp;
532512011SSriharsha.Basavapatna@Sun.COM vio_mblk_t *vmp;
532612011SSriharsha.Basavapatna@Sun.COM vio_net_rx_cb_t vrx_cb = NULL;
532712011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
532812011SSriharsha.Basavapatna@Sun.COM vgen_stats_t *statsp = &ldcp->stats;
532912011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
533012011SSriharsha.Basavapatna@Sun.COM uint_t dring_mode = lp->dring_mode;
533112011SSriharsha.Basavapatna@Sun.COM
533212011SSriharsha.Basavapatna@Sun.COM ASSERT(MUTEX_HELD(&ldcp->cblock));
533312011SSriharsha.Basavapatna@Sun.COM
533412011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
533512011SSriharsha.Basavapatna@Sun.COM
533612011SSriharsha.Basavapatna@Sun.COM size = msglen - VIO_PKT_DATA_HDRSIZE;
533712011SSriharsha.Basavapatna@Sun.COM if (size < ETHERMIN || size > lp->mtu) {
533812011SSriharsha.Basavapatna@Sun.COM (void) atomic_inc_32(&statsp->rx_pri_fail);
533912011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
534012011SSriharsha.Basavapatna@Sun.COM return;
534112011SSriharsha.Basavapatna@Sun.COM }
534212011SSriharsha.Basavapatna@Sun.COM
534312011SSriharsha.Basavapatna@Sun.COM vmp = vio_multipool_allocb(&ldcp->vmp, size);
534412011SSriharsha.Basavapatna@Sun.COM if (vmp == NULL) {
534512011SSriharsha.Basavapatna@Sun.COM mp = allocb(size, BPRI_MED);
534612011SSriharsha.Basavapatna@Sun.COM if (mp == NULL) {
534712011SSriharsha.Basavapatna@Sun.COM (void) atomic_inc_32(&statsp->rx_pri_fail);
534812011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "allocb failure, "
534912011SSriharsha.Basavapatna@Sun.COM "unable to process priority frame\n");
535012011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
535112011SSriharsha.Basavapatna@Sun.COM return;
535212011SSriharsha.Basavapatna@Sun.COM }
535312011SSriharsha.Basavapatna@Sun.COM } else {
535412011SSriharsha.Basavapatna@Sun.COM mp = vmp->mp;
535512011SSriharsha.Basavapatna@Sun.COM }
535612011SSriharsha.Basavapatna@Sun.COM
535712011SSriharsha.Basavapatna@Sun.COM /* copy the frame from the payload of raw data msg into the mblk */
535812011SSriharsha.Basavapatna@Sun.COM bcopy(pkt->data, mp->b_rptr, size);
535912011SSriharsha.Basavapatna@Sun.COM mp->b_wptr = mp->b_rptr + size;
536012011SSriharsha.Basavapatna@Sun.COM
536112011SSriharsha.Basavapatna@Sun.COM if (vmp != NULL) {
536212011SSriharsha.Basavapatna@Sun.COM vmp->state = VIO_MBLK_HAS_DATA;
536312011SSriharsha.Basavapatna@Sun.COM }
536412011SSriharsha.Basavapatna@Sun.COM
536512011SSriharsha.Basavapatna@Sun.COM /* update stats */
536612011SSriharsha.Basavapatna@Sun.COM (void) atomic_inc_64(&statsp->rx_pri_packets);
536712011SSriharsha.Basavapatna@Sun.COM (void) atomic_add_64(&statsp->rx_pri_bytes, size);
536812011SSriharsha.Basavapatna@Sun.COM
536912011SSriharsha.Basavapatna@Sun.COM /*
537012011SSriharsha.Basavapatna@Sun.COM * If polling is currently enabled, add the packet to the priority
537112011SSriharsha.Basavapatna@Sun.COM * packets list and return. It will be picked up by the polling thread.
537212011SSriharsha.Basavapatna@Sun.COM */
537312011SSriharsha.Basavapatna@Sun.COM if (dring_mode == VIO_RX_DRING_DATA) {
537412011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->rxlock);
537512011SSriharsha.Basavapatna@Sun.COM } else {
537612011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->pollq_lock);
537712011SSriharsha.Basavapatna@Sun.COM }
537812011SSriharsha.Basavapatna@Sun.COM
537912011SSriharsha.Basavapatna@Sun.COM if (ldcp->polling_on == B_TRUE) {
538012011SSriharsha.Basavapatna@Sun.COM if (ldcp->rx_pri_tail != NULL) {
538112011SSriharsha.Basavapatna@Sun.COM ldcp->rx_pri_tail->b_next = mp;
538212011SSriharsha.Basavapatna@Sun.COM } else {
538312011SSriharsha.Basavapatna@Sun.COM ldcp->rx_pri_head = ldcp->rx_pri_tail = mp;
538412011SSriharsha.Basavapatna@Sun.COM }
538512011SSriharsha.Basavapatna@Sun.COM } else {
538612011SSriharsha.Basavapatna@Sun.COM vrx_cb = ldcp->portp->vcb.vio_net_rx_cb;
538712011SSriharsha.Basavapatna@Sun.COM }
538812011SSriharsha.Basavapatna@Sun.COM
538912011SSriharsha.Basavapatna@Sun.COM if (dring_mode == VIO_RX_DRING_DATA) {
539012011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->rxlock);
539112011SSriharsha.Basavapatna@Sun.COM } else {
539212011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->pollq_lock);
539312011SSriharsha.Basavapatna@Sun.COM }
539412011SSriharsha.Basavapatna@Sun.COM
539512011SSriharsha.Basavapatna@Sun.COM if (vrx_cb != NULL) {
539612011SSriharsha.Basavapatna@Sun.COM vrx_cb(ldcp->portp->vhp, mp);
539712011SSriharsha.Basavapatna@Sun.COM }
539812011SSriharsha.Basavapatna@Sun.COM
539912011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
540012011SSriharsha.Basavapatna@Sun.COM }
540112011SSriharsha.Basavapatna@Sun.COM
540212011SSriharsha.Basavapatna@Sun.COM /*
540312011SSriharsha.Basavapatna@Sun.COM * dummy pkt data handler function for vnet protocol version 1.0
540412011SSriharsha.Basavapatna@Sun.COM */
540512011SSriharsha.Basavapatna@Sun.COM static void
vgen_handle_pkt_data_nop(void * arg1,void * arg2,uint32_t msglen)540612011SSriharsha.Basavapatna@Sun.COM vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
540712011SSriharsha.Basavapatna@Sun.COM {
540812011SSriharsha.Basavapatna@Sun.COM _NOTE(ARGUNUSED(arg1, arg2, msglen))
540912011SSriharsha.Basavapatna@Sun.COM }
541012011SSriharsha.Basavapatna@Sun.COM
54111991Sheppo /* handler for data messages received from the peer ldc end-point */
54122793Slm66018 static int
vgen_handle_datamsg(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp,uint32_t msglen)54135935Ssb155480 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen)
54141991Sheppo {
541512011SSriharsha.Basavapatna@Sun.COM int rv = 0;
541612011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
541712011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
54184647Sraghuram
54194647Sraghuram DBG1(vgenp, ldcp, "enter\n");
54201991Sheppo
542112011SSriharsha.Basavapatna@Sun.COM if (ldcp->hphase != VH_DONE) {
542212011SSriharsha.Basavapatna@Sun.COM return (0);
542312011SSriharsha.Basavapatna@Sun.COM }
542412011SSriharsha.Basavapatna@Sun.COM
542512011SSriharsha.Basavapatna@Sun.COM /*
542612011SSriharsha.Basavapatna@Sun.COM * We check the data msg seqnum. This is needed only in TxDring mode.
542712011SSriharsha.Basavapatna@Sun.COM */
542812011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_TX_DRING &&
542912011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype == VIO_SUBTYPE_INFO) {
54305935Ssb155480 rv = vgen_check_datamsg_seq(ldcp, tagp);
54315935Ssb155480 if (rv != 0) {
54325935Ssb155480 return (rv);
54335935Ssb155480 }
54345935Ssb155480 }
54355935Ssb155480
54361991Sheppo switch (tagp->vio_subtype_env) {
54371991Sheppo case VIO_DRING_DATA:
543812011SSriharsha.Basavapatna@Sun.COM rv = ldcp->rx_dringdata((void *)ldcp, (void *)tagp);
54391991Sheppo break;
54405935Ssb155480
54415935Ssb155480 case VIO_PKT_DATA:
54425935Ssb155480 ldcp->rx_pktdata((void *)ldcp, (void *)tagp, msglen);
54435935Ssb155480 break;
54441991Sheppo default:
54451991Sheppo break;
54461991Sheppo }
54471991Sheppo
54484647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv);
54492793Slm66018 return (rv);
54501991Sheppo }
54511991Sheppo
54524647Sraghuram
54534647Sraghuram static int
vgen_ldc_reset(vgen_ldc_t * ldcp,vgen_caller_t caller)545412011SSriharsha.Basavapatna@Sun.COM vgen_ldc_reset(vgen_ldc_t *ldcp, vgen_caller_t caller)
54554647Sraghuram {
545612011SSriharsha.Basavapatna@Sun.COM int rv;
545712011SSriharsha.Basavapatna@Sun.COM
545812011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
545912011SSriharsha.Basavapatna@Sun.COM ASSERT(MUTEX_HELD(&ldcp->cblock));
546012011SSriharsha.Basavapatna@Sun.COM }
546112011SSriharsha.Basavapatna@Sun.COM
546212011SSriharsha.Basavapatna@Sun.COM /* Set the flag to indicate reset is in progress */
546312011SSriharsha.Basavapatna@Sun.COM if (atomic_cas_uint(&ldcp->reset_in_progress, 0, 1) != 0) {
546412011SSriharsha.Basavapatna@Sun.COM /* another thread is already in the process of resetting */
546512011SSriharsha.Basavapatna@Sun.COM return (EBUSY);
546612011SSriharsha.Basavapatna@Sun.COM }
546712011SSriharsha.Basavapatna@Sun.COM
546812011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
546912011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
547012011SSriharsha.Basavapatna@Sun.COM }
547112011SSriharsha.Basavapatna@Sun.COM
547212011SSriharsha.Basavapatna@Sun.COM rv = vgen_process_reset(ldcp, VGEN_FLAG_NEED_LDCRESET);
547312011SSriharsha.Basavapatna@Sun.COM
547412011SSriharsha.Basavapatna@Sun.COM if (caller == VGEN_LDC_CB || caller == VGEN_MSG_THR) {
547512011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
547612011SSriharsha.Basavapatna@Sun.COM }
547712011SSriharsha.Basavapatna@Sun.COM
54782793Slm66018 return (rv);
54791991Sheppo }
54801991Sheppo
54811991Sheppo static void
vgen_ldc_up(vgen_ldc_t * ldcp)548212011SSriharsha.Basavapatna@Sun.COM vgen_ldc_up(vgen_ldc_t *ldcp)
54831991Sheppo {
548412011SSriharsha.Basavapatna@Sun.COM int rv;
548512011SSriharsha.Basavapatna@Sun.COM uint32_t retries = 0;
548612011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
548712011SSriharsha.Basavapatna@Sun.COM
548812011SSriharsha.Basavapatna@Sun.COM ASSERT(MUTEX_HELD(&ldcp->cblock));
54891991Sheppo
54901991Sheppo /*
549112011SSriharsha.Basavapatna@Sun.COM * If the channel has been reset max # of times, without successfully
549212011SSriharsha.Basavapatna@Sun.COM * completing handshake, stop and do not bring the channel up.
54931991Sheppo */
549412011SSriharsha.Basavapatna@Sun.COM if (ldcp->ldc_reset_count == vgen_ldc_max_resets) {
549512011SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, "!vnet%d: exceeded number of permitted"
549612011SSriharsha.Basavapatna@Sun.COM " handshake attempts (%d) on channel %ld",
549712011SSriharsha.Basavapatna@Sun.COM vgenp->instance, vgen_ldc_max_resets, ldcp->ldc_id);
549812011SSriharsha.Basavapatna@Sun.COM return;
549912011SSriharsha.Basavapatna@Sun.COM }
550012011SSriharsha.Basavapatna@Sun.COM ldcp->ldc_reset_count++;
550112011SSriharsha.Basavapatna@Sun.COM
550212011SSriharsha.Basavapatna@Sun.COM do {
550312011SSriharsha.Basavapatna@Sun.COM rv = ldc_up(ldcp->ldc_handle);
550412011SSriharsha.Basavapatna@Sun.COM if ((rv != 0) && (rv == EWOULDBLOCK)) {
550512011SSriharsha.Basavapatna@Sun.COM drv_usecwait(VGEN_LDC_UP_DELAY);
550612011SSriharsha.Basavapatna@Sun.COM }
550712011SSriharsha.Basavapatna@Sun.COM if (retries++ >= vgen_ldcup_retries)
550812011SSriharsha.Basavapatna@Sun.COM break;
550912011SSriharsha.Basavapatna@Sun.COM } while (rv == EWOULDBLOCK);
551012011SSriharsha.Basavapatna@Sun.COM
551112011SSriharsha.Basavapatna@Sun.COM if (rv != 0) {
551212011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv);
55131991Sheppo }
55141991Sheppo }
55151991Sheppo
551612011SSriharsha.Basavapatna@Sun.COM int
vgen_enable_intr(void * arg)551712011SSriharsha.Basavapatna@Sun.COM vgen_enable_intr(void *arg)
55181991Sheppo {
551912011SSriharsha.Basavapatna@Sun.COM uint32_t end_ix;
552012011SSriharsha.Basavapatna@Sun.COM vio_dring_msg_t msg;
552112011SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp = (vgen_port_t *)arg;
552212011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp = portp->ldcp;
552312011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
552412011SSriharsha.Basavapatna@Sun.COM
552512011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
552612011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->rxlock);
552712011SSriharsha.Basavapatna@Sun.COM
552812011SSriharsha.Basavapatna@Sun.COM ldcp->polling_on = B_FALSE;
552912011SSriharsha.Basavapatna@Sun.COM /*
553012011SSriharsha.Basavapatna@Sun.COM * We send a stopped message to peer (sender) as we are turning
553112011SSriharsha.Basavapatna@Sun.COM * off polled mode. This effectively restarts data interrupts
553212011SSriharsha.Basavapatna@Sun.COM * by allowing the peer to send further dring data msgs to us.
553312011SSriharsha.Basavapatna@Sun.COM */
553412011SSriharsha.Basavapatna@Sun.COM end_ix = ldcp->next_rxi;
553512011SSriharsha.Basavapatna@Sun.COM DECR_RXI(end_ix, ldcp);
553612011SSriharsha.Basavapatna@Sun.COM msg.dring_ident = ldcp->peer_hparams.dring_ident;
553712011SSriharsha.Basavapatna@Sun.COM (void) vgen_send_dringack_shm(ldcp, (vio_msg_tag_t *)&msg,
553812011SSriharsha.Basavapatna@Sun.COM VNET_START_IDX_UNSPEC, end_ix, VIO_DP_STOPPED);
553912011SSriharsha.Basavapatna@Sun.COM
554012011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->rxlock);
554112011SSriharsha.Basavapatna@Sun.COM } else {
554212011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->pollq_lock);
554312011SSriharsha.Basavapatna@Sun.COM ldcp->polling_on = B_FALSE;
554412011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->pollq_lock);
554512011SSriharsha.Basavapatna@Sun.COM }
554612011SSriharsha.Basavapatna@Sun.COM
554712011SSriharsha.Basavapatna@Sun.COM return (0);
55481991Sheppo }
55491991Sheppo
555012011SSriharsha.Basavapatna@Sun.COM int
vgen_disable_intr(void * arg)555112011SSriharsha.Basavapatna@Sun.COM vgen_disable_intr(void *arg)
55521991Sheppo {
555312011SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp = (vgen_port_t *)arg;
555412011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp = portp->ldcp;
555512011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
555612011SSriharsha.Basavapatna@Sun.COM
555712011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
555812011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->rxlock);
555912011SSriharsha.Basavapatna@Sun.COM ldcp->polling_on = B_TRUE;
556012011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->rxlock);
55611991Sheppo } else {
556212011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->pollq_lock);
556312011SSriharsha.Basavapatna@Sun.COM ldcp->polling_on = B_TRUE;
556412011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->pollq_lock);
556512011SSriharsha.Basavapatna@Sun.COM }
556612011SSriharsha.Basavapatna@Sun.COM
556712011SSriharsha.Basavapatna@Sun.COM return (0);
556812011SSriharsha.Basavapatna@Sun.COM }
556912011SSriharsha.Basavapatna@Sun.COM
557012011SSriharsha.Basavapatna@Sun.COM mblk_t *
vgen_rx_poll(void * arg,int bytes_to_pickup)557112011SSriharsha.Basavapatna@Sun.COM vgen_rx_poll(void *arg, int bytes_to_pickup)
557212011SSriharsha.Basavapatna@Sun.COM {
557312011SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp = (vgen_port_t *)arg;
557412011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp = portp->ldcp;
557512011SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams;
557612011SSriharsha.Basavapatna@Sun.COM mblk_t *mp = NULL;
557712011SSriharsha.Basavapatna@Sun.COM
557812011SSriharsha.Basavapatna@Sun.COM if (lp->dring_mode == VIO_RX_DRING_DATA) {
557912011SSriharsha.Basavapatna@Sun.COM mp = vgen_poll_rcv_shm(ldcp, bytes_to_pickup);
558012011SSriharsha.Basavapatna@Sun.COM } else {
558112011SSriharsha.Basavapatna@Sun.COM mp = vgen_poll_rcv(ldcp, bytes_to_pickup);
558212011SSriharsha.Basavapatna@Sun.COM }
558312011SSriharsha.Basavapatna@Sun.COM
558412011SSriharsha.Basavapatna@Sun.COM return (mp);
55851991Sheppo }
55861991Sheppo
55871991Sheppo /* transmit watchdog timeout handler */
55881991Sheppo static void
vgen_tx_watchdog(void * arg)558912011SSriharsha.Basavapatna@Sun.COM vgen_tx_watchdog(void *arg)
55901991Sheppo {
559112011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp;
559212011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp;
559312011SSriharsha.Basavapatna@Sun.COM int rv;
559412011SSriharsha.Basavapatna@Sun.COM boolean_t tx_blocked;
559512011SSriharsha.Basavapatna@Sun.COM clock_t tx_blocked_lbolt;
55961991Sheppo
55971991Sheppo ldcp = (vgen_ldc_t *)arg;
55982336Snarayan vgenp = LDC_TO_VGEN(ldcp);
55991991Sheppo
560012011SSriharsha.Basavapatna@Sun.COM tx_blocked = ldcp->tx_blocked;
560112011SSriharsha.Basavapatna@Sun.COM tx_blocked_lbolt = ldcp->tx_blocked_lbolt;
560212011SSriharsha.Basavapatna@Sun.COM
560312011SSriharsha.Basavapatna@Sun.COM if (vgen_txwd_timeout &&
560412011SSriharsha.Basavapatna@Sun.COM (tx_blocked == B_TRUE) &&
560512011SSriharsha.Basavapatna@Sun.COM ((ddi_get_lbolt() - tx_blocked_lbolt) >
560612011SSriharsha.Basavapatna@Sun.COM drv_usectohz(vgen_txwd_timeout * 1000))) {
560712011SSriharsha.Basavapatna@Sun.COM /*
560812011SSriharsha.Basavapatna@Sun.COM * Something is wrong; the peer is not picking up the packets
560912011SSriharsha.Basavapatna@Sun.COM * in the transmit dring. We now go ahead and reset the channel
561012011SSriharsha.Basavapatna@Sun.COM * to break out of this condition.
561112011SSriharsha.Basavapatna@Sun.COM */
561212011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "transmit timeout lbolt(%lx), "
561312011SSriharsha.Basavapatna@Sun.COM "tx_blocked_lbolt(%lx)\n",
561412011SSriharsha.Basavapatna@Sun.COM ddi_get_lbolt(), tx_blocked_lbolt);
561512011SSriharsha.Basavapatna@Sun.COM
56161991Sheppo #ifdef DEBUG
561712011SSriharsha.Basavapatna@Sun.COM if (vgen_inject_error(ldcp, VGEN_ERR_TXTIMEOUT)) {
56181991Sheppo /* tx timeout triggered for debugging */
561912011SSriharsha.Basavapatna@Sun.COM vgen_inject_err_flag &= ~(VGEN_ERR_TXTIMEOUT);
56201991Sheppo }
56211991Sheppo #endif
562212011SSriharsha.Basavapatna@Sun.COM
562312011SSriharsha.Basavapatna@Sun.COM /*
562412011SSriharsha.Basavapatna@Sun.COM * Clear tid before invoking vgen_ldc_reset(). Otherwise,
562512011SSriharsha.Basavapatna@Sun.COM * it will result in a deadlock when vgen_process_reset() tries
562612011SSriharsha.Basavapatna@Sun.COM * to untimeout() on seeing a non-zero tid, but it is being
562712011SSriharsha.Basavapatna@Sun.COM * invoked by the timer itself in this case.
562812011SSriharsha.Basavapatna@Sun.COM */
56291991Sheppo mutex_enter(&ldcp->cblock);
563012011SSriharsha.Basavapatna@Sun.COM if (ldcp->wd_tid == 0) {
563112011SSriharsha.Basavapatna@Sun.COM /* Cancelled by vgen_process_reset() */
563212011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
563312011SSriharsha.Basavapatna@Sun.COM return;
56341991Sheppo }
563512011SSriharsha.Basavapatna@Sun.COM ldcp->wd_tid = 0;
563612011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
563712011SSriharsha.Basavapatna@Sun.COM
563812011SSriharsha.Basavapatna@Sun.COM /*
563912011SSriharsha.Basavapatna@Sun.COM * Now reset the channel.
564012011SSriharsha.Basavapatna@Sun.COM */
564112011SSriharsha.Basavapatna@Sun.COM rv = vgen_ldc_reset(ldcp, VGEN_OTHER);
564212011SSriharsha.Basavapatna@Sun.COM if (rv == 0) {
564312011SSriharsha.Basavapatna@Sun.COM /*
564412011SSriharsha.Basavapatna@Sun.COM * We have successfully reset the channel. If we are
564512011SSriharsha.Basavapatna@Sun.COM * in tx flow controlled state, clear it now and enable
564612011SSriharsha.Basavapatna@Sun.COM * transmit in the upper layer.
564712011SSriharsha.Basavapatna@Sun.COM */
564812011SSriharsha.Basavapatna@Sun.COM if (ldcp->tx_blocked) {
564912011SSriharsha.Basavapatna@Sun.COM vio_net_tx_update_t vtx_update =
565012011SSriharsha.Basavapatna@Sun.COM ldcp->portp->vcb.vio_net_tx_update;
565112011SSriharsha.Basavapatna@Sun.COM
565212011SSriharsha.Basavapatna@Sun.COM ldcp->tx_blocked = B_FALSE;
565312011SSriharsha.Basavapatna@Sun.COM vtx_update(ldcp->portp->vhp);
565412011SSriharsha.Basavapatna@Sun.COM }
565512011SSriharsha.Basavapatna@Sun.COM }
565612011SSriharsha.Basavapatna@Sun.COM
565712011SSriharsha.Basavapatna@Sun.COM /*
565812011SSriharsha.Basavapatna@Sun.COM * Channel has been reset by us or some other thread is already
565912011SSriharsha.Basavapatna@Sun.COM * in the process of resetting. In either case, we return
566012011SSriharsha.Basavapatna@Sun.COM * without restarting the timer. When handshake completes and
566112011SSriharsha.Basavapatna@Sun.COM * the channel is ready for data transmit/receive we start a
566212011SSriharsha.Basavapatna@Sun.COM * new watchdog timer.
566312011SSriharsha.Basavapatna@Sun.COM */
566412011SSriharsha.Basavapatna@Sun.COM return;
566512011SSriharsha.Basavapatna@Sun.COM }
566612011SSriharsha.Basavapatna@Sun.COM
566712011SSriharsha.Basavapatna@Sun.COM restart_timer:
566812011SSriharsha.Basavapatna@Sun.COM /* Restart the timer */
566912011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
567012011SSriharsha.Basavapatna@Sun.COM if (ldcp->wd_tid == 0) {
567112011SSriharsha.Basavapatna@Sun.COM /* Cancelled by vgen_process_reset() */
567212011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
567312011SSriharsha.Basavapatna@Sun.COM return;
567412011SSriharsha.Basavapatna@Sun.COM }
567512011SSriharsha.Basavapatna@Sun.COM ldcp->wd_tid = timeout(vgen_tx_watchdog, (caddr_t)ldcp,
567612011SSriharsha.Basavapatna@Sun.COM drv_usectohz(vgen_txwd_interval * 1000));
567712011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
56781991Sheppo }
56791991Sheppo
568012011SSriharsha.Basavapatna@Sun.COM /* Handshake watchdog timeout handler */
56811991Sheppo static void
vgen_hwatchdog(void * arg)568212011SSriharsha.Basavapatna@Sun.COM vgen_hwatchdog(void *arg)
56835935Ssb155480 {
568412011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp = (vgen_ldc_t *)arg;
568512011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
568612011SSriharsha.Basavapatna@Sun.COM
568712011SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "handshake timeout phase(%x) state(%x)\n",
568812011SSriharsha.Basavapatna@Sun.COM ldcp->hphase, ldcp->hstate);
568912011SSriharsha.Basavapatna@Sun.COM
569012011SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
569112011SSriharsha.Basavapatna@Sun.COM if (ldcp->htid == 0) {
569212011SSriharsha.Basavapatna@Sun.COM /* Cancelled by vgen_process_reset() */
569312011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
569412011SSriharsha.Basavapatna@Sun.COM return;
569512011SSriharsha.Basavapatna@Sun.COM }
569612011SSriharsha.Basavapatna@Sun.COM ldcp->htid = 0;
569712011SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
569812011SSriharsha.Basavapatna@Sun.COM
569912011SSriharsha.Basavapatna@Sun.COM /*
570012011SSriharsha.Basavapatna@Sun.COM * Something is wrong; handshake with the peer seems to be hung. We now
570112011SSriharsha.Basavapatna@Sun.COM * go ahead and reset the channel to break out of this condition.
570212011SSriharsha.Basavapatna@Sun.COM */
570312011SSriharsha.Basavapatna@Sun.COM (void) vgen_ldc_reset(ldcp, VGEN_OTHER);
57045935Ssb155480 }
57055935Ssb155480
57061991Sheppo /* Check if the session id in the received message is valid */
57071991Sheppo static int
vgen_check_sid(vgen_ldc_t * ldcp,vio_msg_tag_t * tagp)57081991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp)
57091991Sheppo {
571012011SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
57114647Sraghuram
57121991Sheppo if (tagp->vio_sid != ldcp->peer_sid) {
57134647Sraghuram DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n",
57144647Sraghuram ldcp->peer_sid, tagp->vio_sid);
57151991Sheppo return (VGEN_FAILURE);
57161991Sheppo }
57171991Sheppo else
57181991Sheppo return (VGEN_SUCCESS);
57191991Sheppo }
57201991Sheppo
57214647Sraghuram /*
572212011SSriharsha.Basavapatna@Sun.COM * Initialize the common part of dring registration
572312011SSriharsha.Basavapatna@Sun.COM * message; used in both TxDring and RxDringData modes.
57244647Sraghuram */
57254647Sraghuram static void
vgen_init_dring_reg_msg(vgen_ldc_t * ldcp,vio_dring_reg_msg_t * msg,uint8_t option)572612011SSriharsha.Basavapatna@Sun.COM vgen_init_dring_reg_msg(vgen_ldc_t *ldcp, vio_dring_reg_msg_t *msg,
572712011SSriharsha.Basavapatna@Sun.COM uint8_t option)
57284647Sraghuram {
572912011SSriharsha.Basavapatna@Sun.COM vio_msg_tag_t *tagp;
573012011SSriharsha.Basavapatna@Sun.COM
573112011SSriharsha.Basavapatna@Sun.COM tagp = &msg->tag;
573212011SSriharsha.Basavapatna@Sun.COM tagp->vio_msgtype = VIO_TYPE_CTRL;
573312011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_INFO;
573412011SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype_env = VIO_DRING_REG;
573512011SSriharsha.Basavapatna@Sun.COM tagp->vio_sid = ldcp->local_sid;
573612011SSriharsha.Basavapatna@Sun.COM
573712011SSriharsha.Basavapatna@Sun.COM /* get dring info msg payload from ldcp->local */
573812011SSriharsha.Basavapatna@Sun.COM bcopy(&(ldcp->local_hparams.dring_cookie), &(msg->cookie[0]),
573912011SSriharsha.Basavapatna@Sun.COM sizeof (ldc_mem_cookie_t));
574012011SSriharsha.Basavapatna@Sun.COM msg->ncookies = ldcp->local_hparams.dring_ncookies;
574112011SSriharsha.Basavapatna@Sun.COM msg->num_descriptors = ldcp->local_hparams.num_desc;
574212011SSriharsha.Basavapatna@Sun.COM msg->descriptor_size = ldcp->local_hparams.desc_size;
574312011SSriharsha.Basavapatna@Sun.COM
574412011SSriharsha.Basavapatna@Sun.COM msg->options = option;
57458623SSriharsha.Basavapatna@Sun.COM
57468623SSriharsha.Basavapatna@Sun.COM /*
574712011SSriharsha.Basavapatna@Sun.COM * dring_ident is set to 0. After mapping the dring, peer sets this
574812011SSriharsha.Basavapatna@Sun.COM * value and sends it in the ack, which is saved in
574912011SSriharsha.Basavapatna@Sun.COM * vgen_handle_dring_reg().
57508623SSriharsha.Basavapatna@Sun.COM */
575112011SSriharsha.Basavapatna@Sun.COM msg->dring_ident = 0;
575210309SSriharsha.Basavapatna@Sun.COM }
575310309SSriharsha.Basavapatna@Sun.COM
5754*13098SWentao.Yang@Sun.COM static int
vgen_mapin_avail(vgen_ldc_t * ldcp)5755*13098SWentao.Yang@Sun.COM vgen_mapin_avail(vgen_ldc_t *ldcp)
5756*13098SWentao.Yang@Sun.COM {
5757*13098SWentao.Yang@Sun.COM int rv;
5758*13098SWentao.Yang@Sun.COM ldc_info_t info;
5759*13098SWentao.Yang@Sun.COM uint64_t mapin_sz_req;
5760*13098SWentao.Yang@Sun.COM uint64_t dblk_sz;
5761*13098SWentao.Yang@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp);
5762*13098SWentao.Yang@Sun.COM
5763*13098SWentao.Yang@Sun.COM rv = ldc_info(ldcp->ldc_handle, &info);
5764*13098SWentao.Yang@Sun.COM if (rv != 0) {
5765*13098SWentao.Yang@Sun.COM return (B_FALSE);
5766*13098SWentao.Yang@Sun.COM }
5767*13098SWentao.Yang@Sun.COM
5768*13098SWentao.Yang@Sun.COM dblk_sz = RXDRING_DBLK_SZ(vgenp->max_frame_size);
5769*13098SWentao.Yang@Sun.COM mapin_sz_req = (VGEN_RXDRING_NRBUFS * dblk_sz);
5770*13098SWentao.Yang@Sun.COM
5771*13098SWentao.Yang@Sun.COM if (info.direct_map_size_max >= mapin_sz_req) {
5772*13098SWentao.Yang@Sun.COM return (B_TRUE);
5773*13098SWentao.Yang@Sun.COM }
5774*13098SWentao.Yang@Sun.COM
5775*13098SWentao.Yang@Sun.COM return (B_FALSE);
5776*13098SWentao.Yang@Sun.COM }
5777*13098SWentao.Yang@Sun.COM
57784647Sraghuram #if DEBUG
57794647Sraghuram
57804647Sraghuram /*
57814647Sraghuram * Print debug messages - set to 0xf to enable all msgs
57824647Sraghuram */
578312011SSriharsha.Basavapatna@Sun.COM void
vgen_debug_printf(const char * fname,vgen_t * vgenp,vgen_ldc_t * ldcp,const char * fmt,...)578412011SSriharsha.Basavapatna@Sun.COM vgen_debug_printf(const char *fname, vgen_t *vgenp,
57854647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...)
57864647Sraghuram {
578712011SSriharsha.Basavapatna@Sun.COM char buf[256];
578812011SSriharsha.Basavapatna@Sun.COM char *bufp = buf;
578912011SSriharsha.Basavapatna@Sun.COM va_list ap;
57904647Sraghuram
57914647Sraghuram if ((vgenp != NULL) && (vgenp->vnetp != NULL)) {
57924647Sraghuram (void) sprintf(bufp, "vnet%d:",
57934650Sraghuram ((vnet_t *)(vgenp->vnetp))->instance);
57944647Sraghuram bufp += strlen(bufp);
57954647Sraghuram }
57964647Sraghuram if (ldcp != NULL) {
57974647Sraghuram (void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id);
57984647Sraghuram bufp += strlen(bufp);
57994647Sraghuram }
58004647Sraghuram (void) sprintf(bufp, "%s: ", fname);
58014647Sraghuram bufp += strlen(bufp);
58024647Sraghuram
58034647Sraghuram va_start(ap, fmt);
58044647Sraghuram (void) vsprintf(bufp, fmt, ap);
58054647Sraghuram va_end(ap);
58064647Sraghuram
58074647Sraghuram if ((ldcp == NULL) ||(vgendbg_ldcid == -1) ||
58084647Sraghuram (vgendbg_ldcid == ldcp->ldc_id)) {
58094647Sraghuram cmn_err(CE_CONT, "%s\n", buf);
58104647Sraghuram }
58114647Sraghuram }
58124647Sraghuram #endif
58139336SSriharsha.Basavapatna@Sun.COM
58149336SSriharsha.Basavapatna@Sun.COM #ifdef VNET_IOC_DEBUG
58159336SSriharsha.Basavapatna@Sun.COM
58169336SSriharsha.Basavapatna@Sun.COM static void
vgen_ioctl(void * arg,queue_t * q,mblk_t * mp)58179336SSriharsha.Basavapatna@Sun.COM vgen_ioctl(void *arg, queue_t *q, mblk_t *mp)
58189336SSriharsha.Basavapatna@Sun.COM {
58199336SSriharsha.Basavapatna@Sun.COM struct iocblk *iocp;
58209336SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp;
58219336SSriharsha.Basavapatna@Sun.COM enum ioc_reply {
58229336SSriharsha.Basavapatna@Sun.COM IOC_INVAL = -1, /* bad, NAK with EINVAL */
58239336SSriharsha.Basavapatna@Sun.COM IOC_ACK /* OK, just send ACK */
58249336SSriharsha.Basavapatna@Sun.COM } status;
58259336SSriharsha.Basavapatna@Sun.COM int rv;
58269336SSriharsha.Basavapatna@Sun.COM
58279336SSriharsha.Basavapatna@Sun.COM iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
58289336SSriharsha.Basavapatna@Sun.COM iocp->ioc_error = 0;
58299336SSriharsha.Basavapatna@Sun.COM portp = (vgen_port_t *)arg;
58309336SSriharsha.Basavapatna@Sun.COM
58319336SSriharsha.Basavapatna@Sun.COM if (portp == NULL) {
58329336SSriharsha.Basavapatna@Sun.COM status = IOC_INVAL;
58339336SSriharsha.Basavapatna@Sun.COM goto vgen_ioc_exit;
58349336SSriharsha.Basavapatna@Sun.COM }
58359336SSriharsha.Basavapatna@Sun.COM
58369336SSriharsha.Basavapatna@Sun.COM mutex_enter(&portp->lock);
58379336SSriharsha.Basavapatna@Sun.COM
58389336SSriharsha.Basavapatna@Sun.COM switch (iocp->ioc_cmd) {
58399336SSriharsha.Basavapatna@Sun.COM
58409336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_DOWN:
58419336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_UP:
58429336SSriharsha.Basavapatna@Sun.COM rv = vgen_force_link_state(portp, iocp->ioc_cmd);
58439336SSriharsha.Basavapatna@Sun.COM (rv == 0) ? (status = IOC_ACK) : (status = IOC_INVAL);
58449336SSriharsha.Basavapatna@Sun.COM break;
58459336SSriharsha.Basavapatna@Sun.COM
58469336SSriharsha.Basavapatna@Sun.COM default:
58479336SSriharsha.Basavapatna@Sun.COM status = IOC_INVAL;
58489336SSriharsha.Basavapatna@Sun.COM break;
58499336SSriharsha.Basavapatna@Sun.COM
58509336SSriharsha.Basavapatna@Sun.COM }
58519336SSriharsha.Basavapatna@Sun.COM
58529336SSriharsha.Basavapatna@Sun.COM mutex_exit(&portp->lock);
58539336SSriharsha.Basavapatna@Sun.COM
58549336SSriharsha.Basavapatna@Sun.COM vgen_ioc_exit:
58559336SSriharsha.Basavapatna@Sun.COM
58569336SSriharsha.Basavapatna@Sun.COM switch (status) {
58579336SSriharsha.Basavapatna@Sun.COM default:
58589336SSriharsha.Basavapatna@Sun.COM case IOC_INVAL:
58599336SSriharsha.Basavapatna@Sun.COM /* Error, reply with a NAK and EINVAL error */
58609336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL);
58619336SSriharsha.Basavapatna@Sun.COM break;
58629336SSriharsha.Basavapatna@Sun.COM case IOC_ACK:
58639336SSriharsha.Basavapatna@Sun.COM /* OK, reply with an ACK */
58649336SSriharsha.Basavapatna@Sun.COM miocack(q, mp, 0, 0);
58659336SSriharsha.Basavapatna@Sun.COM break;
58669336SSriharsha.Basavapatna@Sun.COM }
58679336SSriharsha.Basavapatna@Sun.COM }
58689336SSriharsha.Basavapatna@Sun.COM
58699336SSriharsha.Basavapatna@Sun.COM static int
vgen_force_link_state(vgen_port_t * portp,int cmd)58709336SSriharsha.Basavapatna@Sun.COM vgen_force_link_state(vgen_port_t *portp, int cmd)
58719336SSriharsha.Basavapatna@Sun.COM {
58729336SSriharsha.Basavapatna@Sun.COM ldc_status_t istatus;
587312011SSriharsha.Basavapatna@Sun.COM int rv;
587412011SSriharsha.Basavapatna@Sun.COM vgen_ldc_t *ldcp = portp->ldcp;
58759336SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = portp->vgenp;
587612011SSriharsha.Basavapatna@Sun.COM
58779336SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->cblock);
58789336SSriharsha.Basavapatna@Sun.COM
58799336SSriharsha.Basavapatna@Sun.COM switch (cmd) {
58809336SSriharsha.Basavapatna@Sun.COM
58819336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_DOWN:
58829336SSriharsha.Basavapatna@Sun.COM (void) ldc_down(ldcp->ldc_handle);
58839336SSriharsha.Basavapatna@Sun.COM ldcp->link_down_forced = B_TRUE;
58849336SSriharsha.Basavapatna@Sun.COM break;
58859336SSriharsha.Basavapatna@Sun.COM
58869336SSriharsha.Basavapatna@Sun.COM case VNET_FORCE_LINK_UP:
588712011SSriharsha.Basavapatna@Sun.COM vgen_ldc_up(ldcp);
58889336SSriharsha.Basavapatna@Sun.COM ldcp->link_down_forced = B_FALSE;
58899336SSriharsha.Basavapatna@Sun.COM
58909336SSriharsha.Basavapatna@Sun.COM if (ldc_status(ldcp->ldc_handle, &istatus) != 0) {
58919336SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, ldcp, "ldc_status err\n");
58929336SSriharsha.Basavapatna@Sun.COM } else {
58939336SSriharsha.Basavapatna@Sun.COM ldcp->ldc_status = istatus;
58949336SSriharsha.Basavapatna@Sun.COM }
58959336SSriharsha.Basavapatna@Sun.COM
58969336SSriharsha.Basavapatna@Sun.COM /* if channel is already UP - restart handshake */
58979336SSriharsha.Basavapatna@Sun.COM if (ldcp->ldc_status == LDC_UP) {
58989336SSriharsha.Basavapatna@Sun.COM vgen_handle_evt_up(ldcp);
58999336SSriharsha.Basavapatna@Sun.COM }
59009336SSriharsha.Basavapatna@Sun.COM break;
59019336SSriharsha.Basavapatna@Sun.COM
59029336SSriharsha.Basavapatna@Sun.COM }
59039336SSriharsha.Basavapatna@Sun.COM
59049336SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->cblock);
59059336SSriharsha.Basavapatna@Sun.COM
59069336SSriharsha.Basavapatna@Sun.COM return (0);
59079336SSriharsha.Basavapatna@Sun.COM }
59089336SSriharsha.Basavapatna@Sun.COM
59099336SSriharsha.Basavapatna@Sun.COM #else
59109336SSriharsha.Basavapatna@Sun.COM
59119336SSriharsha.Basavapatna@Sun.COM static void
vgen_ioctl(void * arg,queue_t * q,mblk_t * mp)59129336SSriharsha.Basavapatna@Sun.COM vgen_ioctl(void *arg, queue_t *q, mblk_t *mp)
59139336SSriharsha.Basavapatna@Sun.COM {
59149336SSriharsha.Basavapatna@Sun.COM vgen_port_t *portp;
59159336SSriharsha.Basavapatna@Sun.COM
59169336SSriharsha.Basavapatna@Sun.COM portp = (vgen_port_t *)arg;
59179336SSriharsha.Basavapatna@Sun.COM
59189336SSriharsha.Basavapatna@Sun.COM if (portp == NULL) {
59199336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, EINVAL);
59209336SSriharsha.Basavapatna@Sun.COM return;
59219336SSriharsha.Basavapatna@Sun.COM }
59229336SSriharsha.Basavapatna@Sun.COM
59239336SSriharsha.Basavapatna@Sun.COM miocnak(q, mp, 0, ENOTSUP);
59249336SSriharsha.Basavapatna@Sun.COM }
59259336SSriharsha.Basavapatna@Sun.COM
59269336SSriharsha.Basavapatna@Sun.COM #endif
5927