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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * The softmac driver is used to "unify" non-GLDv3 drivers to the GLDv3 28 * framework. It also creates the kernel datalink structure for each 29 * physical network device. 30 * 31 * Specifically, a softmac will be created for each physical network device 32 * (dip) during the device's post-attach process. When this softmac is 33 * created, the following will also be done: 34 * - create the device's <link name, linkid> mapping; 35 * - register the mac if this is a non-GLDv3 device and the media type is 36 * supported by the GLDv3 framework; 37 * - create the kernel data-link structure for this physical device; 38 * 39 * This softmac will be destroyed during the device's pre-detach process, 40 * and all the above will be undone. 41 */ 42 43 #include <sys/types.h> 44 #include <sys/file.h> 45 #include <sys/cred.h> 46 #include <sys/dlpi.h> 47 #include <sys/mac_provider.h> 48 #include <sys/disp.h> 49 #include <sys/sunndi.h> 50 #include <sys/modhash.h> 51 #include <sys/stropts.h> 52 #include <sys/sysmacros.h> 53 #include <sys/vlan.h> 54 #include <sys/softmac_impl.h> 55 #include <sys/softmac.h> 56 #include <sys/dls.h> 57 58 /* Used as a parameter to the mod hash walk of softmac structures */ 59 typedef struct { 60 softmac_t *smw_softmac; 61 boolean_t smw_retry; 62 } softmac_walk_t; 63 64 /* 65 * Softmac hash table including softmacs for both style-2 and style-1 devices. 66 */ 67 static krwlock_t softmac_hash_lock; 68 static mod_hash_t *softmac_hash; 69 static kmutex_t smac_global_lock; 70 static kcondvar_t smac_global_cv; 71 72 #define SOFTMAC_HASHSZ 64 73 74 static void softmac_create_task(void *); 75 static void softmac_mac_register(softmac_t *); 76 static int softmac_create_datalink(softmac_t *); 77 static int softmac_m_start(void *); 78 static void softmac_m_stop(void *); 79 static int softmac_m_open(void *); 80 static void softmac_m_close(void *); 81 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *); 82 83 #define SOFTMAC_M_CALLBACK_FLAGS \ 84 (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE) 85 86 static mac_callbacks_t softmac_m_callbacks = { 87 SOFTMAC_M_CALLBACK_FLAGS, 88 softmac_m_stat, 89 softmac_m_start, 90 softmac_m_stop, 91 softmac_m_promisc, 92 softmac_m_multicst, 93 softmac_m_unicst, 94 softmac_m_tx, 95 softmac_m_ioctl, 96 softmac_m_getcapab, 97 softmac_m_open, 98 softmac_m_close 99 }; 100 101 void 102 softmac_init() 103 { 104 softmac_hash = mod_hash_create_extended("softmac_hash", 105 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 106 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 107 108 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL); 109 mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL); 110 cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL); 111 } 112 113 void 114 softmac_fini() 115 { 116 rw_destroy(&softmac_hash_lock); 117 mod_hash_destroy_hash(softmac_hash); 118 mutex_destroy(&smac_global_lock); 119 cv_destroy(&smac_global_cv); 120 } 121 122 /* ARGSUSED */ 123 static uint_t 124 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 125 { 126 boolean_t *pexist = arg; 127 128 *pexist = B_TRUE; 129 return (MH_WALK_TERMINATE); 130 } 131 132 boolean_t 133 softmac_busy() 134 { 135 boolean_t exist = B_FALSE; 136 137 rw_enter(&softmac_hash_lock, RW_READER); 138 mod_hash_walk(softmac_hash, softmac_exist, &exist); 139 rw_exit(&softmac_hash_lock); 140 return (exist); 141 } 142 143 /* 144 * 145 * softmac_create() is called for each minor node during the post-attach of 146 * each DDI_NT_NET device instance. Note that it is possible that a device 147 * instance has two minor nodes (DLPI style-1 and style-2), so that for that 148 * specific device, softmac_create() could be called twice. 149 * 150 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t 151 * is created to track each minor node. 152 * 153 * For each minor node of a legacy device, a taskq is started to finish 154 * softmac_mac_register(), which will finish the rest of work (see comments 155 * above softmac_mac_register()). 156 * 157 * softmac state machine 158 * -------------------------------------------------------------------------- 159 * OLD STATE EVENT NEW STATE 160 * -------------------------------------------------------------------------- 161 * UNINIT attach of 1st minor node ATTACH_INPROG 162 * okcnt = 0 net_postattach -> softmac_create okcnt = 1 163 * 164 * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE 165 * okcnt = 1 net_postattach -> softmac_create okcnt = 2 166 * 167 * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG 168 * okcnt = 1 net_postattach -> softmac_create okcnt = 2 169 * schedule softmac_mac_register 170 * 171 * ATTACH_INPROG legacy device node ATTACH_DONE 172 * okcnt = 2 softmac_mac_register okcnt = 2 173 * 174 * ATTACH_DONE detach of 1st minor node DETACH_INPROG 175 * okcnt = 2 (success) okcnt = 1 176 * 177 * DETACH_INPROG detach of 2nd minor node UNINIT (or free) 178 * okcnt = 1 (success) okcnt = 0 179 * 180 * ATTACH_DONE detach failure state unchanged 181 * DETACH_INPROG left = okcnt 182 * 183 * DETACH_INPROG reattach ATTACH_INPROG 184 * okcnt = 0,1 net_postattach -> softmac_create 185 * 186 * ATTACH_DONE reattach ATTACH_DONE 187 * left != 0 net_postattach -> softmac_create left = 0 188 * 189 * Abbreviation notes: 190 * states have SOFTMAC_ prefix, 191 * okcnt - softmac_attach_okcnt, 192 * left - softmac_attached_left 193 */ 194 195 #ifdef DEBUG 196 void 197 softmac_state_verify(softmac_t *softmac) 198 { 199 ASSERT(MUTEX_HELD(&softmac->smac_mutex)); 200 201 /* 202 * There are at most 2 minor nodes, one per DLPI style 203 */ 204 ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2); 205 206 /* 207 * The smac_attachok_cnt represents the number of attaches i.e. the 208 * number of times net_postattach -> softmac_create() has been called 209 * for a device instance. 210 */ 211 ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac)); 212 213 /* 214 * softmac_create (or softmac_mac_register) -> softmac_create_datalink 215 * happens only after all minor nodes have been attached 216 */ 217 ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE || 218 softmac->smac_attachok_cnt == softmac->smac_cnt); 219 220 if (softmac->smac_attachok_cnt == 0) { 221 ASSERT(softmac->smac_state == SOFTMAC_UNINIT); 222 ASSERT(softmac->smac_mh == NULL); 223 } else if (softmac->smac_attachok_cnt < softmac->smac_cnt) { 224 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG || 225 softmac->smac_state == SOFTMAC_DETACH_INPROG); 226 ASSERT(softmac->smac_mh == NULL); 227 } else { 228 /* 229 * In the stable condition the state whould be 230 * SOFTMAC_ATTACH_DONE. But there is a small transient window 231 * in softmac_destroy where we change the state to 232 * SOFTMAC_DETACH_INPROG and drop the lock before doing 233 * the link destroy 234 */ 235 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 236 ASSERT(softmac->smac_state != SOFTMAC_UNINIT); 237 } 238 if (softmac->smac_mh != NULL) 239 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 240 } 241 #endif 242 243 #ifdef DEBUG 244 #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac) 245 #else 246 #define SOFTMAC_STATE_VERIFY(softmac) 247 #endif 248 249 int 250 softmac_create(dev_info_t *dip, dev_t dev) 251 { 252 char devname[MAXNAMELEN]; 253 softmac_t *softmac; 254 softmac_dev_t *softmac_dev = NULL; 255 int index; 256 int ppa, err = 0; 257 258 /* 259 * Force the softmac driver to be attached. 260 */ 261 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) { 262 cmn_err(CE_WARN, "softmac_create:softmac attach fails"); 263 return (ENXIO); 264 } 265 266 ppa = ddi_get_instance(dip); 267 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 268 269 /* 270 * We expect legacy devices have at most two minor nodes - one style-1 271 * and one style-2. 272 */ 273 if (!GLDV3_DRV(ddi_driver_major(dip)) && 274 i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) { 275 cmn_err(CE_WARN, "%s has more than 2 minor nodes; unsupported", 276 devname); 277 return (ENOTSUP); 278 } 279 280 /* 281 * Check whether the softmac for the specified device already exists 282 */ 283 rw_enter(&softmac_hash_lock, RW_WRITER); 284 if ((err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 285 (mod_hash_val_t *)&softmac)) != 0) { 286 287 softmac = kmem_zalloc(sizeof (softmac_t), KM_SLEEP); 288 mutex_init(&softmac->smac_mutex, NULL, MUTEX_DRIVER, NULL); 289 cv_init(&softmac->smac_cv, NULL, CV_DRIVER, NULL); 290 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN); 291 /* 292 * Insert the softmac into the hash table. 293 */ 294 err = mod_hash_insert(softmac_hash, 295 (mod_hash_key_t)softmac->smac_devname, 296 (mod_hash_val_t)softmac); 297 ASSERT(err == 0); 298 mutex_enter(&smac_global_lock); 299 cv_broadcast(&smac_global_cv); 300 mutex_exit(&smac_global_lock); 301 } 302 303 mutex_enter(&softmac->smac_mutex); 304 SOFTMAC_STATE_VERIFY(softmac); 305 if (softmac->smac_state != SOFTMAC_ATTACH_DONE) 306 softmac->smac_state = SOFTMAC_ATTACH_INPROG; 307 if (softmac->smac_attachok_cnt == 0) { 308 /* 309 * Initialize the softmac if this is the post-attach of the 310 * first minor node. 311 */ 312 softmac->smac_flags = 0; 313 softmac->smac_umajor = ddi_driver_major(dip); 314 softmac->smac_uppa = ppa; 315 316 /* 317 * Note that for GLDv3 devices, we create devfs minor nodes 318 * for VLANs as well. Assume a GLDv3 driver on which only 319 * a VLAN is created. During the detachment of this device 320 * instance, the following would happen: 321 * a. the pre-detach callback softmac_destroy() succeeds. 322 * Because the physical link itself is not in use, 323 * softmac_destroy() succeeds and destroys softmac_t; 324 * b. the device detach fails in mac_unregister() because 325 * this MAC is still used by a VLAN. 326 * c. the post-attach callback is then called which leads 327 * us here. Note that ddi_minor_node_count() returns 3 328 * (including the minior node of the VLAN). In that case, 329 * we must correct the minor node count to 2 as that is 330 * the count of minor nodes that go through post-attach. 331 */ 332 if (GLDV3_DRV(ddi_driver_major(dip))) { 333 softmac->smac_flags |= SOFTMAC_GLDV3; 334 softmac->smac_cnt = 2; 335 } else { 336 softmac->smac_cnt = 337 i_ddi_minor_node_count(dip, DDI_NT_NET); 338 } 339 } 340 341 index = (getmajor(dev) == ddi_name_to_major("clone")); 342 if (softmac->smac_softmac[index] != NULL) { 343 /* 344 * This is possible if the post_attach() is called after 345 * pre_detach() fails. This seems to be a defect of the DACF 346 * framework. We work around it by using a smac_attached_left 347 * field that tracks this 348 */ 349 ASSERT(softmac->smac_attached_left != 0); 350 softmac->smac_attached_left--; 351 mutex_exit(&softmac->smac_mutex); 352 rw_exit(&softmac_hash_lock); 353 return (0); 354 355 } 356 mutex_exit(&softmac->smac_mutex); 357 rw_exit(&softmac_hash_lock); 358 359 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP); 360 softmac_dev->sd_dev = dev; 361 362 mutex_enter(&softmac->smac_mutex); 363 softmac->smac_softmac[index] = softmac_dev; 364 /* 365 * Continue to register the mac and create the datalink only when all 366 * the minor nodes are attached. 367 */ 368 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) { 369 mutex_exit(&softmac->smac_mutex); 370 return (0); 371 } 372 373 /* 374 * All of the minor nodes have been attached; start a taskq 375 * to do the rest of the work. We use a taskq instead of 376 * doing the work here because: 377 * 378 * We could be called as a result of a open() system call 379 * where spec_open() already SLOCKED the snode. Using a taskq 380 * sidesteps the risk that our ldi_open_by_dev() call would 381 * deadlock trying to set SLOCKED on the snode again. 382 * 383 * The devfs design requires that the downcalls don't use any 384 * interruptible cv_wait which happens when we do door upcalls. 385 * Otherwise the downcalls which may be holding devfs resources 386 * may cause a deadlock if the thread is stopped. Also we need to make 387 * sure these downcalls into softmac_create or softmac_destroy 388 * don't cv_wait on any devfs related condition. Thus softmac_destroy 389 * returns EBUSY if the asynchronous threads started in softmac_create 390 * haven't finished. 391 */ 392 (void) taskq_dispatch(system_taskq, softmac_create_task, 393 softmac, TQ_SLEEP); 394 mutex_exit(&softmac->smac_mutex); 395 return (0); 396 } 397 398 static boolean_t 399 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 400 { 401 softmac_t *softmac = arg; 402 403 if (!(softmac->smac_capab_flags & cap)) 404 return (B_FALSE); 405 406 switch (cap) { 407 case MAC_CAPAB_HCKSUM: { 408 uint32_t *txflags = cap_data; 409 410 *txflags = softmac->smac_hcksum_txflags; 411 break; 412 } 413 case MAC_CAPAB_LEGACY: { 414 mac_capab_legacy_t *legacy = cap_data; 415 416 legacy->ml_unsup_note = ~softmac->smac_notifications & 417 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); 418 legacy->ml_dev = makedevice(softmac->smac_umajor, 419 softmac->smac_uppa + 1); 420 break; 421 } 422 423 /* 424 * For the capabilities below, there's nothing for us to fill in; 425 * simply return B_TRUE if we support it. 426 */ 427 case MAC_CAPAB_NO_ZCOPY: 428 case MAC_CAPAB_NO_NATIVEVLAN: 429 default: 430 break; 431 } 432 return (B_TRUE); 433 } 434 435 static int 436 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) 437 { 438 datalink_id_t linkid = DATALINK_INVALID_LINKID; 439 uint32_t media; 440 int err; 441 442 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, 443 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { 444 *linkidp = linkid; 445 } 446 447 if (err == EEXIST) { 448 /* 449 * There is a link name conflict. Either: 450 * 451 * - An existing link with the same device name with a 452 * different media type from of the given type. 453 * Mark this link back to persistent only; or 454 * 455 * - We cannot assign the "suggested" name because 456 * GLDv3 and therefore vanity naming is not supported 457 * for this link type. Delete this link's <link name, 458 * linkid> mapping. 459 */ 460 if (media != softmac->smac_media) { 461 cmn_err(CE_WARN, "%s device %s conflicts with " 462 "existing %s device %s.", 463 dl_mactypestr(softmac->smac_media), 464 softmac->smac_devname, dl_mactypestr(media), 465 softmac->smac_devname); 466 (void) dls_mgmt_destroy(linkid, B_FALSE); 467 } else { 468 cmn_err(CE_WARN, "link name %s is already in-use.", 469 softmac->smac_devname); 470 (void) dls_mgmt_destroy(linkid, B_TRUE); 471 } 472 473 cmn_err(CE_WARN, "%s device might not be available " 474 "for use.", softmac->smac_devname); 475 cmn_err(CE_WARN, "See dladm(1M) for more information."); 476 } 477 478 return (err); 479 } 480 481 /* 482 * This function: 483 * 1. provides the link's media type to dlmgmtd. 484 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 485 */ 486 static int 487 softmac_create_datalink(softmac_t *softmac) 488 { 489 datalink_id_t linkid = DATALINK_INVALID_LINKID; 490 int err; 491 492 /* 493 * Inform dlmgmtd of this link so that softmac_hold_device() is able 494 * to know the existence of this link. If this failed with EBADF, 495 * it might be because dlmgmtd was not started in time (e.g., 496 * diskless boot); ignore the failure and continue to create 497 * the GLDv3 datalink if needed. 498 */ 499 err = dls_mgmt_create(softmac->smac_devname, 500 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 501 DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); 502 if (err != 0 && err != EBADF) 503 return (err); 504 505 /* 506 * Provide the media type of the physical link to dlmgmtd. 507 */ 508 if ((err != EBADF) && 509 ((err = softmac_update_info(softmac, &linkid)) != 0)) { 510 return (err); 511 } 512 513 /* 514 * Create the GLDv3 datalink. 515 */ 516 if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) && 517 ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) { 518 cmn_err(CE_WARN, "dls_devnet_create failed for %s", 519 softmac->smac_devname); 520 return (err); 521 } 522 523 if (linkid == DATALINK_INVALID_LINKID) { 524 mutex_enter(&softmac->smac_mutex); 525 softmac->smac_flags |= SOFTMAC_NEED_RECREATE; 526 mutex_exit(&softmac->smac_mutex); 527 } 528 529 return (0); 530 } 531 532 static void 533 softmac_create_task(void *arg) 534 { 535 softmac_t *softmac = arg; 536 mac_handle_t mh; 537 int err; 538 539 if (!GLDV3_DRV(softmac->smac_umajor)) { 540 softmac_mac_register(softmac); 541 return; 542 } 543 544 if ((err = mac_open(softmac->smac_devname, &mh)) != 0) 545 goto done; 546 547 mutex_enter(&softmac->smac_mutex); 548 softmac->smac_media = (mac_info(mh))->mi_nativemedia; 549 softmac->smac_mh = mh; 550 mutex_exit(&softmac->smac_mutex); 551 552 /* 553 * We can safely release the reference on the mac because 554 * this mac will only be unregistered and destroyed when 555 * the device detaches, and the softmac will be destroyed 556 * before then (in the pre-detach routine of the device). 557 */ 558 mac_close(mh); 559 560 /* 561 * Create the GLDv3 datalink for this mac. 562 */ 563 err = softmac_create_datalink(softmac); 564 565 done: 566 mutex_enter(&softmac->smac_mutex); 567 if (err != 0) 568 softmac->smac_mh = NULL; 569 softmac->smac_attacherr = err; 570 softmac->smac_state = SOFTMAC_ATTACH_DONE; 571 cv_broadcast(&softmac->smac_cv); 572 mutex_exit(&softmac->smac_mutex); 573 } 574 575 /* 576 * This function is only called for legacy devices. It: 577 * 1. registers the MAC for the legacy devices whose media type is supported 578 * by the GLDv3 framework. 579 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 580 */ 581 static void 582 softmac_mac_register(softmac_t *softmac) 583 { 584 softmac_dev_t *softmac_dev; 585 dev_t dev; 586 ldi_handle_t lh = NULL; 587 ldi_ident_t li = NULL; 588 int index; 589 boolean_t native_vlan = B_FALSE; 590 int err; 591 592 /* 593 * Note that we do not need any locks to access this softmac pointer, 594 * as softmac_destroy() will wait until this function is called. 595 */ 596 ASSERT(softmac != NULL); 597 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 598 softmac->smac_attachok_cnt == softmac->smac_cnt); 599 600 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { 601 mutex_enter(&softmac->smac_mutex); 602 goto done; 603 } 604 605 /* 606 * Determine whether this legacy device support VLANs by opening 607 * the style-2 device node (if it exists) and attaching to a VLAN 608 * PPA (1000 + ppa). 609 */ 610 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); 611 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 612 if (err == 0) { 613 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) 614 native_vlan = B_TRUE; 615 (void) ldi_close(lh, FREAD|FWRITE, kcred); 616 } 617 618 err = EINVAL; 619 for (index = 0; index < 2; index++) { 620 dl_info_ack_t dlia; 621 dl_error_ack_t dlea; 622 uint32_t notes; 623 struct strioctl iocb; 624 uint32_t margin; 625 int rval; 626 627 if ((softmac_dev = softmac->smac_softmac[index]) == NULL) 628 continue; 629 630 softmac->smac_dev = dev = softmac_dev->sd_dev; 631 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, 632 li) != 0) { 633 continue; 634 } 635 636 /* 637 * Pop all the intermediate modules in order to negotiate 638 * capabilities correctly. 639 */ 640 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 641 ; 642 643 /* DLPI style-1 or DLPI style-2? */ 644 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { 645 if (rval == ENOTSUP) { 646 cmn_err(CE_NOTE, "softmac: received " 647 "DL_ERROR_ACK to DL_INFO_ACK; " 648 "DLPI errno 0x%x, UNIX errno %d", 649 dlea.dl_errno, dlea.dl_unix_errno); 650 } 651 (void) ldi_close(lh, FREAD|FWRITE, kcred); 652 continue; 653 } 654 655 /* 656 * Currently only DL_ETHER has GLDv3 mac plugin support. 657 * For media types that GLDv3 does not support, create a 658 * link id for it. 659 */ 660 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { 661 (void) ldi_close(lh, FREAD|FWRITE, kcred); 662 err = 0; 663 break; 664 } 665 666 if ((dlia.dl_provider_style == DL_STYLE2) && 667 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { 668 (void) ldi_close(lh, FREAD|FWRITE, kcred); 669 continue; 670 } 671 672 if ((rval = dl_bind(lh, 0, NULL)) != 0) { 673 if (rval == ENOTSUP) { 674 cmn_err(CE_NOTE, "softmac: received " 675 "DL_ERROR_ACK to DL_BIND_ACK; " 676 "DLPI errno 0x%x, UNIX errno %d", 677 dlea.dl_errno, dlea.dl_unix_errno); 678 } 679 (void) ldi_close(lh, FREAD|FWRITE, kcred); 680 continue; 681 } 682 683 /* 684 * Call dl_info() after dl_bind() because some drivers only 685 * provide correct information (e.g. MAC address) once bound. 686 */ 687 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); 688 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, 689 &softmac->smac_addrlen, &dlea)) != 0) { 690 if (rval == ENOTSUP) { 691 cmn_err(CE_NOTE, "softmac: received " 692 "DL_ERROR_ACK to DL_INFO_ACK; " 693 "DLPI errno 0x%x, UNIX errno %d", 694 dlea.dl_errno, dlea.dl_unix_errno); 695 } 696 (void) ldi_close(lh, FREAD|FWRITE, kcred); 697 continue; 698 } 699 700 softmac->smac_style = dlia.dl_provider_style; 701 softmac->smac_saplen = ABS(dlia.dl_sap_length); 702 softmac->smac_min_sdu = dlia.dl_min_sdu; 703 softmac->smac_max_sdu = dlia.dl_max_sdu; 704 705 if ((softmac->smac_saplen != sizeof (uint16_t)) || 706 (softmac->smac_addrlen != ETHERADDRL) || 707 (dlia.dl_brdcst_addr_length != ETHERADDRL) || 708 (dlia.dl_brdcst_addr_offset == 0)) { 709 (void) ldi_close(lh, FREAD|FWRITE, kcred); 710 continue; 711 } 712 713 /* 714 * Check other DLPI capabilities. Note that this must be after 715 * dl_bind() because some drivers return DL_ERROR_ACK if the 716 * stream is not bound. It is also before mac_register(), so 717 * we don't need any lock protection here. 718 */ 719 softmac->smac_capab_flags = 720 (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); 721 722 softmac->smac_no_capability_req = B_FALSE; 723 if (softmac_fill_capab(lh, softmac) != 0) 724 softmac->smac_no_capability_req = B_TRUE; 725 726 /* 727 * Check the margin of the underlying driver. 728 */ 729 margin = 0; 730 iocb.ic_cmd = DLIOCMARGININFO; 731 iocb.ic_timout = INFTIM; 732 iocb.ic_len = sizeof (margin); 733 iocb.ic_dp = (char *)&margin; 734 softmac->smac_margin = 0; 735 736 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, 737 &rval) == 0) { 738 softmac->smac_margin = margin; 739 } 740 741 /* 742 * If the legacy driver doesn't support DLIOCMARGININFO, but 743 * it can support native VLAN, correct its margin value to 4. 744 */ 745 if (native_vlan) { 746 if (softmac->smac_margin == 0) 747 softmac->smac_margin = VLAN_TAGSZ; 748 } else { 749 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; 750 } 751 752 /* 753 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. 754 */ 755 softmac->smac_notifications = 0; 756 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; 757 switch (dl_notify(lh, ¬es, NULL)) { 758 case 0: 759 softmac->smac_notifications = notes; 760 break; 761 case ENOTSUP: 762 break; 763 default: 764 (void) ldi_close(lh, FREAD|FWRITE, kcred); 765 continue; 766 } 767 768 (void) ldi_close(lh, FREAD|FWRITE, kcred); 769 err = 0; 770 break; 771 } 772 ldi_ident_release(li); 773 774 mutex_enter(&softmac->smac_mutex); 775 776 if (err != 0) 777 goto done; 778 779 if (softmac->smac_media != DL_ETHER) 780 softmac->smac_flags |= SOFTMAC_NOSUPP; 781 782 /* 783 * Finally, we're ready to register ourselves with the MAC layer 784 * interface; if this succeeds, we're all ready to start() 785 */ 786 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 787 mac_register_t *macp; 788 789 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 790 err = ENOMEM; 791 goto done; 792 } 793 794 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 795 macp->m_driver = softmac; 796 macp->m_dip = softmac_dip; 797 798 macp->m_margin = softmac->smac_margin; 799 macp->m_src_addr = softmac->smac_unicst_addr; 800 macp->m_min_sdu = softmac->smac_min_sdu; 801 macp->m_max_sdu = softmac->smac_max_sdu; 802 macp->m_callbacks = &softmac_m_callbacks; 803 macp->m_instance = (uint_t)-1; 804 805 err = mac_register(macp, &softmac->smac_mh); 806 mac_free(macp); 807 if (err != 0) { 808 cmn_err(CE_WARN, "mac_register failed for %s", 809 softmac->smac_devname); 810 goto done; 811 } 812 } 813 mutex_exit(&softmac->smac_mutex); 814 815 /* 816 * Try to create the datalink for this softmac. 817 */ 818 if ((err = softmac_create_datalink(softmac)) != 0) { 819 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 820 (void) mac_unregister(softmac->smac_mh); 821 softmac->smac_mh = NULL; 822 } 823 } 824 /* 825 * If succeed, create the thread which handles the DL_NOTIFY_IND from 826 * the lower stream. 827 */ 828 if (softmac->smac_mh != NULL) { 829 softmac->smac_notify_thread = thread_create(NULL, 0, 830 softmac_notify_thread, softmac, 0, &p0, 831 TS_RUN, minclsyspri); 832 } 833 834 mutex_enter(&softmac->smac_mutex); 835 done: 836 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 837 softmac->smac_attachok_cnt == softmac->smac_cnt); 838 softmac->smac_state = SOFTMAC_ATTACH_DONE; 839 softmac->smac_attacherr = err; 840 cv_broadcast(&softmac->smac_cv); 841 mutex_exit(&softmac->smac_mutex); 842 } 843 844 int 845 softmac_destroy(dev_info_t *dip, dev_t dev) 846 { 847 char devname[MAXNAMELEN]; 848 softmac_t *softmac; 849 softmac_dev_t *softmac_dev; 850 int index; 851 int ppa, err; 852 datalink_id_t linkid; 853 mac_handle_t smac_mh; 854 uint32_t smac_flags; 855 856 ppa = ddi_get_instance(dip); 857 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 858 859 /* 860 * We are called only from the predetach entry point. The DACF 861 * framework ensures there can't be a concurrent postattach call 862 * for the same softmac. The softmac found out from the modhash 863 * below can't vanish beneath us since this is the only place where 864 * it is deleted. 865 */ 866 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 867 (mod_hash_val_t *)&softmac); 868 ASSERT(err == 0); 869 870 mutex_enter(&softmac->smac_mutex); 871 SOFTMAC_STATE_VERIFY(softmac); 872 873 /* 874 * Fail the predetach routine if this softmac is in-use. 875 * Make sure these downcalls into softmac_create or softmac_destroy 876 * don't cv_wait on any devfs related condition. Thus softmac_destroy 877 * returns EBUSY if the asynchronous thread started in softmac_create 878 * hasn't finished 879 */ 880 if ((softmac->smac_hold_cnt != 0) || 881 (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) { 882 softmac->smac_attached_left = softmac->smac_attachok_cnt; 883 mutex_exit(&softmac->smac_mutex); 884 return (EBUSY); 885 } 886 887 /* 888 * Even if the predetach of one minor node has already failed 889 * (smac_attached_left is not 0), the DACF framework will continue 890 * to call the predetach routines of the other minor nodes, 891 * so we fail these calls here. 892 */ 893 if (softmac->smac_attached_left != 0) { 894 mutex_exit(&softmac->smac_mutex); 895 return (EBUSY); 896 } 897 898 smac_mh = softmac->smac_mh; 899 smac_flags = softmac->smac_flags; 900 softmac->smac_state = SOFTMAC_DETACH_INPROG; 901 mutex_exit(&softmac->smac_mutex); 902 903 if (smac_mh != NULL) { 904 /* 905 * This is the first minor node that is being detached for this 906 * softmac. 907 */ 908 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 909 if (!(smac_flags & SOFTMAC_NOSUPP)) { 910 if ((err = dls_devnet_destroy(smac_mh, &linkid, 911 B_FALSE)) != 0) { 912 goto error; 913 } 914 } 915 /* 916 * If softmac_mac_register() succeeds in registering the mac 917 * of the legacy device, unregister it. 918 */ 919 if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { 920 if ((err = mac_disable_nowait(smac_mh)) != 0) { 921 (void) dls_devnet_create(smac_mh, linkid); 922 goto error; 923 } 924 /* 925 * Ask softmac_notify_thread to quit, and wait for 926 * that to be done. 927 */ 928 mutex_enter(&softmac->smac_mutex); 929 softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT; 930 cv_broadcast(&softmac->smac_cv); 931 while (softmac->smac_notify_thread != NULL) { 932 cv_wait(&softmac->smac_cv, 933 &softmac->smac_mutex); 934 } 935 mutex_exit(&softmac->smac_mutex); 936 VERIFY(mac_unregister(smac_mh) == 0); 937 } 938 softmac->smac_mh = NULL; 939 } 940 941 /* 942 * Free softmac_dev 943 */ 944 rw_enter(&softmac_hash_lock, RW_WRITER); 945 mutex_enter(&softmac->smac_mutex); 946 947 ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG && 948 softmac->smac_attachok_cnt != 0); 949 softmac->smac_mh = NULL; 950 index = (getmajor(dev) == ddi_name_to_major("clone")); 951 softmac_dev = softmac->smac_softmac[index]; 952 ASSERT(softmac_dev != NULL); 953 softmac->smac_softmac[index] = NULL; 954 kmem_free(softmac_dev, sizeof (softmac_dev_t)); 955 956 if (--softmac->smac_attachok_cnt == 0) { 957 mod_hash_val_t hashval; 958 959 softmac->smac_state = SOFTMAC_UNINIT; 960 if (softmac->smac_hold_cnt != 0) { 961 /* 962 * Someone did a softmac_hold_device while we dropped 963 * the locks. Leave the softmac itself intact which 964 * will be reused by the reattach 965 */ 966 mutex_exit(&softmac->smac_mutex); 967 rw_exit(&softmac_hash_lock); 968 return (0); 969 } 970 971 err = mod_hash_remove(softmac_hash, 972 (mod_hash_key_t)devname, 973 (mod_hash_val_t *)&hashval); 974 ASSERT(err == 0); 975 976 mutex_exit(&softmac->smac_mutex); 977 rw_exit(&softmac_hash_lock); 978 979 mutex_destroy(&softmac->smac_mutex); 980 cv_destroy(&softmac->smac_cv); 981 kmem_free(softmac, sizeof (softmac_t)); 982 return (0); 983 } 984 mutex_exit(&softmac->smac_mutex); 985 rw_exit(&softmac_hash_lock); 986 return (0); 987 988 error: 989 mutex_enter(&softmac->smac_mutex); 990 softmac->smac_attached_left = softmac->smac_attachok_cnt; 991 softmac->smac_state = SOFTMAC_ATTACH_DONE; 992 cv_broadcast(&softmac->smac_cv); 993 mutex_exit(&softmac->smac_mutex); 994 return (err); 995 } 996 997 /* 998 * This function is called as the result of a newly started dlmgmtd daemon. 999 * 1000 * We walk through every softmac that was created but failed to notify 1001 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs 1002 * when softmacs are created before dlmgmtd is ready. For example, during 1003 * diskless boot, a network device is used (and therefore attached) before 1004 * the datalink-management service starts dlmgmtd. 1005 */ 1006 /* ARGSUSED */ 1007 static uint_t 1008 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1009 { 1010 softmac_t *softmac = (softmac_t *)val; 1011 datalink_id_t linkid; 1012 int err; 1013 softmac_walk_t *smwp = arg; 1014 1015 /* 1016 * The framework itself must not hold any locks across calls to the 1017 * mac perimeter. Thus this function does not call any framework 1018 * function that needs to grab the mac perimeter. 1019 */ 1020 ASSERT(RW_READ_HELD(&softmac_hash_lock)); 1021 1022 smwp->smw_retry = B_FALSE; 1023 mutex_enter(&softmac->smac_mutex); 1024 SOFTMAC_STATE_VERIFY(softmac); 1025 if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) { 1026 /* 1027 * Wait till softmac_create or softmac_mac_register finishes 1028 * Hold the softmac to ensure it stays around. The wait itself 1029 * is done in the caller, since we need to drop all locks 1030 * including the mod hash's internal lock before calling 1031 * cv_wait. 1032 */ 1033 smwp->smw_retry = B_TRUE; 1034 smwp->smw_softmac = softmac; 1035 softmac->smac_hold_cnt++; 1036 return (MH_WALK_TERMINATE); 1037 } 1038 1039 if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) || 1040 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { 1041 mutex_exit(&softmac->smac_mutex); 1042 return (MH_WALK_CONTINUE); 1043 } 1044 1045 /* 1046 * Bumping up the smac_hold_cnt allows us to drop the lock. It also 1047 * makes softmac_destroy() return failure on an attempted device detach. 1048 * We don't want to hold the lock across calls to other subsystems 1049 * like kstats, which will happen in the call to dls_devnet_recreate 1050 */ 1051 softmac->smac_hold_cnt++; 1052 mutex_exit(&softmac->smac_mutex); 1053 1054 if (dls_mgmt_create(softmac->smac_devname, 1055 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 1056 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { 1057 softmac_rele_device((dls_dev_handle_t)softmac); 1058 return (MH_WALK_CONTINUE); 1059 } 1060 1061 if ((err = softmac_update_info(softmac, &linkid)) != 0) { 1062 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " 1063 "failed (%d)", softmac->smac_devname, err); 1064 softmac_rele_device((dls_dev_handle_t)softmac); 1065 return (MH_WALK_CONTINUE); 1066 } 1067 1068 /* 1069 * Create a link for this MAC. The link name will be the same 1070 * as the MAC name. 1071 */ 1072 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 1073 err = dls_devnet_recreate(softmac->smac_mh, linkid); 1074 if (err != 0) { 1075 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " 1076 "%s (linkid %d) failed (%d)", 1077 softmac->smac_devname, linkid, err); 1078 } 1079 } 1080 1081 mutex_enter(&softmac->smac_mutex); 1082 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; 1083 ASSERT(softmac->smac_hold_cnt != 0); 1084 softmac->smac_hold_cnt--; 1085 mutex_exit(&softmac->smac_mutex); 1086 1087 return (MH_WALK_CONTINUE); 1088 } 1089 1090 /* 1091 * See comments above softmac_mac_recreate(). 1092 */ 1093 void 1094 softmac_recreate() 1095 { 1096 softmac_walk_t smw; 1097 softmac_t *softmac; 1098 1099 /* 1100 * Walk through the softmac_hash table. Request to create the 1101 * [link name, linkid] mapping if we failed to do so. 1102 */ 1103 do { 1104 smw.smw_retry = B_FALSE; 1105 rw_enter(&softmac_hash_lock, RW_READER); 1106 mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw); 1107 rw_exit(&softmac_hash_lock); 1108 if (smw.smw_retry) { 1109 /* 1110 * softmac_create or softmac_mac_register hasn't yet 1111 * finished and the softmac is not yet in the 1112 * SOFTMAC_ATTACH_DONE state. 1113 */ 1114 softmac = smw.smw_softmac; 1115 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1116 softmac->smac_hold_cnt--; 1117 mutex_exit(&softmac->smac_mutex); 1118 } 1119 } while (smw.smw_retry); 1120 } 1121 1122 /* ARGSUSED */ 1123 static int 1124 softmac_m_start(void *arg) 1125 { 1126 return (0); 1127 } 1128 1129 /* ARGSUSED */ 1130 static void 1131 softmac_m_stop(void *arg) 1132 { 1133 } 1134 1135 /* 1136 * Set up the lower stream above the legacy device which is shared by 1137 * GLDv3 MAC clients. Put the lower stream into DLIOCRAW mode to send 1138 * and receive the raw data. Further, put the lower stream into 1139 * DL_PROMISC_SAP mode to receive all packets of interest. 1140 */ 1141 static int 1142 softmac_lower_setup(softmac_t *softmac, softmac_lower_t **slpp) 1143 { 1144 ldi_ident_t li; 1145 dev_t dev; 1146 ldi_handle_t lh = NULL; 1147 softmac_lower_t *slp = NULL; 1148 smac_ioc_start_t start_arg; 1149 struct strioctl strioc; 1150 uint32_t notifications; 1151 int err, rval; 1152 1153 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) 1154 return (err); 1155 1156 dev = softmac->smac_dev; 1157 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 1158 ldi_ident_release(li); 1159 if (err != 0) 1160 goto done; 1161 1162 /* 1163 * Pop all the intermediate modules. The autopushed modules will 1164 * be pushed when the softmac node is opened. 1165 */ 1166 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 1167 ; 1168 1169 if ((softmac->smac_style == DL_STYLE2) && 1170 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { 1171 goto done; 1172 } 1173 1174 /* 1175 * Put the lower stream into DLIOCRAW mode to send/receive raw data. 1176 */ 1177 if ((err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, kcred, &rval)) != 0) 1178 goto done; 1179 1180 /* 1181 * Then push the softmac shim layer atop the lower stream. 1182 */ 1183 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, 1184 kcred, &rval)) != 0) { 1185 goto done; 1186 } 1187 1188 /* 1189 * Send the ioctl to get the slp pointer. 1190 */ 1191 strioc.ic_cmd = SMAC_IOC_START; 1192 strioc.ic_timout = INFTIM; 1193 strioc.ic_len = sizeof (start_arg); 1194 strioc.ic_dp = (char *)&start_arg; 1195 1196 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, 1197 kcred, &rval)) != 0) { 1198 goto done; 1199 } 1200 slp = start_arg.si_slp; 1201 slp->sl_lh = lh; 1202 slp->sl_softmac = softmac; 1203 *slpp = slp; 1204 1205 /* 1206 * Bind to SAP 2 on token ring, 0 on other interface types. 1207 * (SAP 0 has special significance on token ring). 1208 * Note that the receive-side packets could come anytime after bind. 1209 */ 1210 if (softmac->smac_media == DL_TPR) 1211 err = softmac_send_bind_req(slp, 2); 1212 else 1213 err = softmac_send_bind_req(slp, 0); 1214 if (err != 0) 1215 goto done; 1216 1217 /* 1218 * Put the lower stream into DL_PROMISC_SAP mode to receive all 1219 * packets of interest. 1220 * 1221 * Some drivers (e.g. the old legacy eri driver) incorrectly pass up 1222 * packets to DL_PROMISC_SAP stream when the lower stream is not bound, 1223 * so we send DL_PROMISON_REQ after DL_BIND_REQ. 1224 */ 1225 if ((err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE)) != 0) 1226 goto done; 1227 1228 /* 1229 * Enable the capabilities the underlying driver claims to support. 1230 * Some drivers require this to be called after the stream is bound. 1231 */ 1232 if ((err = softmac_capab_enable(slp)) != 0) 1233 goto done; 1234 1235 /* 1236 * Send the DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. 1237 * We don't have to wait for the ack. 1238 */ 1239 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | 1240 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | 1241 DL_NOTE_PROMISC_OFF_PHYS; 1242 1243 (void) softmac_send_notify_req(slp, 1244 (notifications & softmac->smac_notifications)); 1245 1246 done: 1247 if (err != 0) 1248 (void) ldi_close(lh, FREAD|FWRITE, kcred); 1249 return (err); 1250 } 1251 1252 static int 1253 softmac_m_open(void *arg) 1254 { 1255 softmac_t *softmac = arg; 1256 softmac_lower_t *slp; 1257 int err; 1258 1259 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1260 ASSERT(softmac->smac_lower_state == SOFTMAC_INITIALIZED); 1261 1262 if ((err = softmac_lower_setup(softmac, &slp)) != 0) 1263 return (err); 1264 1265 softmac->smac_lower = slp; 1266 softmac->smac_lower_state = SOFTMAC_READY; 1267 return (0); 1268 } 1269 1270 static void 1271 softmac_m_close(void *arg) 1272 { 1273 softmac_t *softmac = arg; 1274 softmac_lower_t *slp; 1275 1276 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1277 ASSERT(softmac->smac_lower_state == SOFTMAC_READY); 1278 slp = softmac->smac_lower; 1279 ASSERT(slp != NULL); 1280 1281 /* 1282 * Note that slp is destroyed when lh is closed. 1283 */ 1284 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); 1285 softmac->smac_lower_state = SOFTMAC_INITIALIZED; 1286 softmac->smac_lower = NULL; 1287 } 1288 1289 int 1290 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) 1291 { 1292 dev_info_t *dip; 1293 const char *drvname; 1294 char devname[MAXNAMELEN]; 1295 softmac_t *softmac; 1296 int ppa, err; 1297 1298 if ((ppa = getminor(dev) - 1) > 1000) 1299 return (ENOENT); 1300 1301 /* 1302 * First try to hold this device instance to force the MAC 1303 * to be registered. 1304 */ 1305 if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL) 1306 return (ENOENT); 1307 1308 drvname = ddi_driver_name(dip); 1309 1310 /* 1311 * Exclude non-physical network device instances, for example, aggr0. 1312 */ 1313 if ((ddi_driver_major(dip) != getmajor(dev)) || 1314 !NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) || 1315 (strcmp(drvname, "vnic") == 0)) { 1316 ddi_release_devi(dip); 1317 return (ENOENT); 1318 } 1319 1320 /* 1321 * This is a network device; wait for its softmac to be registered. 1322 */ 1323 (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa); 1324 again: 1325 rw_enter(&softmac_hash_lock, RW_READER); 1326 1327 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 1328 (mod_hash_val_t *)&softmac) != 0) { 1329 /* 1330 * This is rare but possible. It could happen when pre-detach 1331 * routine of the device succeeds. But the softmac will then 1332 * be recreated when device fails to detach (as this device 1333 * is held). 1334 */ 1335 mutex_enter(&smac_global_lock); 1336 rw_exit(&softmac_hash_lock); 1337 cv_wait(&smac_global_cv, &smac_global_lock); 1338 mutex_exit(&smac_global_lock); 1339 goto again; 1340 } 1341 1342 /* 1343 * Bump smac_hold_cnt to prevent device detach. 1344 */ 1345 mutex_enter(&softmac->smac_mutex); 1346 softmac->smac_hold_cnt++; 1347 rw_exit(&softmac_hash_lock); 1348 1349 /* 1350 * Wait till the device is fully attached. 1351 */ 1352 while (softmac->smac_state != SOFTMAC_ATTACH_DONE) 1353 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1354 1355 SOFTMAC_STATE_VERIFY(softmac); 1356 1357 if ((err = softmac->smac_attacherr) != 0) 1358 softmac->smac_hold_cnt--; 1359 else 1360 *ddhp = (dls_dev_handle_t)softmac; 1361 mutex_exit(&softmac->smac_mutex); 1362 1363 ddi_release_devi(dip); 1364 return (err); 1365 } 1366 1367 void 1368 softmac_rele_device(dls_dev_handle_t ddh) 1369 { 1370 softmac_t *softmac; 1371 1372 if (ddh == NULL) 1373 return; 1374 1375 softmac = (softmac_t *)ddh; 1376 mutex_enter(&softmac->smac_mutex); 1377 softmac->smac_hold_cnt--; 1378 mutex_exit(&softmac->smac_mutex); 1379 } 1380