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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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.
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;
39 * This softmac will be destroyed during the device's pre-detach process,
40 * and all the above will be undone.
43 #include <sys/types.h>
47 #include <sys/mac_provider.h>
49 #include <sys/sunndi.h>
50 #include <sys/modhash.h>
51 #include <sys/stropts.h>
52 #include <sys/sysmacros.h>
54 #include <sys/softmac_impl.h>
55 #include <sys/softmac.h>
58 /* Used as a parameter to the mod hash walk of softmac structures */
60 softmac_t
*smw_softmac
;
65 * Softmac hash table including softmacs for both style-2 and style-1 devices.
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
;
72 static kmem_cache_t
*softmac_cachep
;
74 #define SOFTMAC_HASHSZ 64
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
,
88 static void softmac_m_propinfo(void *, const char *, mac_prop_id_t
,
89 mac_prop_info_handle_t
);
91 #define SOFTMAC_M_CALLBACK_FLAGS \
92 (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE | MC_SETPROP | \
93 MC_GETPROP | MC_PROPINFO)
95 static mac_callbacks_t softmac_m_callbacks
= {
96 SOFTMAC_M_CALLBACK_FLAGS
,
116 softmac_constructor(void *buf
, void *arg
, int kmflag
)
118 softmac_t
*softmac
= buf
;
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
));
133 softmac_destructor(void *buf
, void *arg
)
135 softmac_t
*softmac
= buf
;
137 ASSERT(softmac
->smac_fp_disable_clients
== 0);
138 ASSERT(!softmac
->smac_fastpath_admin_disabled
);
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_lower
== NULL
);
147 ASSERT(softmac
->smac_active
== B_FALSE
);
148 ASSERT(softmac
->smac_nactive
== 0);
149 ASSERT(list_is_empty(&softmac
->smac_sup_list
));
151 list_destroy(&softmac
->smac_sup_list
);
152 mutex_destroy(&softmac
->smac_mutex
);
153 mutex_destroy(&softmac
->smac_active_mutex
);
154 mutex_destroy(&softmac
->smac_fp_mutex
);
155 cv_destroy(&softmac
->smac_cv
);
156 cv_destroy(&softmac
->smac_fp_cv
);
162 softmac_hash
= mod_hash_create_extended("softmac_hash",
163 SOFTMAC_HASHSZ
, mod_hash_null_keydtor
, mod_hash_null_valdtor
,
164 mod_hash_bystr
, NULL
, mod_hash_strkey_cmp
, KM_SLEEP
);
166 rw_init(&softmac_hash_lock
, NULL
, RW_DEFAULT
, NULL
);
167 mutex_init(&smac_global_lock
, NULL
, MUTEX_DRIVER
, NULL
);
168 cv_init(&smac_global_cv
, NULL
, CV_DRIVER
, NULL
);
170 softmac_cachep
= kmem_cache_create("softmac_cache",
171 sizeof (softmac_t
), 0, softmac_constructor
,
172 softmac_destructor
, NULL
, NULL
, NULL
, 0);
173 ASSERT(softmac_cachep
!= NULL
);
181 kmem_cache_destroy(softmac_cachep
);
182 rw_destroy(&softmac_hash_lock
);
183 mod_hash_destroy_hash(softmac_hash
);
184 mutex_destroy(&smac_global_lock
);
185 cv_destroy(&smac_global_cv
);
190 softmac_exist(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
192 boolean_t
*pexist
= arg
;
195 return (MH_WALK_TERMINATE
);
201 boolean_t exist
= B_FALSE
;
203 rw_enter(&softmac_hash_lock
, RW_READER
);
204 mod_hash_walk(softmac_hash
, softmac_exist
, &exist
);
205 rw_exit(&softmac_hash_lock
);
211 * softmac_create() is called for each minor node during the post-attach of
212 * each DDI_NT_NET device instance. Note that it is possible that a device
213 * instance has two minor nodes (DLPI style-1 and style-2), so that for that
214 * specific device, softmac_create() could be called twice.
216 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t
217 * is created to track each minor node.
219 * For each minor node of a legacy device, a taskq is started to finish
220 * softmac_mac_register(), which will finish the rest of work (see comments
221 * above softmac_mac_register()).
223 * softmac state machine
224 * --------------------------------------------------------------------------
225 * OLD STATE EVENT NEW STATE
226 * --------------------------------------------------------------------------
227 * UNINIT attach of 1st minor node ATTACH_INPROG
228 * okcnt = 0 net_postattach -> softmac_create okcnt = 1
230 * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE
231 * okcnt = 1 net_postattach -> softmac_create okcnt = 2
233 * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG
234 * okcnt = 1 net_postattach -> softmac_create okcnt = 2
235 * schedule softmac_mac_register
237 * ATTACH_INPROG legacy device node ATTACH_DONE
238 * okcnt = 2 softmac_mac_register okcnt = 2
240 * ATTACH_DONE detach of 1st minor node DETACH_INPROG
241 * okcnt = 2 (success) okcnt = 1
243 * DETACH_INPROG detach of 2nd minor node UNINIT (or free)
244 * okcnt = 1 (success) okcnt = 0
246 * ATTACH_DONE detach failure state unchanged
247 * DETACH_INPROG left = okcnt
249 * DETACH_INPROG reattach ATTACH_INPROG
250 * okcnt = 0,1 net_postattach -> softmac_create
252 * ATTACH_DONE reattach ATTACH_DONE
253 * left != 0 net_postattach -> softmac_create left = 0
255 * Abbreviation notes:
256 * states have SOFTMAC_ prefix,
257 * okcnt - softmac_attach_okcnt,
258 * left - softmac_attached_left
263 softmac_state_verify(softmac_t
*softmac
)
265 ASSERT(MUTEX_HELD(&softmac
->smac_mutex
));
268 * There are at most 2 minor nodes, one per DLPI style
270 ASSERT(softmac
->smac_cnt
<= 2 && softmac
->smac_attachok_cnt
<= 2);
273 * The smac_attachok_cnt represents the number of attaches i.e. the
274 * number of times net_postattach -> softmac_create() has been called
275 * for a device instance.
277 ASSERT(softmac
->smac_attachok_cnt
== SMAC_NONZERO_NODECNT(softmac
));
280 * softmac_create (or softmac_mac_register) -> softmac_create_datalink
281 * happens only after all minor nodes have been attached
283 ASSERT(softmac
->smac_state
!= SOFTMAC_ATTACH_DONE
||
284 softmac
->smac_attachok_cnt
== softmac
->smac_cnt
);
286 if (softmac
->smac_attachok_cnt
== 0) {
287 ASSERT(softmac
->smac_state
== SOFTMAC_UNINIT
);
288 ASSERT(softmac
->smac_mh
== NULL
);
289 } else if (softmac
->smac_attachok_cnt
< softmac
->smac_cnt
) {
290 ASSERT(softmac
->smac_state
== SOFTMAC_ATTACH_INPROG
||
291 softmac
->smac_state
== SOFTMAC_DETACH_INPROG
);
292 ASSERT(softmac
->smac_mh
== NULL
);
295 * In the stable condition the state whould be
296 * SOFTMAC_ATTACH_DONE. But there is a small transient window
297 * in softmac_destroy where we change the state to
298 * SOFTMAC_DETACH_INPROG and drop the lock before doing
301 ASSERT(softmac
->smac_attachok_cnt
== softmac
->smac_cnt
);
302 ASSERT(softmac
->smac_state
!= SOFTMAC_UNINIT
);
304 if (softmac
->smac_mh
!= NULL
)
305 ASSERT(softmac
->smac_attachok_cnt
== softmac
->smac_cnt
);
310 #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac)
312 #define SOFTMAC_STATE_VERIFY(softmac)
316 softmac_create(dev_info_t
*dip
, dev_t dev
)
318 char devname
[MAXNAMELEN
];
320 softmac_dev_t
*softmac_dev
= NULL
;
325 * Force the softmac driver to be attached.
327 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME
) == NULL
) {
328 cmn_err(CE_WARN
, "softmac_create:softmac attach fails");
332 if (GLDV3_DRV(ddi_driver_major(dip
))) {
333 minor_t minor
= getminor(dev
);
335 * For GLDv3, we don't care about the DLPI style 2
336 * compatibility node. (We know that all such devices
337 * have style 1 nodes.)
339 if ((strcmp(ddi_driver_name(dip
), "clone") == 0) ||
340 (getmajor(dev
) == ddi_name_to_major("clone")) ||
346 * Likewise, we know that the minor number for DLPI style 1
347 * nodes is constrained to a maximum value.
349 if (minor
>= DLS_MAX_MINOR
) {
353 * Otherwise we can decode the instance from the minor number,
354 * which allows for situations with multiple mac instances
355 * for a single dev_info_t.
357 ppa
= DLS_MINOR2INST(minor
);
360 * For legacy drivers, we just have to limit them to
361 * two minor nodes, one style 1 and one style 2, and
362 * we assume the ddi_get_instance() is the PPA.
363 * Drivers that need more flexibility should be ported
366 ppa
= ddi_get_instance(dip
);
367 if (i_ddi_minor_node_count(dip
, DDI_NT_NET
) > 2) {
368 cmn_err(CE_WARN
, "%s has more than 2 minor nodes; "
369 "unsupported", devname
);
374 (void) snprintf(devname
, MAXNAMELEN
, "%s%d", ddi_driver_name(dip
), ppa
);
377 * Check whether the softmac for the specified device already exists
379 rw_enter(&softmac_hash_lock
, RW_WRITER
);
380 if ((mod_hash_find(softmac_hash
, (mod_hash_key_t
)devname
,
381 (mod_hash_val_t
*)&softmac
)) != 0) {
383 softmac
= kmem_cache_alloc(softmac_cachep
, KM_SLEEP
);
384 (void) strlcpy(softmac
->smac_devname
, devname
, MAXNAMELEN
);
386 err
= mod_hash_insert(softmac_hash
,
387 (mod_hash_key_t
)softmac
->smac_devname
,
388 (mod_hash_val_t
)softmac
);
390 mutex_enter(&smac_global_lock
);
391 cv_broadcast(&smac_global_cv
);
392 mutex_exit(&smac_global_lock
);
395 mutex_enter(&softmac
->smac_mutex
);
396 SOFTMAC_STATE_VERIFY(softmac
);
397 if (softmac
->smac_state
!= SOFTMAC_ATTACH_DONE
)
398 softmac
->smac_state
= SOFTMAC_ATTACH_INPROG
;
399 if (softmac
->smac_attachok_cnt
== 0) {
401 * Initialize the softmac if this is the post-attach of the
404 softmac
->smac_flags
= 0;
405 softmac
->smac_umajor
= ddi_driver_major(dip
);
406 softmac
->smac_uppa
= ppa
;
409 * For GLDv3, we ignore the style 2 node (see the logic
410 * above on that), and we should have exactly one attach
411 * per MAC instance (possibly more than one per dev_info_t).
413 if (GLDV3_DRV(ddi_driver_major(dip
))) {
414 softmac
->smac_flags
|= SOFTMAC_GLDV3
;
415 softmac
->smac_cnt
= 1;
418 i_ddi_minor_node_count(dip
, DDI_NT_NET
);
422 index
= (getmajor(dev
) == ddi_name_to_major("clone"));
423 if (softmac
->smac_softmac
[index
] != NULL
) {
425 * This is possible if the post_attach() is called after
426 * pre_detach() fails. This seems to be a defect of the DACF
427 * framework. We work around it by using a smac_attached_left
428 * field that tracks this
430 ASSERT(softmac
->smac_attached_left
!= 0);
431 softmac
->smac_attached_left
--;
432 mutex_exit(&softmac
->smac_mutex
);
433 rw_exit(&softmac_hash_lock
);
437 mutex_exit(&softmac
->smac_mutex
);
438 rw_exit(&softmac_hash_lock
);
440 softmac_dev
= kmem_zalloc(sizeof (softmac_dev_t
), KM_SLEEP
);
441 softmac_dev
->sd_dev
= dev
;
443 mutex_enter(&softmac
->smac_mutex
);
444 softmac
->smac_softmac
[index
] = softmac_dev
;
446 * Continue to register the mac and create the datalink only when all
447 * the minor nodes are attached.
449 if (++softmac
->smac_attachok_cnt
!= softmac
->smac_cnt
) {
450 mutex_exit(&softmac
->smac_mutex
);
455 * All of the minor nodes have been attached; start a taskq
456 * to do the rest of the work. We use a taskq instead of
457 * doing the work here because:
459 * We could be called as a result of a open() system call
460 * where spec_open() already SLOCKED the snode. Using a taskq
461 * sidesteps the risk that our ldi_open_by_dev() call would
462 * deadlock trying to set SLOCKED on the snode again.
464 * The devfs design requires that the downcalls don't use any
465 * interruptible cv_wait which happens when we do door upcalls.
466 * Otherwise the downcalls which may be holding devfs resources
467 * may cause a deadlock if the thread is stopped. Also we need to make
468 * sure these downcalls into softmac_create or softmac_destroy
469 * don't cv_wait on any devfs related condition. Thus softmac_destroy
470 * returns EBUSY if the asynchronous threads started in softmac_create
473 (void) taskq_dispatch(system_taskq
, softmac_create_task
,
475 mutex_exit(&softmac
->smac_mutex
);
480 softmac_m_getcapab(void *arg
, mac_capab_t cap
, void *cap_data
)
482 softmac_t
*softmac
= arg
;
484 if (!(softmac
->smac_capab_flags
& cap
))
488 case MAC_CAPAB_HCKSUM
: {
489 uint32_t *txflags
= cap_data
;
491 *txflags
= softmac
->smac_hcksum_txflags
;
494 case MAC_CAPAB_LEGACY
: {
495 mac_capab_legacy_t
*legacy
= cap_data
;
498 * The caller is not interested in the details.
503 legacy
->ml_unsup_note
= ~softmac
->smac_notifications
&
504 (DL_NOTE_LINK_UP
| DL_NOTE_LINK_DOWN
| DL_NOTE_SPEED
);
505 legacy
->ml_active_set
= softmac_active_set
;
506 legacy
->ml_active_clear
= softmac_active_clear
;
507 legacy
->ml_fastpath_disable
= softmac_fastpath_disable
;
508 legacy
->ml_fastpath_enable
= softmac_fastpath_enable
;
509 legacy
->ml_dev
= makedevice(softmac
->smac_umajor
,
510 softmac
->smac_uppa
+ 1);
515 * For the capabilities below, there's nothing for us to fill in;
516 * simply return B_TRUE if we support it.
518 case MAC_CAPAB_NO_ZCOPY
:
519 case MAC_CAPAB_NO_NATIVEVLAN
:
527 softmac_update_info(softmac_t
*softmac
, datalink_id_t
*linkidp
)
529 datalink_id_t linkid
= DATALINK_INVALID_LINKID
;
533 if ((err
= dls_mgmt_update(softmac
->smac_devname
, softmac
->smac_media
,
534 softmac
->smac_flags
& SOFTMAC_NOSUPP
, &media
, &linkid
)) == 0) {
540 * There is a link name conflict. Either:
542 * - An existing link with the same device name with a
543 * different media type from of the given type.
544 * Mark this link back to persistent only; or
546 * - We cannot assign the "suggested" name because
547 * GLDv3 and therefore vanity naming is not supported
548 * for this link type. Delete this link's <link name,
551 if (media
!= softmac
->smac_media
) {
552 cmn_err(CE_WARN
, "%s device %s conflicts with "
553 "existing %s device %s.",
554 dl_mactypestr(softmac
->smac_media
),
555 softmac
->smac_devname
, dl_mactypestr(media
),
556 softmac
->smac_devname
);
557 (void) dls_mgmt_destroy(linkid
, B_FALSE
);
559 cmn_err(CE_WARN
, "link name %s is already in-use.",
560 softmac
->smac_devname
);
561 (void) dls_mgmt_destroy(linkid
, B_TRUE
);
564 cmn_err(CE_WARN
, "%s device might not be available "
565 "for use.", softmac
->smac_devname
);
566 cmn_err(CE_WARN
, "See dladm(8) for more information.");
574 * 1. provides the link's media type to dlmgmtd.
575 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
578 softmac_create_datalink(softmac_t
*softmac
)
580 datalink_id_t linkid
= DATALINK_INVALID_LINKID
;
584 * Inform dlmgmtd of this link so that softmac_hold_device() is able
585 * to know the existence of this link. If this failed with EBADF,
586 * it might be because dlmgmtd was not started in time (e.g.,
587 * diskless boot); ignore the failure and continue to create
588 * the GLDv3 datalink if needed.
590 err
= dls_mgmt_create(softmac
->smac_devname
,
591 makedevice(softmac
->smac_umajor
, softmac
->smac_uppa
+ 1),
592 DATALINK_CLASS_PHYS
, DL_OTHER
, B_TRUE
, &linkid
);
593 if (err
!= 0 && err
!= EBADF
)
597 * Provide the media type of the physical link to dlmgmtd.
599 if ((err
!= EBADF
) &&
600 ((err
= softmac_update_info(softmac
, &linkid
)) != 0)) {
605 * Create the GLDv3 datalink.
607 if (!(softmac
->smac_flags
& SOFTMAC_NOSUPP
)) {
608 err
= dls_devnet_create(softmac
->smac_mh
, linkid
,
609 crgetzoneid(CRED()));
611 cmn_err(CE_WARN
, "dls_devnet_create failed for %s",
612 softmac
->smac_devname
);
617 if (linkid
== DATALINK_INVALID_LINKID
) {
618 mutex_enter(&softmac
->smac_mutex
);
619 softmac
->smac_flags
|= SOFTMAC_NEED_RECREATE
;
620 mutex_exit(&softmac
->smac_mutex
);
627 softmac_create_task(void *arg
)
629 softmac_t
*softmac
= arg
;
633 if (!GLDV3_DRV(softmac
->smac_umajor
)) {
634 softmac_mac_register(softmac
);
638 if ((err
= mac_open(softmac
->smac_devname
, &mh
)) != 0)
641 mutex_enter(&softmac
->smac_mutex
);
642 softmac
->smac_media
= (mac_info(mh
))->mi_nativemedia
;
643 softmac
->smac_mh
= mh
;
644 mutex_exit(&softmac
->smac_mutex
);
647 * We can safely release the reference on the mac because
648 * this mac will only be unregistered and destroyed when
649 * the device detaches, and the softmac will be destroyed
650 * before then (in the pre-detach routine of the device).
655 * Create the GLDv3 datalink for this mac.
657 err
= softmac_create_datalink(softmac
);
660 mutex_enter(&softmac
->smac_mutex
);
662 softmac
->smac_mh
= NULL
;
663 softmac
->smac_attacherr
= err
;
664 softmac
->smac_state
= SOFTMAC_ATTACH_DONE
;
665 cv_broadcast(&softmac
->smac_cv
);
666 mutex_exit(&softmac
->smac_mutex
);
670 * This function is only called for legacy devices. It:
671 * 1. registers the MAC for the legacy devices whose media type is supported
672 * by the GLDv3 framework.
673 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
676 softmac_mac_register(softmac_t
*softmac
)
678 softmac_dev_t
*softmac_dev
;
680 ldi_handle_t lh
= NULL
;
681 ldi_ident_t li
= NULL
;
683 boolean_t native_vlan
= B_FALSE
;
687 * Note that we do not need any locks to access this softmac pointer,
688 * as softmac_destroy() will wait until this function is called.
690 ASSERT(softmac
!= NULL
);
691 ASSERT(softmac
->smac_state
== SOFTMAC_ATTACH_INPROG
&&
692 softmac
->smac_attachok_cnt
== softmac
->smac_cnt
);
694 if ((err
= ldi_ident_from_dip(softmac_dip
, &li
)) != 0) {
695 mutex_enter(&softmac
->smac_mutex
);
700 * Determine whether this legacy device support VLANs by opening
701 * the style-2 device node (if it exists) and attaching to a VLAN
704 dev
= makedevice(ddi_name_to_major("clone"), softmac
->smac_umajor
);
705 err
= ldi_open_by_dev(&dev
, OTYP_CHR
, FREAD
|FWRITE
, kcred
, &lh
, li
);
707 if (dl_attach(lh
, softmac
->smac_uppa
+ 1 * 1000, NULL
) == 0)
708 native_vlan
= B_TRUE
;
709 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
713 for (index
= 0; index
< 2; index
++) {
717 struct strioctl iocb
;
721 if ((softmac_dev
= softmac
->smac_softmac
[index
]) == NULL
)
724 softmac
->smac_dev
= dev
= softmac_dev
->sd_dev
;
725 if (ldi_open_by_dev(&dev
, OTYP_CHR
, FREAD
|FWRITE
, kcred
, &lh
,
731 * Pop all the intermediate modules in order to negotiate
732 * capabilities correctly.
734 while (ldi_ioctl(lh
, I_POP
, 0, FKIOCTL
, kcred
, &rval
) == 0)
737 /* DLPI style-1 or DLPI style-2? */
738 if ((rval
= dl_info(lh
, &dlia
, NULL
, NULL
, &dlea
)) != 0) {
739 if (rval
== ENOTSUP
) {
740 cmn_err(CE_NOTE
, "softmac: received "
741 "DL_ERROR_ACK to DL_INFO_ACK; "
742 "DLPI errno 0x%x, UNIX errno %d",
743 dlea
.dl_errno
, dlea
.dl_unix_errno
);
745 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
750 * Currently only DL_ETHER has GLDv3 mac plugin support.
751 * For media types that GLDv3 does not support, create a
754 if ((softmac
->smac_media
= dlia
.dl_mac_type
) != DL_ETHER
) {
755 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
760 if ((dlia
.dl_provider_style
== DL_STYLE2
) &&
761 (dl_attach(lh
, softmac
->smac_uppa
, NULL
) != 0)) {
762 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
766 if ((rval
= dl_bind(lh
, 0, NULL
)) != 0) {
767 if (rval
== ENOTSUP
) {
768 cmn_err(CE_NOTE
, "softmac: received "
769 "DL_ERROR_ACK to DL_BIND_ACK; "
770 "DLPI errno 0x%x, UNIX errno %d",
771 dlea
.dl_errno
, dlea
.dl_unix_errno
);
773 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
778 * Call dl_info() after dl_bind() because some drivers only
779 * provide correct information (e.g. MAC address) once bound.
781 softmac
->smac_addrlen
= sizeof (softmac
->smac_unicst_addr
);
782 if ((rval
= dl_info(lh
, &dlia
, softmac
->smac_unicst_addr
,
783 &softmac
->smac_addrlen
, &dlea
)) != 0) {
784 if (rval
== ENOTSUP
) {
785 cmn_err(CE_NOTE
, "softmac: received "
786 "DL_ERROR_ACK to DL_INFO_ACK; "
787 "DLPI errno 0x%x, UNIX errno %d",
788 dlea
.dl_errno
, dlea
.dl_unix_errno
);
790 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
794 softmac
->smac_style
= dlia
.dl_provider_style
;
795 softmac
->smac_saplen
= ABS(dlia
.dl_sap_length
);
796 softmac
->smac_min_sdu
= dlia
.dl_min_sdu
;
797 softmac
->smac_max_sdu
= dlia
.dl_max_sdu
;
799 if ((softmac
->smac_saplen
!= sizeof (uint16_t)) ||
800 (softmac
->smac_addrlen
!= ETHERADDRL
) ||
801 (dlia
.dl_brdcst_addr_length
!= ETHERADDRL
) ||
802 (dlia
.dl_brdcst_addr_offset
== 0)) {
803 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
808 * Check other DLPI capabilities. Note that this must be after
809 * dl_bind() because some drivers return DL_ERROR_ACK if the
810 * stream is not bound. It is also before mac_register(), so
811 * we don't need any lock protection here.
813 softmac
->smac_capab_flags
=
814 (MAC_CAPAB_NO_ZCOPY
| MAC_CAPAB_LEGACY
);
816 softmac
->smac_no_capability_req
= B_FALSE
;
817 if (softmac_fill_capab(lh
, softmac
) != 0)
818 softmac
->smac_no_capability_req
= B_TRUE
;
821 * Check the margin of the underlying driver.
824 iocb
.ic_cmd
= DLIOCMARGININFO
;
825 iocb
.ic_timout
= INFTIM
;
826 iocb
.ic_len
= sizeof (margin
);
827 iocb
.ic_dp
= (char *)&margin
;
828 softmac
->smac_margin
= 0;
830 if (ldi_ioctl(lh
, I_STR
, (intptr_t)&iocb
, FKIOCTL
, kcred
,
832 softmac
->smac_margin
= margin
;
836 * If the legacy driver doesn't support DLIOCMARGININFO, but
837 * it can support native VLAN, correct its margin value to 4.
840 if (softmac
->smac_margin
== 0)
841 softmac
->smac_margin
= VLAN_TAGSZ
;
843 softmac
->smac_capab_flags
|= MAC_CAPAB_NO_NATIVEVLAN
;
847 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP.
849 softmac
->smac_notifications
= 0;
850 notes
= DL_NOTE_PHYS_ADDR
| DL_NOTE_LINK_UP
| DL_NOTE_LINK_DOWN
;
851 switch (dl_notify(lh
, ¬es
, NULL
)) {
853 softmac
->smac_notifications
= notes
;
858 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
862 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
866 ldi_ident_release(li
);
868 mutex_enter(&softmac
->smac_mutex
);
873 if (softmac
->smac_media
!= DL_ETHER
)
874 softmac
->smac_flags
|= SOFTMAC_NOSUPP
;
877 * Finally, we're ready to register ourselves with the MAC layer
878 * interface; if this succeeds, we're all ready to start()
880 if (!(softmac
->smac_flags
& SOFTMAC_NOSUPP
)) {
881 mac_register_t
*macp
;
883 if ((macp
= mac_alloc(MAC_VERSION
)) == NULL
) {
888 macp
->m_type_ident
= MAC_PLUGIN_IDENT_ETHER
;
889 macp
->m_driver
= softmac
;
890 macp
->m_dip
= softmac_dip
;
892 macp
->m_margin
= softmac
->smac_margin
;
893 macp
->m_src_addr
= softmac
->smac_unicst_addr
;
894 macp
->m_min_sdu
= softmac
->smac_min_sdu
;
895 macp
->m_max_sdu
= softmac
->smac_max_sdu
;
896 macp
->m_callbacks
= &softmac_m_callbacks
;
897 macp
->m_instance
= (uint_t
)-1;
899 err
= mac_register(macp
, &softmac
->smac_mh
);
902 cmn_err(CE_WARN
, "mac_register failed for %s",
903 softmac
->smac_devname
);
907 mutex_exit(&softmac
->smac_mutex
);
910 * Try to create the datalink for this softmac.
912 if ((err
= softmac_create_datalink(softmac
)) != 0) {
913 if (!(softmac
->smac_flags
& SOFTMAC_NOSUPP
))
914 (void) mac_unregister(softmac
->smac_mh
);
915 mutex_enter(&softmac
->smac_mutex
);
916 softmac
->smac_mh
= NULL
;
920 * If succeed, create the thread which handles the DL_NOTIFY_IND from
923 mutex_enter(&softmac
->smac_mutex
);
924 if (softmac
->smac_mh
!= NULL
) {
925 softmac
->smac_notify_thread
= thread_create(NULL
, 0,
926 softmac_notify_thread
, softmac
, 0, &p0
,
927 TS_RUN
, minclsyspri
);
931 ASSERT(softmac
->smac_state
== SOFTMAC_ATTACH_INPROG
&&
932 softmac
->smac_attachok_cnt
== softmac
->smac_cnt
);
933 softmac
->smac_state
= SOFTMAC_ATTACH_DONE
;
934 softmac
->smac_attacherr
= err
;
935 cv_broadcast(&softmac
->smac_cv
);
936 mutex_exit(&softmac
->smac_mutex
);
940 softmac_destroy(dev_info_t
*dip
, dev_t dev
)
942 char devname
[MAXNAMELEN
];
944 softmac_dev_t
*softmac_dev
;
947 datalink_id_t linkid
;
948 mac_handle_t smac_mh
;
951 if (GLDV3_DRV(ddi_driver_major(dip
))) {
952 minor_t minor
= getminor(dev
);
954 * For an explanation of this logic, see the
955 * equivalent code in softmac_create.
957 if ((strcmp(ddi_driver_name(dip
), "clone") == 0) ||
958 (getmajor(dev
) == ddi_name_to_major("clone")) ||
962 if (minor
>= DLS_MAX_MINOR
) {
965 ppa
= DLS_MINOR2INST(minor
);
967 ppa
= ddi_get_instance(dip
);
970 (void) snprintf(devname
, MAXNAMELEN
, "%s%d", ddi_driver_name(dip
), ppa
);
973 * We are called only from the predetach entry point. The DACF
974 * framework ensures there can't be a concurrent postattach call
975 * for the same softmac. The softmac found out from the modhash
976 * below can't vanish beneath us since this is the only place where
979 err
= mod_hash_find(softmac_hash
, (mod_hash_key_t
)devname
,
980 (mod_hash_val_t
*)&softmac
);
983 mutex_enter(&softmac
->smac_mutex
);
984 SOFTMAC_STATE_VERIFY(softmac
);
987 * Fail the predetach routine if this softmac is in-use.
988 * Make sure these downcalls into softmac_create or softmac_destroy
989 * don't cv_wait on any devfs related condition. Thus softmac_destroy
990 * returns EBUSY if the asynchronous thread started in softmac_create
993 if ((softmac
->smac_hold_cnt
!= 0) ||
994 (softmac
->smac_state
== SOFTMAC_ATTACH_INPROG
)) {
995 softmac
->smac_attached_left
= softmac
->smac_attachok_cnt
;
996 mutex_exit(&softmac
->smac_mutex
);
1001 * Even if the predetach of one minor node has already failed
1002 * (smac_attached_left is not 0), the DACF framework will continue
1003 * to call the predetach routines of the other minor nodes,
1004 * so we fail these calls here.
1006 if (softmac
->smac_attached_left
!= 0) {
1007 mutex_exit(&softmac
->smac_mutex
);
1011 smac_mh
= softmac
->smac_mh
;
1012 smac_flags
= softmac
->smac_flags
;
1013 softmac
->smac_state
= SOFTMAC_DETACH_INPROG
;
1014 mutex_exit(&softmac
->smac_mutex
);
1016 if (smac_mh
!= NULL
) {
1018 * This is the first minor node that is being detached for this
1021 ASSERT(softmac
->smac_attachok_cnt
== softmac
->smac_cnt
);
1022 if (!(smac_flags
& SOFTMAC_NOSUPP
)) {
1023 if ((err
= dls_devnet_destroy(smac_mh
, &linkid
,
1029 * If softmac_mac_register() succeeds in registering the mac
1030 * of the legacy device, unregister it.
1032 if (!(smac_flags
& (SOFTMAC_GLDV3
| SOFTMAC_NOSUPP
))) {
1033 if ((err
= mac_disable_nowait(smac_mh
)) != 0) {
1034 (void) dls_devnet_create(smac_mh
, linkid
,
1035 crgetzoneid(CRED()));
1039 * Ask softmac_notify_thread to quit, and wait for
1042 mutex_enter(&softmac
->smac_mutex
);
1043 softmac
->smac_flags
|= SOFTMAC_NOTIFY_QUIT
;
1044 cv_broadcast(&softmac
->smac_cv
);
1045 while (softmac
->smac_notify_thread
!= NULL
) {
1046 cv_wait(&softmac
->smac_cv
,
1047 &softmac
->smac_mutex
);
1049 mutex_exit(&softmac
->smac_mutex
);
1050 VERIFY(mac_unregister(smac_mh
) == 0);
1052 softmac
->smac_mh
= NULL
;
1058 rw_enter(&softmac_hash_lock
, RW_WRITER
);
1059 mutex_enter(&softmac
->smac_mutex
);
1061 ASSERT(softmac
->smac_state
== SOFTMAC_DETACH_INPROG
&&
1062 softmac
->smac_attachok_cnt
!= 0);
1063 softmac
->smac_mh
= NULL
;
1064 index
= (getmajor(dev
) == ddi_name_to_major("clone"));
1065 softmac_dev
= softmac
->smac_softmac
[index
];
1066 ASSERT(softmac_dev
!= NULL
);
1067 softmac
->smac_softmac
[index
] = NULL
;
1068 kmem_free(softmac_dev
, sizeof (softmac_dev_t
));
1070 if (--softmac
->smac_attachok_cnt
== 0) {
1071 mod_hash_val_t hashval
;
1073 softmac
->smac_state
= SOFTMAC_UNINIT
;
1074 if (softmac
->smac_hold_cnt
!= 0) {
1076 * Someone did a softmac_hold_device while we dropped
1077 * the locks. Leave the softmac itself intact which
1078 * will be reused by the reattach
1080 mutex_exit(&softmac
->smac_mutex
);
1081 rw_exit(&softmac_hash_lock
);
1084 err
= mod_hash_remove(softmac_hash
,
1085 (mod_hash_key_t
)devname
,
1086 (mod_hash_val_t
*)&hashval
);
1089 mutex_exit(&softmac
->smac_mutex
);
1090 rw_exit(&softmac_hash_lock
);
1091 ASSERT(softmac
->smac_fp_disable_clients
== 0);
1092 softmac
->smac_fastpath_admin_disabled
= B_FALSE
;
1093 kmem_cache_free(softmac_cachep
, softmac
);
1096 mutex_exit(&softmac
->smac_mutex
);
1097 rw_exit(&softmac_hash_lock
);
1101 mutex_enter(&softmac
->smac_mutex
);
1102 softmac
->smac_attached_left
= softmac
->smac_attachok_cnt
;
1103 softmac
->smac_state
= SOFTMAC_ATTACH_DONE
;
1104 cv_broadcast(&softmac
->smac_cv
);
1105 mutex_exit(&softmac
->smac_mutex
);
1110 * This function is called as the result of a newly started dlmgmtd daemon.
1112 * We walk through every softmac that was created but failed to notify
1113 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs
1114 * when softmacs are created before dlmgmtd is ready. For example, during
1115 * diskless boot, a network device is used (and therefore attached) before
1116 * the datalink-management service starts dlmgmtd.
1120 softmac_mac_recreate(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
1122 softmac_t
*softmac
= (softmac_t
*)val
;
1123 datalink_id_t linkid
;
1125 softmac_walk_t
*smwp
= arg
;
1128 * The framework itself must not hold any locks across calls to the
1129 * mac perimeter. Thus this function does not call any framework
1130 * function that needs to grab the mac perimeter.
1132 ASSERT(RW_READ_HELD(&softmac_hash_lock
));
1134 smwp
->smw_retry
= B_FALSE
;
1135 mutex_enter(&softmac
->smac_mutex
);
1136 SOFTMAC_STATE_VERIFY(softmac
);
1137 if (softmac
->smac_state
== SOFTMAC_ATTACH_INPROG
) {
1139 * Wait till softmac_create or softmac_mac_register finishes
1140 * Hold the softmac to ensure it stays around. The wait itself
1141 * is done in the caller, since we need to drop all locks
1142 * including the mod hash's internal lock before calling
1145 smwp
->smw_retry
= B_TRUE
;
1146 smwp
->smw_softmac
= softmac
;
1147 softmac
->smac_hold_cnt
++;
1148 return (MH_WALK_TERMINATE
);
1151 if ((softmac
->smac_state
!= SOFTMAC_ATTACH_DONE
) ||
1152 !(softmac
->smac_flags
& SOFTMAC_NEED_RECREATE
)) {
1153 mutex_exit(&softmac
->smac_mutex
);
1154 return (MH_WALK_CONTINUE
);
1158 * Bumping up the smac_hold_cnt allows us to drop the lock. It also
1159 * makes softmac_destroy() return failure on an attempted device detach.
1160 * We don't want to hold the lock across calls to other subsystems
1161 * like kstats, which will happen in the call to dls_devnet_recreate
1163 softmac
->smac_hold_cnt
++;
1164 mutex_exit(&softmac
->smac_mutex
);
1166 if (dls_mgmt_create(softmac
->smac_devname
,
1167 makedevice(softmac
->smac_umajor
, softmac
->smac_uppa
+ 1),
1168 DATALINK_CLASS_PHYS
, softmac
->smac_media
, B_TRUE
, &linkid
) != 0) {
1169 softmac_rele_device((dls_dev_handle_t
)softmac
);
1170 return (MH_WALK_CONTINUE
);
1173 if ((err
= softmac_update_info(softmac
, &linkid
)) != 0) {
1174 cmn_err(CE_WARN
, "softmac: softmac_update_info() for %s "
1175 "failed (%d)", softmac
->smac_devname
, err
);
1176 softmac_rele_device((dls_dev_handle_t
)softmac
);
1177 return (MH_WALK_CONTINUE
);
1181 * Create a link for this MAC. The link name will be the same
1184 if (!(softmac
->smac_flags
& SOFTMAC_NOSUPP
)) {
1185 err
= dls_devnet_recreate(softmac
->smac_mh
, linkid
);
1187 cmn_err(CE_WARN
, "softmac: dls_devnet_recreate() for "
1188 "%s (linkid %d) failed (%d)",
1189 softmac
->smac_devname
, linkid
, err
);
1193 mutex_enter(&softmac
->smac_mutex
);
1194 softmac
->smac_flags
&= ~SOFTMAC_NEED_RECREATE
;
1195 ASSERT(softmac
->smac_hold_cnt
!= 0);
1196 softmac
->smac_hold_cnt
--;
1197 mutex_exit(&softmac
->smac_mutex
);
1199 return (MH_WALK_CONTINUE
);
1203 * See comments above softmac_mac_recreate().
1212 * Walk through the softmac_hash table. Request to create the
1213 * [link name, linkid] mapping if we failed to do so.
1216 smw
.smw_retry
= B_FALSE
;
1217 rw_enter(&softmac_hash_lock
, RW_READER
);
1218 mod_hash_walk(softmac_hash
, softmac_mac_recreate
, &smw
);
1219 rw_exit(&softmac_hash_lock
);
1220 if (smw
.smw_retry
) {
1222 * softmac_create or softmac_mac_register hasn't yet
1223 * finished and the softmac is not yet in the
1224 * SOFTMAC_ATTACH_DONE state.
1226 softmac
= smw
.smw_softmac
;
1227 cv_wait(&softmac
->smac_cv
, &softmac
->smac_mutex
);
1228 softmac
->smac_hold_cnt
--;
1229 mutex_exit(&softmac
->smac_mutex
);
1231 } while (smw
.smw_retry
);
1235 softmac_m_start(void *arg
)
1237 softmac_t
*softmac
= arg
;
1238 softmac_lower_t
*slp
= softmac
->smac_lower
;
1241 ASSERT(MAC_PERIM_HELD(softmac
->smac_mh
));
1243 * Bind to SAP 2 on token ring, 0 on other interface types.
1244 * (SAP 0 has special significance on token ring).
1245 * Note that the receive-side packets could come anytime after bind.
1247 err
= softmac_send_bind_req(slp
, softmac
->smac_media
== DL_TPR
? 2 : 0);
1252 * Put the lower stream to the DL_PROMISC_SAP mode in order to receive
1253 * all packets of interest.
1255 * some driver (e.g. the old legacy eri driver) incorrectly passes up
1256 * packets to DL_PROMISC_SAP stream when the lower stream is not bound,
1257 * so that we send DL_PROMISON_REQ after DL_BIND_REQ.
1259 err
= softmac_send_promisc_req(slp
, DL_PROMISC_SAP
, B_TRUE
);
1261 (void) softmac_send_unbind_req(slp
);
1266 * Enable capabilities the underlying driver claims to support.
1267 * Some driver requires this being called after the stream is bound.
1269 if ((err
= softmac_capab_enable(slp
)) != 0) {
1270 (void) softmac_send_promisc_req(slp
, DL_PROMISC_SAP
, B_FALSE
);
1271 (void) softmac_send_unbind_req(slp
);
1279 softmac_m_stop(void *arg
)
1281 softmac_t
*softmac
= arg
;
1282 softmac_lower_t
*slp
= softmac
->smac_lower
;
1284 ASSERT(MAC_PERIM_HELD(softmac
->smac_mh
));
1287 * It is not needed to reset zerocopy, MDT or HCKSUM capabilities.
1289 (void) softmac_send_promisc_req(slp
, DL_PROMISC_SAP
, B_FALSE
);
1290 (void) softmac_send_unbind_req(slp
);
1294 * Set up the lower stream above the legacy device. There are two different
1295 * type of lower streams:
1297 * - Shared lower-stream
1299 * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW
1300 * mode to send and receive the raw data. Further, put the lower stream into
1301 * DL_PROMISC_SAP mode to receive all packets of interest.
1303 * - Dedicated lower-stream
1305 * The lower-stream which is dedicated to upper IP/ARP stream. This is used
1306 * as fast-path for IP. In this case, the second argument is the pointer to
1307 * the softmac upper-stream.
1310 softmac_lower_setup(softmac_t
*softmac
, softmac_upper_t
*sup
,
1311 softmac_lower_t
**slpp
)
1315 ldi_handle_t lh
= NULL
;
1316 softmac_lower_t
*slp
= NULL
;
1317 smac_ioc_start_t start_arg
;
1318 struct strioctl strioc
;
1319 uint32_t notifications
;
1322 if ((err
= ldi_ident_from_dip(softmac_dip
, &li
)) != 0)
1326 * The GLDv3 framework makes sure that mac_unregister(), mac_open(),
1327 * and mac_close() cannot be called at the same time. So we don't
1328 * need any protection to access softmac here.
1330 dev
= softmac
->smac_dev
;
1332 err
= ldi_open_by_dev(&dev
, OTYP_CHR
, FREAD
|FWRITE
, kcred
, &lh
, li
);
1333 ldi_ident_release(li
);
1338 * Pop all the intermediate modules. The autopushed modules will
1339 * be pushed when the softmac node is opened.
1341 while (ldi_ioctl(lh
, I_POP
, 0, FKIOCTL
, kcred
, &rval
) == 0)
1344 if ((softmac
->smac_style
== DL_STYLE2
) &&
1345 ((err
= dl_attach(lh
, softmac
->smac_uppa
, NULL
)) != 0)) {
1350 * If this is the shared-lower-stream, put the lower stream to
1351 * the DLIOCRAW mode to send/receive raw data.
1353 if ((sup
== NULL
) && (err
= ldi_ioctl(lh
, DLIOCRAW
, 0, FKIOCTL
,
1354 kcred
, &rval
)) != 0) {
1359 * Then push the softmac shim layer atop the lower stream.
1361 if ((err
= ldi_ioctl(lh
, I_PUSH
, (intptr_t)SOFTMAC_DEV_NAME
, FKIOCTL
,
1362 kcred
, &rval
)) != 0) {
1367 * Send the ioctl to get the slp pointer.
1369 strioc
.ic_cmd
= SMAC_IOC_START
;
1370 strioc
.ic_timout
= INFTIM
;
1371 strioc
.ic_len
= sizeof (start_arg
);
1372 strioc
.ic_dp
= (char *)&start_arg
;
1374 if ((err
= ldi_ioctl(lh
, I_STR
, (intptr_t)&strioc
, FKIOCTL
,
1375 kcred
, &rval
)) != 0) {
1378 slp
= start_arg
.si_slp
;
1381 slp
->sl_softmac
= softmac
;
1385 slp
->sl_rxinfo
= &sup
->su_rxinfo
;
1388 * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND.
1389 * We don't have to wait for the ack.
1391 notifications
= DL_NOTE_PHYS_ADDR
| DL_NOTE_LINK_UP
|
1392 DL_NOTE_LINK_DOWN
| DL_NOTE_PROMISC_ON_PHYS
|
1393 DL_NOTE_PROMISC_OFF_PHYS
;
1395 (void) softmac_send_notify_req(slp
,
1396 (notifications
& softmac
->smac_notifications
));
1401 (void) ldi_close(lh
, FREAD
|FWRITE
, kcred
);
1406 softmac_m_open(void *arg
)
1408 softmac_t
*softmac
= arg
;
1409 softmac_lower_t
*slp
;
1412 ASSERT(MAC_PERIM_HELD(softmac
->smac_mh
));
1414 if ((err
= softmac_lower_setup(softmac
, NULL
, &slp
)) != 0)
1417 softmac
->smac_lower
= slp
;
1422 softmac_m_close(void *arg
)
1424 softmac_t
*softmac
= arg
;
1425 softmac_lower_t
*slp
;
1427 ASSERT(MAC_PERIM_HELD(softmac
->smac_mh
));
1428 slp
= softmac
->smac_lower
;
1429 ASSERT(slp
!= NULL
);
1432 * Note that slp is destroyed when lh is closed.
1434 (void) ldi_close(slp
->sl_lh
, FREAD
|FWRITE
, kcred
);
1435 softmac
->smac_lower
= NULL
;
1439 * Softmac supports two priviate link properteis:
1443 * This is a read-only link property which points out the current data-path
1444 * model of the given legacy link. The possible values are "disabled" and
1447 * - "_disable_fastpath"
1449 * This is a read-write link property which can be used to disable or enable
1450 * the fast-path of the given legacy link. The possible values are "true"
1451 * and "false". Note that even when "_disable_fastpath" is set to be
1452 * "false", the fast-path may still not be enabled since there may be
1453 * other mac cleints that request the fast-path to be disabled.
1457 softmac_m_setprop(void *arg
, const char *name
, mac_prop_id_t id
,
1458 uint_t valsize
, const void *val
)
1460 softmac_t
*softmac
= arg
;
1462 if (id
!= MAC_PROP_PRIVATE
|| strcmp(name
, "_disable_fastpath") != 0)
1465 if (strcmp(val
, "true") == 0)
1466 return (softmac_datapath_switch(softmac
, B_TRUE
, B_TRUE
));
1467 else if (strcmp(val
, "false") == 0)
1468 return (softmac_datapath_switch(softmac
, B_FALSE
, B_TRUE
));
1474 softmac_m_getprop(void *arg
, const char *name
, mac_prop_id_t id
,
1475 uint_t valsize
, void *val
)
1477 softmac_t
*softmac
= arg
;
1480 if (id
!= MAC_PROP_PRIVATE
)
1483 if (strcmp(name
, "_fastpath") == 0) {
1484 mutex_enter(&softmac
->smac_fp_mutex
);
1485 fpstr
= (DATAPATH_MODE(softmac
) == SOFTMAC_SLOWPATH
) ?
1486 "disabled" : "enabled";
1487 mutex_exit(&softmac
->smac_fp_mutex
);
1488 } else if (strcmp(name
, "_disable_fastpath") == 0) {
1489 fpstr
= softmac
->smac_fastpath_admin_disabled
?
1491 } else if (strcmp(name
, "_softmac") == 0) {
1497 return (strlcpy(val
, fpstr
, valsize
) >= valsize
? EINVAL
: 0);
1501 softmac_m_propinfo(void *arg
, const char *name
, mac_prop_id_t id
,
1502 mac_prop_info_handle_t prh
)
1504 _NOTE(ARGUNUSED(arg
));
1506 if (id
!= MAC_PROP_PRIVATE
)
1509 if (strcmp(name
, "_fastpath") == 0) {
1510 mac_prop_info_set_perm(prh
, MAC_PROP_PERM_READ
);
1511 } else if (strcmp(name
, "_disable_fastpath") == 0) {
1512 mac_prop_info_set_default_str(prh
, "false");
1518 softmac_hold_device(dev_t dev
, dls_dev_handle_t
*ddhp
)
1521 char devname
[MAXNAMELEN
];
1524 int ppa
, err
= 0, inst
;
1526 major
= getmajor(dev
);
1527 ppa
= getminor(dev
) - 1;
1530 * For GLDv3 devices, look up the device instance using getinfo(9e).
1531 * Otherwise, fall back to the old assumption that inst == ppa. The
1532 * GLDV3_DRV() macro depends on the driver module being loaded, hence
1533 * the call to ddi_hold_driver().
1535 if (ddi_hold_driver(major
) == NULL
)
1537 if (GLDV3_DRV(major
)) {
1538 if ((inst
= dev_to_instance(dev
)) < 0)
1543 ddi_rele_driver(major
);
1548 * First try to hold this device instance to force device to attach
1549 * and ensure that the softmac entry gets created in net_postattach().
1551 if ((dip
= ddi_hold_devi_by_instance(major
, inst
, 0)) == NULL
)
1555 * Exclude non-physical network device instances, for example, aggr0.
1556 * Note: this check *must* occur after the dip is held, or else
1557 * NETWORK_PHYSDRV might return false incorrectly. The
1558 * DN_NETWORK_PHYSDRIVER flag used by NETWORK_PHYSDRV() gets set if
1559 * ddi_create_minor_node() is called during the device's attach
1562 if (!NETWORK_PHYSDRV(major
)) {
1563 ddi_release_devi(dip
);
1567 /* Now wait for its softmac to be created. */
1568 (void) snprintf(devname
, MAXNAMELEN
, "%s%d", ddi_major_to_name(major
),
1571 rw_enter(&softmac_hash_lock
, RW_READER
);
1573 if (mod_hash_find(softmac_hash
, (mod_hash_key_t
)devname
,
1574 (mod_hash_val_t
*)&softmac
) != 0) {
1576 * This is rare but possible. It could happen when pre-detach
1577 * routine of the device succeeds. But the softmac will then
1578 * be recreated when device fails to detach (as this device
1581 mutex_enter(&smac_global_lock
);
1582 rw_exit(&softmac_hash_lock
);
1583 cv_wait(&smac_global_cv
, &smac_global_lock
);
1584 mutex_exit(&smac_global_lock
);
1589 * Bump smac_hold_cnt to prevent device detach.
1591 mutex_enter(&softmac
->smac_mutex
);
1592 softmac
->smac_hold_cnt
++;
1593 rw_exit(&softmac_hash_lock
);
1596 * Wait till the device is fully attached.
1598 while (softmac
->smac_state
!= SOFTMAC_ATTACH_DONE
)
1599 cv_wait(&softmac
->smac_cv
, &softmac
->smac_mutex
);
1601 SOFTMAC_STATE_VERIFY(softmac
);
1603 if ((err
= softmac
->smac_attacherr
) != 0)
1604 softmac
->smac_hold_cnt
--;
1606 *ddhp
= (dls_dev_handle_t
)softmac
;
1607 mutex_exit(&softmac
->smac_mutex
);
1609 ddi_release_devi(dip
);
1614 softmac_rele_device(dls_dev_handle_t ddh
)
1617 softmac_rele((softmac_t
*)ddh
);
1621 softmac_hold(dev_t dev
, softmac_t
**softmacp
)
1626 char mac
[MAXNAMELEN
];
1629 if ((drv
= ddi_major_to_name(getmajor(dev
))) == NULL
)
1632 (void) snprintf(mac
, MAXNAMELEN
, "%s%d", drv
, getminor(dev
) - 1);
1633 if ((err
= mac_open(mac
, &mh
)) != 0)
1636 softmac
= (softmac_t
*)mac_driver(mh
);
1638 mutex_enter(&softmac
->smac_mutex
);
1639 softmac
->smac_hold_cnt
++;
1640 mutex_exit(&softmac
->smac_mutex
);
1642 *softmacp
= softmac
;
1647 softmac_rele(softmac_t
*softmac
)
1649 mutex_enter(&softmac
->smac_mutex
);
1650 softmac
->smac_hold_cnt
--;
1651 mutex_exit(&softmac
->smac_mutex
);