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