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 2008 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 ASSERT(softmac->smac_taskq == NULL); 393 softmac->smac_taskq = taskq_dispatch(system_taskq, 394 softmac_create_task, softmac, TQ_SLEEP); 395 mutex_exit(&softmac->smac_mutex); 396 return (0); 397 } 398 399 static boolean_t 400 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 401 { 402 softmac_t *softmac = arg; 403 404 if (!(softmac->smac_capab_flags & cap)) 405 return (B_FALSE); 406 407 switch (cap) { 408 case MAC_CAPAB_HCKSUM: { 409 uint32_t *txflags = cap_data; 410 411 *txflags = softmac->smac_hcksum_txflags; 412 break; 413 } 414 case MAC_CAPAB_LEGACY: { 415 mac_capab_legacy_t *legacy = cap_data; 416 417 legacy->ml_unsup_note = ~softmac->smac_notifications & 418 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); 419 legacy->ml_dev = makedevice(softmac->smac_umajor, 420 softmac->smac_uppa + 1); 421 break; 422 } 423 424 /* 425 * For the capabilities below, there's nothing for us to fill in; 426 * simply return B_TRUE if we support it. 427 */ 428 case MAC_CAPAB_NO_ZCOPY: 429 case MAC_CAPAB_NO_NATIVEVLAN: 430 default: 431 break; 432 } 433 return (B_TRUE); 434 } 435 436 static int 437 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) 438 { 439 datalink_id_t linkid = DATALINK_INVALID_LINKID; 440 uint32_t media; 441 int err; 442 443 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, 444 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { 445 *linkidp = linkid; 446 } 447 448 if (err == EEXIST) { 449 /* 450 * There is a link name conflict. Either: 451 * 452 * - An existing link with the same device name with a 453 * different media type from of the given type. 454 * Mark this link back to persistent only; or 455 * 456 * - We cannot assign the "suggested" name because 457 * GLDv3 and therefore vanity naming is not supported 458 * for this link type. Delete this link's <link name, 459 * linkid> mapping. 460 */ 461 if (media != softmac->smac_media) { 462 cmn_err(CE_WARN, "%s device %s conflicts with " 463 "existing %s device %s.", 464 dl_mactypestr(softmac->smac_media), 465 softmac->smac_devname, dl_mactypestr(media), 466 softmac->smac_devname); 467 (void) dls_mgmt_destroy(linkid, B_FALSE); 468 } else { 469 cmn_err(CE_WARN, "link name %s is already in-use.", 470 softmac->smac_devname); 471 (void) dls_mgmt_destroy(linkid, B_TRUE); 472 } 473 474 cmn_err(CE_WARN, "%s device might not be available " 475 "for use.", softmac->smac_devname); 476 cmn_err(CE_WARN, "See dladm(1M) for more information."); 477 } 478 479 return (err); 480 } 481 482 /* 483 * This function: 484 * 1. provides the link's media type to dlmgmtd. 485 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 486 */ 487 static int 488 softmac_create_datalink(softmac_t *softmac) 489 { 490 datalink_id_t linkid = DATALINK_INVALID_LINKID; 491 int err; 492 493 /* 494 * Inform dlmgmtd of this link so that softmac_hold_device() is able 495 * to know the existence of this link. If this failed with EBADF, 496 * it might be because dlmgmtd was not started in time (e.g., 497 * diskless boot); ignore the failure and continue to create 498 * the GLDv3 datalink if needed. 499 */ 500 err = dls_mgmt_create(softmac->smac_devname, 501 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 502 DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); 503 if (err != 0 && err != EBADF) 504 return (err); 505 506 /* 507 * Provide the media type of the physical link to dlmgmtd. 508 */ 509 if ((err != EBADF) && 510 ((err = softmac_update_info(softmac, &linkid)) != 0)) { 511 return (err); 512 } 513 514 /* 515 * Create the GLDv3 datalink. 516 */ 517 if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) && 518 ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) { 519 cmn_err(CE_WARN, "dls_devnet_create failed for %s", 520 softmac->smac_devname); 521 return (err); 522 } 523 524 if (linkid == DATALINK_INVALID_LINKID) { 525 mutex_enter(&softmac->smac_mutex); 526 softmac->smac_flags |= SOFTMAC_NEED_RECREATE; 527 mutex_exit(&softmac->smac_mutex); 528 } 529 530 return (0); 531 } 532 533 static void 534 softmac_create_task(void *arg) 535 { 536 softmac_t *softmac = arg; 537 mac_handle_t mh; 538 int err; 539 540 if (!GLDV3_DRV(softmac->smac_umajor)) { 541 softmac_mac_register(softmac); 542 return; 543 } 544 545 if ((err = mac_open(softmac->smac_devname, &mh)) != 0) 546 goto done; 547 548 mutex_enter(&softmac->smac_mutex); 549 softmac->smac_media = (mac_info(mh))->mi_nativemedia; 550 softmac->smac_mh = mh; 551 softmac->smac_taskq = NULL; 552 mutex_exit(&softmac->smac_mutex); 553 554 /* 555 * We can safely release the reference on the mac because 556 * this mac will only be unregistered and destroyed when 557 * the device detaches, and the softmac will be destroyed 558 * before then (in the pre-detach routine of the device). 559 */ 560 mac_close(mh); 561 562 /* 563 * Create the GLDv3 datalink for this mac. 564 */ 565 err = softmac_create_datalink(softmac); 566 567 mutex_enter(&softmac->smac_mutex); 568 done: 569 if (err != 0) { 570 softmac->smac_mh = NULL; 571 softmac->smac_attacherr = err; 572 } 573 softmac->smac_state = SOFTMAC_ATTACH_DONE; 574 softmac->smac_taskq = NULL; 575 cv_broadcast(&softmac->smac_cv); 576 mutex_exit(&softmac->smac_mutex); 577 } 578 579 /* 580 * This function is only called for legacy devices. It: 581 * 1. registers the MAC for the legacy devices whose media type is supported 582 * by the GLDv3 framework. 583 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 584 */ 585 static void 586 softmac_mac_register(softmac_t *softmac) 587 { 588 softmac_dev_t *softmac_dev; 589 dev_t dev; 590 ldi_handle_t lh = NULL; 591 ldi_ident_t li = NULL; 592 int index; 593 boolean_t native_vlan = B_FALSE; 594 int err; 595 596 /* 597 * Note that we do not need any locks to access this softmac pointer, 598 * as softmac_destroy() will wait until this function is called. 599 */ 600 ASSERT(softmac != NULL); 601 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 602 softmac->smac_attachok_cnt == softmac->smac_cnt); 603 604 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { 605 mutex_enter(&softmac->smac_mutex); 606 goto done; 607 } 608 609 /* 610 * Determine whether this legacy device support VLANs by opening 611 * the style-2 device node (if it exists) and attaching to a VLAN 612 * PPA (1000 + ppa). 613 */ 614 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); 615 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 616 if (err == 0) { 617 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) 618 native_vlan = B_TRUE; 619 (void) ldi_close(lh, FREAD|FWRITE, kcred); 620 } 621 622 err = EINVAL; 623 for (index = 0; index < 2; index++) { 624 dl_info_ack_t dlia; 625 dl_error_ack_t dlea; 626 uint32_t notes; 627 struct strioctl iocb; 628 uint32_t margin; 629 int rval; 630 631 if ((softmac_dev = softmac->smac_softmac[index]) == NULL) 632 continue; 633 634 softmac->smac_dev = dev = softmac_dev->sd_dev; 635 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, 636 li) != 0) { 637 continue; 638 } 639 640 /* 641 * Pop all the intermediate modules in order to negotiate 642 * capabilities correctly. 643 */ 644 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 645 ; 646 647 /* DLPI style-1 or DLPI style-2? */ 648 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { 649 if (rval == ENOTSUP) { 650 cmn_err(CE_NOTE, "softmac: received " 651 "DL_ERROR_ACK to DL_INFO_ACK; " 652 "DLPI errno 0x%x, UNIX errno %d", 653 dlea.dl_errno, dlea.dl_unix_errno); 654 } 655 (void) ldi_close(lh, FREAD|FWRITE, kcred); 656 continue; 657 } 658 659 /* 660 * Currently only DL_ETHER has GLDv3 mac plugin support. 661 * For media types that GLDv3 does not support, create a 662 * link id for it. 663 */ 664 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { 665 (void) ldi_close(lh, FREAD|FWRITE, kcred); 666 err = 0; 667 break; 668 } 669 670 if ((dlia.dl_provider_style == DL_STYLE2) && 671 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { 672 (void) ldi_close(lh, FREAD|FWRITE, kcred); 673 continue; 674 } 675 676 if ((rval = dl_bind(lh, 0, NULL)) != 0) { 677 if (rval == ENOTSUP) { 678 cmn_err(CE_NOTE, "softmac: received " 679 "DL_ERROR_ACK to DL_BIND_ACK; " 680 "DLPI errno 0x%x, UNIX errno %d", 681 dlea.dl_errno, dlea.dl_unix_errno); 682 } 683 (void) ldi_close(lh, FREAD|FWRITE, kcred); 684 continue; 685 } 686 687 /* 688 * Call dl_info() after dl_bind() because some drivers only 689 * provide correct information (e.g. MAC address) once bound. 690 */ 691 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); 692 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, 693 &softmac->smac_addrlen, &dlea)) != 0) { 694 if (rval == ENOTSUP) { 695 cmn_err(CE_NOTE, "softmac: received " 696 "DL_ERROR_ACK to DL_INFO_ACK; " 697 "DLPI errno 0x%x, UNIX errno %d", 698 dlea.dl_errno, dlea.dl_unix_errno); 699 } 700 (void) ldi_close(lh, FREAD|FWRITE, kcred); 701 continue; 702 } 703 704 softmac->smac_style = dlia.dl_provider_style; 705 softmac->smac_saplen = ABS(dlia.dl_sap_length); 706 softmac->smac_min_sdu = dlia.dl_min_sdu; 707 softmac->smac_max_sdu = dlia.dl_max_sdu; 708 709 if ((softmac->smac_saplen != sizeof (uint16_t)) || 710 (softmac->smac_addrlen != ETHERADDRL) || 711 (dlia.dl_brdcst_addr_length != ETHERADDRL) || 712 (dlia.dl_brdcst_addr_offset == 0)) { 713 (void) ldi_close(lh, FREAD|FWRITE, kcred); 714 continue; 715 } 716 717 /* 718 * Check other DLPI capabilities. Note that this must be after 719 * dl_bind() because some drivers return DL_ERROR_ACK if the 720 * stream is not bound. It is also before mac_register(), so 721 * we don't need any lock protection here. 722 */ 723 softmac->smac_capab_flags = 724 (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); 725 726 softmac->smac_no_capability_req = B_FALSE; 727 if (softmac_fill_capab(lh, softmac) != 0) 728 softmac->smac_no_capability_req = B_TRUE; 729 730 /* 731 * Check the margin of the underlying driver. 732 */ 733 margin = 0; 734 iocb.ic_cmd = DLIOCMARGININFO; 735 iocb.ic_timout = INFTIM; 736 iocb.ic_len = sizeof (margin); 737 iocb.ic_dp = (char *)&margin; 738 softmac->smac_margin = 0; 739 740 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, 741 &rval) == 0) { 742 softmac->smac_margin = margin; 743 } 744 745 /* 746 * If the legacy driver doesn't support DLIOCMARGININFO, but 747 * it can support native VLAN, correct its margin value to 4. 748 */ 749 if (native_vlan) { 750 if (softmac->smac_margin == 0) 751 softmac->smac_margin = VLAN_TAGSZ; 752 } else { 753 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; 754 } 755 756 /* 757 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. 758 */ 759 softmac->smac_notifications = 0; 760 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; 761 switch (dl_notify(lh, ¬es, NULL)) { 762 case 0: 763 softmac->smac_notifications = notes; 764 break; 765 case ENOTSUP: 766 break; 767 default: 768 (void) ldi_close(lh, FREAD|FWRITE, kcred); 769 continue; 770 } 771 772 (void) ldi_close(lh, FREAD|FWRITE, kcred); 773 err = 0; 774 break; 775 } 776 ldi_ident_release(li); 777 778 mutex_enter(&softmac->smac_mutex); 779 780 if (err != 0) 781 goto done; 782 783 if (softmac->smac_media != DL_ETHER) 784 softmac->smac_flags |= SOFTMAC_NOSUPP; 785 786 /* 787 * Finally, we're ready to register ourselves with the MAC layer 788 * interface; if this succeeds, we're all ready to start() 789 */ 790 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 791 mac_register_t *macp; 792 793 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 794 err = ENOMEM; 795 goto done; 796 } 797 798 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 799 macp->m_driver = softmac; 800 macp->m_dip = softmac_dip; 801 802 macp->m_margin = softmac->smac_margin; 803 macp->m_src_addr = softmac->smac_unicst_addr; 804 macp->m_min_sdu = softmac->smac_min_sdu; 805 macp->m_max_sdu = softmac->smac_max_sdu; 806 macp->m_callbacks = &softmac_m_callbacks; 807 macp->m_instance = (uint_t)-1; 808 809 err = mac_register(macp, &softmac->smac_mh); 810 mac_free(macp); 811 if (err != 0) { 812 cmn_err(CE_WARN, "mac_register failed for %s", 813 softmac->smac_devname); 814 goto done; 815 } 816 } 817 mutex_exit(&softmac->smac_mutex); 818 819 /* 820 * Try to create the datalink for this softmac. 821 */ 822 if ((err = softmac_create_datalink(softmac)) != 0) { 823 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 824 (void) mac_unregister(softmac->smac_mh); 825 softmac->smac_mh = NULL; 826 } 827 } 828 /* 829 * If succeed, create the thread which handles the DL_NOTIFY_IND from 830 * the lower stream. 831 */ 832 if (softmac->smac_mh != NULL) { 833 softmac->smac_notify_thread = thread_create(NULL, 0, 834 softmac_notify_thread, softmac, 0, &p0, 835 TS_RUN, minclsyspri); 836 } 837 838 mutex_enter(&softmac->smac_mutex); 839 done: 840 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 841 softmac->smac_attachok_cnt == softmac->smac_cnt); 842 softmac->smac_state = SOFTMAC_ATTACH_DONE; 843 softmac->smac_attacherr = err; 844 softmac->smac_taskq = NULL; 845 cv_broadcast(&softmac->smac_cv); 846 mutex_exit(&softmac->smac_mutex); 847 } 848 849 int 850 softmac_destroy(dev_info_t *dip, dev_t dev) 851 { 852 char devname[MAXNAMELEN]; 853 softmac_t *softmac; 854 softmac_dev_t *softmac_dev; 855 int index; 856 int ppa, err; 857 datalink_id_t linkid; 858 mac_handle_t smac_mh; 859 uint32_t smac_flags; 860 861 ppa = ddi_get_instance(dip); 862 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 863 864 /* 865 * We are called only from the predetach entry point. The DACF 866 * framework ensures there can't be a concurrent postattach call 867 * for the same softmac. The softmac found out from the modhash 868 * below can't vanish beneath us since this is the only place where 869 * it is deleted. 870 */ 871 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 872 (mod_hash_val_t *)&softmac); 873 ASSERT(err == 0); 874 875 mutex_enter(&softmac->smac_mutex); 876 SOFTMAC_STATE_VERIFY(softmac); 877 878 /* 879 * Fail the predetach routine if this softmac is in-use. 880 * Make sure these downcalls into softmac_create or softmac_destroy 881 * don't cv_wait on any devfs related condition. Thus softmac_destroy 882 * returns EBUSY if the asynchronous thread started in softmac_create 883 * hasn't finished 884 */ 885 if ((softmac->smac_hold_cnt != 0) || 886 (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) { 887 softmac->smac_attached_left = softmac->smac_attachok_cnt; 888 mutex_exit(&softmac->smac_mutex); 889 return (EBUSY); 890 } 891 892 /* 893 * Even if the predetach of one minor node has already failed 894 * (smac_attached_left is not 0), the DACF framework will continue 895 * to call the predetach routines of the other minor nodes, 896 * so we fail these calls here. 897 */ 898 if (softmac->smac_attached_left != 0) { 899 mutex_exit(&softmac->smac_mutex); 900 return (EBUSY); 901 } 902 903 smac_mh = softmac->smac_mh; 904 smac_flags = softmac->smac_flags; 905 softmac->smac_state = SOFTMAC_DETACH_INPROG; 906 mutex_exit(&softmac->smac_mutex); 907 908 if (smac_mh != NULL) { 909 /* 910 * This is the first minor node that is being detached for this 911 * softmac. 912 */ 913 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 914 if (!(smac_flags & SOFTMAC_NOSUPP)) { 915 if ((err = dls_devnet_destroy(smac_mh, &linkid, 916 B_FALSE)) != 0) { 917 goto error; 918 } 919 } 920 /* 921 * If softmac_mac_register() succeeds in registering the mac 922 * of the legacy device, unregister it. 923 */ 924 if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { 925 if ((err = mac_disable_nowait(smac_mh)) != 0) { 926 (void) dls_devnet_create(smac_mh, linkid); 927 goto error; 928 } 929 /* 930 * Ask softmac_notify_thread to quit, and wait for 931 * that to be done. 932 */ 933 mutex_enter(&softmac->smac_mutex); 934 softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT; 935 cv_broadcast(&softmac->smac_cv); 936 while (softmac->smac_notify_thread != NULL) { 937 cv_wait(&softmac->smac_cv, 938 &softmac->smac_mutex); 939 } 940 mutex_exit(&softmac->smac_mutex); 941 VERIFY(mac_unregister(smac_mh) == 0); 942 } 943 softmac->smac_mh = NULL; 944 } 945 946 /* 947 * Free softmac_dev 948 */ 949 rw_enter(&softmac_hash_lock, RW_WRITER); 950 mutex_enter(&softmac->smac_mutex); 951 952 ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG && 953 softmac->smac_attachok_cnt != 0); 954 softmac->smac_mh = NULL; 955 index = (getmajor(dev) == ddi_name_to_major("clone")); 956 softmac_dev = softmac->smac_softmac[index]; 957 ASSERT(softmac_dev != NULL); 958 softmac->smac_softmac[index] = NULL; 959 kmem_free(softmac_dev, sizeof (softmac_dev_t)); 960 961 if (--softmac->smac_attachok_cnt == 0) { 962 mod_hash_val_t hashval; 963 964 softmac->smac_state = SOFTMAC_UNINIT; 965 if (softmac->smac_hold_cnt != 0) { 966 /* 967 * Someone did a softmac_hold_device while we dropped 968 * the locks. Leave the softmac itself intact which 969 * will be reused by the reattach 970 */ 971 mutex_exit(&softmac->smac_mutex); 972 rw_exit(&softmac_hash_lock); 973 return (0); 974 } 975 ASSERT(softmac->smac_taskq == NULL); 976 977 err = mod_hash_remove(softmac_hash, 978 (mod_hash_key_t)devname, 979 (mod_hash_val_t *)&hashval); 980 ASSERT(err == 0); 981 982 mutex_exit(&softmac->smac_mutex); 983 rw_exit(&softmac_hash_lock); 984 985 mutex_destroy(&softmac->smac_mutex); 986 cv_destroy(&softmac->smac_cv); 987 kmem_free(softmac, sizeof (softmac_t)); 988 return (0); 989 } 990 mutex_exit(&softmac->smac_mutex); 991 rw_exit(&softmac_hash_lock); 992 return (0); 993 994 error: 995 mutex_enter(&softmac->smac_mutex); 996 softmac->smac_attached_left = softmac->smac_attachok_cnt; 997 softmac->smac_state = SOFTMAC_ATTACH_DONE; 998 cv_broadcast(&softmac->smac_cv); 999 mutex_exit(&softmac->smac_mutex); 1000 return (err); 1001 } 1002 1003 /* 1004 * This function is called as the result of a newly started dlmgmtd daemon. 1005 * 1006 * We walk through every softmac that was created but failed to notify 1007 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs 1008 * when softmacs are created before dlmgmtd is ready. For example, during 1009 * diskless boot, a network device is used (and therefore attached) before 1010 * the datalink-management service starts dlmgmtd. 1011 */ 1012 /* ARGSUSED */ 1013 static uint_t 1014 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1015 { 1016 softmac_t *softmac = (softmac_t *)val; 1017 datalink_id_t linkid; 1018 int err; 1019 softmac_walk_t *smwp = arg; 1020 1021 /* 1022 * The framework itself must not hold any locks across calls to the 1023 * mac perimeter. Thus this function does not call any framework 1024 * function that needs to grab the mac perimeter. 1025 */ 1026 ASSERT(RW_READ_HELD(&softmac_hash_lock)); 1027 1028 smwp->smw_retry = B_FALSE; 1029 mutex_enter(&softmac->smac_mutex); 1030 SOFTMAC_STATE_VERIFY(softmac); 1031 if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) { 1032 /* 1033 * Wait till softmac_create or softmac_mac_register finishes 1034 * Hold the softmac to ensure it stays around. The wait itself 1035 * is done in the caller, since we need to drop all locks 1036 * including the mod hash's internal lock before calling 1037 * cv_wait. 1038 */ 1039 smwp->smw_retry = B_TRUE; 1040 smwp->smw_softmac = softmac; 1041 softmac->smac_hold_cnt++; 1042 return (MH_WALK_TERMINATE); 1043 } 1044 1045 if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) || 1046 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { 1047 mutex_exit(&softmac->smac_mutex); 1048 return (MH_WALK_CONTINUE); 1049 } 1050 1051 if (dls_mgmt_create(softmac->smac_devname, 1052 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 1053 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { 1054 mutex_exit(&softmac->smac_mutex); 1055 return (MH_WALK_CONTINUE); 1056 } 1057 1058 if ((err = softmac_update_info(softmac, &linkid)) != 0) { 1059 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " 1060 "failed (%d)", softmac->smac_devname, err); 1061 mutex_exit(&softmac->smac_mutex); 1062 return (MH_WALK_CONTINUE); 1063 } 1064 1065 /* 1066 * Create a link for this MAC. The link name will be the same 1067 * as the MAC name. 1068 */ 1069 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 1070 err = dls_devnet_recreate(softmac->smac_mh, linkid); 1071 if (err != 0) { 1072 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " 1073 "%s (linkid %d) failed (%d)", 1074 softmac->smac_devname, linkid, err); 1075 } 1076 } 1077 1078 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; 1079 mutex_exit(&softmac->smac_mutex); 1080 1081 return (MH_WALK_CONTINUE); 1082 } 1083 1084 /* 1085 * See comments above softmac_mac_recreate(). 1086 */ 1087 void 1088 softmac_recreate() 1089 { 1090 softmac_walk_t smw; 1091 softmac_t *softmac; 1092 1093 /* 1094 * Walk through the softmac_hash table. Request to create the 1095 * [link name, linkid] mapping if we failed to do so. 1096 */ 1097 do { 1098 smw.smw_retry = B_FALSE; 1099 rw_enter(&softmac_hash_lock, RW_READER); 1100 mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw); 1101 rw_exit(&softmac_hash_lock); 1102 if (smw.smw_retry) { 1103 /* 1104 * softmac_create or softmac_mac_register hasn't yet 1105 * finished and the softmac is not yet in the 1106 * SOFTMAC_ATTACH_DONE state. 1107 */ 1108 softmac = smw.smw_softmac; 1109 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1110 softmac->smac_hold_cnt--; 1111 mutex_exit(&softmac->smac_mutex); 1112 } 1113 } while (smw.smw_retry); 1114 } 1115 1116 /* ARGSUSED */ 1117 static int 1118 softmac_m_start(void *arg) 1119 { 1120 return (0); 1121 } 1122 1123 /* ARGSUSED */ 1124 static void 1125 softmac_m_stop(void *arg) 1126 { 1127 } 1128 1129 /* 1130 * Set up the lower stream above the legacy device which is shared by 1131 * GLDv3 MAC clients. Put the lower stream into DLIOCRAW mode to send 1132 * and receive the raw data. Further, put the lower stream into 1133 * DL_PROMISC_SAP mode to receive all packets of interest. 1134 */ 1135 static int 1136 softmac_lower_setup(softmac_t *softmac, softmac_lower_t **slpp) 1137 { 1138 ldi_ident_t li; 1139 dev_t dev; 1140 ldi_handle_t lh = NULL; 1141 softmac_lower_t *slp = NULL; 1142 smac_ioc_start_t start_arg; 1143 struct strioctl strioc; 1144 uint32_t notifications; 1145 int err, rval; 1146 1147 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) 1148 return (err); 1149 1150 dev = softmac->smac_dev; 1151 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 1152 ldi_ident_release(li); 1153 if (err != 0) 1154 goto done; 1155 1156 /* 1157 * Pop all the intermediate modules. The autopushed modules will 1158 * be pushed when the softmac node is opened. 1159 */ 1160 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 1161 ; 1162 1163 if ((softmac->smac_style == DL_STYLE2) && 1164 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { 1165 goto done; 1166 } 1167 1168 /* 1169 * Put the lower stream into DLIOCRAW mode to send/receive raw data. 1170 */ 1171 if ((err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, kcred, &rval)) != 0) 1172 goto done; 1173 1174 /* 1175 * Then push the softmac shim layer atop the lower stream. 1176 */ 1177 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, 1178 kcred, &rval)) != 0) { 1179 goto done; 1180 } 1181 1182 /* 1183 * Send the ioctl to get the slp pointer. 1184 */ 1185 strioc.ic_cmd = SMAC_IOC_START; 1186 strioc.ic_timout = INFTIM; 1187 strioc.ic_len = sizeof (start_arg); 1188 strioc.ic_dp = (char *)&start_arg; 1189 1190 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, 1191 kcred, &rval)) != 0) { 1192 goto done; 1193 } 1194 slp = start_arg.si_slp; 1195 slp->sl_lh = lh; 1196 slp->sl_softmac = softmac; 1197 *slpp = slp; 1198 1199 /* 1200 * Bind to SAP 2 on token ring, 0 on other interface types. 1201 * (SAP 0 has special significance on token ring). 1202 * Note that the receive-side packets could come anytime after bind. 1203 */ 1204 if (softmac->smac_media == DL_TPR) 1205 err = softmac_send_bind_req(slp, 2); 1206 else 1207 err = softmac_send_bind_req(slp, 0); 1208 if (err != 0) 1209 goto done; 1210 1211 /* 1212 * Put the lower stream into DL_PROMISC_SAP mode to receive all 1213 * packets of interest. 1214 * 1215 * Some drivers (e.g. the old legacy eri driver) incorrectly pass up 1216 * packets to DL_PROMISC_SAP stream when the lower stream is not bound, 1217 * so we send DL_PROMISON_REQ after DL_BIND_REQ. 1218 */ 1219 if ((err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE)) != 0) 1220 goto done; 1221 1222 /* 1223 * Enable the capabilities the underlying driver claims to support. 1224 * Some drivers require this to be called after the stream is bound. 1225 */ 1226 if ((err = softmac_capab_enable(slp)) != 0) 1227 goto done; 1228 1229 /* 1230 * Send the DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. 1231 * We don't have to wait for the ack. 1232 */ 1233 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | 1234 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | 1235 DL_NOTE_PROMISC_OFF_PHYS; 1236 1237 (void) softmac_send_notify_req(slp, 1238 (notifications & softmac->smac_notifications)); 1239 1240 done: 1241 if (err != 0) 1242 (void) ldi_close(lh, FREAD|FWRITE, kcred); 1243 return (err); 1244 } 1245 1246 static int 1247 softmac_m_open(void *arg) 1248 { 1249 softmac_t *softmac = arg; 1250 softmac_lower_t *slp; 1251 int err; 1252 1253 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1254 ASSERT(softmac->smac_lower_state == SOFTMAC_INITIALIZED); 1255 1256 if ((err = softmac_lower_setup(softmac, &slp)) != 0) 1257 return (err); 1258 1259 softmac->smac_lower = slp; 1260 softmac->smac_lower_state = SOFTMAC_READY; 1261 return (0); 1262 } 1263 1264 static void 1265 softmac_m_close(void *arg) 1266 { 1267 softmac_t *softmac = arg; 1268 softmac_lower_t *slp; 1269 1270 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1271 ASSERT(softmac->smac_lower_state == SOFTMAC_READY); 1272 slp = softmac->smac_lower; 1273 ASSERT(slp != NULL); 1274 1275 /* 1276 * Note that slp is destroyed when lh is closed. 1277 */ 1278 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); 1279 softmac->smac_lower_state = SOFTMAC_INITIALIZED; 1280 softmac->smac_lower = NULL; 1281 } 1282 1283 int 1284 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) 1285 { 1286 dev_info_t *dip; 1287 const char *drvname; 1288 char devname[MAXNAMELEN]; 1289 softmac_t *softmac; 1290 int ppa, err; 1291 1292 if ((ppa = getminor(dev) - 1) > 1000) 1293 return (ENOENT); 1294 1295 /* 1296 * First try to hold this device instance to force the MAC 1297 * to be registered. 1298 */ 1299 if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL) 1300 return (ENOENT); 1301 1302 drvname = ddi_driver_name(dip); 1303 1304 /* 1305 * Exclude non-physical network device instances, for example, aggr0. 1306 */ 1307 if ((ddi_driver_major(dip) != getmajor(dev)) || 1308 !NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) || 1309 (strcmp(drvname, "vnic") == 0)) { 1310 ddi_release_devi(dip); 1311 return (ENOENT); 1312 } 1313 1314 /* 1315 * This is a network device; wait for its softmac to be registered. 1316 */ 1317 (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa); 1318 again: 1319 rw_enter(&softmac_hash_lock, RW_READER); 1320 1321 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 1322 (mod_hash_val_t *)&softmac) != 0) { 1323 /* 1324 * This is rare but possible. It could happen when pre-detach 1325 * routine of the device succeeds. But the softmac will then 1326 * be recreated when device fails to detach (as this device 1327 * is held). 1328 */ 1329 mutex_enter(&smac_global_lock); 1330 rw_exit(&softmac_hash_lock); 1331 cv_wait(&smac_global_cv, &smac_global_lock); 1332 mutex_exit(&smac_global_lock); 1333 goto again; 1334 } 1335 1336 /* 1337 * Bump smac_hold_cnt to prevent device detach. 1338 */ 1339 mutex_enter(&softmac->smac_mutex); 1340 softmac->smac_hold_cnt++; 1341 rw_exit(&softmac_hash_lock); 1342 1343 /* 1344 * Wait till the device is fully attached. 1345 */ 1346 while (softmac->smac_state != SOFTMAC_ATTACH_DONE) 1347 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1348 1349 SOFTMAC_STATE_VERIFY(softmac); 1350 1351 if ((err = softmac->smac_attacherr) != 0) 1352 softmac->smac_hold_cnt--; 1353 else 1354 *ddhp = (dls_dev_handle_t)softmac; 1355 mutex_exit(&softmac->smac_mutex); 1356 1357 ddi_release_devi(dip); 1358 return (err); 1359 } 1360 1361 void 1362 softmac_rele_device(dls_dev_handle_t ddh) 1363 { 1364 softmac_t *softmac; 1365 1366 if (ddh == NULL) 1367 return; 1368 1369 softmac = (softmac_t *)ddh; 1370 mutex_enter(&softmac->smac_mutex); 1371 softmac->smac_hold_cnt--; 1372 mutex_exit(&softmac->smac_mutex); 1373 } 1374