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