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