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