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