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