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