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