1*1991Sheppo /* 2*1991Sheppo * CDDL HEADER START 3*1991Sheppo * 4*1991Sheppo * The contents of this file are subject to the terms of the 5*1991Sheppo * Common Development and Distribution License (the "License"). 6*1991Sheppo * You may not use this file except in compliance with the License. 7*1991Sheppo * 8*1991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1991Sheppo * or http://www.opensolaris.org/os/licensing. 10*1991Sheppo * See the License for the specific language governing permissions 11*1991Sheppo * and limitations under the License. 12*1991Sheppo * 13*1991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 14*1991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1991Sheppo * If applicable, add the following below this CDDL HEADER, with the 16*1991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 17*1991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 18*1991Sheppo * 19*1991Sheppo * CDDL HEADER END 20*1991Sheppo */ 21*1991Sheppo 22*1991Sheppo /* 23*1991Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1991Sheppo * Use is subject to license terms. 25*1991Sheppo */ 26*1991Sheppo 27*1991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 28*1991Sheppo 29*1991Sheppo #include <sys/types.h> 30*1991Sheppo #include <sys/errno.h> 31*1991Sheppo #include <sys/param.h> 32*1991Sheppo #include <sys/stream.h> 33*1991Sheppo #include <sys/kmem.h> 34*1991Sheppo #include <sys/conf.h> 35*1991Sheppo #include <sys/devops.h> 36*1991Sheppo #include <sys/ksynch.h> 37*1991Sheppo #include <sys/stat.h> 38*1991Sheppo #include <sys/modctl.h> 39*1991Sheppo #include <sys/debug.h> 40*1991Sheppo #include <sys/ethernet.h> 41*1991Sheppo #include <sys/ddi.h> 42*1991Sheppo #include <sys/sunddi.h> 43*1991Sheppo #include <sys/strsun.h> 44*1991Sheppo #include <sys/note.h> 45*1991Sheppo #include <sys/mac.h> 46*1991Sheppo #include <sys/ldc.h> 47*1991Sheppo #include <sys/mach_descrip.h> 48*1991Sheppo #include <sys/mdeg.h> 49*1991Sheppo #include <sys/vio_mailbox.h> 50*1991Sheppo #include <sys/vio_common.h> 51*1991Sheppo #include <sys/vnet_common.h> 52*1991Sheppo #include <sys/vnet_gen.h> 53*1991Sheppo #include <sys/vnet_mailbox.h> 54*1991Sheppo 55*1991Sheppo /* 56*1991Sheppo * Implementation of the mac functionality for vnet using the 57*1991Sheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC). 58*1991Sheppo */ 59*1991Sheppo 60*1991Sheppo /* 61*1991Sheppo * Function prototypes. 62*1991Sheppo */ 63*1991Sheppo /* vgen proxy entry points */ 64*1991Sheppo int vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp, 65*1991Sheppo const uint8_t *macaddr, mac_t **vgenmacp); 66*1991Sheppo void vgen_uninit(void *arg); 67*1991Sheppo static int vgen_start(void *arg); 68*1991Sheppo static void vgen_stop(void *arg); 69*1991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp); 70*1991Sheppo static void vgen_resources(void *arg); 71*1991Sheppo static int vgen_multicst(void *arg, boolean_t add, 72*1991Sheppo const uint8_t *mca); 73*1991Sheppo static int vgen_promisc(void *arg, boolean_t on); 74*1991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca); 75*1991Sheppo static uint64_t vgen_stat(void *arg, enum mac_stat stat); 76*1991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp); 77*1991Sheppo 78*1991Sheppo /* externs - functions provided by vnet to add/remove/modify entries in fdb */ 79*1991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 80*1991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 81*1991Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 82*1991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 83*1991Sheppo void vnet_del_def_rte(void *arg); 84*1991Sheppo 85*1991Sheppo /* vgen internal functions */ 86*1991Sheppo static void vgen_detach_ports(vgen_t *vgenp); 87*1991Sheppo static void vgen_port_detach(vgen_port_t *portp); 88*1991Sheppo static void vgen_port_list_insert(vgen_port_t *portp); 89*1991Sheppo static void vgen_port_list_remove(vgen_port_t *portp); 90*1991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp, 91*1991Sheppo int port_num); 92*1991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp); 93*1991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp); 94*1991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 95*1991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 96*1991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 97*1991Sheppo static int vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 98*1991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port); 99*1991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp); 100*1991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, 101*1991Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex); 102*1991Sheppo static uint64_t vgen_port_stat(vgen_port_t *portp, enum mac_stat stat); 103*1991Sheppo 104*1991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id); 105*1991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp); 106*1991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp); 107*1991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp); 108*1991Sheppo static void vgen_init_ports(vgen_t *vgenp); 109*1991Sheppo static void vgen_port_init(vgen_port_t *portp); 110*1991Sheppo static void vgen_uninit_ports(vgen_t *vgenp); 111*1991Sheppo static void vgen_port_uninit(vgen_port_t *portp); 112*1991Sheppo static void vgen_init_ldcs(vgen_port_t *portp); 113*1991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp); 114*1991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp); 115*1991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp); 116*1991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp); 117*1991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp); 118*1991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp); 119*1991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp); 120*1991Sheppo static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, enum mac_stat stat); 121*1991Sheppo static void vgen_init_macp(vgen_t *vgenp, mac_t *macp); 122*1991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg); 123*1991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp); 124*1991Sheppo static int vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp); 125*1991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp); 126*1991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp); 127*1991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp); 128*1991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp); 129*1991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp); 130*1991Sheppo static void vgen_ldc_watchdog(void *arg); 131*1991Sheppo static void vgen_copymsg(mblk_t *mp, void *bufp); 132*1991Sheppo static int vgen_setup_kstats(vgen_ldc_t *ldcp); 133*1991Sheppo static void vgen_destroy_kstats(vgen_ldc_t *ldcp); 134*1991Sheppo static int vgen_kstat_update(kstat_t *ksp, int rw); 135*1991Sheppo 136*1991Sheppo /* vgen handshake functions */ 137*1991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp); 138*1991Sheppo static int vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 139*1991Sheppo uint16_t ver_minor); 140*1991Sheppo static int vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp); 141*1991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 142*1991Sheppo boolean_t caller_holds_lock); 143*1991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp); 144*1991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp); 145*1991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp); 146*1991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp); 147*1991Sheppo static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, 148*1991Sheppo uint32_t end, uint64_t next_txseq); 149*1991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp); 150*1991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp); 151*1991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp); 152*1991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp); 153*1991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp); 154*1991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp); 155*1991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp); 156*1991Sheppo static void vgen_handle_version_negotiate(vgen_ldc_t *ldcp, 157*1991Sheppo vio_msg_tag_t *tagp); 158*1991Sheppo static void vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 159*1991Sheppo static void vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 160*1991Sheppo static void vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 161*1991Sheppo static void vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 162*1991Sheppo static void vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 163*1991Sheppo static void vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 164*1991Sheppo mblk_t **headp, mblk_t **tailp); 165*1991Sheppo static void vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 166*1991Sheppo mblk_t **headp, mblk_t **tailp); 167*1991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 168*1991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 169*1991Sheppo static uint64_t vgen_macaddr_strtoul(const uint8_t *macaddr); 170*1991Sheppo static int vgen_macaddr_ultostr(uint64_t value, uint8_t *macaddr); 171*1991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf); 172*1991Sheppo static void vgen_hwatchdog(void *arg); 173*1991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint); 174*1991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp); 175*1991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp); 176*1991Sheppo 177*1991Sheppo /* 178*1991Sheppo * The handshake process consists of 5 phases defined below, with VH_PHASE0 179*1991Sheppo * being the pre-handshake phase and VH_DONE is the phase to indicate 180*1991Sheppo * successful completion of all phases. 181*1991Sheppo * Each phase may have one to several handshake states which are required 182*1991Sheppo * to complete successfully to move to the next phase. 183*1991Sheppo * Refer to the functions vgen_handshake() and vgen_handshake_done() for 184*1991Sheppo * more details. 185*1991Sheppo */ 186*1991Sheppo /* handshake phases */ 187*1991Sheppo enum { VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 }; 188*1991Sheppo 189*1991Sheppo /* handshake states */ 190*1991Sheppo enum { 191*1991Sheppo 192*1991Sheppo VER_INFO_SENT = 0x1, 193*1991Sheppo VER_ACK_RCVD = 0x2, 194*1991Sheppo VER_INFO_RCVD = 0x4, 195*1991Sheppo VER_ACK_SENT = 0x8, 196*1991Sheppo VER_NEGOTIATED = (VER_ACK_RCVD | VER_ACK_SENT), 197*1991Sheppo 198*1991Sheppo ATTR_INFO_SENT = 0x10, 199*1991Sheppo ATTR_ACK_RCVD = 0x20, 200*1991Sheppo ATTR_INFO_RCVD = 0x40, 201*1991Sheppo ATTR_ACK_SENT = 0x80, 202*1991Sheppo ATTR_INFO_EXCHANGED = (ATTR_ACK_RCVD | ATTR_ACK_SENT), 203*1991Sheppo 204*1991Sheppo DRING_INFO_SENT = 0x100, 205*1991Sheppo DRING_ACK_RCVD = 0x200, 206*1991Sheppo DRING_INFO_RCVD = 0x400, 207*1991Sheppo DRING_ACK_SENT = 0x800, 208*1991Sheppo DRING_INFO_EXCHANGED = (DRING_ACK_RCVD | DRING_ACK_SENT), 209*1991Sheppo 210*1991Sheppo RDX_INFO_SENT = 0x1000, 211*1991Sheppo RDX_ACK_RCVD = 0x2000, 212*1991Sheppo RDX_INFO_RCVD = 0x4000, 213*1991Sheppo RDX_ACK_SENT = 0x8000, 214*1991Sheppo RDX_EXCHANGED = (RDX_ACK_RCVD | RDX_ACK_SENT) 215*1991Sheppo 216*1991Sheppo }; 217*1991Sheppo 218*1991Sheppo #define LDC_LOCK(ldcp) \ 219*1991Sheppo mutex_enter(&((ldcp)->cblock));\ 220*1991Sheppo mutex_enter(&((ldcp)->txlock));\ 221*1991Sheppo mutex_enter(&((ldcp)->tclock)); 222*1991Sheppo #define LDC_UNLOCK(ldcp) \ 223*1991Sheppo mutex_exit(&((ldcp)->tclock));\ 224*1991Sheppo mutex_exit(&((ldcp)->txlock));\ 225*1991Sheppo mutex_exit(&((ldcp)->cblock)); 226*1991Sheppo 227*1991Sheppo static struct ether_addr etherbroadcastaddr = { 228*1991Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 229*1991Sheppo }; 230*1991Sheppo /* 231*1991Sheppo * MIB II broadcast/multicast packets 232*1991Sheppo */ 233*1991Sheppo #define IS_BROADCAST(ehp) \ 234*1991Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 235*1991Sheppo #define IS_MULTICAST(ehp) \ 236*1991Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 237*1991Sheppo 238*1991Sheppo /* 239*1991Sheppo * Property names 240*1991Sheppo */ 241*1991Sheppo static char macaddr_propname[] = "mac-address"; 242*1991Sheppo static char rmacaddr_propname[] = "remote-mac-address"; 243*1991Sheppo static char channel_propname[] = "channel-endpoint"; 244*1991Sheppo static char reg_propname[] = "reg"; 245*1991Sheppo static char port_propname[] = "port"; 246*1991Sheppo static char swport_propname[] = "switch-port"; 247*1991Sheppo static char id_propname[] = "id"; 248*1991Sheppo 249*1991Sheppo /* versions supported - in decreasing order */ 250*1991Sheppo static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 0} }; 251*1991Sheppo 252*1991Sheppo /* Tunables */ 253*1991Sheppo uint32_t vgen_hwd_interval = 1000; /* handshake watchdog freq in msec */ 254*1991Sheppo uint32_t vgen_max_hretries = 1; /* max # of handshake retries */ 255*1991Sheppo 256*1991Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */ 257*1991Sheppo 258*1991Sheppo #ifdef DEBUG 259*1991Sheppo /* flags to simulate error conditions for debugging */ 260*1991Sheppo int vgen_trigger_txtimeout = 0; 261*1991Sheppo int vgen_trigger_rxlost = 0; 262*1991Sheppo #endif 263*1991Sheppo 264*1991Sheppo /* MD update matching structure */ 265*1991Sheppo static md_prop_match_t vport_prop_match[] = { 266*1991Sheppo { MDET_PROP_VAL, "id" }, 267*1991Sheppo { MDET_LIST_END, NULL } 268*1991Sheppo }; 269*1991Sheppo 270*1991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 271*1991Sheppo vport_prop_match }; 272*1991Sheppo 273*1991Sheppo /* template for matching a particular vnet instance */ 274*1991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = { 275*1991Sheppo { MDET_PROP_STR, "name", "network" }, 276*1991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 277*1991Sheppo { MDET_LIST_END, NULL, NULL } 278*1991Sheppo }; 279*1991Sheppo 280*1991Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val) 281*1991Sheppo 282*1991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 283*1991Sheppo 284*1991Sheppo /* externs */ 285*1991Sheppo extern uint32_t vnet_ntxds; 286*1991Sheppo extern uint32_t vnet_reclaim_lowat; 287*1991Sheppo extern uint32_t vnet_reclaim_hiwat; 288*1991Sheppo extern uint32_t vnet_ldcwd_interval; 289*1991Sheppo extern uint32_t vnet_ldcwd_txtimeout; 290*1991Sheppo extern uint32_t vnet_ldc_qlen; 291*1991Sheppo extern int _vnet_dbglevel; 292*1991Sheppo extern void _vnetdebug_printf(void *vnetp, const char *fmt, ...); 293*1991Sheppo 294*1991Sheppo #ifdef DEBUG 295*1991Sheppo 296*1991Sheppo /* 297*1991Sheppo * XXX: definitions below need to be in sync with those in vnet.c 298*1991Sheppo */ 299*1991Sheppo 300*1991Sheppo /* 301*1991Sheppo * debug levels: 302*1991Sheppo * DBG_LEVEL1: Function entry/exit tracing 303*1991Sheppo * DBG_LEVEL2: Info messages 304*1991Sheppo * DBG_LEVEL3: Warning messages 305*1991Sheppo * DBG_LEVEL4: Error messages 306*1991Sheppo */ 307*1991Sheppo 308*1991Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 309*1991Sheppo DBG_LEVEL4 = 0x08 }; 310*1991Sheppo 311*1991Sheppo #define DBG1(_s) do { \ 312*1991Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 313*1991Sheppo _vnetdebug_printf _s; \ 314*1991Sheppo } \ 315*1991Sheppo _NOTE(CONSTCOND) } while (0) 316*1991Sheppo 317*1991Sheppo #define DBG2(_s) do { \ 318*1991Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 319*1991Sheppo _vnetdebug_printf _s; \ 320*1991Sheppo } \ 321*1991Sheppo _NOTE(CONSTCOND) } while (0) 322*1991Sheppo 323*1991Sheppo #define DWARN(_s) do { \ 324*1991Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 325*1991Sheppo _vnetdebug_printf _s; \ 326*1991Sheppo } \ 327*1991Sheppo _NOTE(CONSTCOND) } while (0) 328*1991Sheppo 329*1991Sheppo #define DERR(_s) do { \ 330*1991Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 331*1991Sheppo _vnetdebug_printf _s; \ 332*1991Sheppo } \ 333*1991Sheppo _NOTE(CONSTCOND) } while (0) 334*1991Sheppo 335*1991Sheppo #else 336*1991Sheppo 337*1991Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 338*1991Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 339*1991Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 340*1991Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 341*1991Sheppo 342*1991Sheppo #endif 343*1991Sheppo 344*1991Sheppo #ifdef DEBUG 345*1991Sheppo 346*1991Sheppo /* simulate handshake error conditions for debug */ 347*1991Sheppo uint32_t vgen_hdbg; 348*1991Sheppo #define HDBG_VERSION 0x1 349*1991Sheppo #define HDBG_TIMEOUT 0x2 350*1991Sheppo #define HDBG_BAD_SID 0x4 351*1991Sheppo #define HDBG_OUT_STATE 0x8 352*1991Sheppo 353*1991Sheppo #if 0 354*1991Sheppo /* debug version negotiation, need to redefine VGEN_NUM_VER */ 355*1991Sheppo vgen_ver_t dbg_vgen_versions[VGEN_NUM_VER] = 356*1991Sheppo { {5, 0}, {3, 0}, {2, 1}, {1, 2}, {1, 1} }; 357*1991Sheppo #endif 358*1991Sheppo 359*1991Sheppo #endif 360*1991Sheppo 361*1991Sheppo /* 362*1991Sheppo * vgen_init() is called by an instance of vnet driver to initialize the 363*1991Sheppo * corresponding generic proxy transport layer. The arguments passed by vnet 364*1991Sheppo * are - an opaque pointer to the vnet instance, pointers to dev_info_t and 365*1991Sheppo * mac_t of the vnet device, mac address of the vnet device, and a pointer to 366*1991Sheppo * the mac_t of the generic transport is returned in the last argument. 367*1991Sheppo */ 368*1991Sheppo int 369*1991Sheppo vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp, 370*1991Sheppo const uint8_t *macaddr, mac_t **vgenmacp) 371*1991Sheppo { 372*1991Sheppo vgen_t *vgenp; 373*1991Sheppo mac_t *macp; 374*1991Sheppo int instance; 375*1991Sheppo 376*1991Sheppo if ((vnetp == NULL) || (vnetdip == NULL) ||(vnetmacp == NULL)) 377*1991Sheppo return (DDI_FAILURE); 378*1991Sheppo 379*1991Sheppo instance = ddi_get_instance(vnetdip); 380*1991Sheppo 381*1991Sheppo DBG1((vnetp, "vgen_init: enter vnet_instance(%d)\n", instance)); 382*1991Sheppo 383*1991Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP); 384*1991Sheppo 385*1991Sheppo vgenp->vnetp = vnetp; 386*1991Sheppo vgenp->vnetdip = vnetdip; 387*1991Sheppo vgenp->vnetmacp = vnetmacp; 388*1991Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL); 389*1991Sheppo 390*1991Sheppo /* allocate multicast table */ 391*1991Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE * 392*1991Sheppo sizeof (struct ether_addr), KM_SLEEP); 393*1991Sheppo vgenp->mccount = 0; 394*1991Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE; 395*1991Sheppo 396*1991Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL); 397*1991Sheppo 398*1991Sheppo /* register with MD event generator */ 399*1991Sheppo if (vgen_mdeg_reg(vgenp) != DDI_SUCCESS) { 400*1991Sheppo mutex_destroy(&vgenp->lock); 401*1991Sheppo kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE * 402*1991Sheppo sizeof (struct ether_addr)); 403*1991Sheppo KMEM_FREE(vgenp); 404*1991Sheppo return (DDI_FAILURE); 405*1991Sheppo } 406*1991Sheppo 407*1991Sheppo macp = &vgenp->vgenmac; 408*1991Sheppo vgen_init_macp(vgenp, macp); 409*1991Sheppo 410*1991Sheppo /* register mac_t of this vgen_t with vnet */ 411*1991Sheppo *vgenmacp = macp; 412*1991Sheppo 413*1991Sheppo DBG1((vnetp, "vgen_init: exit vnet_instance(%d)\n", instance)); 414*1991Sheppo return (DDI_SUCCESS); 415*1991Sheppo } 416*1991Sheppo 417*1991Sheppo /* 418*1991Sheppo * Called by vnet to undo the initializations done by vgen_init(). 419*1991Sheppo * The handle provided by generic transport during vgen_init() is the argument. 420*1991Sheppo */ 421*1991Sheppo void 422*1991Sheppo vgen_uninit(void *arg) 423*1991Sheppo { 424*1991Sheppo vgen_t *vgenp = (vgen_t *)arg; 425*1991Sheppo void *vnetp; 426*1991Sheppo int instance; 427*1991Sheppo 428*1991Sheppo if (vgenp == NULL) 429*1991Sheppo return; 430*1991Sheppo 431*1991Sheppo instance = ddi_get_instance(vgenp->vnetdip); 432*1991Sheppo vnetp = vgenp->vnetp; 433*1991Sheppo 434*1991Sheppo DBG1((vnetp, "vgen_uninit: enter vnet_instance(%d)\n", instance)); 435*1991Sheppo 436*1991Sheppo /* unregister with MD event generator */ 437*1991Sheppo vgen_mdeg_unreg(vgenp); 438*1991Sheppo 439*1991Sheppo mutex_enter(&vgenp->lock); 440*1991Sheppo 441*1991Sheppo /* detach all ports from the device */ 442*1991Sheppo vgen_detach_ports(vgenp); 443*1991Sheppo 444*1991Sheppo /* free multicast table */ 445*1991Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr)); 446*1991Sheppo 447*1991Sheppo mutex_exit(&vgenp->lock); 448*1991Sheppo 449*1991Sheppo mutex_destroy(&vgenp->lock); 450*1991Sheppo 451*1991Sheppo KMEM_FREE(vgenp); 452*1991Sheppo 453*1991Sheppo DBG1((vnetp, "vgen_uninit: exit vnet_instance(%d)\n", instance)); 454*1991Sheppo } 455*1991Sheppo 456*1991Sheppo /* enable transmit/receive for the device */ 457*1991Sheppo static int 458*1991Sheppo vgen_start(void *arg) 459*1991Sheppo { 460*1991Sheppo vgen_t *vgenp = (vgen_t *)arg; 461*1991Sheppo 462*1991Sheppo DBG1((vgenp->vnetp, "vgen_start: enter\n")); 463*1991Sheppo 464*1991Sheppo mutex_enter(&vgenp->lock); 465*1991Sheppo vgen_init_ports(vgenp); 466*1991Sheppo vgenp->flags |= VGEN_STARTED; 467*1991Sheppo mutex_exit(&vgenp->lock); 468*1991Sheppo 469*1991Sheppo DBG1((vgenp->vnetp, "vgen_start: exit\n")); 470*1991Sheppo return (DDI_SUCCESS); 471*1991Sheppo } 472*1991Sheppo 473*1991Sheppo /* stop transmit/receive */ 474*1991Sheppo static void 475*1991Sheppo vgen_stop(void *arg) 476*1991Sheppo { 477*1991Sheppo vgen_t *vgenp = (vgen_t *)arg; 478*1991Sheppo 479*1991Sheppo DBG1((vgenp->vnetp, "vgen_stop: enter\n")); 480*1991Sheppo 481*1991Sheppo mutex_enter(&vgenp->lock); 482*1991Sheppo vgen_uninit_ports(vgenp); 483*1991Sheppo vgenp->flags &= ~(VGEN_STARTED); 484*1991Sheppo mutex_exit(&vgenp->lock); 485*1991Sheppo 486*1991Sheppo DBG1((vgenp->vnetp, "vgen_stop: exit\n")); 487*1991Sheppo } 488*1991Sheppo 489*1991Sheppo /* vgen transmit function */ 490*1991Sheppo static mblk_t * 491*1991Sheppo vgen_tx(void *arg, mblk_t *mp) 492*1991Sheppo { 493*1991Sheppo vgen_port_t *portp; 494*1991Sheppo int status; 495*1991Sheppo 496*1991Sheppo portp = (vgen_port_t *)arg; 497*1991Sheppo status = vgen_portsend(portp, mp); 498*1991Sheppo if (status != VGEN_SUCCESS) { 499*1991Sheppo /* failure */ 500*1991Sheppo return (mp); 501*1991Sheppo } 502*1991Sheppo /* success */ 503*1991Sheppo return (NULL); 504*1991Sheppo } 505*1991Sheppo 506*1991Sheppo /* transmit packets over the given port */ 507*1991Sheppo static int 508*1991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp) 509*1991Sheppo { 510*1991Sheppo vgen_ldclist_t *ldclp; 511*1991Sheppo vgen_ldc_t *ldcp; 512*1991Sheppo vgen_t *vgenp; 513*1991Sheppo int status; 514*1991Sheppo 515*1991Sheppo vgenp = portp->vgenp; 516*1991Sheppo ldclp = &portp->ldclist; 517*1991Sheppo READ_ENTER(&ldclp->rwlock); 518*1991Sheppo /* 519*1991Sheppo * XXX - for now, we have a single channel. 520*1991Sheppo */ 521*1991Sheppo if (ldclp->headp == NULL) { 522*1991Sheppo DWARN((vgenp->vnetp, "vgen_portsend: dropping packet\n")); 523*1991Sheppo RW_EXIT(&ldclp->rwlock); 524*1991Sheppo return (VGEN_FAILURE); 525*1991Sheppo } 526*1991Sheppo ldcp = ldclp->headp; 527*1991Sheppo 528*1991Sheppo if (ldcp->need_resched) { 529*1991Sheppo /* out of tx resources, see vgen_ldcsend() for details. */ 530*1991Sheppo DWARN((vgenp->vnetp, "vgen_portsend: dropping packet...\n")); 531*1991Sheppo 532*1991Sheppo mutex_enter(&ldcp->txlock); 533*1991Sheppo ldcp->statsp->tx_no_desc++; 534*1991Sheppo mutex_exit(&ldcp->txlock); 535*1991Sheppo 536*1991Sheppo RW_EXIT(&ldclp->rwlock); 537*1991Sheppo freemsg(mp); 538*1991Sheppo return (VGEN_SUCCESS); 539*1991Sheppo } 540*1991Sheppo 541*1991Sheppo status = vgen_ldcsend(ldcp, mp); 542*1991Sheppo RW_EXIT(&ldclp->rwlock); 543*1991Sheppo 544*1991Sheppo if (status != VGEN_TX_SUCCESS) 545*1991Sheppo return (VGEN_FAILURE); 546*1991Sheppo 547*1991Sheppo return (VGEN_SUCCESS); 548*1991Sheppo } 549*1991Sheppo 550*1991Sheppo /* channel transmit function */ 551*1991Sheppo static int 552*1991Sheppo vgen_ldcsend(vgen_ldc_t *ldcp, mblk_t *mp) 553*1991Sheppo { 554*1991Sheppo void *vnetp; 555*1991Sheppo size_t size; 556*1991Sheppo uint64_t datalen; 557*1991Sheppo uchar_t *rptr; 558*1991Sheppo mblk_t *bp = NULL; 559*1991Sheppo int rv; 560*1991Sheppo uint32_t i; 561*1991Sheppo uint32_t start; 562*1991Sheppo uint32_t end; 563*1991Sheppo int txpending = 0; 564*1991Sheppo int ci; 565*1991Sheppo uint32_t ncookies; 566*1991Sheppo uint64_t nc; 567*1991Sheppo vgen_private_desc_t *tbufp; 568*1991Sheppo vgen_private_desc_t *ntbufp; 569*1991Sheppo vnet_public_desc_t *txdp; 570*1991Sheppo vio_dring_entry_hdr_t *hdrp; 571*1991Sheppo vgen_stats_t *statsp; 572*1991Sheppo struct ether_header *ehp; 573*1991Sheppo boolean_t is_bcast = B_FALSE; 574*1991Sheppo boolean_t is_mcast = B_FALSE; 575*1991Sheppo boolean_t reclaim = B_FALSE; 576*1991Sheppo boolean_t need_intr = B_FALSE; 577*1991Sheppo boolean_t err = B_FALSE; 578*1991Sheppo 579*1991Sheppo vnetp = LDC_TO_VNET(ldcp); 580*1991Sheppo statsp = ldcp->statsp; 581*1991Sheppo DBG1((vnetp, "vgen_ldcsend: enter ldcid(%lx)\n", ldcp->ldc_id)); 582*1991Sheppo 583*1991Sheppo /* drop the packet if handshake is not done or ldc is not up */ 584*1991Sheppo if ((ldcp->hphase != VH_DONE) || (ldcp->ldc_status != LDC_UP)) { 585*1991Sheppo DWARN((vnetp, 586*1991Sheppo "vgen_ldcsend: id(%lx) status(%d), dropping packet\n", 587*1991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 588*1991Sheppo freemsg(mp); 589*1991Sheppo return (VGEN_TX_SUCCESS); 590*1991Sheppo } 591*1991Sheppo 592*1991Sheppo size = msgsize(mp); 593*1991Sheppo if (size > (size_t)ETHERMAX) { 594*1991Sheppo DWARN((vnetp, "vgen_ldcsend: id(%lx) invalid size(%d)\n", 595*1991Sheppo ldcp->ldc_id, size)); 596*1991Sheppo freemsg(mp); 597*1991Sheppo return (VGEN_TX_SUCCESS); 598*1991Sheppo } 599*1991Sheppo if ((size < (size_t)ETHERMIN) || /* needs padding to ETHERMIN */ 600*1991Sheppo (mp->b_cont) || /* more than 1 mblk */ 601*1991Sheppo ((uintptr_t)mp->b_rptr & 0x7) || /* data not 8 byte aligned */ 602*1991Sheppo ((mp->b_wptr - mp->b_rptr) & 0x7)) { /* datalen not multiple of 8 */ 603*1991Sheppo if (size < ETHERMIN) 604*1991Sheppo size = ETHERMIN; 605*1991Sheppo /* 606*1991Sheppo * The data buffer returned by allocb(9F) is 8byte aligned. 607*1991Sheppo * We allocate extra 8 bytes to ensure size is multiple of 608*1991Sheppo * 8 bytes for ldc_mem_bind_handle(). 609*1991Sheppo */ 610*1991Sheppo bp = allocb(size + 8, BPRI_MED); 611*1991Sheppo if (bp == NULL) { 612*1991Sheppo /* drop the packet */ 613*1991Sheppo freemsg(mp); 614*1991Sheppo mutex_enter(&ldcp->txlock); 615*1991Sheppo statsp->tx_allocb_fail++; 616*1991Sheppo mutex_exit(&ldcp->txlock); 617*1991Sheppo return (VGEN_TX_SUCCESS); 618*1991Sheppo } 619*1991Sheppo vgen_copymsg(mp, bp->b_rptr); 620*1991Sheppo bp->b_wptr += size; 621*1991Sheppo datalen = size; /* actual data length without pad */ 622*1991Sheppo size = (datalen + 7) & ~7; 623*1991Sheppo bp->b_wptr += (size - datalen); 624*1991Sheppo } else { /* size/alignment are ok */ 625*1991Sheppo datalen = size; 626*1991Sheppo } 627*1991Sheppo 628*1991Sheppo mutex_enter(&ldcp->txlock); 629*1991Sheppo 630*1991Sheppo /* check if the channel is still up & running */ 631*1991Sheppo if ((ldcp->hphase != VH_DONE) || (ldcp->ldc_status != LDC_UP)) { 632*1991Sheppo DWARN((vnetp, 633*1991Sheppo "vgen_ldcsend: id(%lx) status(%d), dropping packet\n", 634*1991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 635*1991Sheppo err = B_TRUE; 636*1991Sheppo goto vgen_tx_exit; 637*1991Sheppo } 638*1991Sheppo 639*1991Sheppo /* 640*1991Sheppo * allocate a descriptor 641*1991Sheppo */ 642*1991Sheppo tbufp = ldcp->next_tbufp; 643*1991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 644*1991Sheppo if (tbufp->flags != VGEN_PRIV_DESC_FREE || 645*1991Sheppo ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 646*1991Sheppo 647*1991Sheppo mutex_enter(&ldcp->tclock); 648*1991Sheppo if (ntbufp == ldcp->cur_tbufp) 649*1991Sheppo ldcp->need_resched = B_TRUE; 650*1991Sheppo mutex_exit(&ldcp->tclock); 651*1991Sheppo 652*1991Sheppo statsp->tx_no_desc++; 653*1991Sheppo mutex_exit(&ldcp->txlock); 654*1991Sheppo if (bp) 655*1991Sheppo freemsg(bp); 656*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE 657*1991Sheppo /* 658*1991Sheppo * This cflag is disabled by default. This can be enabled if we 659*1991Sheppo * want to return failure to the mac layer when we run out of 660*1991Sheppo * descriptors and use mac_tx_update() to restart tx when 661*1991Sheppo * descriptors become available. However, stopping tx would 662*1991Sheppo * affect traffic going over other ports, as upper mac layer 663*1991Sheppo * has no concept of multiple ports within a device. 664*1991Sheppo * So currently, to avoid this, drop packets when we run out 665*1991Sheppo * of descrs and just return success. See the corresponding 666*1991Sheppo * code in vgen_portsend() and vgen_reclaim_dring(). 667*1991Sheppo */ 668*1991Sheppo return (VGEN_TX_NORESOURCES); 669*1991Sheppo #else 670*1991Sheppo freemsg(mp); /* drop the packet */ 671*1991Sheppo return (VGEN_TX_SUCCESS); 672*1991Sheppo #endif 673*1991Sheppo } 674*1991Sheppo 675*1991Sheppo txpending = vgen_num_txpending(ldcp); 676*1991Sheppo if (txpending >= ldcp->reclaim_hiwat) { 677*1991Sheppo /* 678*1991Sheppo * if num of pending transmits is more than hiwat, 679*1991Sheppo * reclaim now and also enable ack bit. 680*1991Sheppo */ 681*1991Sheppo reclaim = B_TRUE; 682*1991Sheppo need_intr = B_TRUE; 683*1991Sheppo } else { 684*1991Sheppo if (txpending >= ldcp->reclaim_lowat) { 685*1991Sheppo /* 686*1991Sheppo * if the num of pending transmits is more than lowat 687*1991Sheppo * enable ack bit in the descr and reclaim in intr(). 688*1991Sheppo */ 689*1991Sheppo need_intr = B_TRUE; 690*1991Sheppo } 691*1991Sheppo } 692*1991Sheppo 693*1991Sheppo i = tbufp - ldcp->tbufp; 694*1991Sheppo 695*1991Sheppo rptr = bp ? (bp->b_rptr) : (mp->b_rptr); 696*1991Sheppo ci = 0; 697*1991Sheppo rv = ldc_mem_bind_handle(tbufp->memhandle, (caddr_t)rptr, size, 698*1991Sheppo LDC_SHADOW_MAP, LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies); 699*1991Sheppo if (rv != 0) { 700*1991Sheppo DWARN((vnetp, "vgen_ldcsend: id(%lx)ldc_mem_bind_handle failed" 701*1991Sheppo " rv(%d) tbufi(%d)\n", ldcp->ldc_id, rv, i)); 702*1991Sheppo err = B_TRUE; 703*1991Sheppo statsp->oerrors++; 704*1991Sheppo goto vgen_tx_exit; 705*1991Sheppo } 706*1991Sheppo 707*1991Sheppo if ((ncookies < 0) || (ncookies > (uint64_t)MAX_COOKIES)) { 708*1991Sheppo DWARN((vnetp, 709*1991Sheppo "vgen_ldcsend: id(%lx)ldc_mem_bind_handle returned" 710*1991Sheppo " invalid cookies (%d)\n", ldcp->ldc_id, ncookies)); 711*1991Sheppo err = B_TRUE; 712*1991Sheppo statsp->oerrors++; 713*1991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 714*1991Sheppo goto vgen_tx_exit; 715*1991Sheppo } 716*1991Sheppo 717*1991Sheppo if (ncookies > 1) { 718*1991Sheppo nc = ncookies - 1; 719*1991Sheppo while (nc) { 720*1991Sheppo ci++; 721*1991Sheppo rv = ldc_mem_nextcookie(tbufp->memhandle, 722*1991Sheppo &(tbufp->memcookie[ci])); 723*1991Sheppo if (rv != 0) { 724*1991Sheppo DWARN((vnetp, 725*1991Sheppo "vgen_ldcsend: ldc_mem_nextcookie" 726*1991Sheppo " err(%d)\n", rv)); 727*1991Sheppo err = B_TRUE; 728*1991Sheppo statsp->oerrors++; 729*1991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 730*1991Sheppo goto vgen_tx_exit; 731*1991Sheppo } 732*1991Sheppo nc--; 733*1991Sheppo } 734*1991Sheppo } 735*1991Sheppo 736*1991Sheppo ehp = (struct ether_header *)rptr; 737*1991Sheppo is_bcast = IS_BROADCAST(ehp); 738*1991Sheppo is_mcast = IS_MULTICAST(ehp); 739*1991Sheppo /* save the packet, free when the descr done flag is set */ 740*1991Sheppo tbufp->mp = (bp ? bp : mp); 741*1991Sheppo tbufp->flags = VGEN_PRIV_DESC_BUSY; 742*1991Sheppo tbufp->datalen = datalen; 743*1991Sheppo tbufp->ncookies = ncookies; 744*1991Sheppo tbufp->seqnum = ldcp->next_txseq; 745*1991Sheppo 746*1991Sheppo /* initialize the corresponding public descriptor (txd) */ 747*1991Sheppo txdp = tbufp->descp; 748*1991Sheppo hdrp = &txdp->hdr; 749*1991Sheppo hdrp->dstate = VIO_DESC_READY; 750*1991Sheppo if (need_intr) 751*1991Sheppo hdrp->ack = B_TRUE; 752*1991Sheppo txdp->nbytes = datalen; 753*1991Sheppo txdp->ncookies = ncookies; 754*1991Sheppo bcopy((tbufp->memcookie), (txdp->memcookie), 755*1991Sheppo ncookies * sizeof (ldc_mem_cookie_t)); 756*1991Sheppo 757*1991Sheppo /* send dring datamsg to the peer */ 758*1991Sheppo start = end = i; 759*1991Sheppo rv = vgen_send_dring_data(ldcp, start, end, ldcp->next_txseq); 760*1991Sheppo if (rv != 0) { 761*1991Sheppo /* vgen_send_dring_data() error: drop the packet */ 762*1991Sheppo DWARN((vnetp, 763*1991Sheppo "vgen_ldcsend: vgen_send_dring_data(): failed: " 764*1991Sheppo "id(%lx) rv(%d) len (%d)\n", ldcp->ldc_id, rv, datalen)); 765*1991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 766*1991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; /* free tbuf */ 767*1991Sheppo hdrp->dstate = VIO_DESC_FREE; /* free txd */ 768*1991Sheppo hdrp->ack = B_FALSE; 769*1991Sheppo statsp->oerrors++; 770*1991Sheppo err = B_TRUE; 771*1991Sheppo goto vgen_tx_exit; 772*1991Sheppo } 773*1991Sheppo 774*1991Sheppo /* update next available tbuf in the ring */ 775*1991Sheppo ldcp->next_tbufp = ntbufp; 776*1991Sheppo /* update tx seqnum and index */ 777*1991Sheppo ldcp->next_txseq++; 778*1991Sheppo INCR_TXI(ldcp->next_txi, ldcp); 779*1991Sheppo 780*1991Sheppo /* update stats */ 781*1991Sheppo statsp->opackets++; 782*1991Sheppo statsp->obytes += datalen; 783*1991Sheppo if (is_bcast) 784*1991Sheppo statsp->brdcstxmt++; 785*1991Sheppo else if (is_mcast) 786*1991Sheppo statsp->multixmt++; 787*1991Sheppo 788*1991Sheppo vgen_tx_exit: 789*1991Sheppo mutex_exit(&ldcp->txlock); 790*1991Sheppo 791*1991Sheppo if (reclaim) { 792*1991Sheppo vgen_reclaim(ldcp); 793*1991Sheppo } 794*1991Sheppo DBG1((vnetp, "vgen_ldcsend: exit: ldcid (%lx)\n", ldcp->ldc_id)); 795*1991Sheppo 796*1991Sheppo if (err) { 797*1991Sheppo if (bp) 798*1991Sheppo freemsg(bp); 799*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE 800*1991Sheppo return (VGEN_TX_FAILURE); /* transmit failed */ 801*1991Sheppo #else 802*1991Sheppo freemsg(mp); /* drop the packet */ 803*1991Sheppo return (VGEN_TX_SUCCESS); 804*1991Sheppo #endif 805*1991Sheppo } else { 806*1991Sheppo if (bp) /* free original pkt, copy is in bp */ 807*1991Sheppo freemsg(mp); 808*1991Sheppo return (VGEN_TX_SUCCESS); 809*1991Sheppo } 810*1991Sheppo } 811*1991Sheppo 812*1991Sheppo /* register resources */ 813*1991Sheppo static void 814*1991Sheppo vgen_resources(void *arg) 815*1991Sheppo { 816*1991Sheppo vgen_t *vgenp; 817*1991Sheppo mac_rx_fifo_t mrf; 818*1991Sheppo 819*1991Sheppo vgenp = (vgen_t *)arg; 820*1991Sheppo DBG1((vgenp->vnetp, "vgen_resources: enter\n")); 821*1991Sheppo 822*1991Sheppo mrf.mrf_type = MAC_RX_FIFO; 823*1991Sheppo mrf.mrf_blank = NULL; 824*1991Sheppo mrf.mrf_arg = NULL; 825*1991Sheppo mrf.mrf_normal_blank_time = 0; 826*1991Sheppo mrf.mrf_normal_pkt_count = 0; 827*1991Sheppo vgenp->mrh = mac_resource_add(vgenp->vnetmacp, (mac_resource_t *)&mrf); 828*1991Sheppo 829*1991Sheppo DBG1((vgenp->vnetp, "vgen_resources: exit\n")); 830*1991Sheppo } 831*1991Sheppo 832*1991Sheppo /* enable/disable a multicast address */ 833*1991Sheppo static int 834*1991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca) 835*1991Sheppo { 836*1991Sheppo vgen_t *vgenp; 837*1991Sheppo vnet_mcast_msg_t mcastmsg; 838*1991Sheppo vio_msg_tag_t *tagp; 839*1991Sheppo vgen_port_t *portp; 840*1991Sheppo vgen_portlist_t *plistp; 841*1991Sheppo vgen_ldc_t *ldcp; 842*1991Sheppo vgen_ldclist_t *ldclp; 843*1991Sheppo void *vnetp; 844*1991Sheppo struct ether_addr *addrp; 845*1991Sheppo int rv; 846*1991Sheppo uint32_t i; 847*1991Sheppo 848*1991Sheppo vgenp = (vgen_t *)arg; 849*1991Sheppo vnetp = vgenp->vnetp; 850*1991Sheppo addrp = (struct ether_addr *)mca; 851*1991Sheppo tagp = &mcastmsg.tag; 852*1991Sheppo bzero(&mcastmsg, sizeof (mcastmsg)); 853*1991Sheppo 854*1991Sheppo mutex_enter(&vgenp->lock); 855*1991Sheppo 856*1991Sheppo plistp = &(vgenp->vgenports); 857*1991Sheppo 858*1991Sheppo READ_ENTER(&plistp->rwlock); 859*1991Sheppo 860*1991Sheppo portp = vgenp->vsw_portp; 861*1991Sheppo if (portp == NULL) { 862*1991Sheppo RW_EXIT(&plistp->rwlock); 863*1991Sheppo goto vgen_mcast_exit; 864*1991Sheppo } 865*1991Sheppo ldclp = &portp->ldclist; 866*1991Sheppo 867*1991Sheppo READ_ENTER(&ldclp->rwlock); 868*1991Sheppo 869*1991Sheppo ldcp = ldclp->headp; 870*1991Sheppo if (ldcp == NULL) { 871*1991Sheppo RW_EXIT(&ldclp->rwlock); 872*1991Sheppo RW_EXIT(&plistp->rwlock); 873*1991Sheppo goto vgen_mcast_exit; 874*1991Sheppo } 875*1991Sheppo 876*1991Sheppo mutex_enter(&ldcp->cblock); 877*1991Sheppo 878*1991Sheppo if (ldcp->hphase == VH_DONE) { 879*1991Sheppo /* 880*1991Sheppo * If handshake is done, send a msg to vsw to add/remove 881*1991Sheppo * the multicast address. 882*1991Sheppo */ 883*1991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 884*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 885*1991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 886*1991Sheppo tagp->vio_sid = ldcp->local_sid; 887*1991Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL); 888*1991Sheppo mcastmsg.set = add; 889*1991Sheppo mcastmsg.count = 1; 890*1991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), 891*1991Sheppo B_FALSE); 892*1991Sheppo if (rv != VGEN_SUCCESS) { 893*1991Sheppo DWARN((vnetp, "vgen_mutlicst: vgen_sendmsg failed" 894*1991Sheppo "id (%lx)\n", ldcp->ldc_id)); 895*1991Sheppo } 896*1991Sheppo } else { 897*1991Sheppo /* set the flag to send a msg to vsw after handshake is done */ 898*1991Sheppo ldcp->need_mcast_sync = B_TRUE; 899*1991Sheppo } 900*1991Sheppo 901*1991Sheppo mutex_exit(&ldcp->cblock); 902*1991Sheppo 903*1991Sheppo if (add) { 904*1991Sheppo 905*1991Sheppo /* expand multicast table if necessary */ 906*1991Sheppo if (vgenp->mccount >= vgenp->mcsize) { 907*1991Sheppo struct ether_addr *newtab; 908*1991Sheppo uint32_t newsize; 909*1991Sheppo 910*1991Sheppo 911*1991Sheppo newsize = vgenp->mcsize * 2; 912*1991Sheppo 913*1991Sheppo newtab = kmem_zalloc(newsize * 914*1991Sheppo sizeof (struct ether_addr), KM_NOSLEEP); 915*1991Sheppo 916*1991Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize * 917*1991Sheppo sizeof (struct ether_addr)); 918*1991Sheppo kmem_free(vgenp->mctab, 919*1991Sheppo vgenp->mcsize * sizeof (struct ether_addr)); 920*1991Sheppo 921*1991Sheppo vgenp->mctab = newtab; 922*1991Sheppo vgenp->mcsize = newsize; 923*1991Sheppo } 924*1991Sheppo 925*1991Sheppo /* add address to the table */ 926*1991Sheppo vgenp->mctab[vgenp->mccount++] = *addrp; 927*1991Sheppo 928*1991Sheppo } else { 929*1991Sheppo 930*1991Sheppo /* delete address from the table */ 931*1991Sheppo for (i = 0; i < vgenp->mccount; i++) { 932*1991Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) { 933*1991Sheppo 934*1991Sheppo /* 935*1991Sheppo * If there's more than one address in this 936*1991Sheppo * table, delete the unwanted one by moving 937*1991Sheppo * the last one in the list over top of it; 938*1991Sheppo * otherwise, just remove it. 939*1991Sheppo */ 940*1991Sheppo if (vgenp->mccount > 1) { 941*1991Sheppo vgenp->mctab[i] = 942*1991Sheppo vgenp->mctab[vgenp->mccount-1]; 943*1991Sheppo } 944*1991Sheppo vgenp->mccount--; 945*1991Sheppo break; 946*1991Sheppo } 947*1991Sheppo } 948*1991Sheppo } 949*1991Sheppo 950*1991Sheppo RW_EXIT(&ldclp->rwlock); 951*1991Sheppo RW_EXIT(&plistp->rwlock); 952*1991Sheppo 953*1991Sheppo vgen_mcast_exit: 954*1991Sheppo mutex_exit(&vgenp->lock); 955*1991Sheppo return (DDI_SUCCESS); 956*1991Sheppo } 957*1991Sheppo 958*1991Sheppo /* set or clear promiscuous mode on the device */ 959*1991Sheppo static int 960*1991Sheppo vgen_promisc(void *arg, boolean_t on) 961*1991Sheppo { 962*1991Sheppo _NOTE(ARGUNUSED(arg, on)) 963*1991Sheppo return (DDI_SUCCESS); 964*1991Sheppo } 965*1991Sheppo 966*1991Sheppo /* set the unicast mac address of the device */ 967*1991Sheppo static int 968*1991Sheppo vgen_unicst(void *arg, const uint8_t *mca) 969*1991Sheppo { 970*1991Sheppo _NOTE(ARGUNUSED(arg, mca)) 971*1991Sheppo return (DDI_SUCCESS); 972*1991Sheppo } 973*1991Sheppo 974*1991Sheppo /* get device statistics */ 975*1991Sheppo static uint64_t 976*1991Sheppo vgen_stat(void *arg, enum mac_stat stat) 977*1991Sheppo { 978*1991Sheppo vgen_t *vgenp = (vgen_t *)arg; 979*1991Sheppo vgen_port_t *portp; 980*1991Sheppo vgen_portlist_t *plistp; 981*1991Sheppo uint64_t val; 982*1991Sheppo 983*1991Sheppo val = 0; 984*1991Sheppo 985*1991Sheppo plistp = &(vgenp->vgenports); 986*1991Sheppo READ_ENTER(&plistp->rwlock); 987*1991Sheppo 988*1991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 989*1991Sheppo val += vgen_port_stat(portp, stat); 990*1991Sheppo } 991*1991Sheppo 992*1991Sheppo RW_EXIT(&plistp->rwlock); 993*1991Sheppo 994*1991Sheppo return (val); 995*1991Sheppo } 996*1991Sheppo 997*1991Sheppo static void 998*1991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp) 999*1991Sheppo { 1000*1991Sheppo _NOTE(ARGUNUSED(arg, wq, mp)) 1001*1991Sheppo } 1002*1991Sheppo 1003*1991Sheppo /* vgen internal functions */ 1004*1991Sheppo /* detach all ports from the device */ 1005*1991Sheppo static void 1006*1991Sheppo vgen_detach_ports(vgen_t *vgenp) 1007*1991Sheppo { 1008*1991Sheppo vgen_port_t *portp; 1009*1991Sheppo vgen_portlist_t *plistp; 1010*1991Sheppo 1011*1991Sheppo plistp = &(vgenp->vgenports); 1012*1991Sheppo WRITE_ENTER(&plistp->rwlock); 1013*1991Sheppo 1014*1991Sheppo while ((portp = plistp->headp) != NULL) { 1015*1991Sheppo vgen_port_detach(portp); 1016*1991Sheppo } 1017*1991Sheppo 1018*1991Sheppo RW_EXIT(&plistp->rwlock); 1019*1991Sheppo } 1020*1991Sheppo 1021*1991Sheppo /* 1022*1991Sheppo * detach the given port. 1023*1991Sheppo */ 1024*1991Sheppo static void 1025*1991Sheppo vgen_port_detach(vgen_port_t *portp) 1026*1991Sheppo { 1027*1991Sheppo vgen_t *vgenp; 1028*1991Sheppo vgen_ldclist_t *ldclp; 1029*1991Sheppo int port_num; 1030*1991Sheppo 1031*1991Sheppo vgenp = portp->vgenp; 1032*1991Sheppo port_num = portp->port_num; 1033*1991Sheppo 1034*1991Sheppo DBG1((vgenp->vnetp, 1035*1991Sheppo "vgen_port_detach: enter: port_num(%d)\n", port_num)); 1036*1991Sheppo 1037*1991Sheppo /* remove it from port list */ 1038*1991Sheppo vgen_port_list_remove(portp); 1039*1991Sheppo 1040*1991Sheppo /* detach channels from this port */ 1041*1991Sheppo ldclp = &portp->ldclist; 1042*1991Sheppo WRITE_ENTER(&ldclp->rwlock); 1043*1991Sheppo while (ldclp->headp) { 1044*1991Sheppo vgen_ldc_detach(ldclp->headp); 1045*1991Sheppo } 1046*1991Sheppo RW_EXIT(&ldclp->rwlock); 1047*1991Sheppo 1048*1991Sheppo if (vgenp->vsw_portp == portp) { 1049*1991Sheppo vgenp->vsw_portp = NULL; 1050*1991Sheppo } 1051*1991Sheppo KMEM_FREE(portp); 1052*1991Sheppo 1053*1991Sheppo DBG1((vgenp->vnetp, 1054*1991Sheppo "vgen_port_detach: exit: port_num(%d)\n", port_num)); 1055*1991Sheppo } 1056*1991Sheppo 1057*1991Sheppo /* add a port to port list */ 1058*1991Sheppo static void 1059*1991Sheppo vgen_port_list_insert(vgen_port_t *portp) 1060*1991Sheppo { 1061*1991Sheppo vgen_portlist_t *plistp; 1062*1991Sheppo vgen_t *vgenp; 1063*1991Sheppo 1064*1991Sheppo vgenp = portp->vgenp; 1065*1991Sheppo plistp = &(vgenp->vgenports); 1066*1991Sheppo 1067*1991Sheppo if (plistp->headp == NULL) { 1068*1991Sheppo plistp->headp = portp; 1069*1991Sheppo } else { 1070*1991Sheppo plistp->tailp->nextp = portp; 1071*1991Sheppo } 1072*1991Sheppo plistp->tailp = portp; 1073*1991Sheppo portp->nextp = NULL; 1074*1991Sheppo } 1075*1991Sheppo 1076*1991Sheppo /* remove a port from port list */ 1077*1991Sheppo static void 1078*1991Sheppo vgen_port_list_remove(vgen_port_t *portp) 1079*1991Sheppo { 1080*1991Sheppo vgen_port_t *prevp; 1081*1991Sheppo vgen_port_t *nextp; 1082*1991Sheppo vgen_portlist_t *plistp; 1083*1991Sheppo vgen_t *vgenp; 1084*1991Sheppo 1085*1991Sheppo vgenp = portp->vgenp; 1086*1991Sheppo 1087*1991Sheppo plistp = &(vgenp->vgenports); 1088*1991Sheppo 1089*1991Sheppo if (plistp->headp == NULL) 1090*1991Sheppo return; 1091*1991Sheppo 1092*1991Sheppo if (portp == plistp->headp) { 1093*1991Sheppo plistp->headp = portp->nextp; 1094*1991Sheppo if (portp == plistp->tailp) 1095*1991Sheppo plistp->tailp = plistp->headp; 1096*1991Sheppo } else { 1097*1991Sheppo for (prevp = plistp->headp; ((nextp = prevp->nextp) != NULL) && 1098*1991Sheppo (nextp != portp); prevp = nextp); 1099*1991Sheppo if (nextp == portp) { 1100*1991Sheppo prevp->nextp = portp->nextp; 1101*1991Sheppo } 1102*1991Sheppo if (portp == plistp->tailp) 1103*1991Sheppo plistp->tailp = prevp; 1104*1991Sheppo } 1105*1991Sheppo } 1106*1991Sheppo 1107*1991Sheppo /* lookup a port in the list based on port_num */ 1108*1991Sheppo static vgen_port_t * 1109*1991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num) 1110*1991Sheppo { 1111*1991Sheppo vgen_port_t *portp = NULL; 1112*1991Sheppo 1113*1991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 1114*1991Sheppo if (portp->port_num == port_num) { 1115*1991Sheppo break; 1116*1991Sheppo } 1117*1991Sheppo } 1118*1991Sheppo 1119*1991Sheppo return (portp); 1120*1991Sheppo } 1121*1991Sheppo 1122*1991Sheppo /* enable ports for transmit/receive */ 1123*1991Sheppo static void 1124*1991Sheppo vgen_init_ports(vgen_t *vgenp) 1125*1991Sheppo { 1126*1991Sheppo vgen_port_t *portp; 1127*1991Sheppo vgen_portlist_t *plistp; 1128*1991Sheppo 1129*1991Sheppo plistp = &(vgenp->vgenports); 1130*1991Sheppo READ_ENTER(&plistp->rwlock); 1131*1991Sheppo 1132*1991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 1133*1991Sheppo vgen_port_init(portp); 1134*1991Sheppo } 1135*1991Sheppo 1136*1991Sheppo RW_EXIT(&plistp->rwlock); 1137*1991Sheppo } 1138*1991Sheppo 1139*1991Sheppo static void 1140*1991Sheppo vgen_port_init(vgen_port_t *portp) 1141*1991Sheppo { 1142*1991Sheppo vgen_t *vgenp; 1143*1991Sheppo 1144*1991Sheppo vgenp = portp->vgenp; 1145*1991Sheppo /* 1146*1991Sheppo * Create fdb entry in vnet, corresponding to the mac 1147*1991Sheppo * address of this port. Note that the port specified 1148*1991Sheppo * is vsw-port. This is done so that vsw-port acts 1149*1991Sheppo * as the route to reach this macaddr, until the 1150*1991Sheppo * channel for this port comes up (LDC_UP) and 1151*1991Sheppo * handshake is done successfully. 1152*1991Sheppo * eg, if the peer is OBP-vnet, it may not bring the 1153*1991Sheppo * channel up for this port and may communicate via 1154*1991Sheppo * vsw to reach this port. 1155*1991Sheppo * Later, when Solaris-vnet comes up at the other end 1156*1991Sheppo * of the channel for this port and brings up the channel, 1157*1991Sheppo * it is an indication that peer vnet is capable of 1158*1991Sheppo * distributed switching, so the direct route through this 1159*1991Sheppo * port is specified in fdb, using vnet_modify_fdb(macaddr); 1160*1991Sheppo */ 1161*1991Sheppo vnet_add_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr, 1162*1991Sheppo vgen_tx, vgenp->vsw_portp); 1163*1991Sheppo 1164*1991Sheppo if (portp == vgenp->vsw_portp) { 1165*1991Sheppo /* 1166*1991Sheppo * create the default route entry in vnet's fdb. 1167*1991Sheppo * This is the entry used by vnet to reach 1168*1991Sheppo * unknown destinations, which basically goes 1169*1991Sheppo * through vsw on domain0 and out through the 1170*1991Sheppo * physical device bound to vsw. 1171*1991Sheppo */ 1172*1991Sheppo vnet_add_def_rte(vgenp->vnetp, vgen_tx, portp); 1173*1991Sheppo } 1174*1991Sheppo 1175*1991Sheppo /* Bring up the channels of this port */ 1176*1991Sheppo vgen_init_ldcs(portp); 1177*1991Sheppo } 1178*1991Sheppo 1179*1991Sheppo /* disable transmit/receive on ports */ 1180*1991Sheppo static void 1181*1991Sheppo vgen_uninit_ports(vgen_t *vgenp) 1182*1991Sheppo { 1183*1991Sheppo vgen_port_t *portp; 1184*1991Sheppo vgen_portlist_t *plistp; 1185*1991Sheppo 1186*1991Sheppo plistp = &(vgenp->vgenports); 1187*1991Sheppo READ_ENTER(&plistp->rwlock); 1188*1991Sheppo 1189*1991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 1190*1991Sheppo vgen_port_uninit(portp); 1191*1991Sheppo } 1192*1991Sheppo 1193*1991Sheppo RW_EXIT(&plistp->rwlock); 1194*1991Sheppo } 1195*1991Sheppo 1196*1991Sheppo static void 1197*1991Sheppo vgen_port_uninit(vgen_port_t *portp) 1198*1991Sheppo { 1199*1991Sheppo vgen_t *vgenp; 1200*1991Sheppo 1201*1991Sheppo vgenp = portp->vgenp; 1202*1991Sheppo 1203*1991Sheppo vgen_uninit_ldcs(portp); 1204*1991Sheppo /* delete the entry in vnet's fdb for this port */ 1205*1991Sheppo vnet_del_fdb(vgenp->vnetp, (uint8_t *)&portp->macaddr); 1206*1991Sheppo if (portp == vgenp->vsw_portp) { 1207*1991Sheppo /* 1208*1991Sheppo * if this is vsw-port, then delete the default 1209*1991Sheppo * route entry in vnet's fdb. 1210*1991Sheppo */ 1211*1991Sheppo vnet_del_def_rte(vgenp->vnetp); 1212*1991Sheppo } 1213*1991Sheppo } 1214*1991Sheppo 1215*1991Sheppo /* register with MD event generator */ 1216*1991Sheppo static int 1217*1991Sheppo vgen_mdeg_reg(vgen_t *vgenp) 1218*1991Sheppo { 1219*1991Sheppo mdeg_prop_spec_t *pspecp; 1220*1991Sheppo mdeg_node_spec_t *parentp; 1221*1991Sheppo uint_t templatesz; 1222*1991Sheppo int rv; 1223*1991Sheppo mdeg_handle_t hdl; 1224*1991Sheppo int i; 1225*1991Sheppo void *vnetp = vgenp->vnetp; 1226*1991Sheppo 1227*1991Sheppo i = ddi_prop_get_int(DDI_DEV_T_ANY, vgenp->vnetdip, 1228*1991Sheppo DDI_PROP_DONTPASS, reg_propname, -1); 1229*1991Sheppo if (i == -1) { 1230*1991Sheppo return (DDI_FAILURE); 1231*1991Sheppo } 1232*1991Sheppo templatesz = sizeof (vgen_prop_template); 1233*1991Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP); 1234*1991Sheppo if (pspecp == NULL) { 1235*1991Sheppo return (DDI_FAILURE); 1236*1991Sheppo } 1237*1991Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP); 1238*1991Sheppo if (parentp == NULL) { 1239*1991Sheppo kmem_free(pspecp, templatesz); 1240*1991Sheppo return (DDI_FAILURE); 1241*1991Sheppo } 1242*1991Sheppo 1243*1991Sheppo bcopy(vgen_prop_template, pspecp, templatesz); 1244*1991Sheppo 1245*1991Sheppo /* 1246*1991Sheppo * NOTE: The instance here refers to the value of "reg" property and 1247*1991Sheppo * not the dev_info instance (ddi_get_instance()) of vnet. 1248*1991Sheppo */ 1249*1991Sheppo VGEN_SET_MDEG_PROP_INST(pspecp, i); 1250*1991Sheppo 1251*1991Sheppo parentp->namep = "virtual-device"; 1252*1991Sheppo parentp->specp = pspecp; 1253*1991Sheppo 1254*1991Sheppo /* save parentp in vgen_t */ 1255*1991Sheppo vgenp->mdeg_parentp = parentp; 1256*1991Sheppo 1257*1991Sheppo rv = mdeg_register(parentp, &vport_match, vgen_mdeg_cb, vgenp, &hdl); 1258*1991Sheppo if (rv != MDEG_SUCCESS) { 1259*1991Sheppo DERR((vnetp, "vgen_mdeg_reg: mdeg_register failed\n")); 1260*1991Sheppo KMEM_FREE(parentp); 1261*1991Sheppo kmem_free(pspecp, templatesz); 1262*1991Sheppo vgenp->mdeg_parentp = NULL; 1263*1991Sheppo return (DDI_FAILURE); 1264*1991Sheppo } 1265*1991Sheppo 1266*1991Sheppo /* save mdeg handle in vgen_t */ 1267*1991Sheppo vgenp->mdeg_hdl = hdl; 1268*1991Sheppo 1269*1991Sheppo return (DDI_SUCCESS); 1270*1991Sheppo } 1271*1991Sheppo 1272*1991Sheppo /* unregister with MD event generator */ 1273*1991Sheppo static void 1274*1991Sheppo vgen_mdeg_unreg(vgen_t *vgenp) 1275*1991Sheppo { 1276*1991Sheppo (void) mdeg_unregister(vgenp->mdeg_hdl); 1277*1991Sheppo KMEM_FREE(vgenp->mdeg_parentp); 1278*1991Sheppo vgenp->mdeg_parentp = NULL; 1279*1991Sheppo vgenp->mdeg_hdl = NULL; 1280*1991Sheppo } 1281*1991Sheppo 1282*1991Sheppo /* callback function registered with MD event generator */ 1283*1991Sheppo static int 1284*1991Sheppo vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 1285*1991Sheppo { 1286*1991Sheppo int idx; 1287*1991Sheppo int vsw_idx = -1; 1288*1991Sheppo uint64_t val; 1289*1991Sheppo vgen_t *vgenp; 1290*1991Sheppo 1291*1991Sheppo if ((resp == NULL) || (cb_argp == NULL)) { 1292*1991Sheppo return (MDEG_FAILURE); 1293*1991Sheppo } 1294*1991Sheppo 1295*1991Sheppo vgenp = (vgen_t *)cb_argp; 1296*1991Sheppo DBG1((vgenp->vnetp, "vgen_mdeg_cb: enter\n")); 1297*1991Sheppo 1298*1991Sheppo mutex_enter(&vgenp->lock); 1299*1991Sheppo 1300*1991Sheppo DBG1((vgenp->vnetp, 1301*1991Sheppo "vgen_mdeg_cb: ports: removed(%x), added(%x), updated(%x)\n", 1302*1991Sheppo resp->removed.nelem, resp->added.nelem, resp->match_curr.nelem)); 1303*1991Sheppo 1304*1991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 1305*1991Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp, 1306*1991Sheppo resp->removed.mdep[idx]); 1307*1991Sheppo } 1308*1991Sheppo 1309*1991Sheppo if (vgenp->vsw_portp == NULL) { 1310*1991Sheppo /* 1311*1991Sheppo * find vsw_port and add it first, because other ports need 1312*1991Sheppo * this when adding fdb entry (see vgen_port_init()). 1313*1991Sheppo */ 1314*1991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 1315*1991Sheppo if (!(md_get_prop_val(resp->added.mdp, 1316*1991Sheppo resp->added.mdep[idx], swport_propname, &val))) { 1317*1991Sheppo if (val == 0) { 1318*1991Sheppo /* 1319*1991Sheppo * This port is connected to the 1320*1991Sheppo * vsw on dom0. 1321*1991Sheppo */ 1322*1991Sheppo vsw_idx = idx; 1323*1991Sheppo (void) vgen_add_port(vgenp, 1324*1991Sheppo resp->added.mdp, 1325*1991Sheppo resp->added.mdep[idx]); 1326*1991Sheppo break; 1327*1991Sheppo } 1328*1991Sheppo } 1329*1991Sheppo } 1330*1991Sheppo if (vsw_idx == -1) { 1331*1991Sheppo DWARN((vgenp->vnetp, "vgen_mdeg_cb: " 1332*1991Sheppo "can't find vsw_port\n")); 1333*1991Sheppo return (MDEG_FAILURE); 1334*1991Sheppo } 1335*1991Sheppo } 1336*1991Sheppo 1337*1991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 1338*1991Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */ 1339*1991Sheppo continue; 1340*1991Sheppo (void) vgen_add_port(vgenp, resp->added.mdp, 1341*1991Sheppo resp->added.mdep[idx]); 1342*1991Sheppo } 1343*1991Sheppo 1344*1991Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) { 1345*1991Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp, 1346*1991Sheppo resp->match_curr.mdep[idx], 1347*1991Sheppo resp->match_prev.mdp, 1348*1991Sheppo resp->match_prev.mdep[idx]); 1349*1991Sheppo } 1350*1991Sheppo 1351*1991Sheppo mutex_exit(&vgenp->lock); 1352*1991Sheppo DBG1((vgenp->vnetp, "vgen_mdeg_cb: exit\n")); 1353*1991Sheppo return (MDEG_SUCCESS); 1354*1991Sheppo } 1355*1991Sheppo 1356*1991Sheppo /* add a new port to the device */ 1357*1991Sheppo static int 1358*1991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 1359*1991Sheppo { 1360*1991Sheppo uint64_t port_num; 1361*1991Sheppo uint64_t *ldc_ids; 1362*1991Sheppo uint64_t macaddr; 1363*1991Sheppo uint64_t val; 1364*1991Sheppo int num_ldcs; 1365*1991Sheppo int vsw_port = B_FALSE; 1366*1991Sheppo int i; 1367*1991Sheppo int addrsz; 1368*1991Sheppo int num_nodes = 0; 1369*1991Sheppo int listsz = 0; 1370*1991Sheppo mde_cookie_t *listp = NULL; 1371*1991Sheppo uint8_t *addrp; 1372*1991Sheppo struct ether_addr ea; 1373*1991Sheppo 1374*1991Sheppo /* read "id" property to get the port number */ 1375*1991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 1376*1991Sheppo DWARN((vgenp->vnetp, 1377*1991Sheppo "vgen_add_port: prop(%s) not found\n", id_propname)); 1378*1991Sheppo return (DDI_FAILURE); 1379*1991Sheppo } 1380*1991Sheppo 1381*1991Sheppo /* 1382*1991Sheppo * Find the channel endpoint node(s) under this port node. 1383*1991Sheppo */ 1384*1991Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 1385*1991Sheppo DWARN((vgenp->vnetp, 1386*1991Sheppo "vgen_add_port: invalid number of nodes found (%d)", 1387*1991Sheppo num_nodes)); 1388*1991Sheppo return (DDI_FAILURE); 1389*1991Sheppo } 1390*1991Sheppo 1391*1991Sheppo /* allocate space for node list */ 1392*1991Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 1393*1991Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP); 1394*1991Sheppo if (listp == NULL) 1395*1991Sheppo return (DDI_FAILURE); 1396*1991Sheppo 1397*1991Sheppo num_ldcs = md_scan_dag(mdp, mdex, 1398*1991Sheppo md_find_name(mdp, channel_propname), 1399*1991Sheppo md_find_name(mdp, "fwd"), listp); 1400*1991Sheppo 1401*1991Sheppo if (num_ldcs <= 0) { 1402*1991Sheppo DWARN((vgenp->vnetp, 1403*1991Sheppo "vgen_add_port: can't find %s nodes", channel_propname)); 1404*1991Sheppo kmem_free(listp, listsz); 1405*1991Sheppo return (DDI_FAILURE); 1406*1991Sheppo } 1407*1991Sheppo 1408*1991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: num_ldcs %d", num_ldcs)); 1409*1991Sheppo 1410*1991Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP); 1411*1991Sheppo if (ldc_ids == NULL) { 1412*1991Sheppo kmem_free(listp, listsz); 1413*1991Sheppo return (DDI_FAILURE); 1414*1991Sheppo } 1415*1991Sheppo 1416*1991Sheppo for (i = 0; i < num_ldcs; i++) { 1417*1991Sheppo /* read channel ids */ 1418*1991Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) { 1419*1991Sheppo DWARN((vgenp->vnetp, 1420*1991Sheppo "vgen_add_port: prop(%s) not found\n", 1421*1991Sheppo id_propname)); 1422*1991Sheppo kmem_free(listp, listsz); 1423*1991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 1424*1991Sheppo return (DDI_FAILURE); 1425*1991Sheppo } 1426*1991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: ldc_id 0x%llx", 1427*1991Sheppo ldc_ids[i])); 1428*1991Sheppo } 1429*1991Sheppo 1430*1991Sheppo kmem_free(listp, listsz); 1431*1991Sheppo 1432*1991Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp, 1433*1991Sheppo &addrsz)) { 1434*1991Sheppo DWARN((vgenp->vnetp, 1435*1991Sheppo "vgen_add_port: prop(%s) not found\n", rmacaddr_propname)); 1436*1991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 1437*1991Sheppo return (DDI_FAILURE); 1438*1991Sheppo } 1439*1991Sheppo 1440*1991Sheppo if (addrsz < ETHERADDRL) { 1441*1991Sheppo DWARN((vgenp->vnetp, 1442*1991Sheppo "vgen_add_port: invalid address size (%d)\n", addrsz)); 1443*1991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 1444*1991Sheppo return (DDI_FAILURE); 1445*1991Sheppo } 1446*1991Sheppo 1447*1991Sheppo macaddr = *((uint64_t *)addrp); 1448*1991Sheppo 1449*1991Sheppo DBG2((vgenp->vnetp, "vgen_add_port: remote mac address 0x%llx\n", 1450*1991Sheppo macaddr)); 1451*1991Sheppo 1452*1991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 1453*1991Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 1454*1991Sheppo macaddr >>= 8; 1455*1991Sheppo } 1456*1991Sheppo 1457*1991Sheppo if (vgenp->vsw_portp == NULL) { 1458*1991Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) { 1459*1991Sheppo if (val == 0) { 1460*1991Sheppo /* This port is connected to the vsw on dom0 */ 1461*1991Sheppo vsw_port = B_TRUE; 1462*1991Sheppo } 1463*1991Sheppo } 1464*1991Sheppo } 1465*1991Sheppo (void) vgen_port_attach_mdeg(vgenp, (int)port_num, ldc_ids, num_ldcs, 1466*1991Sheppo &ea, vsw_port); 1467*1991Sheppo 1468*1991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 1469*1991Sheppo 1470*1991Sheppo return (DDI_SUCCESS); 1471*1991Sheppo } 1472*1991Sheppo 1473*1991Sheppo /* remove a port from the device */ 1474*1991Sheppo static int 1475*1991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 1476*1991Sheppo { 1477*1991Sheppo uint64_t port_num; 1478*1991Sheppo vgen_port_t *portp; 1479*1991Sheppo vgen_portlist_t *plistp; 1480*1991Sheppo 1481*1991Sheppo /* read "id" property to get the port number */ 1482*1991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 1483*1991Sheppo DWARN((vgenp->vnetp, 1484*1991Sheppo "vgen_remove_port: prop(%s) not found\n", id_propname)); 1485*1991Sheppo return (DDI_FAILURE); 1486*1991Sheppo } 1487*1991Sheppo 1488*1991Sheppo plistp = &(vgenp->vgenports); 1489*1991Sheppo 1490*1991Sheppo WRITE_ENTER(&plistp->rwlock); 1491*1991Sheppo portp = vgen_port_lookup(plistp, (int)port_num); 1492*1991Sheppo if (portp == NULL) { 1493*1991Sheppo DWARN((vgenp->vnetp, "vgen_remove_port: can't find port(%lx)\n", 1494*1991Sheppo port_num)); 1495*1991Sheppo RW_EXIT(&plistp->rwlock); 1496*1991Sheppo return (DDI_FAILURE); 1497*1991Sheppo } 1498*1991Sheppo 1499*1991Sheppo vgen_port_detach_mdeg(portp); 1500*1991Sheppo RW_EXIT(&plistp->rwlock); 1501*1991Sheppo 1502*1991Sheppo return (DDI_SUCCESS); 1503*1991Sheppo } 1504*1991Sheppo 1505*1991Sheppo /* attach a port to the device based on mdeg data */ 1506*1991Sheppo static int 1507*1991Sheppo vgen_port_attach_mdeg(vgen_t *vgenp, int port_num, uint64_t *ldcids, 1508*1991Sheppo int num_ids, struct ether_addr *macaddr, boolean_t vsw_port) 1509*1991Sheppo { 1510*1991Sheppo vgen_port_t *portp; 1511*1991Sheppo vgen_portlist_t *plistp; 1512*1991Sheppo int i; 1513*1991Sheppo 1514*1991Sheppo portp = kmem_zalloc(sizeof (vgen_port_t), KM_NOSLEEP); 1515*1991Sheppo if (portp == NULL) { 1516*1991Sheppo return (DDI_FAILURE); 1517*1991Sheppo } 1518*1991Sheppo portp->vgenp = vgenp; 1519*1991Sheppo portp->port_num = port_num; 1520*1991Sheppo 1521*1991Sheppo DBG1((vgenp->vnetp, 1522*1991Sheppo "vgen_port_attach_mdeg: port_num(%d)\n", portp->port_num)); 1523*1991Sheppo 1524*1991Sheppo portp->ldclist.num_ldcs = 0; 1525*1991Sheppo portp->ldclist.headp = NULL; 1526*1991Sheppo rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL); 1527*1991Sheppo 1528*1991Sheppo ether_copy(macaddr, &portp->macaddr); 1529*1991Sheppo for (i = 0; i < num_ids; i++) { 1530*1991Sheppo DBG2((vgenp->vnetp, "vgen_port_attach_mdeg: ldcid (%lx)\n", 1531*1991Sheppo ldcids[i])); 1532*1991Sheppo (void) vgen_ldc_attach(portp, ldcids[i]); 1533*1991Sheppo } 1534*1991Sheppo 1535*1991Sheppo /* link it into the list of ports */ 1536*1991Sheppo plistp = &(vgenp->vgenports); 1537*1991Sheppo WRITE_ENTER(&plistp->rwlock); 1538*1991Sheppo vgen_port_list_insert(portp); 1539*1991Sheppo RW_EXIT(&plistp->rwlock); 1540*1991Sheppo 1541*1991Sheppo /* This port is connected to the vsw on domain0 */ 1542*1991Sheppo if (vsw_port) 1543*1991Sheppo vgenp->vsw_portp = portp; 1544*1991Sheppo 1545*1991Sheppo if (vgenp->flags & VGEN_STARTED) { /* interface is configured */ 1546*1991Sheppo vgen_port_init(portp); 1547*1991Sheppo } 1548*1991Sheppo 1549*1991Sheppo DBG1((vgenp->vnetp, 1550*1991Sheppo "vgen_port_attach_mdeg: exit: port_num(%d)\n", portp->port_num)); 1551*1991Sheppo return (DDI_SUCCESS); 1552*1991Sheppo } 1553*1991Sheppo 1554*1991Sheppo /* detach a port from the device based on mdeg data */ 1555*1991Sheppo static void 1556*1991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp) 1557*1991Sheppo { 1558*1991Sheppo vgen_t *vgenp = portp->vgenp; 1559*1991Sheppo 1560*1991Sheppo DBG1((vgenp->vnetp, 1561*1991Sheppo "vgen_port_detach_mdeg: enter: port_num(%d)\n", portp->port_num)); 1562*1991Sheppo /* stop the port if needed */ 1563*1991Sheppo if (vgenp->flags & VGEN_STARTED) { 1564*1991Sheppo vgen_port_uninit(portp); 1565*1991Sheppo } 1566*1991Sheppo vgen_port_detach(portp); 1567*1991Sheppo 1568*1991Sheppo DBG1((vgenp->vnetp, 1569*1991Sheppo "vgen_port_detach_mdeg: exit: port_num(%d)\n", portp->port_num)); 1570*1991Sheppo } 1571*1991Sheppo 1572*1991Sheppo static int 1573*1991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex, 1574*1991Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex) 1575*1991Sheppo { 1576*1991Sheppo _NOTE(ARGUNUSED(vgenp, curr_mdp, curr_mdex, prev_mdp, prev_mdex)) 1577*1991Sheppo 1578*1991Sheppo /* XXX: TBD */ 1579*1991Sheppo return (DDI_SUCCESS); 1580*1991Sheppo } 1581*1991Sheppo 1582*1991Sheppo static uint64_t 1583*1991Sheppo vgen_port_stat(vgen_port_t *portp, enum mac_stat stat) 1584*1991Sheppo { 1585*1991Sheppo vgen_ldclist_t *ldclp; 1586*1991Sheppo vgen_ldc_t *ldcp; 1587*1991Sheppo uint64_t val; 1588*1991Sheppo 1589*1991Sheppo val = 0; 1590*1991Sheppo ldclp = &portp->ldclist; 1591*1991Sheppo 1592*1991Sheppo READ_ENTER(&ldclp->rwlock); 1593*1991Sheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) { 1594*1991Sheppo val += vgen_ldc_stat(ldcp, stat); 1595*1991Sheppo } 1596*1991Sheppo RW_EXIT(&ldclp->rwlock); 1597*1991Sheppo 1598*1991Sheppo return (val); 1599*1991Sheppo } 1600*1991Sheppo 1601*1991Sheppo /* attach the channel corresponding to the given ldc_id to the port */ 1602*1991Sheppo static int 1603*1991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id) 1604*1991Sheppo { 1605*1991Sheppo vgen_t *vgenp; 1606*1991Sheppo vgen_ldclist_t *ldclp; 1607*1991Sheppo vgen_ldc_t *ldcp, **prev_ldcp; 1608*1991Sheppo ldc_attr_t attr; 1609*1991Sheppo int status; 1610*1991Sheppo ldc_status_t istatus; 1611*1991Sheppo enum {AST_init = 0x0, AST_ldc_alloc = 0x1, 1612*1991Sheppo AST_mutex_init = 0x2, AST_ldc_init = 0x4, 1613*1991Sheppo AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10} 1614*1991Sheppo attach_state; 1615*1991Sheppo 1616*1991Sheppo attach_state = AST_init; 1617*1991Sheppo vgenp = portp->vgenp; 1618*1991Sheppo ldclp = &portp->ldclist; 1619*1991Sheppo 1620*1991Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP); 1621*1991Sheppo if (ldcp == NULL) { 1622*1991Sheppo goto ldc_attach_failed; 1623*1991Sheppo } 1624*1991Sheppo ldcp->ldc_id = ldc_id; 1625*1991Sheppo ldcp->portp = portp; 1626*1991Sheppo ldcp->reclaim_lowat = vnet_reclaim_lowat; 1627*1991Sheppo ldcp->reclaim_hiwat = vnet_reclaim_hiwat; 1628*1991Sheppo 1629*1991Sheppo attach_state |= AST_ldc_alloc; 1630*1991Sheppo 1631*1991Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL); 1632*1991Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL); 1633*1991Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL); 1634*1991Sheppo 1635*1991Sheppo attach_state |= AST_mutex_init; 1636*1991Sheppo 1637*1991Sheppo attr.devclass = LDC_DEV_NT; 1638*1991Sheppo attr.instance = ddi_get_instance(vgenp->vnetdip); 1639*1991Sheppo attr.mode = LDC_MODE_UNRELIABLE; 1640*1991Sheppo attr.qlen = vnet_ldc_qlen; 1641*1991Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 1642*1991Sheppo if (status != 0) { 1643*1991Sheppo DWARN((vgenp->vnetp, "ldc_init failed, id (%lx) rv (%d)\n", 1644*1991Sheppo ldc_id, status)); 1645*1991Sheppo goto ldc_attach_failed; 1646*1991Sheppo } 1647*1991Sheppo attach_state |= AST_ldc_init; 1648*1991Sheppo 1649*1991Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp); 1650*1991Sheppo if (status != 0) { 1651*1991Sheppo DWARN((vgenp->vnetp, 1652*1991Sheppo "ldc_reg_callback failed, id (%lx) rv (%d)\n", 1653*1991Sheppo ldc_id, status)); 1654*1991Sheppo goto ldc_attach_failed; 1655*1991Sheppo } 1656*1991Sheppo attach_state |= AST_ldc_reg_cb; 1657*1991Sheppo 1658*1991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 1659*1991Sheppo ASSERT(istatus == LDC_INIT); 1660*1991Sheppo ldcp->ldc_status = istatus; 1661*1991Sheppo 1662*1991Sheppo /* allocate transmit resources */ 1663*1991Sheppo status = vgen_alloc_tx_ring(ldcp); 1664*1991Sheppo if (status != 0) { 1665*1991Sheppo goto ldc_attach_failed; 1666*1991Sheppo } 1667*1991Sheppo attach_state |= AST_alloc_tx_ring; 1668*1991Sheppo 1669*1991Sheppo /* Setup kstats for the channel */ 1670*1991Sheppo status = vgen_setup_kstats(ldcp); 1671*1991Sheppo if (status != VGEN_SUCCESS) { 1672*1991Sheppo goto ldc_attach_failed; 1673*1991Sheppo } 1674*1991Sheppo 1675*1991Sheppo /* initialize vgen_versions supported */ 1676*1991Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions)); 1677*1991Sheppo 1678*1991Sheppo /* link it into the list of channels for this port */ 1679*1991Sheppo WRITE_ENTER(&ldclp->rwlock); 1680*1991Sheppo prev_ldcp = (vgen_ldc_t **)(&ldclp->headp); 1681*1991Sheppo ldcp->nextp = *prev_ldcp; 1682*1991Sheppo *prev_ldcp = ldcp; 1683*1991Sheppo ldclp->num_ldcs++; 1684*1991Sheppo RW_EXIT(&ldclp->rwlock); 1685*1991Sheppo 1686*1991Sheppo ldcp->flags |= CHANNEL_ATTACHED; 1687*1991Sheppo return (DDI_SUCCESS); 1688*1991Sheppo 1689*1991Sheppo ldc_attach_failed: 1690*1991Sheppo if (attach_state & AST_alloc_tx_ring) { 1691*1991Sheppo vgen_free_tx_ring(ldcp); 1692*1991Sheppo } 1693*1991Sheppo if (attach_state & AST_ldc_reg_cb) { 1694*1991Sheppo (void) ldc_unreg_callback(ldcp->ldc_handle); 1695*1991Sheppo } 1696*1991Sheppo if (attach_state & AST_ldc_init) { 1697*1991Sheppo (void) ldc_fini(ldcp->ldc_handle); 1698*1991Sheppo } 1699*1991Sheppo if (attach_state & AST_mutex_init) { 1700*1991Sheppo mutex_destroy(&ldcp->tclock); 1701*1991Sheppo mutex_destroy(&ldcp->txlock); 1702*1991Sheppo mutex_destroy(&ldcp->cblock); 1703*1991Sheppo } 1704*1991Sheppo if (attach_state & AST_ldc_alloc) { 1705*1991Sheppo KMEM_FREE(ldcp); 1706*1991Sheppo } 1707*1991Sheppo return (DDI_FAILURE); 1708*1991Sheppo } 1709*1991Sheppo 1710*1991Sheppo /* detach a channel from the port */ 1711*1991Sheppo static void 1712*1991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp) 1713*1991Sheppo { 1714*1991Sheppo vgen_port_t *portp; 1715*1991Sheppo vgen_t *vgenp; 1716*1991Sheppo vgen_ldc_t *pldcp; 1717*1991Sheppo vgen_ldc_t **prev_ldcp; 1718*1991Sheppo vgen_ldclist_t *ldclp; 1719*1991Sheppo 1720*1991Sheppo portp = ldcp->portp; 1721*1991Sheppo vgenp = portp->vgenp; 1722*1991Sheppo ldclp = &portp->ldclist; 1723*1991Sheppo 1724*1991Sheppo prev_ldcp = (vgen_ldc_t **)&ldclp->headp; 1725*1991Sheppo for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) { 1726*1991Sheppo if (pldcp == ldcp) { 1727*1991Sheppo break; 1728*1991Sheppo } 1729*1991Sheppo } 1730*1991Sheppo 1731*1991Sheppo if (pldcp == NULL) { 1732*1991Sheppo /* invalid ldcp? */ 1733*1991Sheppo return; 1734*1991Sheppo } 1735*1991Sheppo 1736*1991Sheppo if (ldcp->ldc_status != LDC_INIT) { 1737*1991Sheppo DWARN((vgenp->vnetp, 1738*1991Sheppo "vgen_ldc_detach: ldc_status is not INIT id(%lx)\n", 1739*1991Sheppo ldcp->ldc_id)); 1740*1991Sheppo } 1741*1991Sheppo 1742*1991Sheppo if (ldcp->flags & CHANNEL_ATTACHED) { 1743*1991Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED); 1744*1991Sheppo 1745*1991Sheppo vgen_destroy_kstats(ldcp); 1746*1991Sheppo /* free transmit resources */ 1747*1991Sheppo vgen_free_tx_ring(ldcp); 1748*1991Sheppo (void) ldc_unreg_callback(ldcp->ldc_handle); 1749*1991Sheppo (void) ldc_fini(ldcp->ldc_handle); 1750*1991Sheppo mutex_destroy(&ldcp->tclock); 1751*1991Sheppo mutex_destroy(&ldcp->txlock); 1752*1991Sheppo mutex_destroy(&ldcp->cblock); 1753*1991Sheppo 1754*1991Sheppo /* unlink it from the list */ 1755*1991Sheppo *prev_ldcp = ldcp->nextp; 1756*1991Sheppo ldclp->num_ldcs--; 1757*1991Sheppo KMEM_FREE(ldcp); 1758*1991Sheppo } 1759*1991Sheppo } 1760*1991Sheppo 1761*1991Sheppo /* 1762*1991Sheppo * This function allocates transmit resources for the channel. 1763*1991Sheppo * The resources consist of a transmit descriptor ring and an associated 1764*1991Sheppo * transmit buffer ring. 1765*1991Sheppo */ 1766*1991Sheppo static int 1767*1991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp) 1768*1991Sheppo { 1769*1991Sheppo void *tbufp; 1770*1991Sheppo ldc_mem_info_t minfo; 1771*1991Sheppo uint32_t txdsize; 1772*1991Sheppo uint32_t tbufsize; 1773*1991Sheppo int status; 1774*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 1775*1991Sheppo 1776*1991Sheppo ldcp->num_txds = vnet_ntxds; 1777*1991Sheppo txdsize = sizeof (vnet_public_desc_t); 1778*1991Sheppo tbufsize = sizeof (vgen_private_desc_t); 1779*1991Sheppo 1780*1991Sheppo /* allocate transmit buffer ring */ 1781*1991Sheppo tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP); 1782*1991Sheppo if (tbufp == NULL) { 1783*1991Sheppo return (DDI_FAILURE); 1784*1991Sheppo } 1785*1991Sheppo 1786*1991Sheppo /* create transmit descriptor ring */ 1787*1991Sheppo status = ldc_mem_dring_create(ldcp->num_txds, txdsize, 1788*1991Sheppo &ldcp->tx_dhandle); 1789*1991Sheppo if (status) { 1790*1991Sheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_create() " 1791*1991Sheppo "failed, id(%lx)\n", ldcp->ldc_id)); 1792*1991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 1793*1991Sheppo return (DDI_FAILURE); 1794*1991Sheppo } 1795*1991Sheppo 1796*1991Sheppo /* get the addr of descripror ring */ 1797*1991Sheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo); 1798*1991Sheppo if (status) { 1799*1991Sheppo DWARN((vnetp, "vgen_alloc_tx_ring: ldc_mem_dring_info() " 1800*1991Sheppo "failed, id(%lx)\n", ldcp->ldc_id)); 1801*1991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 1802*1991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 1803*1991Sheppo ldcp->tbufp = NULL; 1804*1991Sheppo return (DDI_FAILURE); 1805*1991Sheppo } 1806*1991Sheppo ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr); 1807*1991Sheppo ldcp->tbufp = tbufp; 1808*1991Sheppo 1809*1991Sheppo ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]); 1810*1991Sheppo ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]); 1811*1991Sheppo 1812*1991Sheppo return (DDI_SUCCESS); 1813*1991Sheppo } 1814*1991Sheppo 1815*1991Sheppo /* Free transmit resources for the channel */ 1816*1991Sheppo static void 1817*1991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp) 1818*1991Sheppo { 1819*1991Sheppo int tbufsize = sizeof (vgen_private_desc_t); 1820*1991Sheppo 1821*1991Sheppo /* free transmit descriptor ring */ 1822*1991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 1823*1991Sheppo 1824*1991Sheppo /* free transmit buffer ring */ 1825*1991Sheppo kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize); 1826*1991Sheppo ldcp->txdp = ldcp->txdendp = NULL; 1827*1991Sheppo ldcp->tbufp = ldcp->tbufendp = NULL; 1828*1991Sheppo } 1829*1991Sheppo 1830*1991Sheppo /* enable transmit/receive on the channels for the port */ 1831*1991Sheppo static void 1832*1991Sheppo vgen_init_ldcs(vgen_port_t *portp) 1833*1991Sheppo { 1834*1991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 1835*1991Sheppo vgen_ldc_t *ldcp; 1836*1991Sheppo 1837*1991Sheppo READ_ENTER(&ldclp->rwlock); 1838*1991Sheppo ldcp = ldclp->headp; 1839*1991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 1840*1991Sheppo (void) vgen_ldc_init(ldcp); 1841*1991Sheppo } 1842*1991Sheppo RW_EXIT(&ldclp->rwlock); 1843*1991Sheppo } 1844*1991Sheppo 1845*1991Sheppo /* stop transmit/receive on the channels for the port */ 1846*1991Sheppo static void 1847*1991Sheppo vgen_uninit_ldcs(vgen_port_t *portp) 1848*1991Sheppo { 1849*1991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 1850*1991Sheppo vgen_ldc_t *ldcp; 1851*1991Sheppo 1852*1991Sheppo READ_ENTER(&ldclp->rwlock); 1853*1991Sheppo ldcp = ldclp->headp; 1854*1991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 1855*1991Sheppo vgen_ldc_uninit(ldcp); 1856*1991Sheppo } 1857*1991Sheppo RW_EXIT(&ldclp->rwlock); 1858*1991Sheppo } 1859*1991Sheppo 1860*1991Sheppo /* enable transmit/receive on the channel */ 1861*1991Sheppo static int 1862*1991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp) 1863*1991Sheppo { 1864*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 1865*1991Sheppo ldc_status_t istatus; 1866*1991Sheppo int rv; 1867*1991Sheppo enum { ST_init = 0x0, ST_init_tbufs = 0x1, 1868*1991Sheppo ST_ldc_open = 0x2, ST_dring_bind = 0x4 1869*1991Sheppo } 1870*1991Sheppo init_state; 1871*1991Sheppo uint32_t ncookies = 0; 1872*1991Sheppo 1873*1991Sheppo init_state = ST_init; 1874*1991Sheppo 1875*1991Sheppo LDC_LOCK(ldcp); 1876*1991Sheppo 1877*1991Sheppo rv = ldc_open(ldcp->ldc_handle); 1878*1991Sheppo if (rv != 0) { 1879*1991Sheppo DWARN((vnetp, 1880*1991Sheppo "vgen_ldcinit: ldc_open failed: id<%lx> rv(%d)\n", 1881*1991Sheppo ldcp->ldc_id, rv)); 1882*1991Sheppo goto ldcinit_failed; 1883*1991Sheppo } 1884*1991Sheppo init_state |= ST_ldc_open; 1885*1991Sheppo 1886*1991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 1887*1991Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) { 1888*1991Sheppo DWARN((vnetp, 1889*1991Sheppo "vgen_ldcinit: id (%lx) status(%d) is not OPEN/READY\n", 1890*1991Sheppo ldcp->ldc_id, istatus)); 1891*1991Sheppo goto ldcinit_failed; 1892*1991Sheppo } 1893*1991Sheppo ldcp->ldc_status = istatus; 1894*1991Sheppo 1895*1991Sheppo rv = vgen_init_tbufs(ldcp); 1896*1991Sheppo if (rv != 0) { 1897*1991Sheppo DWARN((vnetp, 1898*1991Sheppo "vgen_ldcinit: vgen_init_tbufs() failed: id(%lx)\n", 1899*1991Sheppo ldcp->ldc_id)); 1900*1991Sheppo goto ldcinit_failed; 1901*1991Sheppo } 1902*1991Sheppo init_state |= ST_init_tbufs; 1903*1991Sheppo 1904*1991Sheppo /* Bind descriptor ring to the channel */ 1905*1991Sheppo rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle, 1906*1991Sheppo LDC_SHADOW_MAP, LDC_MEM_RW, &ldcp->tx_dcookie, &ncookies); 1907*1991Sheppo if (rv != 0) { 1908*1991Sheppo DWARN((vnetp, "vgen_ldcinit: id (%lx) " 1909*1991Sheppo "ldc_mem_dring_bind failed\n", ldcp->ldc_id)); 1910*1991Sheppo goto ldcinit_failed; 1911*1991Sheppo } 1912*1991Sheppo 1913*1991Sheppo ASSERT(ncookies == 1); 1914*1991Sheppo ldcp->num_txdcookies = ncookies; 1915*1991Sheppo 1916*1991Sheppo init_state |= ST_dring_bind; 1917*1991Sheppo 1918*1991Sheppo rv = ldc_up(ldcp->ldc_handle); 1919*1991Sheppo if (rv != 0) { 1920*1991Sheppo DBG2((vnetp, 1921*1991Sheppo "vgen_ldcinit: ldc_up err id(%lx) rv(%d)\n", 1922*1991Sheppo ldcp->ldc_id, rv)); 1923*1991Sheppo } 1924*1991Sheppo 1925*1991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 1926*1991Sheppo if (istatus != LDC_UP) { 1927*1991Sheppo DBG2((vnetp, "vgen_ldcinit: id(%lx) status(%d) is not UP\n", 1928*1991Sheppo ldcp->ldc_id, istatus)); 1929*1991Sheppo } 1930*1991Sheppo ldcp->ldc_status = istatus; 1931*1991Sheppo 1932*1991Sheppo /* initialize transmit watchdog timeout */ 1933*1991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 1934*1991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 1935*1991Sheppo 1936*1991Sheppo ldcp->flags |= CHANNEL_STARTED; 1937*1991Sheppo 1938*1991Sheppo LDC_UNLOCK(ldcp); 1939*1991Sheppo return (DDI_SUCCESS); 1940*1991Sheppo 1941*1991Sheppo ldcinit_failed: 1942*1991Sheppo if (init_state & ST_dring_bind) { 1943*1991Sheppo (void) ldc_mem_dring_unbind(ldcp->tx_dhandle); 1944*1991Sheppo } 1945*1991Sheppo if (init_state & ST_init_tbufs) { 1946*1991Sheppo vgen_uninit_tbufs(ldcp); 1947*1991Sheppo } 1948*1991Sheppo if (init_state & ST_ldc_open) { 1949*1991Sheppo (void) ldc_close(ldcp->ldc_handle); 1950*1991Sheppo } 1951*1991Sheppo LDC_UNLOCK(ldcp); 1952*1991Sheppo return (DDI_FAILURE); 1953*1991Sheppo } 1954*1991Sheppo 1955*1991Sheppo /* stop transmit/receive on the channel */ 1956*1991Sheppo static void 1957*1991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp) 1958*1991Sheppo { 1959*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 1960*1991Sheppo int rv; 1961*1991Sheppo 1962*1991Sheppo DBG1((vnetp, "vgen_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id)); 1963*1991Sheppo LDC_LOCK(ldcp); 1964*1991Sheppo 1965*1991Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) { 1966*1991Sheppo LDC_UNLOCK(ldcp); 1967*1991Sheppo DWARN((vnetp, "vgen_ldc_uninit: id(%lx) CHANNEL_STARTED" 1968*1991Sheppo " flag is not set\n", ldcp->ldc_id)); 1969*1991Sheppo return; 1970*1991Sheppo } 1971*1991Sheppo 1972*1991Sheppo /* disable further callbacks */ 1973*1991Sheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 1974*1991Sheppo if (rv != 0) { 1975*1991Sheppo DWARN((vnetp, "vgen_ldc_uninit: id (%lx) " 1976*1991Sheppo "ldc_set_cb_mode failed\n", ldcp->ldc_id)); 1977*1991Sheppo } 1978*1991Sheppo 1979*1991Sheppo /* clear handshake done bit and wait for pending tx and cb to finish */ 1980*1991Sheppo ldcp->hphase &= ~(VH_DONE); 1981*1991Sheppo LDC_UNLOCK(ldcp); 1982*1991Sheppo drv_usecwait(1000); 1983*1991Sheppo LDC_LOCK(ldcp); 1984*1991Sheppo 1985*1991Sheppo vgen_reset_hphase(ldcp); 1986*1991Sheppo 1987*1991Sheppo /* reset transmit watchdog timeout */ 1988*1991Sheppo if (ldcp->wd_tid) { 1989*1991Sheppo (void) untimeout(ldcp->wd_tid); 1990*1991Sheppo ldcp->wd_tid = 0; 1991*1991Sheppo } 1992*1991Sheppo 1993*1991Sheppo /* unbind tx descriptor ring from the channel */ 1994*1991Sheppo rv = ldc_mem_dring_unbind(ldcp->tx_dhandle); 1995*1991Sheppo if (rv != 0) { 1996*1991Sheppo DWARN((vnetp, "vgen_ldcuninit: ldc_mem_dring_unbind " 1997*1991Sheppo "failed id(%lx)\n", ldcp->ldc_id)); 1998*1991Sheppo } 1999*1991Sheppo 2000*1991Sheppo vgen_uninit_tbufs(ldcp); 2001*1991Sheppo 2002*1991Sheppo rv = ldc_close(ldcp->ldc_handle); 2003*1991Sheppo if (rv != 0) { 2004*1991Sheppo DWARN((vnetp, "vgen_ldcuninit: ldc_close err id(%lx)\n", 2005*1991Sheppo ldcp->ldc_id)); 2006*1991Sheppo } 2007*1991Sheppo ldcp->ldc_status = LDC_INIT; 2008*1991Sheppo ldcp->flags &= ~(CHANNEL_STARTED); 2009*1991Sheppo 2010*1991Sheppo LDC_UNLOCK(ldcp); 2011*1991Sheppo 2012*1991Sheppo DBG1((vnetp, "vgen_ldc_uninit: exit: id(%lx)\n", ldcp->ldc_id)); 2013*1991Sheppo } 2014*1991Sheppo 2015*1991Sheppo /* Initialize the transmit buffer ring for the channel */ 2016*1991Sheppo static int 2017*1991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp) 2018*1991Sheppo { 2019*1991Sheppo vgen_private_desc_t *tbufp; 2020*1991Sheppo vnet_public_desc_t *txdp; 2021*1991Sheppo vio_dring_entry_hdr_t *hdrp; 2022*1991Sheppo int i; 2023*1991Sheppo int rv; 2024*1991Sheppo 2025*1991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 2026*1991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 2027*1991Sheppo 2028*1991Sheppo /* 2029*1991Sheppo * for each tx buf (priv_desc), allocate a ldc mem_handle which is 2030*1991Sheppo * required to map the data during transmit, set the flags 2031*1991Sheppo * to free (available for use by transmit routine). 2032*1991Sheppo */ 2033*1991Sheppo 2034*1991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 2035*1991Sheppo tbufp = &(ldcp->tbufp[i]); 2036*1991Sheppo rv = ldc_mem_alloc_handle(ldcp->ldc_handle, 2037*1991Sheppo &(tbufp->memhandle)); 2038*1991Sheppo if (rv) { 2039*1991Sheppo tbufp->memhandle = 0; 2040*1991Sheppo goto init_tbufs_failed; 2041*1991Sheppo } 2042*1991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 2043*1991Sheppo txdp = &(ldcp->txdp[i]); 2044*1991Sheppo hdrp = &txdp->hdr; 2045*1991Sheppo hdrp->dstate = VIO_DESC_FREE; 2046*1991Sheppo hdrp->ack = B_FALSE; 2047*1991Sheppo tbufp->descp = txdp; 2048*1991Sheppo } 2049*1991Sheppo 2050*1991Sheppo /* reset tbuf walking pointers */ 2051*1991Sheppo ldcp->next_tbufp = ldcp->tbufp; 2052*1991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 2053*1991Sheppo 2054*1991Sheppo /* initialize tx seqnum and index */ 2055*1991Sheppo ldcp->next_txseq = VNET_ISS; 2056*1991Sheppo ldcp->next_txi = 0; 2057*1991Sheppo 2058*1991Sheppo return (DDI_SUCCESS); 2059*1991Sheppo 2060*1991Sheppo init_tbufs_failed:; 2061*1991Sheppo vgen_uninit_tbufs(ldcp); 2062*1991Sheppo return (DDI_FAILURE); 2063*1991Sheppo } 2064*1991Sheppo 2065*1991Sheppo /* Uninitialize transmit buffer ring for the channel */ 2066*1991Sheppo static void 2067*1991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp) 2068*1991Sheppo { 2069*1991Sheppo vgen_private_desc_t *tbufp = ldcp->tbufp; 2070*1991Sheppo vnet_public_desc_t *txdp; 2071*1991Sheppo vio_dring_entry_hdr_t *hdrp; 2072*1991Sheppo int i; 2073*1991Sheppo 2074*1991Sheppo /* for each tbuf (priv_desc), free ldc mem_handle */ 2075*1991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 2076*1991Sheppo 2077*1991Sheppo tbufp = &(ldcp->tbufp[i]); 2078*1991Sheppo txdp = tbufp->descp; 2079*1991Sheppo hdrp = &txdp->hdr; 2080*1991Sheppo 2081*1991Sheppo if (tbufp->flags != VGEN_PRIV_DESC_FREE) { 2082*1991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 2083*1991Sheppo freemsg(tbufp->mp); 2084*1991Sheppo tbufp->mp = NULL; 2085*1991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 2086*1991Sheppo hdrp->dstate = VIO_DESC_FREE; 2087*1991Sheppo hdrp->ack = B_FALSE; 2088*1991Sheppo } 2089*1991Sheppo if (tbufp->memhandle) { 2090*1991Sheppo (void) ldc_mem_free_handle(tbufp->memhandle); 2091*1991Sheppo tbufp->memhandle = 0; 2092*1991Sheppo } 2093*1991Sheppo tbufp->descp = NULL; 2094*1991Sheppo } 2095*1991Sheppo 2096*1991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 2097*1991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 2098*1991Sheppo } 2099*1991Sheppo 2100*1991Sheppo /* clobber tx descriptor ring */ 2101*1991Sheppo static void 2102*1991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp) 2103*1991Sheppo { 2104*1991Sheppo vnet_public_desc_t *txdp; 2105*1991Sheppo vgen_private_desc_t *tbufp; 2106*1991Sheppo vio_dring_entry_hdr_t *hdrp; 2107*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2108*1991Sheppo int i; 2109*1991Sheppo #ifdef DEBUG 2110*1991Sheppo int ndone = 0; 2111*1991Sheppo #endif 2112*1991Sheppo 2113*1991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 2114*1991Sheppo 2115*1991Sheppo tbufp = &(ldcp->tbufp[i]); 2116*1991Sheppo txdp = tbufp->descp; 2117*1991Sheppo hdrp = &txdp->hdr; 2118*1991Sheppo 2119*1991Sheppo if (tbufp->flags & VGEN_PRIV_DESC_BUSY) { 2120*1991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 2121*1991Sheppo freemsg(tbufp->mp); 2122*1991Sheppo tbufp->mp = NULL; 2123*1991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 2124*1991Sheppo #ifdef DEBUG 2125*1991Sheppo if (hdrp->dstate == VIO_DESC_DONE) 2126*1991Sheppo ndone++; 2127*1991Sheppo #endif 2128*1991Sheppo hdrp->dstate = VIO_DESC_FREE; 2129*1991Sheppo hdrp->ack = B_FALSE; 2130*1991Sheppo } 2131*1991Sheppo } 2132*1991Sheppo /* reset tbuf walking pointers */ 2133*1991Sheppo ldcp->next_tbufp = ldcp->tbufp; 2134*1991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 2135*1991Sheppo 2136*1991Sheppo /* reset tx seqnum and index */ 2137*1991Sheppo ldcp->next_txseq = VNET_ISS; 2138*1991Sheppo ldcp->next_txi = 0; 2139*1991Sheppo #ifdef DEBUG 2140*1991Sheppo DBG2((vnetp, 2141*1991Sheppo "vgen_clobber_tbufs: id(0x%lx) num descrs done (%d)\n", 2142*1991Sheppo ldcp->ldc_id, ndone)); 2143*1991Sheppo #endif 2144*1991Sheppo } 2145*1991Sheppo 2146*1991Sheppo /* clobber receive descriptor ring */ 2147*1991Sheppo static void 2148*1991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp) 2149*1991Sheppo { 2150*1991Sheppo ldcp->rx_dhandle = 0; 2151*1991Sheppo bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie)); 2152*1991Sheppo ldcp->rxdp = NULL; 2153*1991Sheppo ldcp->next_rxi = 0; 2154*1991Sheppo ldcp->num_rxds = 0; 2155*1991Sheppo ldcp->next_rxseq = VNET_ISS; 2156*1991Sheppo } 2157*1991Sheppo 2158*1991Sheppo /* initialize receive descriptor ring */ 2159*1991Sheppo static int 2160*1991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size, 2161*1991Sheppo ldc_mem_cookie_t *dcookie, uint32_t ncookies) 2162*1991Sheppo { 2163*1991Sheppo int rv; 2164*1991Sheppo ldc_mem_info_t minfo; 2165*1991Sheppo 2166*1991Sheppo rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc, 2167*1991Sheppo desc_size, LDC_SHADOW_MAP, &(ldcp->rx_dhandle)); 2168*1991Sheppo if (rv != 0) { 2169*1991Sheppo return (DDI_FAILURE); 2170*1991Sheppo } 2171*1991Sheppo 2172*1991Sheppo /* 2173*1991Sheppo * sucessfully mapped, now try to 2174*1991Sheppo * get info about the mapped dring 2175*1991Sheppo */ 2176*1991Sheppo rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo); 2177*1991Sheppo if (rv != 0) { 2178*1991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 2179*1991Sheppo return (DDI_FAILURE); 2180*1991Sheppo } 2181*1991Sheppo 2182*1991Sheppo /* 2183*1991Sheppo * save ring address, number of descriptors. 2184*1991Sheppo */ 2185*1991Sheppo ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr); 2186*1991Sheppo bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie)); 2187*1991Sheppo ldcp->num_rxdcookies = ncookies; 2188*1991Sheppo ldcp->num_rxds = num_desc; 2189*1991Sheppo ldcp->next_rxi = 0; 2190*1991Sheppo ldcp->next_rxseq = VNET_ISS; 2191*1991Sheppo 2192*1991Sheppo return (DDI_SUCCESS); 2193*1991Sheppo } 2194*1991Sheppo 2195*1991Sheppo /* get channel statistics */ 2196*1991Sheppo static uint64_t 2197*1991Sheppo vgen_ldc_stat(vgen_ldc_t *ldcp, enum mac_stat stat) 2198*1991Sheppo { 2199*1991Sheppo vgen_stats_t *statsp; 2200*1991Sheppo uint64_t val; 2201*1991Sheppo 2202*1991Sheppo val = 0; 2203*1991Sheppo statsp = ldcp->statsp; 2204*1991Sheppo switch (stat) { 2205*1991Sheppo 2206*1991Sheppo case MAC_STAT_MULTIRCV: 2207*1991Sheppo val = statsp->multircv; 2208*1991Sheppo break; 2209*1991Sheppo 2210*1991Sheppo case MAC_STAT_BRDCSTRCV: 2211*1991Sheppo val = statsp->brdcstrcv; 2212*1991Sheppo break; 2213*1991Sheppo 2214*1991Sheppo case MAC_STAT_MULTIXMT: 2215*1991Sheppo val = statsp->multixmt; 2216*1991Sheppo break; 2217*1991Sheppo 2218*1991Sheppo case MAC_STAT_BRDCSTXMT: 2219*1991Sheppo val = statsp->brdcstxmt; 2220*1991Sheppo break; 2221*1991Sheppo 2222*1991Sheppo case MAC_STAT_NORCVBUF: 2223*1991Sheppo val = statsp->norcvbuf; 2224*1991Sheppo break; 2225*1991Sheppo 2226*1991Sheppo case MAC_STAT_IERRORS: 2227*1991Sheppo val = statsp->ierrors; 2228*1991Sheppo break; 2229*1991Sheppo 2230*1991Sheppo case MAC_STAT_NOXMTBUF: 2231*1991Sheppo val = statsp->noxmtbuf; 2232*1991Sheppo break; 2233*1991Sheppo 2234*1991Sheppo case MAC_STAT_OERRORS: 2235*1991Sheppo val = statsp->oerrors; 2236*1991Sheppo break; 2237*1991Sheppo 2238*1991Sheppo case MAC_STAT_COLLISIONS: 2239*1991Sheppo break; 2240*1991Sheppo 2241*1991Sheppo case MAC_STAT_RBYTES: 2242*1991Sheppo val = statsp->rbytes; 2243*1991Sheppo break; 2244*1991Sheppo 2245*1991Sheppo case MAC_STAT_IPACKETS: 2246*1991Sheppo val = statsp->ipackets; 2247*1991Sheppo break; 2248*1991Sheppo 2249*1991Sheppo case MAC_STAT_OBYTES: 2250*1991Sheppo val = statsp->obytes; 2251*1991Sheppo break; 2252*1991Sheppo 2253*1991Sheppo case MAC_STAT_OPACKETS: 2254*1991Sheppo val = statsp->opackets; 2255*1991Sheppo break; 2256*1991Sheppo 2257*1991Sheppo /* stats not relevant to ldc, return 0 */ 2258*1991Sheppo case MAC_STAT_IFSPEED: 2259*1991Sheppo case MAC_STAT_ALIGN_ERRORS: 2260*1991Sheppo case MAC_STAT_FCS_ERRORS: 2261*1991Sheppo case MAC_STAT_FIRST_COLLISIONS: 2262*1991Sheppo case MAC_STAT_MULTI_COLLISIONS: 2263*1991Sheppo case MAC_STAT_DEFER_XMTS: 2264*1991Sheppo case MAC_STAT_TX_LATE_COLLISIONS: 2265*1991Sheppo case MAC_STAT_EX_COLLISIONS: 2266*1991Sheppo case MAC_STAT_MACXMT_ERRORS: 2267*1991Sheppo case MAC_STAT_CARRIER_ERRORS: 2268*1991Sheppo case MAC_STAT_TOOLONG_ERRORS: 2269*1991Sheppo case MAC_STAT_XCVR_ADDR: 2270*1991Sheppo case MAC_STAT_XCVR_ID: 2271*1991Sheppo case MAC_STAT_XCVR_INUSE: 2272*1991Sheppo case MAC_STAT_CAP_1000FDX: 2273*1991Sheppo case MAC_STAT_CAP_1000HDX: 2274*1991Sheppo case MAC_STAT_CAP_100FDX: 2275*1991Sheppo case MAC_STAT_CAP_100HDX: 2276*1991Sheppo case MAC_STAT_CAP_10FDX: 2277*1991Sheppo case MAC_STAT_CAP_10HDX: 2278*1991Sheppo case MAC_STAT_CAP_ASMPAUSE: 2279*1991Sheppo case MAC_STAT_CAP_PAUSE: 2280*1991Sheppo case MAC_STAT_CAP_AUTONEG: 2281*1991Sheppo case MAC_STAT_ADV_CAP_1000FDX: 2282*1991Sheppo case MAC_STAT_ADV_CAP_1000HDX: 2283*1991Sheppo case MAC_STAT_ADV_CAP_100FDX: 2284*1991Sheppo case MAC_STAT_ADV_CAP_100HDX: 2285*1991Sheppo case MAC_STAT_ADV_CAP_10FDX: 2286*1991Sheppo case MAC_STAT_ADV_CAP_10HDX: 2287*1991Sheppo case MAC_STAT_ADV_CAP_ASMPAUSE: 2288*1991Sheppo case MAC_STAT_ADV_CAP_PAUSE: 2289*1991Sheppo case MAC_STAT_ADV_CAP_AUTONEG: 2290*1991Sheppo case MAC_STAT_LP_CAP_1000FDX: 2291*1991Sheppo case MAC_STAT_LP_CAP_1000HDX: 2292*1991Sheppo case MAC_STAT_LP_CAP_100FDX: 2293*1991Sheppo case MAC_STAT_LP_CAP_100HDX: 2294*1991Sheppo case MAC_STAT_LP_CAP_10FDX: 2295*1991Sheppo case MAC_STAT_LP_CAP_10HDX: 2296*1991Sheppo case MAC_STAT_LP_CAP_ASMPAUSE: 2297*1991Sheppo case MAC_STAT_LP_CAP_PAUSE: 2298*1991Sheppo case MAC_STAT_LP_CAP_AUTONEG: 2299*1991Sheppo case MAC_STAT_LINK_ASMPAUSE: 2300*1991Sheppo case MAC_STAT_LINK_PAUSE: 2301*1991Sheppo case MAC_STAT_LINK_AUTONEG: 2302*1991Sheppo case MAC_STAT_LINK_DUPLEX: 2303*1991Sheppo default: 2304*1991Sheppo val = 0; 2305*1991Sheppo break; 2306*1991Sheppo 2307*1991Sheppo } 2308*1991Sheppo return (val); 2309*1991Sheppo } 2310*1991Sheppo 2311*1991Sheppo static void 2312*1991Sheppo vgen_init_macp(vgen_t *vgenp, mac_t *macp) 2313*1991Sheppo { 2314*1991Sheppo macp->m_driver = (void *)vgenp; 2315*1991Sheppo macp->m_start = vgen_start; 2316*1991Sheppo macp->m_stop = vgen_stop; 2317*1991Sheppo macp->m_tx = vgen_tx; 2318*1991Sheppo macp->m_resources = vgen_resources; 2319*1991Sheppo macp->m_multicst = vgen_multicst; 2320*1991Sheppo macp->m_promisc = vgen_promisc; 2321*1991Sheppo macp->m_unicst = vgen_unicst; 2322*1991Sheppo macp->m_stat = vgen_stat; 2323*1991Sheppo macp->m_ioctl = vgen_ioctl; 2324*1991Sheppo } 2325*1991Sheppo 2326*1991Sheppo /* Interrupt handler for the channel */ 2327*1991Sheppo static uint_t 2328*1991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg) 2329*1991Sheppo { 2330*1991Sheppo _NOTE(ARGUNUSED(event)) 2331*1991Sheppo vgen_ldc_t *ldcp; 2332*1991Sheppo void *vnetp; 2333*1991Sheppo vgen_t *vgenp; 2334*1991Sheppo size_t msglen; 2335*1991Sheppo ldc_status_t istatus; 2336*1991Sheppo uint64_t ldcmsg[7]; 2337*1991Sheppo int rv; 2338*1991Sheppo vio_msg_tag_t *tagp; 2339*1991Sheppo mblk_t *mp = NULL; 2340*1991Sheppo mblk_t *bp = NULL; 2341*1991Sheppo mblk_t *bpt = NULL; 2342*1991Sheppo mblk_t *headp = NULL; 2343*1991Sheppo mblk_t *tailp = NULL; 2344*1991Sheppo vgen_stats_t *statsp; 2345*1991Sheppo 2346*1991Sheppo ldcp = (vgen_ldc_t *)arg; 2347*1991Sheppo vgenp = LDC_TO_VGEN(ldcp); 2348*1991Sheppo vnetp = LDC_TO_VNET(ldcp); 2349*1991Sheppo statsp = ldcp->statsp; 2350*1991Sheppo 2351*1991Sheppo DBG1((vnetp, "vgen_ldc_cb enter: ldcid (%lx)\n", ldcp->ldc_id)); 2352*1991Sheppo 2353*1991Sheppo mutex_enter(&ldcp->cblock); 2354*1991Sheppo statsp->callbacks++; 2355*1991Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 2356*1991Sheppo DWARN((vnetp, "vgen_ldc_cb: id(%lx), status(%d) is LDC_INIT\n", 2357*1991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 2358*1991Sheppo mutex_exit(&ldcp->cblock); 2359*1991Sheppo return (LDC_SUCCESS); 2360*1991Sheppo } 2361*1991Sheppo 2362*1991Sheppo /* check ldc status change events first */ 2363*1991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 2364*1991Sheppo 2365*1991Sheppo if (istatus != ldcp->ldc_status) { 2366*1991Sheppo switch (istatus) { 2367*1991Sheppo case LDC_UP: 2368*1991Sheppo ldcp->ldc_status = istatus; 2369*1991Sheppo DBG1((vnetp, 2370*1991Sheppo "vgen_ldc_cb: id(%lx) status(%d) is LDC_UP\n", 2371*1991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 2372*1991Sheppo 2373*1991Sheppo if (ldcp->portp != vgenp->vsw_portp) { 2374*1991Sheppo /* 2375*1991Sheppo * modify fdb entry to use this port as the 2376*1991Sheppo * channel is up, instead of going through the 2377*1991Sheppo * vsw-port (see comments in vgen_port_init()) 2378*1991Sheppo */ 2379*1991Sheppo vnet_modify_fdb(vnetp, 2380*1991Sheppo (uint8_t *)&ldcp->portp->macaddr, 2381*1991Sheppo vgen_tx, ldcp->portp); 2382*1991Sheppo } 2383*1991Sheppo /* Initialize local session id */ 2384*1991Sheppo ldcp->local_sid = ddi_get_lbolt(); 2385*1991Sheppo /* clear peer session id */ 2386*1991Sheppo ldcp->peer_sid = 0; 2387*1991Sheppo ldcp->hretries = 0; 2388*1991Sheppo /* Initiate Handshake process with peer ldc endpoint */ 2389*1991Sheppo vgen_handshake_reset(ldcp); 2390*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 2391*1991Sheppo break; 2392*1991Sheppo 2393*1991Sheppo case LDC_OPEN: 2394*1991Sheppo case LDC_READY: 2395*1991Sheppo ldcp->ldc_status = istatus; 2396*1991Sheppo if ((ldcp->portp != vgenp->vsw_portp) && 2397*1991Sheppo (vgenp->vsw_portp != NULL)) { 2398*1991Sheppo /* 2399*1991Sheppo * modify fdb entry to use vsw-port as the 2400*1991Sheppo * channel is reset and we don't have a direct 2401*1991Sheppo * link to the destination (see comments 2402*1991Sheppo * in vgen_port_init()). 2403*1991Sheppo */ 2404*1991Sheppo vnet_modify_fdb(vnetp, 2405*1991Sheppo (uint8_t *)&ldcp->portp->macaddr, 2406*1991Sheppo vgen_tx, vgenp->vsw_portp); 2407*1991Sheppo } 2408*1991Sheppo /* clear sids */ 2409*1991Sheppo ldcp->local_sid = 0; 2410*1991Sheppo ldcp->peer_sid = 0; 2411*1991Sheppo if (ldcp->hphase != VH_PHASE0) { 2412*1991Sheppo vgen_handshake_reset(ldcp); 2413*1991Sheppo } 2414*1991Sheppo DBG1((vnetp, 2415*1991Sheppo "vgen_ldc_cb: id(%lx) status is (%d)\n", 2416*1991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 2417*1991Sheppo break; 2418*1991Sheppo 2419*1991Sheppo default: 2420*1991Sheppo DWARN((vnetp, 2421*1991Sheppo "vgen_ldc_cb: id(%lx) istatus=(%d) status(%d) is" 2422*1991Sheppo " *UNKNOWN*\n", 2423*1991Sheppo ldcp->ldc_id, istatus, ldcp->ldc_status)); 2424*1991Sheppo break; 2425*1991Sheppo } 2426*1991Sheppo } 2427*1991Sheppo 2428*1991Sheppo if (istatus != LDC_UP) { 2429*1991Sheppo DBG1((vnetp, "vgen_ldc_cb: id(%lx) status(%d) is NOT LDC_UP\n", 2430*1991Sheppo ldcp->ldc_id, ldcp->ldc_status)); 2431*1991Sheppo mutex_exit(&ldcp->cblock); 2432*1991Sheppo return (LDC_SUCCESS); 2433*1991Sheppo } 2434*1991Sheppo 2435*1991Sheppo /* if ldc_status is UP, receive all packets */ 2436*1991Sheppo do { 2437*1991Sheppo msglen = sizeof (ldcmsg); 2438*1991Sheppo rv = ldc_read(ldcp->ldc_handle, (caddr_t)&ldcmsg, &msglen); 2439*1991Sheppo 2440*1991Sheppo if (rv != 0) { 2441*1991Sheppo DWARN((vnetp, 2442*1991Sheppo "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) " 2443*1991Sheppo "len(%d)\n", ldcp->ldc_id, rv, msglen)); 2444*1991Sheppo break; 2445*1991Sheppo } 2446*1991Sheppo if (msglen == 0) { 2447*1991Sheppo DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx) NODATA", 2448*1991Sheppo ldcp->ldc_id)); 2449*1991Sheppo break; 2450*1991Sheppo } 2451*1991Sheppo DBG2((vnetp, "vgen_ldc_cb: ldc_read id(%lx): msglen(%d)", 2452*1991Sheppo ldcp->ldc_id, msglen)); 2453*1991Sheppo 2454*1991Sheppo tagp = (vio_msg_tag_t *)ldcmsg; 2455*1991Sheppo 2456*1991Sheppo if (ldcp->peer_sid) { 2457*1991Sheppo /* 2458*1991Sheppo * check sid only after we have received peer's sid 2459*1991Sheppo * in the version negotiate msg. 2460*1991Sheppo */ 2461*1991Sheppo #ifdef DEBUG 2462*1991Sheppo if (vgen_hdbg & HDBG_BAD_SID) { 2463*1991Sheppo /* simulate bad sid condition */ 2464*1991Sheppo tagp->vio_sid = 0; 2465*1991Sheppo vgen_hdbg &= ~(HDBG_BAD_SID); 2466*1991Sheppo } 2467*1991Sheppo #endif 2468*1991Sheppo if (vgen_check_sid(ldcp, tagp) == VGEN_FAILURE) { 2469*1991Sheppo /* 2470*1991Sheppo * If sid mismatch is detected, 2471*1991Sheppo * reset the channel. 2472*1991Sheppo */ 2473*1991Sheppo ldcp->need_ldc_reset = B_TRUE; 2474*1991Sheppo vgen_handshake_reset(ldcp); 2475*1991Sheppo mutex_exit(&ldcp->cblock); 2476*1991Sheppo return (LDC_SUCCESS); 2477*1991Sheppo } 2478*1991Sheppo } 2479*1991Sheppo 2480*1991Sheppo switch (tagp->vio_msgtype) { 2481*1991Sheppo case VIO_TYPE_CTRL: 2482*1991Sheppo vgen_handle_ctrlmsg(ldcp, tagp); 2483*1991Sheppo break; 2484*1991Sheppo 2485*1991Sheppo case VIO_TYPE_DATA: 2486*1991Sheppo headp = tailp = NULL; 2487*1991Sheppo vgen_handle_datamsg(ldcp, tagp, &headp, &tailp); 2488*1991Sheppo /* build a chain of received packets */ 2489*1991Sheppo if (headp != NULL) { 2490*1991Sheppo if (bp == NULL) { 2491*1991Sheppo bp = headp; 2492*1991Sheppo bpt = tailp; 2493*1991Sheppo } else { 2494*1991Sheppo bpt->b_next = headp; 2495*1991Sheppo bpt = tailp; 2496*1991Sheppo } 2497*1991Sheppo } 2498*1991Sheppo break; 2499*1991Sheppo 2500*1991Sheppo case VIO_TYPE_ERR: 2501*1991Sheppo vgen_handle_errmsg(ldcp, tagp); 2502*1991Sheppo break; 2503*1991Sheppo 2504*1991Sheppo default: 2505*1991Sheppo DWARN((vnetp, 2506*1991Sheppo "vgen_ldc_cb: Unknown VIO_TYPE(%x)\n", 2507*1991Sheppo tagp->vio_msgtype)); 2508*1991Sheppo break; 2509*1991Sheppo } 2510*1991Sheppo 2511*1991Sheppo } while (msglen); 2512*1991Sheppo 2513*1991Sheppo mutex_exit(&ldcp->cblock); 2514*1991Sheppo /* send up the received packets to MAC layer */ 2515*1991Sheppo while (bp != NULL) { 2516*1991Sheppo mp = bp; 2517*1991Sheppo bp = bp->b_next; 2518*1991Sheppo mp->b_next = mp->b_prev = NULL; 2519*1991Sheppo DBG2((vnetp, "vgen_ldc_cb: id(%lx) rx pkt len (%lx)\n", 2520*1991Sheppo ldcp->ldc_id, MBLKL(mp))); 2521*1991Sheppo mac_rx((mac_t *)vgenp->vnetmacp, vgenp->mrh, mp); 2522*1991Sheppo } 2523*1991Sheppo DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id)); 2524*1991Sheppo 2525*1991Sheppo return (LDC_SUCCESS); 2526*1991Sheppo } 2527*1991Sheppo 2528*1991Sheppo /* vgen handshake functions */ 2529*1991Sheppo 2530*1991Sheppo /* change the hphase for the channel to the next phase */ 2531*1991Sheppo static vgen_ldc_t * 2532*1991Sheppo vh_nextphase(vgen_ldc_t *ldcp) 2533*1991Sheppo { 2534*1991Sheppo if (ldcp->hphase == VH_PHASE3) { 2535*1991Sheppo ldcp->hphase = VH_DONE; 2536*1991Sheppo } else { 2537*1991Sheppo ldcp->hphase++; 2538*1991Sheppo } 2539*1991Sheppo return (ldcp); 2540*1991Sheppo } 2541*1991Sheppo 2542*1991Sheppo /* 2543*1991Sheppo * Check whether the given version is supported or not and 2544*1991Sheppo * return VGEN_SUCCESS if supported. 2545*1991Sheppo */ 2546*1991Sheppo static int 2547*1991Sheppo vgen_supported_version(vgen_ldc_t *ldcp, uint16_t ver_major, 2548*1991Sheppo uint16_t ver_minor) 2549*1991Sheppo { 2550*1991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 2551*1991Sheppo int i = 0; 2552*1991Sheppo 2553*1991Sheppo while (i < VGEN_NUM_VER) { 2554*1991Sheppo if ((versions[i].ver_major == 0) && 2555*1991Sheppo (versions[i].ver_minor == 0)) { 2556*1991Sheppo break; 2557*1991Sheppo } 2558*1991Sheppo if ((versions[i].ver_major == ver_major) && 2559*1991Sheppo (versions[i].ver_minor == ver_minor)) { 2560*1991Sheppo return (VGEN_SUCCESS); 2561*1991Sheppo } 2562*1991Sheppo i++; 2563*1991Sheppo } 2564*1991Sheppo return (VGEN_FAILURE); 2565*1991Sheppo } 2566*1991Sheppo 2567*1991Sheppo /* 2568*1991Sheppo * Given a version, return VGEN_SUCCESS if a lower version is supported. 2569*1991Sheppo */ 2570*1991Sheppo static int 2571*1991Sheppo vgen_next_version(vgen_ldc_t *ldcp, vgen_ver_t *verp) 2572*1991Sheppo { 2573*1991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 2574*1991Sheppo int i = 0; 2575*1991Sheppo 2576*1991Sheppo while (i < VGEN_NUM_VER) { 2577*1991Sheppo if ((versions[i].ver_major == 0) && 2578*1991Sheppo (versions[i].ver_minor == 0)) { 2579*1991Sheppo break; 2580*1991Sheppo } 2581*1991Sheppo /* 2582*1991Sheppo * if we support a lower minor version within the same major 2583*1991Sheppo * version, or if we support a lower major version, 2584*1991Sheppo * update the verp parameter with this lower version and 2585*1991Sheppo * return success. 2586*1991Sheppo */ 2587*1991Sheppo if (((versions[i].ver_major == verp->ver_major) && 2588*1991Sheppo (versions[i].ver_minor < verp->ver_minor)) || 2589*1991Sheppo (versions[i].ver_major < verp->ver_major)) { 2590*1991Sheppo verp->ver_major = versions[i].ver_major; 2591*1991Sheppo verp->ver_minor = versions[i].ver_minor; 2592*1991Sheppo return (VGEN_SUCCESS); 2593*1991Sheppo } 2594*1991Sheppo i++; 2595*1991Sheppo } 2596*1991Sheppo 2597*1991Sheppo return (VGEN_FAILURE); 2598*1991Sheppo } 2599*1991Sheppo 2600*1991Sheppo /* 2601*1991Sheppo * wrapper routine to send the given message over ldc using ldc_write(). 2602*1991Sheppo */ 2603*1991Sheppo static int 2604*1991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 2605*1991Sheppo boolean_t caller_holds_lock) 2606*1991Sheppo { 2607*1991Sheppo int rv; 2608*1991Sheppo size_t len; 2609*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2610*1991Sheppo uint32_t retries = 0; 2611*1991Sheppo 2612*1991Sheppo len = msglen; 2613*1991Sheppo if ((len == 0) || (msg == NULL)) 2614*1991Sheppo return (VGEN_FAILURE); 2615*1991Sheppo 2616*1991Sheppo if (!caller_holds_lock) { 2617*1991Sheppo mutex_enter(&ldcp->txlock); 2618*1991Sheppo } 2619*1991Sheppo 2620*1991Sheppo do { 2621*1991Sheppo len = msglen; 2622*1991Sheppo rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len); 2623*1991Sheppo if (retries++ >= vgen_ldcwr_retries) 2624*1991Sheppo break; 2625*1991Sheppo } while (rv == EWOULDBLOCK); 2626*1991Sheppo 2627*1991Sheppo if (!caller_holds_lock) { 2628*1991Sheppo mutex_exit(&ldcp->txlock); 2629*1991Sheppo } 2630*1991Sheppo 2631*1991Sheppo if ((rv != 0) || (len != msglen)) { 2632*1991Sheppo DWARN((vnetp, 2633*1991Sheppo "vgen_sendmsg: ldc_write failed: id(%lx) rv(%d)" 2634*1991Sheppo " msglen (%d)\n", ldcp->ldc_id, rv, msglen)); 2635*1991Sheppo return (VGEN_FAILURE); 2636*1991Sheppo } 2637*1991Sheppo return (VGEN_SUCCESS); 2638*1991Sheppo } 2639*1991Sheppo 2640*1991Sheppo /* send version negotiate message to the peer over ldc */ 2641*1991Sheppo static int 2642*1991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp) 2643*1991Sheppo { 2644*1991Sheppo vio_ver_msg_t vermsg; 2645*1991Sheppo vio_msg_tag_t *tagp = &vermsg.tag; 2646*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2647*1991Sheppo int rv; 2648*1991Sheppo 2649*1991Sheppo bzero(&vermsg, sizeof (vermsg)); 2650*1991Sheppo 2651*1991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 2652*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 2653*1991Sheppo tagp->vio_subtype_env = VIO_VER_INFO; 2654*1991Sheppo tagp->vio_sid = ldcp->local_sid; 2655*1991Sheppo 2656*1991Sheppo /* get version msg payload from ldcp->local */ 2657*1991Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major; 2658*1991Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor; 2659*1991Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class; 2660*1991Sheppo 2661*1991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE); 2662*1991Sheppo if (rv != VGEN_SUCCESS) { 2663*1991Sheppo DWARN((vnetp, "vgen_send_version_negotiate: vgen_sendmsg failed" 2664*1991Sheppo "id (%lx)\n", ldcp->ldc_id)); 2665*1991Sheppo return (VGEN_FAILURE); 2666*1991Sheppo } 2667*1991Sheppo 2668*1991Sheppo ldcp->hstate |= VER_INFO_SENT; 2669*1991Sheppo DBG2((vnetp, 2670*1991Sheppo "vgen_send_version_negotiate: VER_INFO_SENT id (%lx) ver(%d,%d)\n", 2671*1991Sheppo ldcp->ldc_id, vermsg.ver_major, vermsg.ver_minor)); 2672*1991Sheppo 2673*1991Sheppo return (VGEN_SUCCESS); 2674*1991Sheppo } 2675*1991Sheppo 2676*1991Sheppo /* send attr info message to the peer over ldc */ 2677*1991Sheppo static int 2678*1991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp) 2679*1991Sheppo { 2680*1991Sheppo vnet_attr_msg_t attrmsg; 2681*1991Sheppo vio_msg_tag_t *tagp = &attrmsg.tag; 2682*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2683*1991Sheppo int rv; 2684*1991Sheppo 2685*1991Sheppo bzero(&attrmsg, sizeof (attrmsg)); 2686*1991Sheppo 2687*1991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 2688*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 2689*1991Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO; 2690*1991Sheppo tagp->vio_sid = ldcp->local_sid; 2691*1991Sheppo 2692*1991Sheppo /* get attr msg payload from ldcp->local */ 2693*1991Sheppo attrmsg.mtu = ldcp->local_hparams.mtu; 2694*1991Sheppo attrmsg.addr = ldcp->local_hparams.addr; 2695*1991Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type; 2696*1991Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode; 2697*1991Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq; 2698*1991Sheppo 2699*1991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE); 2700*1991Sheppo if (rv != VGEN_SUCCESS) { 2701*1991Sheppo DWARN((vnetp, "vgen_send_attr_info: vgen_sendmsg failed" 2702*1991Sheppo "id (%lx)\n", ldcp->ldc_id)); 2703*1991Sheppo return (VGEN_FAILURE); 2704*1991Sheppo } 2705*1991Sheppo 2706*1991Sheppo ldcp->hstate |= ATTR_INFO_SENT; 2707*1991Sheppo DBG2((vnetp, "vgen_send_attr_info: ATTR_INFO_SENT id (%lx)\n", 2708*1991Sheppo ldcp->ldc_id)); 2709*1991Sheppo 2710*1991Sheppo return (VGEN_SUCCESS); 2711*1991Sheppo } 2712*1991Sheppo 2713*1991Sheppo /* send descriptor ring register message to the peer over ldc */ 2714*1991Sheppo static int 2715*1991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp) 2716*1991Sheppo { 2717*1991Sheppo vio_dring_reg_msg_t msg; 2718*1991Sheppo vio_msg_tag_t *tagp = &msg.tag; 2719*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2720*1991Sheppo int rv; 2721*1991Sheppo 2722*1991Sheppo bzero(&msg, sizeof (msg)); 2723*1991Sheppo 2724*1991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 2725*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 2726*1991Sheppo tagp->vio_subtype_env = VIO_DRING_REG; 2727*1991Sheppo tagp->vio_sid = ldcp->local_sid; 2728*1991Sheppo 2729*1991Sheppo /* get dring info msg payload from ldcp->local */ 2730*1991Sheppo bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie), 2731*1991Sheppo sizeof (ldc_mem_cookie_t)); 2732*1991Sheppo msg.ncookies = ldcp->local_hparams.num_dcookies; 2733*1991Sheppo msg.num_descriptors = ldcp->local_hparams.num_desc; 2734*1991Sheppo msg.descriptor_size = ldcp->local_hparams.desc_size; 2735*1991Sheppo 2736*1991Sheppo /* 2737*1991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 2738*1991Sheppo * value and sends it in the ack, which is saved in 2739*1991Sheppo * vgen_handle_dring_reg(). 2740*1991Sheppo */ 2741*1991Sheppo msg.dring_ident = 0; 2742*1991Sheppo 2743*1991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE); 2744*1991Sheppo if (rv != VGEN_SUCCESS) { 2745*1991Sheppo DWARN((vnetp, "vgen_send_dring_reg: vgen_sendmsg failed" 2746*1991Sheppo "id (%lx)\n", ldcp->ldc_id)); 2747*1991Sheppo return (VGEN_FAILURE); 2748*1991Sheppo } 2749*1991Sheppo 2750*1991Sheppo ldcp->hstate |= DRING_INFO_SENT; 2751*1991Sheppo DBG2((vnetp, "vgen_send_dring_reg: DRING_INFO_SENT id (%lx)\n", 2752*1991Sheppo ldcp->ldc_id)); 2753*1991Sheppo 2754*1991Sheppo return (VGEN_SUCCESS); 2755*1991Sheppo } 2756*1991Sheppo 2757*1991Sheppo static int 2758*1991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp) 2759*1991Sheppo { 2760*1991Sheppo vio_rdx_msg_t rdxmsg; 2761*1991Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag; 2762*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2763*1991Sheppo int rv; 2764*1991Sheppo 2765*1991Sheppo bzero(&rdxmsg, sizeof (rdxmsg)); 2766*1991Sheppo 2767*1991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 2768*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 2769*1991Sheppo tagp->vio_subtype_env = VIO_RDX; 2770*1991Sheppo tagp->vio_sid = ldcp->local_sid; 2771*1991Sheppo 2772*1991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE); 2773*1991Sheppo if (rv != VGEN_SUCCESS) { 2774*1991Sheppo DWARN((vnetp, "vgen_send_rdx_info: vgen_sendmsg failed" 2775*1991Sheppo "id (%lx)\n", ldcp->ldc_id)); 2776*1991Sheppo return (VGEN_FAILURE); 2777*1991Sheppo } 2778*1991Sheppo 2779*1991Sheppo ldcp->hstate |= RDX_INFO_SENT; 2780*1991Sheppo DBG2((vnetp, "vgen_send_rdx_info: RDX_INFO_SENT id (%lx)\n", 2781*1991Sheppo ldcp->ldc_id)); 2782*1991Sheppo 2783*1991Sheppo return (VGEN_SUCCESS); 2784*1991Sheppo } 2785*1991Sheppo 2786*1991Sheppo /* send descriptor ring data message to the peer over ldc */ 2787*1991Sheppo static int 2788*1991Sheppo vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, uint32_t end, 2789*1991Sheppo uint64_t next_txseq) 2790*1991Sheppo { 2791*1991Sheppo vio_dring_msg_t dringmsg, *msgp = &dringmsg; 2792*1991Sheppo vio_msg_tag_t *tagp = &msgp->tag; 2793*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2794*1991Sheppo int rv; 2795*1991Sheppo 2796*1991Sheppo bzero(msgp, sizeof (*msgp)); 2797*1991Sheppo 2798*1991Sheppo tagp->vio_msgtype = VIO_TYPE_DATA; 2799*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 2800*1991Sheppo tagp->vio_subtype_env = VIO_DRING_DATA; 2801*1991Sheppo tagp->vio_sid = ldcp->local_sid; 2802*1991Sheppo 2803*1991Sheppo msgp->seq_num = next_txseq; 2804*1991Sheppo msgp->dring_ident = ldcp->local_hparams.dring_ident; 2805*1991Sheppo msgp->start_idx = start; 2806*1991Sheppo msgp->end_idx = end; 2807*1991Sheppo 2808*1991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE); 2809*1991Sheppo if (rv != VGEN_SUCCESS) { 2810*1991Sheppo DWARN((vnetp, "vgen_send_dring_data: vgen_sendmsg failed" 2811*1991Sheppo "id (%lx)\n", ldcp->ldc_id)); 2812*1991Sheppo return (VGEN_FAILURE); 2813*1991Sheppo } 2814*1991Sheppo 2815*1991Sheppo DBG2((vnetp, "vgen_send_dring_data: DRING_DATA_SENT id (%lx)\n", 2816*1991Sheppo ldcp->ldc_id)); 2817*1991Sheppo 2818*1991Sheppo return (VGEN_SUCCESS); 2819*1991Sheppo } 2820*1991Sheppo 2821*1991Sheppo /* send multicast addr info message to vsw */ 2822*1991Sheppo static int 2823*1991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp) 2824*1991Sheppo { 2825*1991Sheppo vnet_mcast_msg_t mcastmsg; 2826*1991Sheppo vnet_mcast_msg_t *msgp; 2827*1991Sheppo vio_msg_tag_t *tagp; 2828*1991Sheppo vgen_t *vgenp; 2829*1991Sheppo void *vnetp; 2830*1991Sheppo struct ether_addr *mca; 2831*1991Sheppo int rv; 2832*1991Sheppo int i; 2833*1991Sheppo uint32_t size; 2834*1991Sheppo uint32_t mccount; 2835*1991Sheppo uint32_t n; 2836*1991Sheppo 2837*1991Sheppo msgp = &mcastmsg; 2838*1991Sheppo tagp = &msgp->tag; 2839*1991Sheppo vgenp = LDC_TO_VGEN(ldcp); 2840*1991Sheppo vnetp = LDC_TO_VNET(ldcp); 2841*1991Sheppo 2842*1991Sheppo mccount = vgenp->mccount; 2843*1991Sheppo i = 0; 2844*1991Sheppo 2845*1991Sheppo do { 2846*1991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 2847*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 2848*1991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 2849*1991Sheppo tagp->vio_sid = ldcp->local_sid; 2850*1991Sheppo 2851*1991Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount); 2852*1991Sheppo size = n * sizeof (struct ether_addr); 2853*1991Sheppo 2854*1991Sheppo mca = &(vgenp->mctab[i]); 2855*1991Sheppo bcopy(mca, (msgp->mca), size); 2856*1991Sheppo msgp->set = B_TRUE; 2857*1991Sheppo msgp->count = n; 2858*1991Sheppo 2859*1991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), 2860*1991Sheppo B_FALSE); 2861*1991Sheppo if (rv != VGEN_SUCCESS) { 2862*1991Sheppo DWARN((vnetp, "vgen_send_mcast_info: vgen_sendmsg err" 2863*1991Sheppo "id (%lx)\n", ldcp->ldc_id)); 2864*1991Sheppo return (VGEN_FAILURE); 2865*1991Sheppo } 2866*1991Sheppo 2867*1991Sheppo mccount -= n; 2868*1991Sheppo i += n; 2869*1991Sheppo 2870*1991Sheppo } while (mccount); 2871*1991Sheppo 2872*1991Sheppo return (VGEN_SUCCESS); 2873*1991Sheppo } 2874*1991Sheppo 2875*1991Sheppo /* Initiate Phase 2 of handshake */ 2876*1991Sheppo static int 2877*1991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp) 2878*1991Sheppo { 2879*1991Sheppo int rv; 2880*1991Sheppo #ifdef DEBUG 2881*1991Sheppo if (vgen_hdbg & HDBG_OUT_STATE) { 2882*1991Sheppo /* simulate out of state condition */ 2883*1991Sheppo vgen_hdbg &= ~(HDBG_OUT_STATE); 2884*1991Sheppo rv = vgen_send_rdx_info(ldcp); 2885*1991Sheppo return (rv); 2886*1991Sheppo } 2887*1991Sheppo if (vgen_hdbg & HDBG_TIMEOUT) { 2888*1991Sheppo /* simulate timeout condition */ 2889*1991Sheppo vgen_hdbg &= ~(HDBG_TIMEOUT); 2890*1991Sheppo return (VGEN_SUCCESS); 2891*1991Sheppo } 2892*1991Sheppo #endif 2893*1991Sheppo if ((rv = vgen_send_attr_info(ldcp)) != VGEN_SUCCESS) { 2894*1991Sheppo return (rv); 2895*1991Sheppo } 2896*1991Sheppo if ((rv = vgen_send_dring_reg(ldcp)) != VGEN_SUCCESS) { 2897*1991Sheppo return (rv); 2898*1991Sheppo } 2899*1991Sheppo 2900*1991Sheppo return (VGEN_SUCCESS); 2901*1991Sheppo } 2902*1991Sheppo 2903*1991Sheppo /* 2904*1991Sheppo * This function resets the handshake phase to VH_PHASE0(pre-handshake phase). 2905*1991Sheppo * This can happen after a channel comes up (status: LDC_UP) or 2906*1991Sheppo * when handshake gets terminated due to various conditions. 2907*1991Sheppo */ 2908*1991Sheppo static void 2909*1991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp) 2910*1991Sheppo { 2911*1991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 2912*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 2913*1991Sheppo ldc_status_t istatus; 2914*1991Sheppo 2915*1991Sheppo DBG2((vnetp, "vgen_reset_hphase: id(0x%lx)\n", ldcp->ldc_id)); 2916*1991Sheppo /* reset hstate and hphase */ 2917*1991Sheppo ldcp->hstate = 0; 2918*1991Sheppo ldcp->hphase = VH_PHASE0; 2919*1991Sheppo 2920*1991Sheppo /* reset handshake watchdog timeout */ 2921*1991Sheppo if (ldcp->htid) { 2922*1991Sheppo (void) untimeout(ldcp->htid); 2923*1991Sheppo ldcp->htid = 0; 2924*1991Sheppo } 2925*1991Sheppo 2926*1991Sheppo /* 2927*1991Sheppo * Unmap drings, if dring_ready is set. 2928*1991Sheppo */ 2929*1991Sheppo if (ldcp->local_hparams.dring_ready) { 2930*1991Sheppo ldcp->local_hparams.dring_ready = B_FALSE; 2931*1991Sheppo /* do not unbind our dring */ 2932*1991Sheppo } 2933*1991Sheppo 2934*1991Sheppo if (ldcp->peer_hparams.dring_ready) { 2935*1991Sheppo ldcp->peer_hparams.dring_ready = B_FALSE; 2936*1991Sheppo /* Unmap peer's dring */ 2937*1991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 2938*1991Sheppo vgen_clobber_rxds(ldcp); 2939*1991Sheppo } 2940*1991Sheppo 2941*1991Sheppo vgen_clobber_tbufs(ldcp); 2942*1991Sheppo 2943*1991Sheppo /* 2944*1991Sheppo * clear local handshake params and initialize. 2945*1991Sheppo */ 2946*1991Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams)); 2947*1991Sheppo 2948*1991Sheppo #ifdef DEBUG 2949*1991Sheppo #if 0 2950*1991Sheppo if (vgen_hdbg & HDBG_VERSION) { 2951*1991Sheppo bcopy(dbg_vgen_versions, ldcp->vgen_versions, 2952*1991Sheppo sizeof (ldcp->vgen_versions)); 2953*1991Sheppo } 2954*1991Sheppo #endif 2955*1991Sheppo #endif 2956*1991Sheppo /* set version to the highest version supported */ 2957*1991Sheppo ldcp->local_hparams.ver_major = 2958*1991Sheppo ldcp->vgen_versions[0].ver_major; 2959*1991Sheppo ldcp->local_hparams.ver_minor = 2960*1991Sheppo ldcp->vgen_versions[0].ver_minor; 2961*1991Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK; 2962*1991Sheppo 2963*1991Sheppo /* set attr_info params */ 2964*1991Sheppo ldcp->local_hparams.mtu = ETHERMAX; 2965*1991Sheppo ldcp->local_hparams.addr = 2966*1991Sheppo vgen_macaddr_strtoul(vgenp->macaddr); 2967*1991Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC; 2968*1991Sheppo ldcp->local_hparams.xfer_mode = VIO_DRING_MODE; 2969*1991Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */ 2970*1991Sheppo 2971*1991Sheppo #ifdef DEBUG 2972*1991Sheppo #if 0 2973*1991Sheppo vgen_print_attr_info(ldcp, VGEN_LOCAL); 2974*1991Sheppo #endif 2975*1991Sheppo #endif 2976*1991Sheppo 2977*1991Sheppo /* 2978*1991Sheppo * set dring_info params. 2979*1991Sheppo * Note: dring is already created and bound. 2980*1991Sheppo */ 2981*1991Sheppo bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie), 2982*1991Sheppo sizeof (ldc_mem_cookie_t)); 2983*1991Sheppo ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies; 2984*1991Sheppo ldcp->local_hparams.num_desc = ldcp->num_txds; 2985*1991Sheppo ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t); 2986*1991Sheppo 2987*1991Sheppo /* 2988*1991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 2989*1991Sheppo * value and sends it in the ack, which is saved in 2990*1991Sheppo * vgen_handle_dring_reg(). 2991*1991Sheppo */ 2992*1991Sheppo ldcp->local_hparams.dring_ident = 0; 2993*1991Sheppo 2994*1991Sheppo /* clear peer_hparams */ 2995*1991Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams)); 2996*1991Sheppo 2997*1991Sheppo /* reset the channel if required */ 2998*1991Sheppo if (ldcp->need_ldc_reset) { 2999*1991Sheppo DWARN((vnetp, 3000*1991Sheppo "vgen_reset_hphase: id (%lx), Doing Channel Reset...\n", 3001*1991Sheppo ldcp->ldc_id)); 3002*1991Sheppo ldcp->need_ldc_reset = B_FALSE; 3003*1991Sheppo (void) ldc_reset(ldcp->ldc_handle); 3004*1991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 3005*1991Sheppo DBG2((vnetp, 3006*1991Sheppo "vgen_reset_hphase: id (%lx), RESET Done,ldc_status(%x)\n", 3007*1991Sheppo ldcp->ldc_id, istatus)); 3008*1991Sheppo ldcp->ldc_status = istatus; 3009*1991Sheppo /* clear sids */ 3010*1991Sheppo ldcp->local_sid = 0; 3011*1991Sheppo ldcp->peer_sid = 0; 3012*1991Sheppo (void) ldc_up(ldcp->ldc_handle); 3013*1991Sheppo } 3014*1991Sheppo } 3015*1991Sheppo 3016*1991Sheppo /* wrapper function for vgen_reset_hphase */ 3017*1991Sheppo static void 3018*1991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp) 3019*1991Sheppo { 3020*1991Sheppo ASSERT(MUTEX_HELD(&ldcp->cblock)); 3021*1991Sheppo mutex_enter(&ldcp->txlock); 3022*1991Sheppo mutex_enter(&ldcp->tclock); 3023*1991Sheppo 3024*1991Sheppo vgen_reset_hphase(ldcp); 3025*1991Sheppo 3026*1991Sheppo mutex_exit(&ldcp->tclock); 3027*1991Sheppo mutex_exit(&ldcp->txlock); 3028*1991Sheppo } 3029*1991Sheppo 3030*1991Sheppo /* 3031*1991Sheppo * Initiate handshake with the peer by sending various messages 3032*1991Sheppo * based on the handshake-phase that the channel is currently in. 3033*1991Sheppo */ 3034*1991Sheppo static void 3035*1991Sheppo vgen_handshake(vgen_ldc_t *ldcp) 3036*1991Sheppo { 3037*1991Sheppo uint32_t hphase = ldcp->hphase; 3038*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3039*1991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 3040*1991Sheppo 3041*1991Sheppo switch (hphase) { 3042*1991Sheppo 3043*1991Sheppo case VH_PHASE1: 3044*1991Sheppo 3045*1991Sheppo /* 3046*1991Sheppo * start timer, for entire handshake process, turn this timer 3047*1991Sheppo * off if all phases of handshake complete successfully and 3048*1991Sheppo * hphase goes to VH_DONE(below) or 3049*1991Sheppo * vgen_reset_hphase() gets called or 3050*1991Sheppo * channel is reset due to errors or 3051*1991Sheppo * vgen_ldc_uninit() is invoked(vgen_stop). 3052*1991Sheppo */ 3053*1991Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp, 3054*1991Sheppo drv_usectohz(vgen_hwd_interval * 1000)); 3055*1991Sheppo 3056*1991Sheppo /* Phase 1 involves negotiating the version */ 3057*1991Sheppo if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) { 3058*1991Sheppo vgen_handshake_reset(ldcp); 3059*1991Sheppo } 3060*1991Sheppo break; 3061*1991Sheppo 3062*1991Sheppo case VH_PHASE2: 3063*1991Sheppo if (vgen_handshake_phase2(ldcp) != VGEN_SUCCESS) { 3064*1991Sheppo vgen_handshake_reset(ldcp); 3065*1991Sheppo } 3066*1991Sheppo break; 3067*1991Sheppo 3068*1991Sheppo case VH_PHASE3: 3069*1991Sheppo if (vgen_send_rdx_info(ldcp) != VGEN_SUCCESS) { 3070*1991Sheppo vgen_handshake_reset(ldcp); 3071*1991Sheppo } 3072*1991Sheppo break; 3073*1991Sheppo 3074*1991Sheppo case VH_DONE: 3075*1991Sheppo /* reset handshake watchdog timeout */ 3076*1991Sheppo if (ldcp->htid) { 3077*1991Sheppo (void) untimeout(ldcp->htid); 3078*1991Sheppo ldcp->htid = 0; 3079*1991Sheppo } 3080*1991Sheppo ldcp->hretries = 0; 3081*1991Sheppo #if 0 3082*1991Sheppo vgen_print_ldcinfo(ldcp); 3083*1991Sheppo #endif 3084*1991Sheppo DBG1((vnetp, "vgen_handshake: id(0x%lx) Handshake Done\n", 3085*1991Sheppo ldcp->ldc_id)); 3086*1991Sheppo 3087*1991Sheppo if (ldcp->need_mcast_sync) { 3088*1991Sheppo /* need to sync multicast table with vsw */ 3089*1991Sheppo 3090*1991Sheppo ldcp->need_mcast_sync = B_FALSE; 3091*1991Sheppo mutex_exit(&ldcp->cblock); 3092*1991Sheppo 3093*1991Sheppo mutex_enter(&vgenp->lock); 3094*1991Sheppo (void) vgen_send_mcast_info(ldcp); 3095*1991Sheppo mutex_exit(&vgenp->lock); 3096*1991Sheppo 3097*1991Sheppo mutex_enter(&ldcp->cblock); 3098*1991Sheppo 3099*1991Sheppo } 3100*1991Sheppo break; 3101*1991Sheppo 3102*1991Sheppo default: 3103*1991Sheppo break; 3104*1991Sheppo } 3105*1991Sheppo } 3106*1991Sheppo 3107*1991Sheppo /* 3108*1991Sheppo * Check if the current handshake phase has completed successfully and 3109*1991Sheppo * return the status. 3110*1991Sheppo */ 3111*1991Sheppo static int 3112*1991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp) 3113*1991Sheppo { 3114*1991Sheppo uint32_t hphase = ldcp->hphase; 3115*1991Sheppo int status = 0; 3116*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3117*1991Sheppo 3118*1991Sheppo switch (hphase) { 3119*1991Sheppo 3120*1991Sheppo case VH_PHASE1: 3121*1991Sheppo /* 3122*1991Sheppo * Phase1 is done, if version negotiation 3123*1991Sheppo * completed successfully. 3124*1991Sheppo */ 3125*1991Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) == 3126*1991Sheppo VER_NEGOTIATED); 3127*1991Sheppo break; 3128*1991Sheppo 3129*1991Sheppo case VH_PHASE2: 3130*1991Sheppo /* 3131*1991Sheppo * Phase 2 is done, if attr info and dring info 3132*1991Sheppo * have been exchanged successfully. 3133*1991Sheppo */ 3134*1991Sheppo status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) == 3135*1991Sheppo ATTR_INFO_EXCHANGED) && 3136*1991Sheppo ((ldcp->hstate & DRING_INFO_EXCHANGED) == 3137*1991Sheppo DRING_INFO_EXCHANGED)); 3138*1991Sheppo break; 3139*1991Sheppo 3140*1991Sheppo case VH_PHASE3: 3141*1991Sheppo /* Phase 3 is done, if rdx msg has been exchanged */ 3142*1991Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) == 3143*1991Sheppo RDX_EXCHANGED); 3144*1991Sheppo break; 3145*1991Sheppo 3146*1991Sheppo default: 3147*1991Sheppo break; 3148*1991Sheppo } 3149*1991Sheppo 3150*1991Sheppo if (status == 0) { 3151*1991Sheppo return (VGEN_FAILURE); 3152*1991Sheppo } 3153*1991Sheppo DBG2((vnetp, "VNET_HANDSHAKE_DONE: PHASE(%d)\n", hphase)); 3154*1991Sheppo return (VGEN_SUCCESS); 3155*1991Sheppo } 3156*1991Sheppo 3157*1991Sheppo /* retry handshake on failure */ 3158*1991Sheppo static void 3159*1991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp) 3160*1991Sheppo { 3161*1991Sheppo /* reset handshake phase */ 3162*1991Sheppo vgen_handshake_reset(ldcp); 3163*1991Sheppo if (vgen_max_hretries) { /* handshake retry is specified */ 3164*1991Sheppo if (ldcp->hretries++ < vgen_max_hretries) 3165*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3166*1991Sheppo } 3167*1991Sheppo } 3168*1991Sheppo 3169*1991Sheppo /* 3170*1991Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer 3171*1991Sheppo * to a version info msg that we sent. 3172*1991Sheppo */ 3173*1991Sheppo static void 3174*1991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 3175*1991Sheppo { 3176*1991Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp; 3177*1991Sheppo int ack = 0; 3178*1991Sheppo int failed = 0; 3179*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3180*1991Sheppo int idx; 3181*1991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 3182*1991Sheppo 3183*1991Sheppo DBG1((vnetp, "vgen_handle_version_negotiate: enter\n")); 3184*1991Sheppo switch (tagp->vio_subtype) { 3185*1991Sheppo case VIO_SUBTYPE_INFO: 3186*1991Sheppo 3187*1991Sheppo /* Cache sid of peer if this is the first time */ 3188*1991Sheppo if (ldcp->peer_sid == 0) { 3189*1991Sheppo DBG2((vnetp, 3190*1991Sheppo "vgen_handle_version_negotiate: id (%lx) Caching" 3191*1991Sheppo " peer_sid(%x)\n", ldcp->ldc_id, tagp->vio_sid)); 3192*1991Sheppo ldcp->peer_sid = tagp->vio_sid; 3193*1991Sheppo } 3194*1991Sheppo 3195*1991Sheppo if (ldcp->hphase != VH_PHASE1) { 3196*1991Sheppo /* 3197*1991Sheppo * If we are not already in VH_PHASE1, reset to 3198*1991Sheppo * pre-handshake state, and initiate handshake 3199*1991Sheppo * to the peer too. 3200*1991Sheppo */ 3201*1991Sheppo vgen_handshake_reset(ldcp); 3202*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3203*1991Sheppo } 3204*1991Sheppo ldcp->hstate |= VER_INFO_RCVD; 3205*1991Sheppo 3206*1991Sheppo /* save peer's requested values */ 3207*1991Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major; 3208*1991Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor; 3209*1991Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class; 3210*1991Sheppo 3211*1991Sheppo if ((vermsg->dev_class != VDEV_NETWORK) && 3212*1991Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) { 3213*1991Sheppo /* unsupported dev_class, send NACK */ 3214*1991Sheppo 3215*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 3216*1991Sheppo tagp->vio_sid = ldcp->local_sid; 3217*1991Sheppo /* send reply msg back to peer */ 3218*1991Sheppo (void) vgen_sendmsg(ldcp, (caddr_t)tagp, 3219*1991Sheppo sizeof (*vermsg), B_FALSE); 3220*1991Sheppo DWARN((vnetp, 3221*1991Sheppo "vgen_handle_version_negotiate: Version" 3222*1991Sheppo " Negotiation Failed id (%lx)\n", ldcp->ldc_id)); 3223*1991Sheppo vgen_handshake_reset(ldcp); 3224*1991Sheppo return; 3225*1991Sheppo } 3226*1991Sheppo 3227*1991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate: VER_INFO_RCVD," 3228*1991Sheppo " id (%lx), ver(%d,%d)\n", ldcp->ldc_id, 3229*1991Sheppo vermsg->ver_major, vermsg->ver_minor)); 3230*1991Sheppo 3231*1991Sheppo idx = 0; 3232*1991Sheppo 3233*1991Sheppo for (;;) { 3234*1991Sheppo 3235*1991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 3236*1991Sheppo 3237*1991Sheppo /* nack with next lower version */ 3238*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 3239*1991Sheppo vermsg->ver_major = versions[idx].ver_major; 3240*1991Sheppo vermsg->ver_minor = versions[idx].ver_minor; 3241*1991Sheppo break; 3242*1991Sheppo } 3243*1991Sheppo 3244*1991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 3245*1991Sheppo 3246*1991Sheppo /* major version match - ACK version */ 3247*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 3248*1991Sheppo ack = 1; 3249*1991Sheppo 3250*1991Sheppo /* 3251*1991Sheppo * lower minor version to the one this endpt 3252*1991Sheppo * supports, if necessary 3253*1991Sheppo */ 3254*1991Sheppo if (vermsg->ver_minor > 3255*1991Sheppo versions[idx].ver_minor) { 3256*1991Sheppo vermsg->ver_minor = 3257*1991Sheppo versions[idx].ver_minor; 3258*1991Sheppo ldcp->peer_hparams.ver_minor = 3259*1991Sheppo versions[idx].ver_minor; 3260*1991Sheppo } 3261*1991Sheppo break; 3262*1991Sheppo } 3263*1991Sheppo 3264*1991Sheppo idx++; 3265*1991Sheppo 3266*1991Sheppo if (idx == VGEN_NUM_VER) { 3267*1991Sheppo 3268*1991Sheppo /* no version match - send NACK */ 3269*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 3270*1991Sheppo vermsg->ver_major = 0; 3271*1991Sheppo vermsg->ver_minor = 0; 3272*1991Sheppo failed = 1; 3273*1991Sheppo break; 3274*1991Sheppo } 3275*1991Sheppo 3276*1991Sheppo } 3277*1991Sheppo 3278*1991Sheppo tagp->vio_sid = ldcp->local_sid; 3279*1991Sheppo 3280*1991Sheppo /* send reply msg back to peer */ 3281*1991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg), 3282*1991Sheppo B_FALSE) != VGEN_SUCCESS) { 3283*1991Sheppo vgen_handshake_reset(ldcp); 3284*1991Sheppo return; 3285*1991Sheppo } 3286*1991Sheppo 3287*1991Sheppo if (ack) { 3288*1991Sheppo ldcp->hstate |= VER_ACK_SENT; 3289*1991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 3290*1991Sheppo " VER_ACK_SENT, id (%lx) ver(%d,%d) \n", 3291*1991Sheppo ldcp->ldc_id, vermsg->ver_major, 3292*1991Sheppo vermsg->ver_minor)); 3293*1991Sheppo } 3294*1991Sheppo if (failed) { 3295*1991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 3296*1991Sheppo " Version Negotiation Failed id (%lx)\n", 3297*1991Sheppo ldcp->ldc_id)); 3298*1991Sheppo vgen_handshake_reset(ldcp); 3299*1991Sheppo return; 3300*1991Sheppo } 3301*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3302*1991Sheppo 3303*1991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 3304*1991Sheppo 3305*1991Sheppo /* local and peer versions match? */ 3306*1991Sheppo ASSERT((ldcp->local_hparams.ver_major == 3307*1991Sheppo ldcp->peer_hparams.ver_major) && 3308*1991Sheppo (ldcp->local_hparams.ver_minor == 3309*1991Sheppo ldcp->peer_hparams.ver_minor)); 3310*1991Sheppo 3311*1991Sheppo /* move to the next phase */ 3312*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3313*1991Sheppo } 3314*1991Sheppo 3315*1991Sheppo break; 3316*1991Sheppo 3317*1991Sheppo case VIO_SUBTYPE_ACK: 3318*1991Sheppo 3319*1991Sheppo if (ldcp->hphase != VH_PHASE1) { 3320*1991Sheppo /* This should not happen. */ 3321*1991Sheppo DWARN((vnetp, 3322*1991Sheppo "vgen_handle_version_negotiate:" 3323*1991Sheppo " VER_ACK_RCVD id (%lx) Invalid Phase(%u)\n", 3324*1991Sheppo ldcp->ldc_id, ldcp->hphase)); 3325*1991Sheppo vgen_handshake_reset(ldcp); 3326*1991Sheppo return; 3327*1991Sheppo } 3328*1991Sheppo 3329*1991Sheppo /* SUCCESS - we have agreed on a version */ 3330*1991Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major; 3331*1991Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor; 3332*1991Sheppo ldcp->hstate |= VER_ACK_RCVD; 3333*1991Sheppo 3334*1991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 3335*1991Sheppo " VER_ACK_RCVD, id (%lx) ver(%d,%d) \n", 3336*1991Sheppo ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor)); 3337*1991Sheppo 3338*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3339*1991Sheppo 3340*1991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 3341*1991Sheppo 3342*1991Sheppo /* local and peer versions match? */ 3343*1991Sheppo ASSERT((ldcp->local_hparams.ver_major == 3344*1991Sheppo ldcp->peer_hparams.ver_major) && 3345*1991Sheppo (ldcp->local_hparams.ver_minor == 3346*1991Sheppo ldcp->peer_hparams.ver_minor)); 3347*1991Sheppo 3348*1991Sheppo /* move to the next phase */ 3349*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3350*1991Sheppo } 3351*1991Sheppo break; 3352*1991Sheppo 3353*1991Sheppo case VIO_SUBTYPE_NACK: 3354*1991Sheppo 3355*1991Sheppo if (ldcp->hphase != VH_PHASE1) { 3356*1991Sheppo /* This should not happen. */ 3357*1991Sheppo DWARN((vnetp, 3358*1991Sheppo "vgen_handle_version_negotiate:" 3359*1991Sheppo " VER_NACK_RCVD id (%lx) Invalid Phase(%u)\n", 3360*1991Sheppo ldcp->ldc_id, ldcp->hphase)); 3361*1991Sheppo vgen_handshake_reset(ldcp); 3362*1991Sheppo return; 3363*1991Sheppo } 3364*1991Sheppo 3365*1991Sheppo DBG2((vnetp, "vgen_handle_version_negotiate:" 3366*1991Sheppo " VER_NACK_RCVD id(%lx) next ver(%d,%d)\n", 3367*1991Sheppo ldcp->ldc_id, vermsg->ver_major, vermsg->ver_minor)); 3368*1991Sheppo 3369*1991Sheppo /* check if version in NACK is zero */ 3370*1991Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) { 3371*1991Sheppo /* 3372*1991Sheppo * Version Negotiation has failed. 3373*1991Sheppo */ 3374*1991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 3375*1991Sheppo " Version Negotiation Failed id (%lx)\n", 3376*1991Sheppo ldcp->ldc_id)); 3377*1991Sheppo vgen_handshake_reset(ldcp); 3378*1991Sheppo return; 3379*1991Sheppo } 3380*1991Sheppo 3381*1991Sheppo idx = 0; 3382*1991Sheppo 3383*1991Sheppo for (;;) { 3384*1991Sheppo 3385*1991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 3386*1991Sheppo /* select next lower version */ 3387*1991Sheppo 3388*1991Sheppo ldcp->local_hparams.ver_major = 3389*1991Sheppo versions[idx].ver_major; 3390*1991Sheppo ldcp->local_hparams.ver_minor = 3391*1991Sheppo versions[idx].ver_minor; 3392*1991Sheppo break; 3393*1991Sheppo } 3394*1991Sheppo 3395*1991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 3396*1991Sheppo /* major version match */ 3397*1991Sheppo 3398*1991Sheppo ldcp->local_hparams.ver_major = 3399*1991Sheppo versions[idx].ver_major; 3400*1991Sheppo 3401*1991Sheppo ldcp->local_hparams.ver_minor = 3402*1991Sheppo versions[idx].ver_minor; 3403*1991Sheppo break; 3404*1991Sheppo } 3405*1991Sheppo 3406*1991Sheppo idx++; 3407*1991Sheppo 3408*1991Sheppo if (idx == VGEN_NUM_VER) { 3409*1991Sheppo /* 3410*1991Sheppo * no version match. 3411*1991Sheppo * Version Negotiation has failed. 3412*1991Sheppo */ 3413*1991Sheppo DWARN((vnetp, "vgen_handle_version_negotiate:" 3414*1991Sheppo " Version Negotiation Failed id (%lx)\n", 3415*1991Sheppo ldcp->ldc_id)); 3416*1991Sheppo vgen_handshake_reset(ldcp); 3417*1991Sheppo return; 3418*1991Sheppo } 3419*1991Sheppo 3420*1991Sheppo } 3421*1991Sheppo 3422*1991Sheppo if (vgen_send_version_negotiate(ldcp) != VGEN_SUCCESS) { 3423*1991Sheppo vgen_handshake_reset(ldcp); 3424*1991Sheppo return; 3425*1991Sheppo } 3426*1991Sheppo 3427*1991Sheppo break; 3428*1991Sheppo } 3429*1991Sheppo DBG1((vnetp, "vgen_handle_version_negotiate: exit\n")); 3430*1991Sheppo } 3431*1991Sheppo 3432*1991Sheppo /* Check if the attributes are supported */ 3433*1991Sheppo static int 3434*1991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 3435*1991Sheppo { 3436*1991Sheppo _NOTE(ARGUNUSED(ldcp)) 3437*1991Sheppo 3438*1991Sheppo #if 0 3439*1991Sheppo uint64_t port_macaddr; 3440*1991Sheppo port_macaddr = vgen_macaddr_strtoul((uint8_t *) 3441*1991Sheppo &(ldcp->portp->macaddr)); 3442*1991Sheppo #endif 3443*1991Sheppo /* 3444*1991Sheppo * currently, we support these attr values: 3445*1991Sheppo * mtu of ethernet, addr_type of mac, xfer_mode of 3446*1991Sheppo * ldc shared memory, ack_freq of 0 (data is acked if 3447*1991Sheppo * the ack bit is set in the descriptor) and the address should 3448*1991Sheppo * match the address in the port node. 3449*1991Sheppo */ 3450*1991Sheppo if ((msg->mtu != ETHERMAX) || 3451*1991Sheppo (msg->addr_type != ADDR_TYPE_MAC) || 3452*1991Sheppo (msg->xfer_mode != VIO_DRING_MODE) || 3453*1991Sheppo (msg->ack_freq > 64)) { 3454*1991Sheppo #if 0 3455*1991Sheppo (msg->addr != port_macaddr)) 3456*1991Sheppo cmn_err(CE_CONT, "vgen_check_attr_info: msg->addr(%lx), port_macaddr(%lx)\n", 3457*1991Sheppo msg->addr, port_macaddr); 3458*1991Sheppo #endif 3459*1991Sheppo return (VGEN_FAILURE); 3460*1991Sheppo } 3461*1991Sheppo 3462*1991Sheppo return (VGEN_SUCCESS); 3463*1991Sheppo } 3464*1991Sheppo 3465*1991Sheppo /* 3466*1991Sheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer 3467*1991Sheppo * to an attr info msg that we sent. 3468*1991Sheppo */ 3469*1991Sheppo static void 3470*1991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 3471*1991Sheppo { 3472*1991Sheppo vnet_attr_msg_t *attrmsg = (vnet_attr_msg_t *)tagp; 3473*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3474*1991Sheppo int ack = 0; 3475*1991Sheppo 3476*1991Sheppo DBG1((vnetp, "vgen_handle_attr_info: enter\n")); 3477*1991Sheppo if (ldcp->hphase != VH_PHASE2) { 3478*1991Sheppo DWARN((vnetp, 3479*1991Sheppo "vgen_handle_attr_info: Rcvd ATTR_INFO id(%lx)" 3480*1991Sheppo " subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 3481*1991Sheppo tagp->vio_subtype, ldcp->hphase)); 3482*1991Sheppo vgen_handshake_reset(ldcp); 3483*1991Sheppo return; 3484*1991Sheppo } 3485*1991Sheppo switch (tagp->vio_subtype) { 3486*1991Sheppo case VIO_SUBTYPE_INFO: 3487*1991Sheppo 3488*1991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_INFO_RCVD id(%lx)\n", 3489*1991Sheppo ldcp->ldc_id)); 3490*1991Sheppo ldcp->hstate |= ATTR_INFO_RCVD; 3491*1991Sheppo 3492*1991Sheppo /* save peer's values */ 3493*1991Sheppo ldcp->peer_hparams.mtu = attrmsg->mtu; 3494*1991Sheppo ldcp->peer_hparams.addr = attrmsg->addr; 3495*1991Sheppo ldcp->peer_hparams.addr_type = attrmsg->addr_type; 3496*1991Sheppo ldcp->peer_hparams.xfer_mode = attrmsg->xfer_mode; 3497*1991Sheppo ldcp->peer_hparams.ack_freq = attrmsg->ack_freq; 3498*1991Sheppo 3499*1991Sheppo if (vgen_check_attr_info(ldcp, attrmsg) == VGEN_FAILURE) { 3500*1991Sheppo /* unsupported attr, send NACK */ 3501*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 3502*1991Sheppo } else { 3503*1991Sheppo ack = 1; 3504*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 3505*1991Sheppo } 3506*1991Sheppo tagp->vio_sid = ldcp->local_sid; 3507*1991Sheppo 3508*1991Sheppo /* send reply msg back to peer */ 3509*1991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*attrmsg), 3510*1991Sheppo B_FALSE) != VGEN_SUCCESS) { 3511*1991Sheppo vgen_handshake_reset(ldcp); 3512*1991Sheppo return; 3513*1991Sheppo } 3514*1991Sheppo 3515*1991Sheppo if (ack) { 3516*1991Sheppo ldcp->hstate |= ATTR_ACK_SENT; 3517*1991Sheppo DBG2((vnetp, "vgen_handle_attr_info:" 3518*1991Sheppo " ATTR_ACK_SENT id(%lx)\n", ldcp->ldc_id)); 3519*1991Sheppo #ifdef DEBUG 3520*1991Sheppo #if 0 3521*1991Sheppo vgen_print_attr_info(ldcp, VGEN_PEER); 3522*1991Sheppo #endif 3523*1991Sheppo #endif 3524*1991Sheppo } else { 3525*1991Sheppo /* failed */ 3526*1991Sheppo DWARN((vnetp, "vgen_handle_attr_info:" 3527*1991Sheppo " ATTR_NACK_SENT id(%lx)\n", ldcp->ldc_id)); 3528*1991Sheppo vgen_handshake_reset(ldcp); 3529*1991Sheppo return; 3530*1991Sheppo } 3531*1991Sheppo 3532*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3533*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3534*1991Sheppo } 3535*1991Sheppo 3536*1991Sheppo break; 3537*1991Sheppo 3538*1991Sheppo case VIO_SUBTYPE_ACK: 3539*1991Sheppo 3540*1991Sheppo ldcp->hstate |= ATTR_ACK_RCVD; 3541*1991Sheppo 3542*1991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_ACK_RCVD id(%lx)\n", 3543*1991Sheppo ldcp->ldc_id)); 3544*1991Sheppo 3545*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3546*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3547*1991Sheppo } 3548*1991Sheppo break; 3549*1991Sheppo 3550*1991Sheppo case VIO_SUBTYPE_NACK: 3551*1991Sheppo 3552*1991Sheppo DBG2((vnetp, "vgen_handle_attr_info: ATTR_NACK_RCVD id(%lx)\n", 3553*1991Sheppo ldcp->ldc_id)); 3554*1991Sheppo vgen_handshake_reset(ldcp); 3555*1991Sheppo break; 3556*1991Sheppo } 3557*1991Sheppo DBG1((vnetp, "vgen_handle_attr_info: exit\n")); 3558*1991Sheppo } 3559*1991Sheppo 3560*1991Sheppo /* Check if the dring info msg is ok */ 3561*1991Sheppo static int 3562*1991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg) 3563*1991Sheppo { 3564*1991Sheppo /* check if msg contents are ok */ 3565*1991Sheppo if ((msg->num_descriptors < 128) || (msg->descriptor_size < 3566*1991Sheppo sizeof (vnet_public_desc_t))) { 3567*1991Sheppo return (VGEN_FAILURE); 3568*1991Sheppo } 3569*1991Sheppo return (VGEN_SUCCESS); 3570*1991Sheppo } 3571*1991Sheppo 3572*1991Sheppo /* 3573*1991Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from 3574*1991Sheppo * the peer to a dring register msg that we sent. 3575*1991Sheppo */ 3576*1991Sheppo static void 3577*1991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 3578*1991Sheppo { 3579*1991Sheppo vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp; 3580*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3581*1991Sheppo ldc_mem_cookie_t dcookie; 3582*1991Sheppo int ack = 0; 3583*1991Sheppo int rv = 0; 3584*1991Sheppo 3585*1991Sheppo DBG1((vnetp, "vgen_handle_dring_reg: enter\n")); 3586*1991Sheppo if (ldcp->hphase < VH_PHASE2) { 3587*1991Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */ 3588*1991Sheppo DWARN((vnetp, 3589*1991Sheppo "vgen_handle_dring_reg: Rcvd DRING_INFO, id (%lx)" 3590*1991Sheppo " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 3591*1991Sheppo tagp->vio_subtype, ldcp->hphase)); 3592*1991Sheppo vgen_handshake_reset(ldcp); 3593*1991Sheppo return; 3594*1991Sheppo } 3595*1991Sheppo switch (tagp->vio_subtype) { 3596*1991Sheppo case VIO_SUBTYPE_INFO: 3597*1991Sheppo 3598*1991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_INFO_RCVD id(%lx)\n", 3599*1991Sheppo ldcp->ldc_id)); 3600*1991Sheppo ldcp->hstate |= DRING_INFO_RCVD; 3601*1991Sheppo bcopy((msg->cookie), &dcookie, sizeof (dcookie)); 3602*1991Sheppo 3603*1991Sheppo ASSERT(msg->ncookies == 1); 3604*1991Sheppo 3605*1991Sheppo if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) { 3606*1991Sheppo /* 3607*1991Sheppo * verified dring info msg to be ok, 3608*1991Sheppo * now try to map the remote dring. 3609*1991Sheppo */ 3610*1991Sheppo rv = vgen_init_rxds(ldcp, msg->num_descriptors, 3611*1991Sheppo msg->descriptor_size, &dcookie, 3612*1991Sheppo msg->ncookies); 3613*1991Sheppo if (rv == DDI_SUCCESS) { 3614*1991Sheppo /* now we can ack the peer */ 3615*1991Sheppo ack = 1; 3616*1991Sheppo } 3617*1991Sheppo } 3618*1991Sheppo if (ack == 0) { 3619*1991Sheppo /* failed, send NACK */ 3620*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 3621*1991Sheppo } else { 3622*1991Sheppo if (!(ldcp->peer_hparams.dring_ready)) { 3623*1991Sheppo 3624*1991Sheppo /* save peer's dring_info values */ 3625*1991Sheppo bcopy(&dcookie, 3626*1991Sheppo &(ldcp->peer_hparams.dring_cookie), 3627*1991Sheppo sizeof (dcookie)); 3628*1991Sheppo ldcp->peer_hparams.num_desc = 3629*1991Sheppo msg->num_descriptors; 3630*1991Sheppo ldcp->peer_hparams.desc_size = 3631*1991Sheppo msg->descriptor_size; 3632*1991Sheppo ldcp->peer_hparams.num_dcookies = 3633*1991Sheppo msg->ncookies; 3634*1991Sheppo 3635*1991Sheppo /* set dring_ident for the peer */ 3636*1991Sheppo ldcp->peer_hparams.dring_ident = 3637*1991Sheppo (uint64_t)ldcp->rxdp; 3638*1991Sheppo /* return the dring_ident in ack msg */ 3639*1991Sheppo msg->dring_ident = 3640*1991Sheppo (uint64_t)ldcp->rxdp; 3641*1991Sheppo 3642*1991Sheppo ldcp->peer_hparams.dring_ready = B_TRUE; 3643*1991Sheppo } 3644*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 3645*1991Sheppo } 3646*1991Sheppo tagp->vio_sid = ldcp->local_sid; 3647*1991Sheppo /* send reply msg back to peer */ 3648*1991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 3649*1991Sheppo B_FALSE) != VGEN_SUCCESS) { 3650*1991Sheppo vgen_handshake_reset(ldcp); 3651*1991Sheppo return; 3652*1991Sheppo } 3653*1991Sheppo 3654*1991Sheppo if (ack) { 3655*1991Sheppo ldcp->hstate |= DRING_ACK_SENT; 3656*1991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_SENT" 3657*1991Sheppo " id (%lx)\n", ldcp->ldc_id)); 3658*1991Sheppo } else { 3659*1991Sheppo DWARN((vnetp, "vgen_handle_dring_reg: DRING_NACK_SENT" 3660*1991Sheppo " id (%lx)\n", ldcp->ldc_id)); 3661*1991Sheppo vgen_handshake_reset(ldcp); 3662*1991Sheppo return; 3663*1991Sheppo } 3664*1991Sheppo 3665*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3666*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3667*1991Sheppo } 3668*1991Sheppo 3669*1991Sheppo break; 3670*1991Sheppo 3671*1991Sheppo case VIO_SUBTYPE_ACK: 3672*1991Sheppo 3673*1991Sheppo ldcp->hstate |= DRING_ACK_RCVD; 3674*1991Sheppo 3675*1991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_ACK_RCVD" 3676*1991Sheppo " id (%lx)\n", ldcp->ldc_id)); 3677*1991Sheppo 3678*1991Sheppo if (!(ldcp->local_hparams.dring_ready)) { 3679*1991Sheppo /* local dring is now ready */ 3680*1991Sheppo ldcp->local_hparams.dring_ready = B_TRUE; 3681*1991Sheppo 3682*1991Sheppo /* save dring_ident acked by peer */ 3683*1991Sheppo ldcp->local_hparams.dring_ident = 3684*1991Sheppo msg->dring_ident; 3685*1991Sheppo } 3686*1991Sheppo 3687*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3688*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3689*1991Sheppo } 3690*1991Sheppo 3691*1991Sheppo break; 3692*1991Sheppo 3693*1991Sheppo case VIO_SUBTYPE_NACK: 3694*1991Sheppo 3695*1991Sheppo DBG2((vnetp, "vgen_handle_dring_reg: DRING_NACK_RCVD" 3696*1991Sheppo " id (%lx)\n", ldcp->ldc_id)); 3697*1991Sheppo vgen_handshake_reset(ldcp); 3698*1991Sheppo break; 3699*1991Sheppo } 3700*1991Sheppo DBG1((vnetp, "vgen_handle_dring_reg: exit\n")); 3701*1991Sheppo } 3702*1991Sheppo 3703*1991Sheppo /* 3704*1991Sheppo * Handle a rdx info msg from the peer or an ACK/NACK 3705*1991Sheppo * from the peer to a rdx info msg that we sent. 3706*1991Sheppo */ 3707*1991Sheppo static void 3708*1991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 3709*1991Sheppo { 3710*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3711*1991Sheppo 3712*1991Sheppo DBG1((vnetp, "vgen_handle_rdx_info: enter\n")); 3713*1991Sheppo if (ldcp->hphase != VH_PHASE3) { 3714*1991Sheppo DWARN((vnetp, 3715*1991Sheppo "vgen_handle_rdx_info: Rcvd RDX_INFO, id (%lx)" 3716*1991Sheppo " Subtype (%d), Invalid Phase(%u)\n", ldcp->ldc_id, 3717*1991Sheppo tagp->vio_subtype, ldcp->hphase)); 3718*1991Sheppo vgen_handshake_reset(ldcp); 3719*1991Sheppo return; 3720*1991Sheppo } 3721*1991Sheppo switch (tagp->vio_subtype) { 3722*1991Sheppo case VIO_SUBTYPE_INFO: 3723*1991Sheppo 3724*1991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_INFO_RCVD id (%lx)\n", 3725*1991Sheppo ldcp->ldc_id)); 3726*1991Sheppo ldcp->hstate |= RDX_INFO_RCVD; 3727*1991Sheppo 3728*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 3729*1991Sheppo tagp->vio_sid = ldcp->local_sid; 3730*1991Sheppo /* send reply msg back to peer */ 3731*1991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, 3732*1991Sheppo sizeof (vio_rdx_msg_t), B_FALSE) != VGEN_SUCCESS) { 3733*1991Sheppo vgen_handshake_reset(ldcp); 3734*1991Sheppo return; 3735*1991Sheppo } 3736*1991Sheppo 3737*1991Sheppo ldcp->hstate |= RDX_ACK_SENT; 3738*1991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_SENT id (%lx)\n", 3739*1991Sheppo ldcp->ldc_id)); 3740*1991Sheppo 3741*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3742*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3743*1991Sheppo } 3744*1991Sheppo 3745*1991Sheppo break; 3746*1991Sheppo 3747*1991Sheppo case VIO_SUBTYPE_ACK: 3748*1991Sheppo 3749*1991Sheppo ldcp->hstate |= RDX_ACK_RCVD; 3750*1991Sheppo 3751*1991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_ACK_RCVD id (%lx)\n", 3752*1991Sheppo ldcp->ldc_id)); 3753*1991Sheppo 3754*1991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 3755*1991Sheppo vgen_handshake(vh_nextphase(ldcp)); 3756*1991Sheppo } 3757*1991Sheppo break; 3758*1991Sheppo 3759*1991Sheppo case VIO_SUBTYPE_NACK: 3760*1991Sheppo 3761*1991Sheppo DBG2((vnetp, "vgen_handle_rdx_info: RDX_NACK_RCVD id (%lx)\n", 3762*1991Sheppo ldcp->ldc_id)); 3763*1991Sheppo vgen_handshake_reset(ldcp); 3764*1991Sheppo break; 3765*1991Sheppo } 3766*1991Sheppo DBG1((vnetp, "vgen_handle_rdx_info: exit\n")); 3767*1991Sheppo } 3768*1991Sheppo 3769*1991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */ 3770*1991Sheppo static void 3771*1991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 3772*1991Sheppo { 3773*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3774*1991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 3775*1991Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp; 3776*1991Sheppo struct ether_addr *addrp; 3777*1991Sheppo int count; 3778*1991Sheppo int i; 3779*1991Sheppo 3780*1991Sheppo DBG1((vnetp, "vgen_handle_mcast_info: enter\n")); 3781*1991Sheppo switch (tagp->vio_subtype) { 3782*1991Sheppo 3783*1991Sheppo case VIO_SUBTYPE_INFO: 3784*1991Sheppo 3785*1991Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */ 3786*1991Sheppo DWARN((vnetp, 3787*1991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_INFO id (%lx)\n", 3788*1991Sheppo ldcp->ldc_id)); 3789*1991Sheppo break; 3790*1991Sheppo 3791*1991Sheppo case VIO_SUBTYPE_ACK: 3792*1991Sheppo 3793*1991Sheppo /* success adding/removing multicast addr */ 3794*1991Sheppo DBG2((vnetp, 3795*1991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_ACK id (%lx)\n", 3796*1991Sheppo ldcp->ldc_id)); 3797*1991Sheppo break; 3798*1991Sheppo 3799*1991Sheppo case VIO_SUBTYPE_NACK: 3800*1991Sheppo 3801*1991Sheppo DWARN((vnetp, 3802*1991Sheppo "vgen_handle_mcast_info: rcvd SET_MCAST_NACK id (%lx)\n", 3803*1991Sheppo ldcp->ldc_id)); 3804*1991Sheppo if (!(msgp->set)) { 3805*1991Sheppo /* multicast remove request failed */ 3806*1991Sheppo break; 3807*1991Sheppo } 3808*1991Sheppo 3809*1991Sheppo /* multicast add request failed */ 3810*1991Sheppo for (count = 0; count < msgp->count; count++) { 3811*1991Sheppo addrp = &(msgp->mca[count]); 3812*1991Sheppo 3813*1991Sheppo /* delete address from the table */ 3814*1991Sheppo for (i = 0; i < vgenp->mccount; i++) { 3815*1991Sheppo if (ether_cmp(addrp, 3816*1991Sheppo &(vgenp->mctab[i])) == 0) { 3817*1991Sheppo if (vgenp->mccount > 1) { 3818*1991Sheppo vgenp->mctab[i] = 3819*1991Sheppo vgenp->mctab[vgenp->mccount-1]; 3820*1991Sheppo } 3821*1991Sheppo vgenp->mccount--; 3822*1991Sheppo break; 3823*1991Sheppo } 3824*1991Sheppo } 3825*1991Sheppo } 3826*1991Sheppo break; 3827*1991Sheppo 3828*1991Sheppo } 3829*1991Sheppo DBG1((vnetp, "vgen_handle_mcast_info: exit\n")); 3830*1991Sheppo } 3831*1991Sheppo 3832*1991Sheppo /* handler for control messages received from the peer ldc end-point */ 3833*1991Sheppo static void 3834*1991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 3835*1991Sheppo { 3836*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3837*1991Sheppo 3838*1991Sheppo DBG1((vnetp, "vgen_handle_ctrlmsg: enter\n")); 3839*1991Sheppo switch (tagp->vio_subtype_env) { 3840*1991Sheppo 3841*1991Sheppo case VIO_VER_INFO: 3842*1991Sheppo vgen_handle_version_negotiate(ldcp, tagp); 3843*1991Sheppo break; 3844*1991Sheppo 3845*1991Sheppo case VIO_ATTR_INFO: 3846*1991Sheppo vgen_handle_attr_info(ldcp, tagp); 3847*1991Sheppo break; 3848*1991Sheppo 3849*1991Sheppo case VIO_DRING_REG: 3850*1991Sheppo vgen_handle_dring_reg(ldcp, tagp); 3851*1991Sheppo break; 3852*1991Sheppo 3853*1991Sheppo case VIO_RDX: 3854*1991Sheppo vgen_handle_rdx_info(ldcp, tagp); 3855*1991Sheppo break; 3856*1991Sheppo 3857*1991Sheppo case VNET_MCAST_INFO: 3858*1991Sheppo vgen_handle_mcast_info(ldcp, tagp); 3859*1991Sheppo break; 3860*1991Sheppo 3861*1991Sheppo } 3862*1991Sheppo DBG1((vnetp, "vgen_handle_ctrlmsg: exit\n")); 3863*1991Sheppo } 3864*1991Sheppo 3865*1991Sheppo /* handler for data messages received from the peer ldc end-point */ 3866*1991Sheppo static void 3867*1991Sheppo vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 3868*1991Sheppo mblk_t **headp, mblk_t **tailp) 3869*1991Sheppo { 3870*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3871*1991Sheppo 3872*1991Sheppo DBG1((vnetp, "vgen_handle_datamsg: enter\n")); 3873*1991Sheppo 3874*1991Sheppo if (ldcp->hphase != VH_DONE) 3875*1991Sheppo return; 3876*1991Sheppo switch (tagp->vio_subtype_env) { 3877*1991Sheppo case VIO_DRING_DATA: 3878*1991Sheppo vgen_handle_dring_data(ldcp, tagp, headp, tailp); 3879*1991Sheppo break; 3880*1991Sheppo default: 3881*1991Sheppo break; 3882*1991Sheppo } 3883*1991Sheppo 3884*1991Sheppo DBG1((vnetp, "vgen_handle_datamsg: exit\n")); 3885*1991Sheppo } 3886*1991Sheppo 3887*1991Sheppo static void 3888*1991Sheppo vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 3889*1991Sheppo mblk_t **headp, mblk_t **tailp) 3890*1991Sheppo { 3891*1991Sheppo vio_dring_msg_t *dringmsg; 3892*1991Sheppo vnet_public_desc_t *rxdp; 3893*1991Sheppo vnet_public_desc_t *txdp; 3894*1991Sheppo vio_dring_entry_hdr_t *hdrp; 3895*1991Sheppo vgen_stats_t *statsp; 3896*1991Sheppo struct ether_header *ehp; 3897*1991Sheppo mblk_t *mp = NULL; 3898*1991Sheppo mblk_t *bp = NULL; 3899*1991Sheppo mblk_t *bpt = NULL; 3900*1991Sheppo size_t nbytes; 3901*1991Sheppo size_t nread; 3902*1991Sheppo uint64_t off = 0; 3903*1991Sheppo uint32_t start; 3904*1991Sheppo uint32_t end; 3905*1991Sheppo uint32_t datalen; 3906*1991Sheppo uint32_t ncookies; 3907*1991Sheppo uint32_t sync_start; 3908*1991Sheppo uint32_t sync_end; 3909*1991Sheppo uint32_t rxi; 3910*1991Sheppo uint32_t txi; 3911*1991Sheppo int rv; 3912*1991Sheppo boolean_t rxd_err = B_FALSE; 3913*1991Sheppo boolean_t sync_done = B_FALSE; 3914*1991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 3915*1991Sheppo int n; 3916*1991Sheppo #endif 3917*1991Sheppo #ifdef VGEN_REXMIT 3918*1991Sheppo uint64_t seqnum; 3919*1991Sheppo vgen_private_desc_t *tbufp; 3920*1991Sheppo #endif 3921*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 3922*1991Sheppo 3923*1991Sheppo dringmsg = (vio_dring_msg_t *)tagp; 3924*1991Sheppo start = dringmsg->start_idx; 3925*1991Sheppo end = dringmsg->end_idx; 3926*1991Sheppo statsp = ldcp->statsp; 3927*1991Sheppo 3928*1991Sheppo DBG1((vnetp, "vgen_handle_dring_data: enter\n")); 3929*1991Sheppo switch (tagp->vio_subtype) { 3930*1991Sheppo 3931*1991Sheppo case VIO_SUBTYPE_INFO: 3932*1991Sheppo /* 3933*1991Sheppo * received a data msg, which contains the start and end 3934*1991Sheppo * indeces of the descriptors within the rx ring holding data, 3935*1991Sheppo * the seq_num of data packet corresponding to the start index, 3936*1991Sheppo * and the dring_ident. 3937*1991Sheppo * We can now read the contents of each of these descriptors 3938*1991Sheppo * and gather data from it. 3939*1991Sheppo */ 3940*1991Sheppo DBG2((vnetp, 3941*1991Sheppo "vgen_handle_dring_data: INFO: start(%d), end(%d)\n", 3942*1991Sheppo start, end)); 3943*1991Sheppo 3944*1991Sheppo /* validate rx start and end indeces */ 3945*1991Sheppo if (!(CHECK_RXI(start, ldcp)) || !(CHECK_RXI(end, ldcp))) { 3946*1991Sheppo /* drop the message if invalid index */ 3947*1991Sheppo break; 3948*1991Sheppo } 3949*1991Sheppo 3950*1991Sheppo /* validate dring_ident */ 3951*1991Sheppo if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) { 3952*1991Sheppo /* invalid dring_ident, drop the msg */ 3953*1991Sheppo break; 3954*1991Sheppo } 3955*1991Sheppo #ifdef DEBUG 3956*1991Sheppo if (vgen_trigger_rxlost) { 3957*1991Sheppo /* drop this msg to simulate lost pkts for debugging */ 3958*1991Sheppo vgen_trigger_rxlost = 0; 3959*1991Sheppo break; 3960*1991Sheppo } 3961*1991Sheppo #endif 3962*1991Sheppo 3963*1991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 3964*1991Sheppo 3965*1991Sheppo /* receive start index doesn't match expected index */ 3966*1991Sheppo if (ldcp->next_rxi != start) { 3967*1991Sheppo 3968*1991Sheppo DWARN((vnetp, "vgen_handle_dring_data: id(%lx) " 3969*1991Sheppo "next_rxi(%d) != start(%d)\n", 3970*1991Sheppo ldcp->ldc_id, ldcp->next_rxi, start)); 3971*1991Sheppo 3972*1991Sheppo /* calculate the number of pkts lost */ 3973*1991Sheppo if (start >= ldcp->next_rxi) { 3974*1991Sheppo n = start - ldcp->next_rxi; 3975*1991Sheppo } else { 3976*1991Sheppo n = ldcp->num_rxds - (ldcp->next_rxi - start); 3977*1991Sheppo } 3978*1991Sheppo 3979*1991Sheppo /* 3980*1991Sheppo * Starting sequence number of the received packets 3981*1991Sheppo * is less than the next sequence number that 3982*1991Sheppo * is expected: 3983*1991Sheppo * 3984*1991Sheppo * drop the message and the corresponding packets. 3985*1991Sheppo */ 3986*1991Sheppo if (ldcp->next_rxseq > dringmsg->seq_num) { 3987*1991Sheppo DWARN((vnetp, "vgen_handle_dring_data: id(%lx) " 3988*1991Sheppo "dropping pkts, expected rxseq(0x%lx) " 3989*1991Sheppo "> recvd(0x%lx)\n", 3990*1991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 3991*1991Sheppo dringmsg->seq_num)); 3992*1991Sheppo /* 3993*1991Sheppo * duplicate/multiple retransmissions from 3994*1991Sheppo * sender?? drop this msg. 3995*1991Sheppo */ 3996*1991Sheppo break; 3997*1991Sheppo } 3998*1991Sheppo 3999*1991Sheppo /* 4000*1991Sheppo * Starting sequence number of the received packets 4001*1991Sheppo * is greater than the next expected sequence number 4002*1991Sheppo * 4003*1991Sheppo * send a NACK back to the peer to indicate lost 4004*1991Sheppo * packets. 4005*1991Sheppo */ 4006*1991Sheppo if (dringmsg->seq_num > ldcp->next_rxseq) { 4007*1991Sheppo statsp->rx_lost_pkts += n; 4008*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 4009*1991Sheppo tagp->vio_sid = ldcp->local_sid; 4010*1991Sheppo /* indicate the range of lost descriptors */ 4011*1991Sheppo dringmsg->start_idx = ldcp->next_rxi; 4012*1991Sheppo rxi = start; 4013*1991Sheppo DECR_RXI(rxi, ldcp); 4014*1991Sheppo dringmsg->end_idx = rxi; 4015*1991Sheppo /* dring ident is left unchanged */ 4016*1991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, 4017*1991Sheppo sizeof (*dringmsg), B_FALSE)) { 4018*1991Sheppo DWARN((vnetp, 4019*1991Sheppo "vgen_handle_dring_data: id(%lx) " 4020*1991Sheppo "vgen_sendmsg failed, " 4021*1991Sheppo "stype: NACK\n", ldcp->ldc_id)); 4022*1991Sheppo } 4023*1991Sheppo #ifdef VGEN_REXMIT 4024*1991Sheppo /* 4025*1991Sheppo * stop further processing until peer 4026*1991Sheppo * retransmits with the right index and seqnum. 4027*1991Sheppo */ 4028*1991Sheppo break; 4029*1991Sheppo #else /* VGEN_REXMIT */ 4030*1991Sheppo /* 4031*1991Sheppo * treat this range of descrs/pkts as dropped 4032*1991Sheppo * and set the new expected values for next_rxi 4033*1991Sheppo * and next_rxseq. continue(below) to process 4034*1991Sheppo * from the new start index. 4035*1991Sheppo */ 4036*1991Sheppo ldcp->next_rxi = start; 4037*1991Sheppo ldcp->next_rxseq += n; 4038*1991Sheppo #endif /* VGEN_REXMIT */ 4039*1991Sheppo 4040*1991Sheppo } else if (dringmsg->seq_num == ldcp->next_rxseq) { 4041*1991Sheppo /* 4042*1991Sheppo * expected and starting seqnums match, but 4043*1991Sheppo * the descriptor indeces don't? 4044*1991Sheppo * 4045*1991Sheppo * restart handshake with peer. 4046*1991Sheppo */ 4047*1991Sheppo DWARN((vnetp, 4048*1991Sheppo "vgen_handle_dring_data: id(%lx) " 4049*1991Sheppo "next_rxseq(0x%lx) == seq_num(0x%lx)\n", 4050*1991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 4051*1991Sheppo dringmsg->seq_num)); 4052*1991Sheppo 4053*1991Sheppo #if 0 4054*1991Sheppo vgen_handshake_retry(ldcp); 4055*1991Sheppo break; 4056*1991Sheppo #endif 4057*1991Sheppo 4058*1991Sheppo } 4059*1991Sheppo 4060*1991Sheppo } else { 4061*1991Sheppo /* expected and start dring indeces match */ 4062*1991Sheppo 4063*1991Sheppo if (dringmsg->seq_num != ldcp->next_rxseq) { 4064*1991Sheppo 4065*1991Sheppo /* seqnums don't match */ 4066*1991Sheppo 4067*1991Sheppo DWARN((vnetp, 4068*1991Sheppo "vgen_handle_dring_data: id(%lx) " 4069*1991Sheppo "next_rxseq(0x%lx) != seq_num(0x%lx)\n", 4070*1991Sheppo ldcp->ldc_id, ldcp->next_rxseq, 4071*1991Sheppo dringmsg->seq_num)); 4072*1991Sheppo 4073*1991Sheppo #if 0 4074*1991Sheppo vgen_handshake_retry(ldcp); 4075*1991Sheppo break; 4076*1991Sheppo #endif 4077*1991Sheppo } 4078*1991Sheppo } 4079*1991Sheppo 4080*1991Sheppo #endif /* VGEN_HANDLE_LOST_PKTS */ 4081*1991Sheppo 4082*1991Sheppo /* 4083*1991Sheppo * Start processing the descriptor range, specified 4084*1991Sheppo * in the dring data msg. 4085*1991Sheppo */ 4086*1991Sheppo if (ldc_mem_dring_acquire(ldcp->rx_dhandle, start, end)) { 4087*1991Sheppo DWARN((vnetp, "vgen_handle_dring_data: " 4088*1991Sheppo "id(%lx), ldc_mem_dring_acquire() failed\n", 4089*1991Sheppo ldcp->ldc_id)); 4090*1991Sheppo statsp->ierrors++; 4091*1991Sheppo } 4092*1991Sheppo rxi = start; 4093*1991Sheppo sync_start = start; 4094*1991Sheppo do { 4095*1991Sheppo /* recv packets from 'start' to 'end' */ 4096*1991Sheppo 4097*1991Sheppo rxdp = &(ldcp->rxdp[rxi]); 4098*1991Sheppo hdrp = &rxdp->hdr; 4099*1991Sheppo 4100*1991Sheppo datalen = rxdp->nbytes; 4101*1991Sheppo ncookies = rxdp->ncookies; 4102*1991Sheppo if ((datalen < ETHERMIN) || 4103*1991Sheppo (ncookies == 0) || 4104*1991Sheppo (ncookies > (uint64_t)MAX_COOKIES) || 4105*1991Sheppo (hdrp->dstate != VIO_DESC_READY)) { 4106*1991Sheppo rxd_err = B_TRUE; 4107*1991Sheppo } else { 4108*1991Sheppo /* 4109*1991Sheppo * The data buffer returned by allocb(9F) is 4110*1991Sheppo * 8byte aligned. We allocate extra 8 bytes to 4111*1991Sheppo * ensure size is multiple of 8 bytes for 4112*1991Sheppo * ldc_mem_copy(). 4113*1991Sheppo */ 4114*1991Sheppo mp = allocb(datalen + 8, BPRI_MED); 4115*1991Sheppo nbytes = (datalen + 7) & ~7; 4116*1991Sheppo } 4117*1991Sheppo if ((rxd_err) || (mp == NULL)) { 4118*1991Sheppo /* 4119*1991Sheppo * rxd_err or allocb() failure, 4120*1991Sheppo * drop this packet, get next. 4121*1991Sheppo */ 4122*1991Sheppo if (rxd_err) { 4123*1991Sheppo statsp->ierrors++; 4124*1991Sheppo rxd_err = B_FALSE; 4125*1991Sheppo } else { 4126*1991Sheppo statsp->rx_allocb_fail++; 4127*1991Sheppo } 4128*1991Sheppo 4129*1991Sheppo /* set descriptor done bit */ 4130*1991Sheppo hdrp->dstate = VIO_DESC_DONE; 4131*1991Sheppo 4132*1991Sheppo if (hdrp->ack) { 4133*1991Sheppo /* 4134*1991Sheppo * sender needs ack for this packet. 4135*1991Sheppo * sync pkts upto this index and 4136*1991Sheppo * send the ack to the peer. 4137*1991Sheppo */ 4138*1991Sheppo sync_end = rxi; 4139*1991Sheppo (void) ldc_mem_dring_release( 4140*1991Sheppo ldcp->rx_dhandle, sync_start, 4141*1991Sheppo sync_end); 4142*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 4143*1991Sheppo tagp->vio_sid = ldcp->local_sid; 4144*1991Sheppo dringmsg = (vio_dring_msg_t *)tagp; 4145*1991Sheppo dringmsg->start_idx = sync_start; 4146*1991Sheppo dringmsg->end_idx = sync_end; 4147*1991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, 4148*1991Sheppo sizeof (*dringmsg), B_FALSE)) { 4149*1991Sheppo DWARN((vnetp, 4150*1991Sheppo "vgen_handle_dring_data: " 4151*1991Sheppo "id(%lx) vgen_sendmsg " 4152*1991Sheppo "failed, stype: ACK\n", 4153*1991Sheppo ldcp->ldc_id)); 4154*1991Sheppo } 4155*1991Sheppo /* save new sync index start */ 4156*1991Sheppo if (sync_end != end) { 4157*1991Sheppo INCR_RXI(sync_end, ldcp); 4158*1991Sheppo sync_start = sync_end; 4159*1991Sheppo } else 4160*1991Sheppo sync_done = B_TRUE; 4161*1991Sheppo } 4162*1991Sheppo goto vgen_next_rxi; 4163*1991Sheppo } 4164*1991Sheppo 4165*1991Sheppo nread = nbytes; 4166*1991Sheppo rv = ldc_mem_copy(ldcp->ldc_handle, 4167*1991Sheppo (caddr_t)mp->b_rptr, off, &nread, 4168*1991Sheppo rxdp->memcookie, ncookies, LDC_COPY_IN); 4169*1991Sheppo 4170*1991Sheppo /* set done bit irrespective of rv of ldc_mem_copy() */ 4171*1991Sheppo hdrp->dstate = VIO_DESC_DONE; 4172*1991Sheppo 4173*1991Sheppo if (hdrp->ack) { 4174*1991Sheppo /* 4175*1991Sheppo * sender needs ack for this packet. 4176*1991Sheppo * sync pkts upto this index and 4177*1991Sheppo * send the ack to the peer. 4178*1991Sheppo */ 4179*1991Sheppo sync_end = rxi; 4180*1991Sheppo (void) ldc_mem_dring_release(ldcp->rx_dhandle, 4181*1991Sheppo sync_start, sync_end); 4182*1991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 4183*1991Sheppo tagp->vio_sid = ldcp->local_sid; 4184*1991Sheppo dringmsg = (vio_dring_msg_t *)tagp; 4185*1991Sheppo dringmsg->start_idx = sync_start; 4186*1991Sheppo dringmsg->end_idx = sync_end; 4187*1991Sheppo if (vgen_sendmsg(ldcp, (caddr_t)tagp, 4188*1991Sheppo sizeof (*dringmsg), B_FALSE)) { 4189*1991Sheppo DWARN((vnetp, 4190*1991Sheppo "vgen_handle_dring_data: id(%lx) " 4191*1991Sheppo "vgen_sendmsg failed stype: ACK\n", 4192*1991Sheppo ldcp->ldc_id)); 4193*1991Sheppo } 4194*1991Sheppo /* save new sync index start */ 4195*1991Sheppo if (sync_end != end) { 4196*1991Sheppo INCR_RXI(sync_end, ldcp); 4197*1991Sheppo sync_start = sync_end; 4198*1991Sheppo } else 4199*1991Sheppo sync_done = B_TRUE; 4200*1991Sheppo } 4201*1991Sheppo /* if ldc_mem_copy() failed */ 4202*1991Sheppo if (rv) { 4203*1991Sheppo DWARN((vnetp, 4204*1991Sheppo "vgen_handle_dring_data: id(%lx) " 4205*1991Sheppo "ldc_mem_copy failed\n", ldcp->ldc_id)); 4206*1991Sheppo statsp->ierrors++; 4207*1991Sheppo freemsg(mp); 4208*1991Sheppo goto vgen_next_rxi; 4209*1991Sheppo } 4210*1991Sheppo if (nread != nbytes) { 4211*1991Sheppo DWARN((vnetp, 4212*1991Sheppo "vgen_handle_dring_data: id(%lx) " 4213*1991Sheppo "ldc_mem_copy nread(%lx), nbytes(%lx)\n", 4214*1991Sheppo ldcp->ldc_id, nread, nbytes)); 4215*1991Sheppo statsp->ierrors++; 4216*1991Sheppo freemsg(mp); 4217*1991Sheppo goto vgen_next_rxi; 4218*1991Sheppo } 4219*1991Sheppo 4220*1991Sheppo /* point to the actual end of data */ 4221*1991Sheppo mp->b_wptr = mp->b_rptr + datalen; 4222*1991Sheppo 4223*1991Sheppo /* update stats */ 4224*1991Sheppo statsp->ipackets++; 4225*1991Sheppo statsp->rbytes += datalen; 4226*1991Sheppo ehp = (struct ether_header *)mp->b_rptr; 4227*1991Sheppo if (IS_BROADCAST(ehp)) 4228*1991Sheppo statsp->brdcstrcv++; 4229*1991Sheppo else if (IS_MULTICAST(ehp)) 4230*1991Sheppo statsp->multircv++; 4231*1991Sheppo 4232*1991Sheppo /* build a chain of received packets */ 4233*1991Sheppo if (bp == NULL) { 4234*1991Sheppo /* first pkt */ 4235*1991Sheppo bp = mp; 4236*1991Sheppo bpt = bp; 4237*1991Sheppo bpt->b_next = NULL; 4238*1991Sheppo } else { 4239*1991Sheppo mp->b_next = NULL; 4240*1991Sheppo bpt->b_next = mp; 4241*1991Sheppo bpt = mp; 4242*1991Sheppo } 4243*1991Sheppo 4244*1991Sheppo vgen_next_rxi: if (rxi == end) { 4245*1991Sheppo break; 4246*1991Sheppo } 4247*1991Sheppo /* increment recv index */ 4248*1991Sheppo INCR_RXI(rxi, ldcp); 4249*1991Sheppo 4250*1991Sheppo _NOTE(CONSTCOND) 4251*1991Sheppo } while (1); 4252*1991Sheppo 4253*1991Sheppo if (!sync_done) { 4254*1991Sheppo /* sync remote descriptor range */ 4255*1991Sheppo sync_end = rxi; 4256*1991Sheppo (void) ldc_mem_dring_release(ldcp->rx_dhandle, 4257*1991Sheppo sync_start, sync_end); 4258*1991Sheppo DBG2((vnetp, 4259*1991Sheppo "vgen_handle_dring_data: not sending ACK\n")); 4260*1991Sheppo } 4261*1991Sheppo 4262*1991Sheppo /* save new recv index */ 4263*1991Sheppo INCR_RXI(rxi, ldcp); 4264*1991Sheppo ldcp->next_rxi = rxi; 4265*1991Sheppo ldcp->next_rxseq += ((end >= start) ? 4266*1991Sheppo ((end - start) + 1) : (start - end)); 4267*1991Sheppo 4268*1991Sheppo /* try to reclaim transmit descrs also */ 4269*1991Sheppo vgen_reclaim(ldcp); 4270*1991Sheppo break; 4271*1991Sheppo 4272*1991Sheppo case VIO_SUBTYPE_ACK: 4273*1991Sheppo /* 4274*1991Sheppo * received an ack corresponding to a specific descriptor for 4275*1991Sheppo * which we had set the ACK bit in the descriptor (during 4276*1991Sheppo * transmit). This enables us to reclaim descriptors. 4277*1991Sheppo */ 4278*1991Sheppo DBG2((vnetp, 4279*1991Sheppo "vgen_handle_dring_data: ACK: start(%d), end(%d)\n", 4280*1991Sheppo start, end)); 4281*1991Sheppo 4282*1991Sheppo /* validate start and end indeces in the tx ack msg */ 4283*1991Sheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 4284*1991Sheppo /* drop the message if invalid index */ 4285*1991Sheppo break; 4286*1991Sheppo } 4287*1991Sheppo /* validate dring_ident */ 4288*1991Sheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 4289*1991Sheppo /* invalid dring_ident, drop the msg */ 4290*1991Sheppo break; 4291*1991Sheppo } 4292*1991Sheppo statsp->dring_data_acks++; 4293*1991Sheppo vgen_reclaim(ldcp); 4294*1991Sheppo break; 4295*1991Sheppo 4296*1991Sheppo case VIO_SUBTYPE_NACK: 4297*1991Sheppo /* 4298*1991Sheppo * peer sent a NACK msg to indicate lost packets. 4299*1991Sheppo * The start and end correspond to the range of descriptors 4300*1991Sheppo * for which the peer didn't receive a dring data msg and so 4301*1991Sheppo * didn't receive the corresponding data. 4302*1991Sheppo */ 4303*1991Sheppo DWARN((vnetp, 4304*1991Sheppo "vgen_handle_dring_data: NACK: start(%d), end(%d)\n", 4305*1991Sheppo start, end)); 4306*1991Sheppo 4307*1991Sheppo /* validate start and end indeces in the tx nack msg */ 4308*1991Sheppo if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 4309*1991Sheppo /* drop the message if invalid index */ 4310*1991Sheppo break; 4311*1991Sheppo } 4312*1991Sheppo /* validate dring_ident */ 4313*1991Sheppo if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 4314*1991Sheppo /* invalid dring_ident, drop the msg */ 4315*1991Sheppo break; 4316*1991Sheppo } 4317*1991Sheppo mutex_enter(&ldcp->txlock); 4318*1991Sheppo mutex_enter(&ldcp->tclock); 4319*1991Sheppo 4320*1991Sheppo if (ldcp->next_tbufp == ldcp->cur_tbufp) { 4321*1991Sheppo /* no busy descriptors, bogus nack ? */ 4322*1991Sheppo mutex_exit(&ldcp->tclock); 4323*1991Sheppo mutex_exit(&ldcp->txlock); 4324*1991Sheppo break; 4325*1991Sheppo } 4326*1991Sheppo 4327*1991Sheppo #ifdef VGEN_REXMIT 4328*1991Sheppo /* send a new dring data msg including the lost descrs */ 4329*1991Sheppo end = ldcp->next_tbufp - ldcp->tbufp; 4330*1991Sheppo DECR_TXI(end, ldcp); 4331*1991Sheppo seqnum = ldcp->tbufp[start].seqnum; 4332*1991Sheppo /* no need to increment ldcp->next_txseq as this is rexmit */ 4333*1991Sheppo rv = vgen_send_dring_data(ldcp, start, end, seqnum); 4334*1991Sheppo if (rv != 0) { 4335*1991Sheppo /* 4336*1991Sheppo * vgen_send_dring_data() error: drop all packets 4337*1991Sheppo * in this descr range 4338*1991Sheppo */ 4339*1991Sheppo DWARN((vnetp, 4340*1991Sheppo "vgen_handle_dring_data: " 4341*1991Sheppo "vgen_send_dring_data failed :" 4342*1991Sheppo "id(%lx) rv(%d)\n", ldcp->ldc_id, rv)); 4343*1991Sheppo for (txi = start; txi <= end; ) { 4344*1991Sheppo tbufp = &(ldcp->tbufp[txi]); 4345*1991Sheppo txdp = tbufp->descp; 4346*1991Sheppo hdrp = &txdp->hdr; 4347*1991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 4348*1991Sheppo freemsg(tbufp->mp); 4349*1991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 4350*1991Sheppo hdrp->dstate = VIO_DESC_FREE; 4351*1991Sheppo hdrp->ack = B_FALSE; 4352*1991Sheppo statsp->oerrors++; 4353*1991Sheppo } 4354*1991Sheppo 4355*1991Sheppo /* update next pointer */ 4356*1991Sheppo ldcp->next_tbufp = &(ldcp->tbufp[start]); 4357*1991Sheppo ldcp->next_txseq = seqnum; 4358*1991Sheppo ldcp->next_txi = start; 4359*1991Sheppo } 4360*1991Sheppo DBG2((vnetp, 4361*1991Sheppo "vgen_handle_dring_data: rexmit: start(%d) end(%d)\n", 4362*1991Sheppo start, end)); 4363*1991Sheppo #else /* VGEN_REXMIT */ 4364*1991Sheppo /* we just mark the descrs as done so they can be reclaimed */ 4365*1991Sheppo for (txi = start; txi <= end; ) { 4366*1991Sheppo txdp = &(ldcp->txdp[txi]); 4367*1991Sheppo hdrp = &txdp->hdr; 4368*1991Sheppo if (hdrp->dstate == VIO_DESC_READY) 4369*1991Sheppo hdrp->dstate = VIO_DESC_DONE; 4370*1991Sheppo INCR_TXI(txi, ldcp); 4371*1991Sheppo } 4372*1991Sheppo #endif /* VGEN_REXMIT */ 4373*1991Sheppo mutex_exit(&ldcp->tclock); 4374*1991Sheppo mutex_exit(&ldcp->txlock); 4375*1991Sheppo 4376*1991Sheppo vgen_reclaim(ldcp); 4377*1991Sheppo 4378*1991Sheppo break; 4379*1991Sheppo } 4380*1991Sheppo 4381*1991Sheppo DBG1((vnetp, "vgen_handle_dring_data: exit\n")); 4382*1991Sheppo *headp = bp; 4383*1991Sheppo *tailp = bpt; 4384*1991Sheppo } 4385*1991Sheppo 4386*1991Sheppo static void 4387*1991Sheppo vgen_reclaim(vgen_ldc_t *ldcp) 4388*1991Sheppo { 4389*1991Sheppo if (mutex_tryenter(&ldcp->tclock) == 0) 4390*1991Sheppo return; /* already in progress */ 4391*1991Sheppo vgen_reclaim_dring(ldcp); 4392*1991Sheppo ldcp->reclaim_lbolt = ddi_get_lbolt(); 4393*1991Sheppo mutex_exit(&ldcp->tclock); 4394*1991Sheppo } 4395*1991Sheppo 4396*1991Sheppo /* 4397*1991Sheppo * transmit reclaim function. starting from the current reclaim index 4398*1991Sheppo * look for descriptors marked DONE and reclaim the descriptor and the 4399*1991Sheppo * corresponding buffers (tbuf). 4400*1991Sheppo */ 4401*1991Sheppo static void 4402*1991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp) 4403*1991Sheppo { 4404*1991Sheppo vnet_public_desc_t *txdp; 4405*1991Sheppo vgen_private_desc_t *tbufp; 4406*1991Sheppo vio_dring_entry_hdr_t *hdrp; 4407*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE 4408*1991Sheppo vgen_t *vgenp = (vgen_t *)ldcp->vgenp; 4409*1991Sheppo #endif 4410*1991Sheppo 4411*1991Sheppo #ifdef DEBUG 4412*1991Sheppo if (vgen_trigger_txtimeout) 4413*1991Sheppo return; 4414*1991Sheppo #endif 4415*1991Sheppo 4416*1991Sheppo tbufp = ldcp->cur_tbufp; 4417*1991Sheppo txdp = tbufp->descp; 4418*1991Sheppo hdrp = &txdp->hdr; 4419*1991Sheppo 4420*1991Sheppo while ((hdrp->dstate == VIO_DESC_DONE) && 4421*1991Sheppo (tbufp != ldcp->next_tbufp)) { 4422*1991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 4423*1991Sheppo freemsg(tbufp->mp); 4424*1991Sheppo tbufp->mp = NULL; 4425*1991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 4426*1991Sheppo hdrp->dstate = VIO_DESC_FREE; 4427*1991Sheppo hdrp->ack = B_FALSE; 4428*1991Sheppo 4429*1991Sheppo tbufp = NEXTTBUF(ldcp, tbufp); 4430*1991Sheppo txdp = tbufp->descp; 4431*1991Sheppo hdrp = &txdp->hdr; 4432*1991Sheppo } 4433*1991Sheppo 4434*1991Sheppo ldcp->cur_tbufp = tbufp; 4435*1991Sheppo 4436*1991Sheppo /* 4437*1991Sheppo * Check if mac layer should be notified to restart transmissions 4438*1991Sheppo */ 4439*1991Sheppo if (ldcp->need_resched) { 4440*1991Sheppo ldcp->need_resched = B_FALSE; 4441*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE 4442*1991Sheppo mac_tx_update(vgenp->vnetmacp); 4443*1991Sheppo #endif 4444*1991Sheppo } 4445*1991Sheppo } 4446*1991Sheppo 4447*1991Sheppo /* return the number of pending transmits for the channel */ 4448*1991Sheppo static int 4449*1991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp) 4450*1991Sheppo { 4451*1991Sheppo int n; 4452*1991Sheppo 4453*1991Sheppo if (ldcp->next_tbufp >= ldcp->cur_tbufp) { 4454*1991Sheppo n = ldcp->next_tbufp - ldcp->cur_tbufp; 4455*1991Sheppo } else { 4456*1991Sheppo /* cur_tbufp > next_tbufp */ 4457*1991Sheppo n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp); 4458*1991Sheppo } 4459*1991Sheppo 4460*1991Sheppo return (n); 4461*1991Sheppo } 4462*1991Sheppo 4463*1991Sheppo /* determine if the transmit descriptor ring is full */ 4464*1991Sheppo static int 4465*1991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp) 4466*1991Sheppo { 4467*1991Sheppo vgen_private_desc_t *tbufp; 4468*1991Sheppo vgen_private_desc_t *ntbufp; 4469*1991Sheppo 4470*1991Sheppo tbufp = ldcp->next_tbufp; 4471*1991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 4472*1991Sheppo if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 4473*1991Sheppo #if 0 4474*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 4475*1991Sheppo DWARN((vnetp, "vgen_tx_dring_full: id(%lx)\n", 4476*1991Sheppo ldcp->ldc_id)); 4477*1991Sheppo #endif 4478*1991Sheppo return (VGEN_SUCCESS); 4479*1991Sheppo } 4480*1991Sheppo return (VGEN_FAILURE); 4481*1991Sheppo } 4482*1991Sheppo 4483*1991Sheppo /* determine if timeout condition has occured */ 4484*1991Sheppo static int 4485*1991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp) 4486*1991Sheppo { 4487*1991Sheppo if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) > 4488*1991Sheppo drv_usectohz(vnet_ldcwd_txtimeout * 1000)) && 4489*1991Sheppo (vnet_ldcwd_txtimeout) && 4490*1991Sheppo (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) { 4491*1991Sheppo #if 0 4492*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 4493*1991Sheppo DWARN((vnetp, "vgen_ldc_txtimeout: id(%lx)\n", 4494*1991Sheppo ldcp->ldc_id)); 4495*1991Sheppo #endif 4496*1991Sheppo return (VGEN_SUCCESS); 4497*1991Sheppo } else { 4498*1991Sheppo return (VGEN_FAILURE); 4499*1991Sheppo } 4500*1991Sheppo } 4501*1991Sheppo 4502*1991Sheppo /* transmit watchdog timeout handler */ 4503*1991Sheppo static void 4504*1991Sheppo vgen_ldc_watchdog(void *arg) 4505*1991Sheppo { 4506*1991Sheppo vgen_ldc_t *ldcp; 4507*1991Sheppo void *vnetp; 4508*1991Sheppo int rv; 4509*1991Sheppo 4510*1991Sheppo ldcp = (vgen_ldc_t *)arg; 4511*1991Sheppo vnetp = LDC_TO_VNET(ldcp); 4512*1991Sheppo 4513*1991Sheppo rv = vgen_ldc_txtimeout(ldcp); 4514*1991Sheppo if (rv == VGEN_SUCCESS) { 4515*1991Sheppo DWARN((vnetp, 4516*1991Sheppo "vgen_ldc_watchdog: transmit timeout ldcid(%lx)\n", 4517*1991Sheppo ldcp->ldc_id)); 4518*1991Sheppo #ifdef DEBUG 4519*1991Sheppo if (vgen_trigger_txtimeout) { 4520*1991Sheppo /* tx timeout triggered for debugging */ 4521*1991Sheppo vgen_trigger_txtimeout = 0; 4522*1991Sheppo } 4523*1991Sheppo #endif 4524*1991Sheppo mutex_enter(&ldcp->cblock); 4525*1991Sheppo vgen_handshake_retry(ldcp); 4526*1991Sheppo mutex_exit(&ldcp->cblock); 4527*1991Sheppo if (ldcp->need_resched) { 4528*1991Sheppo ldcp->need_resched = B_FALSE; 4529*1991Sheppo #ifdef VGEN_USE_MAC_TX_UPDATE 4530*1991Sheppo mac_tx_update(ldcp->vgenp->vnetmacp); 4531*1991Sheppo #endif 4532*1991Sheppo } 4533*1991Sheppo } 4534*1991Sheppo 4535*1991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 4536*1991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 4537*1991Sheppo } 4538*1991Sheppo 4539*1991Sheppo /* based on mcopymsg() */ 4540*1991Sheppo static void 4541*1991Sheppo vgen_copymsg(mblk_t *mp, void *bufp) 4542*1991Sheppo { 4543*1991Sheppo caddr_t dest = bufp; 4544*1991Sheppo mblk_t *bp; 4545*1991Sheppo size_t n; 4546*1991Sheppo 4547*1991Sheppo for (bp = mp; bp != NULL; bp = bp->b_cont) { 4548*1991Sheppo n = MBLKL(bp); 4549*1991Sheppo bcopy(bp->b_rptr, dest, n); 4550*1991Sheppo dest += n; 4551*1991Sheppo } 4552*1991Sheppo } 4553*1991Sheppo 4554*1991Sheppo static int 4555*1991Sheppo vgen_setup_kstats(vgen_ldc_t *ldcp) 4556*1991Sheppo { 4557*1991Sheppo vgen_t *vgenp; 4558*1991Sheppo struct kstat *ksp; 4559*1991Sheppo vgen_stats_t *statsp; 4560*1991Sheppo vgen_kstats_t *ldckp; 4561*1991Sheppo int instance; 4562*1991Sheppo size_t size; 4563*1991Sheppo char name[MAXNAMELEN]; 4564*1991Sheppo 4565*1991Sheppo vgenp = LDC_TO_VGEN(ldcp); 4566*1991Sheppo instance = ddi_get_instance(vgenp->vnetdip); 4567*1991Sheppo (void) sprintf(name, "vnetldc0x%lx", ldcp->ldc_id); 4568*1991Sheppo statsp = kmem_zalloc(sizeof (vgen_stats_t), KM_SLEEP); 4569*1991Sheppo if (statsp == NULL) { 4570*1991Sheppo return (VGEN_FAILURE); 4571*1991Sheppo } 4572*1991Sheppo size = sizeof (vgen_kstats_t) / sizeof (kstat_named_t); 4573*1991Sheppo ksp = kstat_create("vnet", instance, name, "net", KSTAT_TYPE_NAMED, 4574*1991Sheppo size, 0); 4575*1991Sheppo if (ksp == NULL) { 4576*1991Sheppo KMEM_FREE(statsp); 4577*1991Sheppo return (VGEN_FAILURE); 4578*1991Sheppo } 4579*1991Sheppo 4580*1991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 4581*1991Sheppo kstat_named_init(&ldckp->ipackets, "ipackets", 4582*1991Sheppo KSTAT_DATA_ULONG); 4583*1991Sheppo kstat_named_init(&ldckp->ipackets64, "ipackets64", 4584*1991Sheppo KSTAT_DATA_ULONGLONG); 4585*1991Sheppo kstat_named_init(&ldckp->ierrors, "ierrors", 4586*1991Sheppo KSTAT_DATA_ULONG); 4587*1991Sheppo kstat_named_init(&ldckp->opackets, "opackets", 4588*1991Sheppo KSTAT_DATA_ULONG); 4589*1991Sheppo kstat_named_init(&ldckp->opackets64, "opackets64", 4590*1991Sheppo KSTAT_DATA_ULONGLONG); 4591*1991Sheppo kstat_named_init(&ldckp->oerrors, "oerrors", 4592*1991Sheppo KSTAT_DATA_ULONG); 4593*1991Sheppo 4594*1991Sheppo 4595*1991Sheppo /* MIB II kstat variables */ 4596*1991Sheppo kstat_named_init(&ldckp->rbytes, "rbytes", 4597*1991Sheppo KSTAT_DATA_ULONG); 4598*1991Sheppo kstat_named_init(&ldckp->rbytes64, "rbytes64", 4599*1991Sheppo KSTAT_DATA_ULONGLONG); 4600*1991Sheppo kstat_named_init(&ldckp->obytes, "obytes", 4601*1991Sheppo KSTAT_DATA_ULONG); 4602*1991Sheppo kstat_named_init(&ldckp->obytes64, "obytes64", 4603*1991Sheppo KSTAT_DATA_ULONGLONG); 4604*1991Sheppo kstat_named_init(&ldckp->multircv, "multircv", 4605*1991Sheppo KSTAT_DATA_ULONG); 4606*1991Sheppo kstat_named_init(&ldckp->multixmt, "multixmt", 4607*1991Sheppo KSTAT_DATA_ULONG); 4608*1991Sheppo kstat_named_init(&ldckp->brdcstrcv, "brdcstrcv", 4609*1991Sheppo KSTAT_DATA_ULONG); 4610*1991Sheppo kstat_named_init(&ldckp->brdcstxmt, "brdcstxmt", 4611*1991Sheppo KSTAT_DATA_ULONG); 4612*1991Sheppo kstat_named_init(&ldckp->norcvbuf, "norcvbuf", 4613*1991Sheppo KSTAT_DATA_ULONG); 4614*1991Sheppo kstat_named_init(&ldckp->noxmtbuf, "noxmtbuf", 4615*1991Sheppo KSTAT_DATA_ULONG); 4616*1991Sheppo 4617*1991Sheppo /* Tx stats */ 4618*1991Sheppo kstat_named_init(&ldckp->tx_no_desc, "tx_no_desc", 4619*1991Sheppo KSTAT_DATA_ULONG); 4620*1991Sheppo kstat_named_init(&ldckp->tx_allocb_fail, "tx_allocb_fail", 4621*1991Sheppo KSTAT_DATA_ULONG); 4622*1991Sheppo 4623*1991Sheppo /* Rx stats */ 4624*1991Sheppo kstat_named_init(&ldckp->rx_no_desc, "rx_no_desc", 4625*1991Sheppo KSTAT_DATA_ULONG); 4626*1991Sheppo kstat_named_init(&ldckp->rx_allocb_fail, "rx_allocb_fail", 4627*1991Sheppo KSTAT_DATA_ULONG); 4628*1991Sheppo kstat_named_init(&ldckp->rx_lost_pkts, "rx_lost_pkts", 4629*1991Sheppo KSTAT_DATA_ULONG); 4630*1991Sheppo 4631*1991Sheppo /* Interrupt stats */ 4632*1991Sheppo kstat_named_init(&ldckp->callbacks, "callbacks", 4633*1991Sheppo KSTAT_DATA_ULONG); 4634*1991Sheppo kstat_named_init(&ldckp->dring_data_acks, "dring_data_acks", 4635*1991Sheppo KSTAT_DATA_ULONG); 4636*1991Sheppo 4637*1991Sheppo ksp->ks_update = vgen_kstat_update; 4638*1991Sheppo ksp->ks_private = (void *)ldcp; 4639*1991Sheppo kstat_install(ksp); 4640*1991Sheppo 4641*1991Sheppo ldcp->ksp = ksp; 4642*1991Sheppo ldcp->statsp = statsp; 4643*1991Sheppo return (VGEN_SUCCESS); 4644*1991Sheppo } 4645*1991Sheppo 4646*1991Sheppo static void 4647*1991Sheppo vgen_destroy_kstats(vgen_ldc_t *ldcp) 4648*1991Sheppo { 4649*1991Sheppo if (ldcp->ksp) 4650*1991Sheppo kstat_delete(ldcp->ksp); 4651*1991Sheppo KMEM_FREE(ldcp->statsp); 4652*1991Sheppo } 4653*1991Sheppo 4654*1991Sheppo static int 4655*1991Sheppo vgen_kstat_update(kstat_t *ksp, int rw) 4656*1991Sheppo { 4657*1991Sheppo vgen_ldc_t *ldcp; 4658*1991Sheppo vgen_stats_t *statsp; 4659*1991Sheppo vgen_kstats_t *ldckp; 4660*1991Sheppo 4661*1991Sheppo ldcp = (vgen_ldc_t *)ksp->ks_private; 4662*1991Sheppo statsp = ldcp->statsp; 4663*1991Sheppo ldckp = (vgen_kstats_t *)ksp->ks_data; 4664*1991Sheppo 4665*1991Sheppo if (rw == KSTAT_READ) { 4666*1991Sheppo ldckp->ipackets.value.ul = (uint32_t)statsp->ipackets; 4667*1991Sheppo ldckp->ipackets64.value.ull = statsp->ipackets; 4668*1991Sheppo ldckp->ierrors.value.ul = statsp->ierrors; 4669*1991Sheppo ldckp->opackets.value.ul = (uint32_t)statsp->opackets; 4670*1991Sheppo ldckp->opackets64.value.ull = statsp->opackets; 4671*1991Sheppo ldckp->oerrors.value.ul = statsp->oerrors; 4672*1991Sheppo 4673*1991Sheppo /* 4674*1991Sheppo * MIB II kstat variables 4675*1991Sheppo */ 4676*1991Sheppo ldckp->rbytes.value.ul = (uint32_t)statsp->rbytes; 4677*1991Sheppo ldckp->rbytes64.value.ull = statsp->rbytes; 4678*1991Sheppo ldckp->obytes.value.ul = (uint32_t)statsp->obytes; 4679*1991Sheppo ldckp->obytes64.value.ull = statsp->obytes; 4680*1991Sheppo ldckp->multircv.value.ul = statsp->multircv; 4681*1991Sheppo ldckp->multixmt.value.ul = statsp->multixmt; 4682*1991Sheppo ldckp->brdcstrcv.value.ul = statsp->brdcstrcv; 4683*1991Sheppo ldckp->brdcstxmt.value.ul = statsp->brdcstxmt; 4684*1991Sheppo ldckp->norcvbuf.value.ul = statsp->norcvbuf; 4685*1991Sheppo ldckp->noxmtbuf.value.ul = statsp->noxmtbuf; 4686*1991Sheppo 4687*1991Sheppo ldckp->tx_no_desc.value.ul = statsp->tx_no_desc; 4688*1991Sheppo ldckp->tx_allocb_fail.value.ul = statsp->tx_allocb_fail; 4689*1991Sheppo 4690*1991Sheppo ldckp->rx_no_desc.value.ul = statsp->rx_no_desc; 4691*1991Sheppo ldckp->rx_allocb_fail.value.ul = statsp->rx_allocb_fail; 4692*1991Sheppo ldckp->rx_lost_pkts.value.ul = statsp->rx_lost_pkts; 4693*1991Sheppo 4694*1991Sheppo ldckp->callbacks.value.ul = statsp->callbacks; 4695*1991Sheppo ldckp->dring_data_acks.value.ul = statsp->dring_data_acks; 4696*1991Sheppo } else { 4697*1991Sheppo statsp->ipackets = ldckp->ipackets64.value.ull; 4698*1991Sheppo statsp->ierrors = ldckp->ierrors.value.ul; 4699*1991Sheppo statsp->opackets = ldckp->opackets64.value.ull; 4700*1991Sheppo statsp->oerrors = ldckp->oerrors.value.ul; 4701*1991Sheppo 4702*1991Sheppo /* 4703*1991Sheppo * MIB II kstat variables 4704*1991Sheppo */ 4705*1991Sheppo statsp->rbytes = ldckp->rbytes64.value.ull; 4706*1991Sheppo statsp->obytes = ldckp->obytes64.value.ull; 4707*1991Sheppo statsp->multircv = ldckp->multircv.value.ul; 4708*1991Sheppo statsp->multixmt = ldckp->multixmt.value.ul; 4709*1991Sheppo statsp->brdcstrcv = ldckp->brdcstrcv.value.ul; 4710*1991Sheppo statsp->brdcstxmt = ldckp->brdcstxmt.value.ul; 4711*1991Sheppo statsp->norcvbuf = ldckp->norcvbuf.value.ul; 4712*1991Sheppo statsp->noxmtbuf = ldckp->noxmtbuf.value.ul; 4713*1991Sheppo 4714*1991Sheppo statsp->tx_no_desc = ldckp->tx_no_desc.value.ul; 4715*1991Sheppo statsp->tx_allocb_fail = ldckp->tx_allocb_fail.value.ul; 4716*1991Sheppo 4717*1991Sheppo statsp->rx_no_desc = ldckp->rx_no_desc.value.ul; 4718*1991Sheppo statsp->rx_allocb_fail = ldckp->rx_allocb_fail.value.ul; 4719*1991Sheppo statsp->rx_lost_pkts = ldckp->rx_lost_pkts.value.ul; 4720*1991Sheppo 4721*1991Sheppo statsp->callbacks = ldckp->callbacks.value.ul; 4722*1991Sheppo statsp->dring_data_acks = ldckp->dring_data_acks.value.ul; 4723*1991Sheppo } 4724*1991Sheppo 4725*1991Sheppo return (VGEN_SUCCESS); 4726*1991Sheppo } 4727*1991Sheppo 4728*1991Sheppo /* handler for error messages received from the peer ldc end-point */ 4729*1991Sheppo static void 4730*1991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 4731*1991Sheppo { 4732*1991Sheppo _NOTE(ARGUNUSED(ldcp, tagp)) 4733*1991Sheppo } 4734*1991Sheppo 4735*1991Sheppo /* Check if the session id in the received message is valid */ 4736*1991Sheppo static int 4737*1991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 4738*1991Sheppo { 4739*1991Sheppo if (tagp->vio_sid != ldcp->peer_sid) { 4740*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 4741*1991Sheppo DWARN((vnetp, 4742*1991Sheppo "sid mismatch: expected(%x), rcvd(%x)\n", 4743*1991Sheppo ldcp->peer_sid, tagp->vio_sid)); 4744*1991Sheppo return (VGEN_FAILURE); 4745*1991Sheppo } 4746*1991Sheppo else 4747*1991Sheppo return (VGEN_SUCCESS); 4748*1991Sheppo } 4749*1991Sheppo 4750*1991Sheppo /* convert mac address from string to uint64_t */ 4751*1991Sheppo static uint64_t 4752*1991Sheppo vgen_macaddr_strtoul(const uint8_t *macaddr) 4753*1991Sheppo { 4754*1991Sheppo uint64_t val = 0; 4755*1991Sheppo int i; 4756*1991Sheppo 4757*1991Sheppo #if 0 4758*1991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 4759*1991Sheppo #endif 4760*1991Sheppo for (i = 0; i < ETHERADDRL; i++) { 4761*1991Sheppo val <<= 8; 4762*1991Sheppo val |= macaddr[i]; 4763*1991Sheppo } 4764*1991Sheppo 4765*1991Sheppo #if 0 4766*1991Sheppo cmn_err(CE_CONT, "vgen_macaddr_strtoul: str(%x:%x:%x:%x:%x:%x)\n", 4767*1991Sheppo macaddr[0], macaddr[1], macaddr[2], 4768*1991Sheppo macaddr[3], macaddr[4], macaddr[5]); 4769*1991Sheppo cmn_err(CE_CONT, "vgen_macaddr_strtoul: val(0x%lx)\n", val); 4770*1991Sheppo #endif 4771*1991Sheppo return (val); 4772*1991Sheppo } 4773*1991Sheppo 4774*1991Sheppo /* convert mac address from uint64_t to string */ 4775*1991Sheppo static int 4776*1991Sheppo vgen_macaddr_ultostr(uint64_t val, uint8_t *macaddr) 4777*1991Sheppo { 4778*1991Sheppo int i; 4779*1991Sheppo uint64_t value; 4780*1991Sheppo 4781*1991Sheppo value = val; 4782*1991Sheppo #if 0 4783*1991Sheppo for (i = 0; i < ETHERADDRL; i++) { 4784*1991Sheppo #endif 4785*1991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 4786*1991Sheppo macaddr[i] = value & 0xFF; 4787*1991Sheppo value >>= 8; 4788*1991Sheppo } 4789*1991Sheppo #if 0 4790*1991Sheppo cmn_err(CE_CONT, "vgen_macaddr_ultostr: val(0x%lx)\n", val); 4791*1991Sheppo cmn_err(CE_CONT, "vgen_macaddr_ultostr: str(%x:%x:%x:%x:%x:%x)\n", 4792*1991Sheppo macaddr[0], macaddr[1], macaddr[2], 4793*1991Sheppo macaddr[3], macaddr[4], macaddr[5]); 4794*1991Sheppo #endif 4795*1991Sheppo return (VGEN_SUCCESS); 4796*1991Sheppo } 4797*1991Sheppo 4798*1991Sheppo static caddr_t 4799*1991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf) 4800*1991Sheppo { 4801*1991Sheppo (void) sprintf(ebuf, 4802*1991Sheppo "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); 4803*1991Sheppo return (ebuf); 4804*1991Sheppo } 4805*1991Sheppo 4806*1991Sheppo /* Handshake watchdog timeout handler */ 4807*1991Sheppo static void 4808*1991Sheppo vgen_hwatchdog(void *arg) 4809*1991Sheppo { 4810*1991Sheppo vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 4811*1991Sheppo void *vnetp = LDC_TO_VNET(ldcp); 4812*1991Sheppo 4813*1991Sheppo DWARN((vnetp, 4814*1991Sheppo "vgen_hwatchdog: handshake timeout ldc(%lx) phase(%x) state(%x)\n", 4815*1991Sheppo ldcp->ldc_id, ldcp->hphase, ldcp->hstate)); 4816*1991Sheppo 4817*1991Sheppo mutex_enter(&ldcp->cblock); 4818*1991Sheppo ldcp->htid = 0; 4819*1991Sheppo vgen_handshake_retry(ldcp); 4820*1991Sheppo mutex_exit(&ldcp->cblock); 4821*1991Sheppo } 4822*1991Sheppo 4823*1991Sheppo static void 4824*1991Sheppo vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint) 4825*1991Sheppo { 4826*1991Sheppo vgen_hparams_t *hp; 4827*1991Sheppo char ep[8]; 4828*1991Sheppo uint8_t addr[6]; 4829*1991Sheppo char ea[6]; 4830*1991Sheppo 4831*1991Sheppo if (endpoint == VGEN_LOCAL) { 4832*1991Sheppo hp = &ldcp->local_hparams; 4833*1991Sheppo (void) sprintf(ep, "Local"); 4834*1991Sheppo } else { 4835*1991Sheppo hp = &ldcp->peer_hparams; 4836*1991Sheppo (void) sprintf(ep, "Peer"); 4837*1991Sheppo } 4838*1991Sheppo (void) vgen_macaddr_ultostr(hp->addr, addr); 4839*1991Sheppo cmn_err(CE_CONT, "attr_info: %s: \n", ep); 4840*1991Sheppo cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu, 4841*1991Sheppo vgen_print_ethaddr(addr, ea)); 4842*1991Sheppo cmn_err(CE_CONT, "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n", 4843*1991Sheppo hp->addr_type, hp->xfer_mode, hp->ack_freq); 4844*1991Sheppo } 4845*1991Sheppo 4846*1991Sheppo static void 4847*1991Sheppo vgen_print_hparams(vgen_hparams_t *hp) 4848*1991Sheppo { 4849*1991Sheppo uint8_t addr[6]; 4850*1991Sheppo char ea[6]; 4851*1991Sheppo ldc_mem_cookie_t *dc; 4852*1991Sheppo 4853*1991Sheppo cmn_err(CE_CONT, "version_info:\n"); 4854*1991Sheppo cmn_err(CE_CONT, 4855*1991Sheppo "\tver_major: %d, ver_minor: %d, dev_class: %d\n", 4856*1991Sheppo hp->ver_major, hp->ver_minor, hp->dev_class); 4857*1991Sheppo 4858*1991Sheppo (void) vgen_macaddr_ultostr(hp->addr, addr); 4859*1991Sheppo cmn_err(CE_CONT, "attr_info:\n"); 4860*1991Sheppo cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu, 4861*1991Sheppo vgen_print_ethaddr(addr, ea)); 4862*1991Sheppo cmn_err(CE_CONT, 4863*1991Sheppo "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n", 4864*1991Sheppo hp->addr_type, hp->xfer_mode, hp->ack_freq); 4865*1991Sheppo 4866*1991Sheppo dc = &hp->dring_cookie; 4867*1991Sheppo cmn_err(CE_CONT, "dring_info:\n"); 4868*1991Sheppo cmn_err(CE_CONT, 4869*1991Sheppo "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size); 4870*1991Sheppo cmn_err(CE_CONT, 4871*1991Sheppo "\tldc_addr: 0x%lx, ldc_size: %ld\n", 4872*1991Sheppo dc->addr, dc->size); 4873*1991Sheppo cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident); 4874*1991Sheppo } 4875*1991Sheppo 4876*1991Sheppo static void 4877*1991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp) 4878*1991Sheppo { 4879*1991Sheppo vgen_hparams_t *hp; 4880*1991Sheppo 4881*1991Sheppo cmn_err(CE_CONT, "Channel Information:\n"); 4882*1991Sheppo cmn_err(CE_CONT, 4883*1991Sheppo "\tldc_id: 0x%lx, ldc_status: 0x%x\n", 4884*1991Sheppo ldcp->ldc_id, ldcp->ldc_status); 4885*1991Sheppo cmn_err(CE_CONT, 4886*1991Sheppo "\tlocal_sid: 0x%x, peer_sid: 0x%x\n", 4887*1991Sheppo ldcp->local_sid, ldcp->peer_sid); 4888*1991Sheppo cmn_err(CE_CONT, 4889*1991Sheppo "\thphase: 0x%x, hstate: 0x%x\n", 4890*1991Sheppo ldcp->hphase, ldcp->hstate); 4891*1991Sheppo 4892*1991Sheppo cmn_err(CE_CONT, "Local handshake params:\n"); 4893*1991Sheppo hp = &ldcp->local_hparams; 4894*1991Sheppo vgen_print_hparams(hp); 4895*1991Sheppo 4896*1991Sheppo cmn_err(CE_CONT, "Peer handshake params:\n"); 4897*1991Sheppo hp = &ldcp->peer_hparams; 4898*1991Sheppo vgen_print_hparams(hp); 4899*1991Sheppo } 4900