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