1d62bc4baSyz147064 /*
2d62bc4baSyz147064 * CDDL HEADER START
3d62bc4baSyz147064 *
4d62bc4baSyz147064 * The contents of this file are subject to the terms of the
5d62bc4baSyz147064 * Common Development and Distribution License (the "License").
6d62bc4baSyz147064 * You may not use this file except in compliance with the License.
7d62bc4baSyz147064 *
8d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz147064 * See the License for the specific language governing permissions
11d62bc4baSyz147064 * and limitations under the License.
12d62bc4baSyz147064 *
13d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz147064 *
19d62bc4baSyz147064 * CDDL HEADER END
20d62bc4baSyz147064 */
21d62bc4baSyz147064 /*
22*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23d62bc4baSyz147064 * Use is subject to license terms.
24d62bc4baSyz147064 */
25d62bc4baSyz147064
26d62bc4baSyz147064 /*
27d62bc4baSyz147064 * The softmac driver is used to "unify" non-GLDv3 drivers to the GLDv3
28d62bc4baSyz147064 * framework. It also creates the kernel datalink structure for each
29d62bc4baSyz147064 * physical network device.
30d62bc4baSyz147064 *
31d62bc4baSyz147064 * Specifically, a softmac will be created for each physical network device
32d62bc4baSyz147064 * (dip) during the device's post-attach process. When this softmac is
33d62bc4baSyz147064 * created, the following will also be done:
34d62bc4baSyz147064 * - create the device's <link name, linkid> mapping;
35d62bc4baSyz147064 * - register the mac if this is a non-GLDv3 device and the media type is
36d62bc4baSyz147064 * supported by the GLDv3 framework;
37d62bc4baSyz147064 * - create the kernel data-link structure for this physical device;
38d62bc4baSyz147064 *
39d62bc4baSyz147064 * This softmac will be destroyed during the device's pre-detach process,
40d62bc4baSyz147064 * and all the above will be undone.
41d62bc4baSyz147064 */
42d62bc4baSyz147064
43d62bc4baSyz147064 #include <sys/types.h>
44d62bc4baSyz147064 #include <sys/file.h>
45d62bc4baSyz147064 #include <sys/cred.h>
46d62bc4baSyz147064 #include <sys/dlpi.h>
47da14cebeSEric Cheng #include <sys/mac_provider.h>
48da14cebeSEric Cheng #include <sys/disp.h>
49d62bc4baSyz147064 #include <sys/sunndi.h>
50d62bc4baSyz147064 #include <sys/modhash.h>
51d62bc4baSyz147064 #include <sys/stropts.h>
52d62bc4baSyz147064 #include <sys/sysmacros.h>
53d62bc4baSyz147064 #include <sys/vlan.h>
54d62bc4baSyz147064 #include <sys/softmac_impl.h>
55d62bc4baSyz147064 #include <sys/softmac.h>
56d62bc4baSyz147064 #include <sys/dls.h>
57d62bc4baSyz147064
58da14cebeSEric Cheng /* Used as a parameter to the mod hash walk of softmac structures */
59da14cebeSEric Cheng typedef struct {
60da14cebeSEric Cheng softmac_t *smw_softmac;
61da14cebeSEric Cheng boolean_t smw_retry;
62da14cebeSEric Cheng } softmac_walk_t;
63da14cebeSEric Cheng
64d62bc4baSyz147064 /*
65d62bc4baSyz147064 * Softmac hash table including softmacs for both style-2 and style-1 devices.
66d62bc4baSyz147064 */
67d62bc4baSyz147064 static krwlock_t softmac_hash_lock;
68d62bc4baSyz147064 static mod_hash_t *softmac_hash;
69da14cebeSEric Cheng static kmutex_t smac_global_lock;
70da14cebeSEric Cheng static kcondvar_t smac_global_cv;
71d62bc4baSyz147064
725d460eafSCathy Zhou static kmem_cache_t *softmac_cachep;
735d460eafSCathy Zhou
74d62bc4baSyz147064 #define SOFTMAC_HASHSZ 64
75d62bc4baSyz147064
760dc974a9SCathy Zhou static void softmac_create_task(void *);
770dc974a9SCathy Zhou static void softmac_mac_register(softmac_t *);
78d62bc4baSyz147064 static int softmac_create_datalink(softmac_t *);
79d62bc4baSyz147064 static int softmac_m_start(void *);
80d62bc4baSyz147064 static void softmac_m_stop(void *);
81d62bc4baSyz147064 static int softmac_m_open(void *);
82d62bc4baSyz147064 static void softmac_m_close(void *);
83d62bc4baSyz147064 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *);
845d460eafSCathy Zhou static int softmac_m_setprop(void *, const char *, mac_prop_id_t,
855d460eafSCathy Zhou uint_t, const void *);
865d460eafSCathy Zhou static int softmac_m_getprop(void *, const char *, mac_prop_id_t,
87*0dc2366fSVenugopal Iyer uint_t, void *);
88*0dc2366fSVenugopal Iyer static void softmac_m_propinfo(void *, const char *, mac_prop_id_t,
89*0dc2366fSVenugopal Iyer mac_prop_info_handle_t);
90d62bc4baSyz147064
91d62bc4baSyz147064 #define SOFTMAC_M_CALLBACK_FLAGS \
92*0dc2366fSVenugopal Iyer (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE | MC_SETPROP | \
93*0dc2366fSVenugopal Iyer MC_GETPROP | MC_PROPINFO)
94d62bc4baSyz147064
95d62bc4baSyz147064 static mac_callbacks_t softmac_m_callbacks = {
96d62bc4baSyz147064 SOFTMAC_M_CALLBACK_FLAGS,
97d62bc4baSyz147064 softmac_m_stat,
98d62bc4baSyz147064 softmac_m_start,
99d62bc4baSyz147064 softmac_m_stop,
100d62bc4baSyz147064 softmac_m_promisc,
101d62bc4baSyz147064 softmac_m_multicst,
102d62bc4baSyz147064 softmac_m_unicst,
103d62bc4baSyz147064 softmac_m_tx,
104*0dc2366fSVenugopal Iyer NULL,
105d62bc4baSyz147064 softmac_m_ioctl,
106d62bc4baSyz147064 softmac_m_getcapab,
107d62bc4baSyz147064 softmac_m_open,
1085d460eafSCathy Zhou softmac_m_close,
1095d460eafSCathy Zhou softmac_m_setprop,
110*0dc2366fSVenugopal Iyer softmac_m_getprop,
111*0dc2366fSVenugopal Iyer softmac_m_propinfo
112d62bc4baSyz147064 };
113d62bc4baSyz147064
1145d460eafSCathy Zhou /*ARGSUSED*/
1155d460eafSCathy Zhou static int
softmac_constructor(void * buf,void * arg,int kmflag)1165d460eafSCathy Zhou softmac_constructor(void *buf, void *arg, int kmflag)
1175d460eafSCathy Zhou {
1185d460eafSCathy Zhou softmac_t *softmac = buf;
1195d460eafSCathy Zhou
1205d460eafSCathy Zhou bzero(buf, sizeof (softmac_t));
1215d460eafSCathy Zhou mutex_init(&softmac->smac_mutex, NULL, MUTEX_DEFAULT, NULL);
1225d460eafSCathy Zhou mutex_init(&softmac->smac_active_mutex, NULL, MUTEX_DEFAULT, NULL);
1235d460eafSCathy Zhou mutex_init(&softmac->smac_fp_mutex, NULL, MUTEX_DEFAULT, NULL);
1245d460eafSCathy Zhou cv_init(&softmac->smac_cv, NULL, CV_DEFAULT, NULL);
1255d460eafSCathy Zhou cv_init(&softmac->smac_fp_cv, NULL, CV_DEFAULT, NULL);
1265d460eafSCathy Zhou list_create(&softmac->smac_sup_list, sizeof (softmac_upper_t),
1275d460eafSCathy Zhou offsetof(softmac_upper_t, su_list_node));
1285d460eafSCathy Zhou return (0);
1295d460eafSCathy Zhou }
1305d460eafSCathy Zhou
1315d460eafSCathy Zhou /*ARGSUSED*/
1325d460eafSCathy Zhou static void
softmac_destructor(void * buf,void * arg)1335d460eafSCathy Zhou softmac_destructor(void *buf, void *arg)
1345d460eafSCathy Zhou {
1355d460eafSCathy Zhou softmac_t *softmac = buf;
1365d460eafSCathy Zhou
1375d460eafSCathy Zhou ASSERT(softmac->smac_fp_disable_clients == 0);
1385d460eafSCathy Zhou ASSERT(!softmac->smac_fastpath_admin_disabled);
1395d460eafSCathy Zhou
1405d460eafSCathy Zhou ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
1415d460eafSCathy Zhou ASSERT(softmac->smac_hold_cnt == 0);
1425d460eafSCathy Zhou ASSERT(softmac->smac_attachok_cnt == 0);
1435d460eafSCathy Zhou ASSERT(softmac->smac_mh == NULL);
1445d460eafSCathy Zhou ASSERT(softmac->smac_softmac[0] == NULL &&
1455d460eafSCathy Zhou softmac->smac_softmac[1] == NULL);
1465d460eafSCathy Zhou ASSERT(softmac->smac_lower == NULL);
1475d460eafSCathy Zhou ASSERT(softmac->smac_active == B_FALSE);
1485d460eafSCathy Zhou ASSERT(softmac->smac_nactive == 0);
1495d460eafSCathy Zhou ASSERT(list_is_empty(&softmac->smac_sup_list));
1505d460eafSCathy Zhou
1515d460eafSCathy Zhou list_destroy(&softmac->smac_sup_list);
1525d460eafSCathy Zhou mutex_destroy(&softmac->smac_mutex);
1535d460eafSCathy Zhou mutex_destroy(&softmac->smac_active_mutex);
1545d460eafSCathy Zhou mutex_destroy(&softmac->smac_fp_mutex);
1555d460eafSCathy Zhou cv_destroy(&softmac->smac_cv);
1565d460eafSCathy Zhou cv_destroy(&softmac->smac_fp_cv);
1575d460eafSCathy Zhou }
1585d460eafSCathy Zhou
159d62bc4baSyz147064 void
softmac_init()160d62bc4baSyz147064 softmac_init()
161d62bc4baSyz147064 {
162d62bc4baSyz147064 softmac_hash = mod_hash_create_extended("softmac_hash",
163d62bc4baSyz147064 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
164d62bc4baSyz147064 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
165d62bc4baSyz147064
166d62bc4baSyz147064 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL);
167da14cebeSEric Cheng mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL);
168da14cebeSEric Cheng cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL);
1695d460eafSCathy Zhou
1705d460eafSCathy Zhou softmac_cachep = kmem_cache_create("softmac_cache",
1715d460eafSCathy Zhou sizeof (softmac_t), 0, softmac_constructor,
1725d460eafSCathy Zhou softmac_destructor, NULL, NULL, NULL, 0);
1735d460eafSCathy Zhou ASSERT(softmac_cachep != NULL);
1745d460eafSCathy Zhou softmac_fp_init();
175d62bc4baSyz147064 }
176d62bc4baSyz147064
177d62bc4baSyz147064 void
softmac_fini()178d62bc4baSyz147064 softmac_fini()
179d62bc4baSyz147064 {
1805d460eafSCathy Zhou softmac_fp_fini();
1815d460eafSCathy Zhou kmem_cache_destroy(softmac_cachep);
182d62bc4baSyz147064 rw_destroy(&softmac_hash_lock);
183d62bc4baSyz147064 mod_hash_destroy_hash(softmac_hash);
184da14cebeSEric Cheng mutex_destroy(&smac_global_lock);
185da14cebeSEric Cheng cv_destroy(&smac_global_cv);
186d62bc4baSyz147064 }
187d62bc4baSyz147064
188d62bc4baSyz147064 /* ARGSUSED */
189d62bc4baSyz147064 static uint_t
softmac_exist(mod_hash_key_t key,mod_hash_val_t * val,void * arg)190d62bc4baSyz147064 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
191d62bc4baSyz147064 {
192d62bc4baSyz147064 boolean_t *pexist = arg;
193d62bc4baSyz147064
194d62bc4baSyz147064 *pexist = B_TRUE;
195d62bc4baSyz147064 return (MH_WALK_TERMINATE);
196d62bc4baSyz147064 }
197d62bc4baSyz147064
198d62bc4baSyz147064 boolean_t
softmac_busy()199d62bc4baSyz147064 softmac_busy()
200d62bc4baSyz147064 {
201d62bc4baSyz147064 boolean_t exist = B_FALSE;
202d62bc4baSyz147064
203d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_READER);
204d62bc4baSyz147064 mod_hash_walk(softmac_hash, softmac_exist, &exist);
205d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
206d62bc4baSyz147064 return (exist);
207d62bc4baSyz147064 }
208d62bc4baSyz147064
209d62bc4baSyz147064 /*
210da14cebeSEric Cheng *
211da14cebeSEric Cheng * softmac_create() is called for each minor node during the post-attach of
212d62bc4baSyz147064 * each DDI_NT_NET device instance. Note that it is possible that a device
213d62bc4baSyz147064 * instance has two minor nodes (DLPI style-1 and style-2), so that for that
214d62bc4baSyz147064 * specific device, softmac_create() could be called twice.
215d62bc4baSyz147064 *
216d62bc4baSyz147064 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t
217d62bc4baSyz147064 * is created to track each minor node.
218d62bc4baSyz147064 *
219d62bc4baSyz147064 * For each minor node of a legacy device, a taskq is started to finish
220d62bc4baSyz147064 * softmac_mac_register(), which will finish the rest of work (see comments
221d62bc4baSyz147064 * above softmac_mac_register()).
222da14cebeSEric Cheng *
223da14cebeSEric Cheng * softmac state machine
224da14cebeSEric Cheng * --------------------------------------------------------------------------
225da14cebeSEric Cheng * OLD STATE EVENT NEW STATE
226da14cebeSEric Cheng * --------------------------------------------------------------------------
227da14cebeSEric Cheng * UNINIT attach of 1st minor node ATTACH_INPROG
228da14cebeSEric Cheng * okcnt = 0 net_postattach -> softmac_create okcnt = 1
229da14cebeSEric Cheng *
230da14cebeSEric Cheng * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE
231da14cebeSEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2
232da14cebeSEric Cheng *
233da14cebeSEric Cheng * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG
234da14cebeSEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2
235da14cebeSEric Cheng * schedule softmac_mac_register
236da14cebeSEric Cheng *
237da14cebeSEric Cheng * ATTACH_INPROG legacy device node ATTACH_DONE
238da14cebeSEric Cheng * okcnt = 2 softmac_mac_register okcnt = 2
239da14cebeSEric Cheng *
240da14cebeSEric Cheng * ATTACH_DONE detach of 1st minor node DETACH_INPROG
241da14cebeSEric Cheng * okcnt = 2 (success) okcnt = 1
242da14cebeSEric Cheng *
243da14cebeSEric Cheng * DETACH_INPROG detach of 2nd minor node UNINIT (or free)
244da14cebeSEric Cheng * okcnt = 1 (success) okcnt = 0
245da14cebeSEric Cheng *
246da14cebeSEric Cheng * ATTACH_DONE detach failure state unchanged
247da14cebeSEric Cheng * DETACH_INPROG left = okcnt
248da14cebeSEric Cheng *
249da14cebeSEric Cheng * DETACH_INPROG reattach ATTACH_INPROG
250da14cebeSEric Cheng * okcnt = 0,1 net_postattach -> softmac_create
251da14cebeSEric Cheng *
252da14cebeSEric Cheng * ATTACH_DONE reattach ATTACH_DONE
253da14cebeSEric Cheng * left != 0 net_postattach -> softmac_create left = 0
254da14cebeSEric Cheng *
255da14cebeSEric Cheng * Abbreviation notes:
256da14cebeSEric Cheng * states have SOFTMAC_ prefix,
257da14cebeSEric Cheng * okcnt - softmac_attach_okcnt,
258da14cebeSEric Cheng * left - softmac_attached_left
259d62bc4baSyz147064 */
260da14cebeSEric Cheng
261da14cebeSEric Cheng #ifdef DEBUG
262da14cebeSEric Cheng void
softmac_state_verify(softmac_t * softmac)263da14cebeSEric Cheng softmac_state_verify(softmac_t *softmac)
264da14cebeSEric Cheng {
265da14cebeSEric Cheng ASSERT(MUTEX_HELD(&softmac->smac_mutex));
266da14cebeSEric Cheng
267da14cebeSEric Cheng /*
268da14cebeSEric Cheng * There are at most 2 minor nodes, one per DLPI style
269da14cebeSEric Cheng */
270da14cebeSEric Cheng ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2);
271da14cebeSEric Cheng
272da14cebeSEric Cheng /*
273da14cebeSEric Cheng * The smac_attachok_cnt represents the number of attaches i.e. the
274da14cebeSEric Cheng * number of times net_postattach -> softmac_create() has been called
275da14cebeSEric Cheng * for a device instance.
276da14cebeSEric Cheng */
277da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac));
278da14cebeSEric Cheng
279da14cebeSEric Cheng /*
280da14cebeSEric Cheng * softmac_create (or softmac_mac_register) -> softmac_create_datalink
281da14cebeSEric Cheng * happens only after all minor nodes have been attached
282da14cebeSEric Cheng */
283da14cebeSEric Cheng ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE ||
284da14cebeSEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt);
285da14cebeSEric Cheng
286da14cebeSEric Cheng if (softmac->smac_attachok_cnt == 0) {
287da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_UNINIT);
288da14cebeSEric Cheng ASSERT(softmac->smac_mh == NULL);
289da14cebeSEric Cheng } else if (softmac->smac_attachok_cnt < softmac->smac_cnt) {
290da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG ||
291da14cebeSEric Cheng softmac->smac_state == SOFTMAC_DETACH_INPROG);
292da14cebeSEric Cheng ASSERT(softmac->smac_mh == NULL);
293da14cebeSEric Cheng } else {
294da14cebeSEric Cheng /*
295da14cebeSEric Cheng * In the stable condition the state whould be
296da14cebeSEric Cheng * SOFTMAC_ATTACH_DONE. But there is a small transient window
297da14cebeSEric Cheng * in softmac_destroy where we change the state to
298da14cebeSEric Cheng * SOFTMAC_DETACH_INPROG and drop the lock before doing
299da14cebeSEric Cheng * the link destroy
300da14cebeSEric Cheng */
301da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
302da14cebeSEric Cheng ASSERT(softmac->smac_state != SOFTMAC_UNINIT);
303da14cebeSEric Cheng }
304da14cebeSEric Cheng if (softmac->smac_mh != NULL)
305da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
306da14cebeSEric Cheng }
307da14cebeSEric Cheng #endif
308da14cebeSEric Cheng
309da14cebeSEric Cheng #ifdef DEBUG
310da14cebeSEric Cheng #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac)
311da14cebeSEric Cheng #else
312da14cebeSEric Cheng #define SOFTMAC_STATE_VERIFY(softmac)
313da14cebeSEric Cheng #endif
314da14cebeSEric Cheng
315d62bc4baSyz147064 int
softmac_create(dev_info_t * dip,dev_t dev)316d62bc4baSyz147064 softmac_create(dev_info_t *dip, dev_t dev)
317d62bc4baSyz147064 {
318d62bc4baSyz147064 char devname[MAXNAMELEN];
319d62bc4baSyz147064 softmac_t *softmac;
320d62bc4baSyz147064 softmac_dev_t *softmac_dev = NULL;
321d62bc4baSyz147064 int index;
322d62bc4baSyz147064 int ppa, err = 0;
323d62bc4baSyz147064
324d62bc4baSyz147064 /*
325d62bc4baSyz147064 * Force the softmac driver to be attached.
326d62bc4baSyz147064 */
327d62bc4baSyz147064 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) {
328d62bc4baSyz147064 cmn_err(CE_WARN, "softmac_create:softmac attach fails");
329d62bc4baSyz147064 return (ENXIO);
330d62bc4baSyz147064 }
331d62bc4baSyz147064
33261af1958SGarrett D'Amore if (GLDV3_DRV(ddi_driver_major(dip))) {
33361af1958SGarrett D'Amore minor_t minor = getminor(dev);
33461af1958SGarrett D'Amore /*
33561af1958SGarrett D'Amore * For GLDv3, we don't care about the DLPI style 2
33661af1958SGarrett D'Amore * compatibility node. (We know that all such devices
33761af1958SGarrett D'Amore * have style 1 nodes.)
33861af1958SGarrett D'Amore */
33961af1958SGarrett D'Amore if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
34061af1958SGarrett D'Amore (getmajor(dev) == ddi_name_to_major("clone")) ||
34161af1958SGarrett D'Amore (minor == 0)) {
34261af1958SGarrett D'Amore return (0);
34361af1958SGarrett D'Amore }
344d62bc4baSyz147064
345d62bc4baSyz147064 /*
34661af1958SGarrett D'Amore * Likewise, we know that the minor number for DLPI style 1
34761af1958SGarrett D'Amore * nodes is constrained to a maximum value.
348d62bc4baSyz147064 */
34961af1958SGarrett D'Amore if (minor >= DLS_MAX_MINOR) {
350d62bc4baSyz147064 return (ENOTSUP);
351d62bc4baSyz147064 }
35261af1958SGarrett D'Amore /*
35361af1958SGarrett D'Amore * Otherwise we can decode the instance from the minor number,
35461af1958SGarrett D'Amore * which allows for situations with multiple mac instances
35561af1958SGarrett D'Amore * for a single dev_info_t.
35661af1958SGarrett D'Amore */
35761af1958SGarrett D'Amore ppa = DLS_MINOR2INST(minor);
35861af1958SGarrett D'Amore } else {
35961af1958SGarrett D'Amore /*
36061af1958SGarrett D'Amore * For legacy drivers, we just have to limit them to
36161af1958SGarrett D'Amore * two minor nodes, one style 1 and one style 2, and
36261af1958SGarrett D'Amore * we assume the ddi_get_instance() is the PPA.
36361af1958SGarrett D'Amore * Drivers that need more flexibility should be ported
36461af1958SGarrett D'Amore * to GLDv3.
36561af1958SGarrett D'Amore */
36661af1958SGarrett D'Amore ppa = ddi_get_instance(dip);
36761af1958SGarrett D'Amore if (i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) {
36861af1958SGarrett D'Amore cmn_err(CE_WARN, "%s has more than 2 minor nodes; "
36961af1958SGarrett D'Amore "unsupported", devname);
37061af1958SGarrett D'Amore return (ENOTSUP);
37161af1958SGarrett D'Amore }
37261af1958SGarrett D'Amore }
37361af1958SGarrett D'Amore
37461af1958SGarrett D'Amore (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
375d62bc4baSyz147064
376d62bc4baSyz147064 /*
377d62bc4baSyz147064 * Check whether the softmac for the specified device already exists
378d62bc4baSyz147064 */
379d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_WRITER);
3805d460eafSCathy Zhou if ((mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
381d62bc4baSyz147064 (mod_hash_val_t *)&softmac)) != 0) {
382d62bc4baSyz147064
3835d460eafSCathy Zhou softmac = kmem_cache_alloc(softmac_cachep, KM_SLEEP);
384d62bc4baSyz147064 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN);
3855d460eafSCathy Zhou
386d62bc4baSyz147064 err = mod_hash_insert(softmac_hash,
387d62bc4baSyz147064 (mod_hash_key_t)softmac->smac_devname,
388d62bc4baSyz147064 (mod_hash_val_t)softmac);
389d62bc4baSyz147064 ASSERT(err == 0);
390da14cebeSEric Cheng mutex_enter(&smac_global_lock);
391da14cebeSEric Cheng cv_broadcast(&smac_global_cv);
392da14cebeSEric Cheng mutex_exit(&smac_global_lock);
393d62bc4baSyz147064 }
394d62bc4baSyz147064
395d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex);
396da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac);
397da14cebeSEric Cheng if (softmac->smac_state != SOFTMAC_ATTACH_DONE)
398da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_INPROG;
399d62bc4baSyz147064 if (softmac->smac_attachok_cnt == 0) {
400d62bc4baSyz147064 /*
401d62bc4baSyz147064 * Initialize the softmac if this is the post-attach of the
402d62bc4baSyz147064 * first minor node.
403d62bc4baSyz147064 */
404d62bc4baSyz147064 softmac->smac_flags = 0;
405d62bc4baSyz147064 softmac->smac_umajor = ddi_driver_major(dip);
406d62bc4baSyz147064 softmac->smac_uppa = ppa;
407d62bc4baSyz147064
408d62bc4baSyz147064 /*
40961af1958SGarrett D'Amore * For GLDv3, we ignore the style 2 node (see the logic
41061af1958SGarrett D'Amore * above on that), and we should have exactly one attach
41161af1958SGarrett D'Amore * per MAC instance (possibly more than one per dev_info_t).
412d62bc4baSyz147064 */
413d62bc4baSyz147064 if (GLDV3_DRV(ddi_driver_major(dip))) {
414d62bc4baSyz147064 softmac->smac_flags |= SOFTMAC_GLDV3;
41561af1958SGarrett D'Amore softmac->smac_cnt = 1;
416d62bc4baSyz147064 } else {
417d62bc4baSyz147064 softmac->smac_cnt =
418d62bc4baSyz147064 i_ddi_minor_node_count(dip, DDI_NT_NET);
419d62bc4baSyz147064 }
420d62bc4baSyz147064 }
421d62bc4baSyz147064
422d62bc4baSyz147064 index = (getmajor(dev) == ddi_name_to_major("clone"));
423d62bc4baSyz147064 if (softmac->smac_softmac[index] != NULL) {
424d62bc4baSyz147064 /*
425da14cebeSEric Cheng * This is possible if the post_attach() is called after
426da14cebeSEric Cheng * pre_detach() fails. This seems to be a defect of the DACF
427da14cebeSEric Cheng * framework. We work around it by using a smac_attached_left
428da14cebeSEric Cheng * field that tracks this
429d62bc4baSyz147064 */
430da14cebeSEric Cheng ASSERT(softmac->smac_attached_left != 0);
431d62bc4baSyz147064 softmac->smac_attached_left--;
432d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
433d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
434d62bc4baSyz147064 return (0);
435da14cebeSEric Cheng
436d62bc4baSyz147064 }
437d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
438d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
439d62bc4baSyz147064
440d62bc4baSyz147064 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP);
441d62bc4baSyz147064 softmac_dev->sd_dev = dev;
442d62bc4baSyz147064
443da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex);
444da14cebeSEric Cheng softmac->smac_softmac[index] = softmac_dev;
445d62bc4baSyz147064 /*
446d62bc4baSyz147064 * Continue to register the mac and create the datalink only when all
447d62bc4baSyz147064 * the minor nodes are attached.
448d62bc4baSyz147064 */
449d62bc4baSyz147064 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) {
450d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
451d62bc4baSyz147064 return (0);
452d62bc4baSyz147064 }
453d62bc4baSyz147064
454d62bc4baSyz147064 /*
4550dc974a9SCathy Zhou * All of the minor nodes have been attached; start a taskq
456da14cebeSEric Cheng * to do the rest of the work. We use a taskq instead of
4570dc974a9SCathy Zhou * doing the work here because:
458d62bc4baSyz147064 *
459da14cebeSEric Cheng * We could be called as a result of a open() system call
4600dc974a9SCathy Zhou * where spec_open() already SLOCKED the snode. Using a taskq
4610dc974a9SCathy Zhou * sidesteps the risk that our ldi_open_by_dev() call would
4620dc974a9SCathy Zhou * deadlock trying to set SLOCKED on the snode again.
4630dc974a9SCathy Zhou *
464da14cebeSEric Cheng * The devfs design requires that the downcalls don't use any
465da14cebeSEric Cheng * interruptible cv_wait which happens when we do door upcalls.
466da14cebeSEric Cheng * Otherwise the downcalls which may be holding devfs resources
467da14cebeSEric Cheng * may cause a deadlock if the thread is stopped. Also we need to make
468da14cebeSEric Cheng * sure these downcalls into softmac_create or softmac_destroy
469da14cebeSEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy
470da14cebeSEric Cheng * returns EBUSY if the asynchronous threads started in softmac_create
471da14cebeSEric Cheng * haven't finished.
472d62bc4baSyz147064 */
47365041820SCathy Zhou (void) taskq_dispatch(system_taskq, softmac_create_task,
47465041820SCathy Zhou softmac, TQ_SLEEP);
475d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
476d62bc4baSyz147064 return (0);
477d62bc4baSyz147064 }
478d62bc4baSyz147064
479d62bc4baSyz147064 static boolean_t
softmac_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)480d62bc4baSyz147064 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
481d62bc4baSyz147064 {
482d62bc4baSyz147064 softmac_t *softmac = arg;
483d62bc4baSyz147064
484d62bc4baSyz147064 if (!(softmac->smac_capab_flags & cap))
485d62bc4baSyz147064 return (B_FALSE);
486d62bc4baSyz147064
487d62bc4baSyz147064 switch (cap) {
488d62bc4baSyz147064 case MAC_CAPAB_HCKSUM: {
489d62bc4baSyz147064 uint32_t *txflags = cap_data;
490d62bc4baSyz147064
491d62bc4baSyz147064 *txflags = softmac->smac_hcksum_txflags;
492d62bc4baSyz147064 break;
493d62bc4baSyz147064 }
494d62bc4baSyz147064 case MAC_CAPAB_LEGACY: {
495d62bc4baSyz147064 mac_capab_legacy_t *legacy = cap_data;
496d62bc4baSyz147064
4975d460eafSCathy Zhou /*
4985d460eafSCathy Zhou * The caller is not interested in the details.
4995d460eafSCathy Zhou */
5005d460eafSCathy Zhou if (legacy == NULL)
5015d460eafSCathy Zhou break;
5025d460eafSCathy Zhou
503d62bc4baSyz147064 legacy->ml_unsup_note = ~softmac->smac_notifications &
504d62bc4baSyz147064 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED);
5055d460eafSCathy Zhou legacy->ml_active_set = softmac_active_set;
5065d460eafSCathy Zhou legacy->ml_active_clear = softmac_active_clear;
5075d460eafSCathy Zhou legacy->ml_fastpath_disable = softmac_fastpath_disable;
5085d460eafSCathy Zhou legacy->ml_fastpath_enable = softmac_fastpath_enable;
509d62bc4baSyz147064 legacy->ml_dev = makedevice(softmac->smac_umajor,
510d62bc4baSyz147064 softmac->smac_uppa + 1);
511d62bc4baSyz147064 break;
512d62bc4baSyz147064 }
513d62bc4baSyz147064
514d62bc4baSyz147064 /*
515d62bc4baSyz147064 * For the capabilities below, there's nothing for us to fill in;
516d62bc4baSyz147064 * simply return B_TRUE if we support it.
517d62bc4baSyz147064 */
518d62bc4baSyz147064 case MAC_CAPAB_NO_ZCOPY:
519d62bc4baSyz147064 case MAC_CAPAB_NO_NATIVEVLAN:
520d62bc4baSyz147064 default:
521d62bc4baSyz147064 break;
522d62bc4baSyz147064 }
523d62bc4baSyz147064 return (B_TRUE);
524d62bc4baSyz147064 }
525d62bc4baSyz147064
526d62bc4baSyz147064 static int
softmac_update_info(softmac_t * softmac,datalink_id_t * linkidp)527d62bc4baSyz147064 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp)
528d62bc4baSyz147064 {
529d62bc4baSyz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID;
530d62bc4baSyz147064 uint32_t media;
531d62bc4baSyz147064 int err;
532d62bc4baSyz147064
533d62bc4baSyz147064 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media,
534d62bc4baSyz147064 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) {
535d62bc4baSyz147064 *linkidp = linkid;
536d62bc4baSyz147064 }
537d62bc4baSyz147064
538d62bc4baSyz147064 if (err == EEXIST) {
539d62bc4baSyz147064 /*
540d62bc4baSyz147064 * There is a link name conflict. Either:
541d62bc4baSyz147064 *
542d62bc4baSyz147064 * - An existing link with the same device name with a
543d62bc4baSyz147064 * different media type from of the given type.
544d62bc4baSyz147064 * Mark this link back to persistent only; or
545d62bc4baSyz147064 *
546d62bc4baSyz147064 * - We cannot assign the "suggested" name because
547d62bc4baSyz147064 * GLDv3 and therefore vanity naming is not supported
548d62bc4baSyz147064 * for this link type. Delete this link's <link name,
549d62bc4baSyz147064 * linkid> mapping.
550d62bc4baSyz147064 */
551d62bc4baSyz147064 if (media != softmac->smac_media) {
552d62bc4baSyz147064 cmn_err(CE_WARN, "%s device %s conflicts with "
553d62bc4baSyz147064 "existing %s device %s.",
554d62bc4baSyz147064 dl_mactypestr(softmac->smac_media),
555d62bc4baSyz147064 softmac->smac_devname, dl_mactypestr(media),
556d62bc4baSyz147064 softmac->smac_devname);
557d62bc4baSyz147064 (void) dls_mgmt_destroy(linkid, B_FALSE);
558d62bc4baSyz147064 } else {
559d62bc4baSyz147064 cmn_err(CE_WARN, "link name %s is already in-use.",
560d62bc4baSyz147064 softmac->smac_devname);
561d62bc4baSyz147064 (void) dls_mgmt_destroy(linkid, B_TRUE);
562d62bc4baSyz147064 }
563d62bc4baSyz147064
564d62bc4baSyz147064 cmn_err(CE_WARN, "%s device might not be available "
565d62bc4baSyz147064 "for use.", softmac->smac_devname);
566d62bc4baSyz147064 cmn_err(CE_WARN, "See dladm(1M) for more information.");
567d62bc4baSyz147064 }
568d62bc4baSyz147064
569d62bc4baSyz147064 return (err);
570d62bc4baSyz147064 }
571d62bc4baSyz147064
572d62bc4baSyz147064 /*
573d62bc4baSyz147064 * This function:
574d62bc4baSyz147064 * 1. provides the link's media type to dlmgmtd.
575d62bc4baSyz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
576d62bc4baSyz147064 */
577d62bc4baSyz147064 static int
softmac_create_datalink(softmac_t * softmac)578d62bc4baSyz147064 softmac_create_datalink(softmac_t *softmac)
579d62bc4baSyz147064 {
580d62bc4baSyz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID;
581d62bc4baSyz147064 int err;
582d62bc4baSyz147064
583d62bc4baSyz147064 /*
5840dc974a9SCathy Zhou * Inform dlmgmtd of this link so that softmac_hold_device() is able
5850dc974a9SCathy Zhou * to know the existence of this link. If this failed with EBADF,
5860dc974a9SCathy Zhou * it might be because dlmgmtd was not started in time (e.g.,
5870dc974a9SCathy Zhou * diskless boot); ignore the failure and continue to create
5880dc974a9SCathy Zhou * the GLDv3 datalink if needed.
589d62bc4baSyz147064 */
5900dc974a9SCathy Zhou err = dls_mgmt_create(softmac->smac_devname,
5910dc974a9SCathy Zhou makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
5920dc974a9SCathy Zhou DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid);
5930dc974a9SCathy Zhou if (err != 0 && err != EBADF)
5940dc974a9SCathy Zhou return (err);
5950dc974a9SCathy Zhou
5960dc974a9SCathy Zhou /*
5970dc974a9SCathy Zhou * Provide the media type of the physical link to dlmgmtd.
5980dc974a9SCathy Zhou */
5990dc974a9SCathy Zhou if ((err != EBADF) &&
6000dc974a9SCathy Zhou ((err = softmac_update_info(softmac, &linkid)) != 0)) {
601d62bc4baSyz147064 return (err);
602d62bc4baSyz147064 }
603d62bc4baSyz147064
604d62bc4baSyz147064 /*
605d62bc4baSyz147064 * Create the GLDv3 datalink.
606d62bc4baSyz147064 */
6072b24ab6bSSebastien Roy if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
6082b24ab6bSSebastien Roy err = dls_devnet_create(softmac->smac_mh, linkid,
6092b24ab6bSSebastien Roy crgetzoneid(CRED()));
6102b24ab6bSSebastien Roy if (err != 0) {
611d62bc4baSyz147064 cmn_err(CE_WARN, "dls_devnet_create failed for %s",
612d62bc4baSyz147064 softmac->smac_devname);
613d62bc4baSyz147064 return (err);
614d62bc4baSyz147064 }
6152b24ab6bSSebastien Roy }
616d62bc4baSyz147064
617da14cebeSEric Cheng if (linkid == DATALINK_INVALID_LINKID) {
618da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex);
619d62bc4baSyz147064 softmac->smac_flags |= SOFTMAC_NEED_RECREATE;
620da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
621da14cebeSEric Cheng }
622d62bc4baSyz147064
623d62bc4baSyz147064 return (0);
624d62bc4baSyz147064 }
625d62bc4baSyz147064
6260dc974a9SCathy Zhou static void
softmac_create_task(void * arg)6270dc974a9SCathy Zhou softmac_create_task(void *arg)
6280dc974a9SCathy Zhou {
6290dc974a9SCathy Zhou softmac_t *softmac = arg;
6300dc974a9SCathy Zhou mac_handle_t mh;
6310dc974a9SCathy Zhou int err;
6320dc974a9SCathy Zhou
6330dc974a9SCathy Zhou if (!GLDV3_DRV(softmac->smac_umajor)) {
6340dc974a9SCathy Zhou softmac_mac_register(softmac);
6350dc974a9SCathy Zhou return;
6360dc974a9SCathy Zhou }
6370dc974a9SCathy Zhou
6380dc974a9SCathy Zhou if ((err = mac_open(softmac->smac_devname, &mh)) != 0)
6390dc974a9SCathy Zhou goto done;
6400dc974a9SCathy Zhou
6410dc974a9SCathy Zhou mutex_enter(&softmac->smac_mutex);
6420dc974a9SCathy Zhou softmac->smac_media = (mac_info(mh))->mi_nativemedia;
6430dc974a9SCathy Zhou softmac->smac_mh = mh;
644da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
6450dc974a9SCathy Zhou
6460dc974a9SCathy Zhou /*
6470dc974a9SCathy Zhou * We can safely release the reference on the mac because
6480dc974a9SCathy Zhou * this mac will only be unregistered and destroyed when
6490dc974a9SCathy Zhou * the device detaches, and the softmac will be destroyed
6500dc974a9SCathy Zhou * before then (in the pre-detach routine of the device).
6510dc974a9SCathy Zhou */
6520dc974a9SCathy Zhou mac_close(mh);
6530dc974a9SCathy Zhou
6540dc974a9SCathy Zhou /*
6550dc974a9SCathy Zhou * Create the GLDv3 datalink for this mac.
6560dc974a9SCathy Zhou */
6570dc974a9SCathy Zhou err = softmac_create_datalink(softmac);
6580dc974a9SCathy Zhou
6590dc974a9SCathy Zhou done:
66065041820SCathy Zhou mutex_enter(&softmac->smac_mutex);
66165041820SCathy Zhou if (err != 0)
662da14cebeSEric Cheng softmac->smac_mh = NULL;
6630dc974a9SCathy Zhou softmac->smac_attacherr = err;
664da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE;
6650dc974a9SCathy Zhou cv_broadcast(&softmac->smac_cv);
6660dc974a9SCathy Zhou mutex_exit(&softmac->smac_mutex);
6670dc974a9SCathy Zhou }
6680dc974a9SCathy Zhou
669d62bc4baSyz147064 /*
670d62bc4baSyz147064 * This function is only called for legacy devices. It:
671d62bc4baSyz147064 * 1. registers the MAC for the legacy devices whose media type is supported
672d62bc4baSyz147064 * by the GLDv3 framework.
673d62bc4baSyz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
674d62bc4baSyz147064 */
675d62bc4baSyz147064 static void
softmac_mac_register(softmac_t * softmac)6760dc974a9SCathy Zhou softmac_mac_register(softmac_t *softmac)
677d62bc4baSyz147064 {
678d62bc4baSyz147064 softmac_dev_t *softmac_dev;
679d62bc4baSyz147064 dev_t dev;
680d62bc4baSyz147064 ldi_handle_t lh = NULL;
681d62bc4baSyz147064 ldi_ident_t li = NULL;
682d62bc4baSyz147064 int index;
683d62bc4baSyz147064 boolean_t native_vlan = B_FALSE;
684d62bc4baSyz147064 int err;
685d62bc4baSyz147064
686d62bc4baSyz147064 /*
687d62bc4baSyz147064 * Note that we do not need any locks to access this softmac pointer,
688d62bc4baSyz147064 * as softmac_destroy() will wait until this function is called.
689d62bc4baSyz147064 */
690d62bc4baSyz147064 ASSERT(softmac != NULL);
691da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
692da14cebeSEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt);
693d62bc4baSyz147064
694d62bc4baSyz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) {
695d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex);
696d62bc4baSyz147064 goto done;
697d62bc4baSyz147064 }
698d62bc4baSyz147064
699d62bc4baSyz147064 /*
700d62bc4baSyz147064 * Determine whether this legacy device support VLANs by opening
701d62bc4baSyz147064 * the style-2 device node (if it exists) and attaching to a VLAN
702d62bc4baSyz147064 * PPA (1000 + ppa).
703d62bc4baSyz147064 */
704d62bc4baSyz147064 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor);
705d62bc4baSyz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
706d62bc4baSyz147064 if (err == 0) {
707d62bc4baSyz147064 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0)
708d62bc4baSyz147064 native_vlan = B_TRUE;
709d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
710d62bc4baSyz147064 }
711d62bc4baSyz147064
712d62bc4baSyz147064 err = EINVAL;
713d62bc4baSyz147064 for (index = 0; index < 2; index++) {
714d62bc4baSyz147064 dl_info_ack_t dlia;
715d62bc4baSyz147064 dl_error_ack_t dlea;
716d62bc4baSyz147064 uint32_t notes;
717d62bc4baSyz147064 struct strioctl iocb;
718d62bc4baSyz147064 uint32_t margin;
719d62bc4baSyz147064 int rval;
720d62bc4baSyz147064
721d62bc4baSyz147064 if ((softmac_dev = softmac->smac_softmac[index]) == NULL)
722d62bc4baSyz147064 continue;
723d62bc4baSyz147064
724d62bc4baSyz147064 softmac->smac_dev = dev = softmac_dev->sd_dev;
725d62bc4baSyz147064 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh,
726d62bc4baSyz147064 li) != 0) {
727d62bc4baSyz147064 continue;
728d62bc4baSyz147064 }
729d62bc4baSyz147064
730d62bc4baSyz147064 /*
731d62bc4baSyz147064 * Pop all the intermediate modules in order to negotiate
732d62bc4baSyz147064 * capabilities correctly.
733d62bc4baSyz147064 */
734d62bc4baSyz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
735d62bc4baSyz147064 ;
736d62bc4baSyz147064
737d62bc4baSyz147064 /* DLPI style-1 or DLPI style-2? */
738d62bc4baSyz147064 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) {
739d62bc4baSyz147064 if (rval == ENOTSUP) {
740d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: received "
741d62bc4baSyz147064 "DL_ERROR_ACK to DL_INFO_ACK; "
742d62bc4baSyz147064 "DLPI errno 0x%x, UNIX errno %d",
743d62bc4baSyz147064 dlea.dl_errno, dlea.dl_unix_errno);
744d62bc4baSyz147064 }
745d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
746d62bc4baSyz147064 continue;
747d62bc4baSyz147064 }
748d62bc4baSyz147064
749d62bc4baSyz147064 /*
750d62bc4baSyz147064 * Currently only DL_ETHER has GLDv3 mac plugin support.
751d62bc4baSyz147064 * For media types that GLDv3 does not support, create a
752d62bc4baSyz147064 * link id for it.
753d62bc4baSyz147064 */
754d62bc4baSyz147064 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) {
755d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
756d62bc4baSyz147064 err = 0;
757d62bc4baSyz147064 break;
758d62bc4baSyz147064 }
759d62bc4baSyz147064
760d62bc4baSyz147064 if ((dlia.dl_provider_style == DL_STYLE2) &&
761d62bc4baSyz147064 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) {
762d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
763d62bc4baSyz147064 continue;
764d62bc4baSyz147064 }
765d62bc4baSyz147064
766d62bc4baSyz147064 if ((rval = dl_bind(lh, 0, NULL)) != 0) {
767d62bc4baSyz147064 if (rval == ENOTSUP) {
768d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: received "
769d62bc4baSyz147064 "DL_ERROR_ACK to DL_BIND_ACK; "
770d62bc4baSyz147064 "DLPI errno 0x%x, UNIX errno %d",
771d62bc4baSyz147064 dlea.dl_errno, dlea.dl_unix_errno);
772d62bc4baSyz147064 }
773d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
774d62bc4baSyz147064 continue;
775d62bc4baSyz147064 }
776d62bc4baSyz147064
777d62bc4baSyz147064 /*
778d62bc4baSyz147064 * Call dl_info() after dl_bind() because some drivers only
779d62bc4baSyz147064 * provide correct information (e.g. MAC address) once bound.
780d62bc4baSyz147064 */
781d62bc4baSyz147064 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr);
782d62bc4baSyz147064 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr,
783d62bc4baSyz147064 &softmac->smac_addrlen, &dlea)) != 0) {
784d62bc4baSyz147064 if (rval == ENOTSUP) {
785d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: received "
786d62bc4baSyz147064 "DL_ERROR_ACK to DL_INFO_ACK; "
787d62bc4baSyz147064 "DLPI errno 0x%x, UNIX errno %d",
788d62bc4baSyz147064 dlea.dl_errno, dlea.dl_unix_errno);
789d62bc4baSyz147064 }
790d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
791d62bc4baSyz147064 continue;
792d62bc4baSyz147064 }
793d62bc4baSyz147064
794d62bc4baSyz147064 softmac->smac_style = dlia.dl_provider_style;
795d62bc4baSyz147064 softmac->smac_saplen = ABS(dlia.dl_sap_length);
796d62bc4baSyz147064 softmac->smac_min_sdu = dlia.dl_min_sdu;
797d62bc4baSyz147064 softmac->smac_max_sdu = dlia.dl_max_sdu;
798d62bc4baSyz147064
799d62bc4baSyz147064 if ((softmac->smac_saplen != sizeof (uint16_t)) ||
800d62bc4baSyz147064 (softmac->smac_addrlen != ETHERADDRL) ||
801d62bc4baSyz147064 (dlia.dl_brdcst_addr_length != ETHERADDRL) ||
802d62bc4baSyz147064 (dlia.dl_brdcst_addr_offset == 0)) {
803d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
804d62bc4baSyz147064 continue;
805d62bc4baSyz147064 }
806d62bc4baSyz147064
807d62bc4baSyz147064 /*
808d62bc4baSyz147064 * Check other DLPI capabilities. Note that this must be after
809d62bc4baSyz147064 * dl_bind() because some drivers return DL_ERROR_ACK if the
810d62bc4baSyz147064 * stream is not bound. It is also before mac_register(), so
811d62bc4baSyz147064 * we don't need any lock protection here.
812d62bc4baSyz147064 */
813d62bc4baSyz147064 softmac->smac_capab_flags =
814da14cebeSEric Cheng (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY);
815d62bc4baSyz147064
816d62bc4baSyz147064 softmac->smac_no_capability_req = B_FALSE;
817d62bc4baSyz147064 if (softmac_fill_capab(lh, softmac) != 0)
818d62bc4baSyz147064 softmac->smac_no_capability_req = B_TRUE;
819d62bc4baSyz147064
820d62bc4baSyz147064 /*
821d62bc4baSyz147064 * Check the margin of the underlying driver.
822d62bc4baSyz147064 */
823d62bc4baSyz147064 margin = 0;
824d62bc4baSyz147064 iocb.ic_cmd = DLIOCMARGININFO;
825d62bc4baSyz147064 iocb.ic_timout = INFTIM;
826d62bc4baSyz147064 iocb.ic_len = sizeof (margin);
827d62bc4baSyz147064 iocb.ic_dp = (char *)&margin;
828d62bc4baSyz147064 softmac->smac_margin = 0;
829d62bc4baSyz147064
830d62bc4baSyz147064 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred,
831d62bc4baSyz147064 &rval) == 0) {
832d62bc4baSyz147064 softmac->smac_margin = margin;
833d62bc4baSyz147064 }
834d62bc4baSyz147064
835d62bc4baSyz147064 /*
836d62bc4baSyz147064 * If the legacy driver doesn't support DLIOCMARGININFO, but
837d62bc4baSyz147064 * it can support native VLAN, correct its margin value to 4.
838d62bc4baSyz147064 */
839d62bc4baSyz147064 if (native_vlan) {
840d62bc4baSyz147064 if (softmac->smac_margin == 0)
841d62bc4baSyz147064 softmac->smac_margin = VLAN_TAGSZ;
842d62bc4baSyz147064 } else {
843d62bc4baSyz147064 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN;
844d62bc4baSyz147064 }
845d62bc4baSyz147064
846d62bc4baSyz147064 /*
847d62bc4baSyz147064 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP.
848d62bc4baSyz147064 */
849d62bc4baSyz147064 softmac->smac_notifications = 0;
850d62bc4baSyz147064 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN;
851d62bc4baSyz147064 switch (dl_notify(lh, ¬es, NULL)) {
852d62bc4baSyz147064 case 0:
853d62bc4baSyz147064 softmac->smac_notifications = notes;
854d62bc4baSyz147064 break;
855d62bc4baSyz147064 case ENOTSUP:
856d62bc4baSyz147064 break;
857d62bc4baSyz147064 default:
858d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
859d62bc4baSyz147064 continue;
860d62bc4baSyz147064 }
861d62bc4baSyz147064
862d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
863d62bc4baSyz147064 err = 0;
864d62bc4baSyz147064 break;
865d62bc4baSyz147064 }
866d62bc4baSyz147064 ldi_ident_release(li);
867d62bc4baSyz147064
868d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex);
869d62bc4baSyz147064
870d62bc4baSyz147064 if (err != 0)
871d62bc4baSyz147064 goto done;
872d62bc4baSyz147064
873d62bc4baSyz147064 if (softmac->smac_media != DL_ETHER)
874d62bc4baSyz147064 softmac->smac_flags |= SOFTMAC_NOSUPP;
875d62bc4baSyz147064
876d62bc4baSyz147064 /*
877d62bc4baSyz147064 * Finally, we're ready to register ourselves with the MAC layer
878d62bc4baSyz147064 * interface; if this succeeds, we're all ready to start()
879d62bc4baSyz147064 */
880d62bc4baSyz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
881d62bc4baSyz147064 mac_register_t *macp;
882d62bc4baSyz147064
883d62bc4baSyz147064 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
884d62bc4baSyz147064 err = ENOMEM;
885d62bc4baSyz147064 goto done;
886d62bc4baSyz147064 }
887d62bc4baSyz147064
888d62bc4baSyz147064 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
889d62bc4baSyz147064 macp->m_driver = softmac;
890d62bc4baSyz147064 macp->m_dip = softmac_dip;
891d62bc4baSyz147064
892d62bc4baSyz147064 macp->m_margin = softmac->smac_margin;
893d62bc4baSyz147064 macp->m_src_addr = softmac->smac_unicst_addr;
894d62bc4baSyz147064 macp->m_min_sdu = softmac->smac_min_sdu;
895d62bc4baSyz147064 macp->m_max_sdu = softmac->smac_max_sdu;
896d62bc4baSyz147064 macp->m_callbacks = &softmac_m_callbacks;
897d62bc4baSyz147064 macp->m_instance = (uint_t)-1;
898d62bc4baSyz147064
899d62bc4baSyz147064 err = mac_register(macp, &softmac->smac_mh);
900d62bc4baSyz147064 mac_free(macp);
901d62bc4baSyz147064 if (err != 0) {
902d62bc4baSyz147064 cmn_err(CE_WARN, "mac_register failed for %s",
903d62bc4baSyz147064 softmac->smac_devname);
904d62bc4baSyz147064 goto done;
905d62bc4baSyz147064 }
906d62bc4baSyz147064 }
907da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
908d62bc4baSyz147064
909d62bc4baSyz147064 /*
910d62bc4baSyz147064 * Try to create the datalink for this softmac.
911d62bc4baSyz147064 */
912d62bc4baSyz147064 if ((err = softmac_create_datalink(softmac)) != 0) {
9135d460eafSCathy Zhou if (!(softmac->smac_flags & SOFTMAC_NOSUPP))
914d62bc4baSyz147064 (void) mac_unregister(softmac->smac_mh);
9155d460eafSCathy Zhou mutex_enter(&softmac->smac_mutex);
916d62bc4baSyz147064 softmac->smac_mh = NULL;
9175d460eafSCathy Zhou goto done;
918d62bc4baSyz147064 }
919da14cebeSEric Cheng /*
920da14cebeSEric Cheng * If succeed, create the thread which handles the DL_NOTIFY_IND from
921da14cebeSEric Cheng * the lower stream.
922da14cebeSEric Cheng */
9235d460eafSCathy Zhou mutex_enter(&softmac->smac_mutex);
924da14cebeSEric Cheng if (softmac->smac_mh != NULL) {
925da14cebeSEric Cheng softmac->smac_notify_thread = thread_create(NULL, 0,
926da14cebeSEric Cheng softmac_notify_thread, softmac, 0, &p0,
927da14cebeSEric Cheng TS_RUN, minclsyspri);
928da14cebeSEric Cheng }
929d62bc4baSyz147064
930d62bc4baSyz147064 done:
931da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
932da14cebeSEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt);
933da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE;
934d62bc4baSyz147064 softmac->smac_attacherr = err;
935d62bc4baSyz147064 cv_broadcast(&softmac->smac_cv);
936d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
937d62bc4baSyz147064 }
938d62bc4baSyz147064
939d62bc4baSyz147064 int
softmac_destroy(dev_info_t * dip,dev_t dev)940d62bc4baSyz147064 softmac_destroy(dev_info_t *dip, dev_t dev)
941d62bc4baSyz147064 {
942d62bc4baSyz147064 char devname[MAXNAMELEN];
943d62bc4baSyz147064 softmac_t *softmac;
944d62bc4baSyz147064 softmac_dev_t *softmac_dev;
945d62bc4baSyz147064 int index;
946d62bc4baSyz147064 int ppa, err;
947d62bc4baSyz147064 datalink_id_t linkid;
948da14cebeSEric Cheng mac_handle_t smac_mh;
949da14cebeSEric Cheng uint32_t smac_flags;
950d62bc4baSyz147064
95161af1958SGarrett D'Amore if (GLDV3_DRV(ddi_driver_major(dip))) {
95261af1958SGarrett D'Amore minor_t minor = getminor(dev);
95361af1958SGarrett D'Amore /*
95461af1958SGarrett D'Amore * For an explanation of this logic, see the
95561af1958SGarrett D'Amore * equivalent code in softmac_create.
95661af1958SGarrett D'Amore */
95761af1958SGarrett D'Amore if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
95861af1958SGarrett D'Amore (getmajor(dev) == ddi_name_to_major("clone")) ||
95961af1958SGarrett D'Amore (minor == 0)) {
96061af1958SGarrett D'Amore return (0);
96161af1958SGarrett D'Amore }
96261af1958SGarrett D'Amore if (minor >= DLS_MAX_MINOR) {
96361af1958SGarrett D'Amore return (ENOTSUP);
96461af1958SGarrett D'Amore }
96561af1958SGarrett D'Amore ppa = DLS_MINOR2INST(minor);
96661af1958SGarrett D'Amore } else {
967d62bc4baSyz147064 ppa = ddi_get_instance(dip);
96861af1958SGarrett D'Amore }
96961af1958SGarrett D'Amore
970d62bc4baSyz147064 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
971d62bc4baSyz147064
972da14cebeSEric Cheng /*
973da14cebeSEric Cheng * We are called only from the predetach entry point. The DACF
974da14cebeSEric Cheng * framework ensures there can't be a concurrent postattach call
975da14cebeSEric Cheng * for the same softmac. The softmac found out from the modhash
976da14cebeSEric Cheng * below can't vanish beneath us since this is the only place where
977da14cebeSEric Cheng * it is deleted.
978da14cebeSEric Cheng */
979d62bc4baSyz147064 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
980d62bc4baSyz147064 (mod_hash_val_t *)&softmac);
981d62bc4baSyz147064 ASSERT(err == 0);
982d62bc4baSyz147064
983d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex);
984da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac);
985d62bc4baSyz147064
986d62bc4baSyz147064 /*
987d62bc4baSyz147064 * Fail the predetach routine if this softmac is in-use.
988da14cebeSEric Cheng * Make sure these downcalls into softmac_create or softmac_destroy
989da14cebeSEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy
990da14cebeSEric Cheng * returns EBUSY if the asynchronous thread started in softmac_create
991da14cebeSEric Cheng * hasn't finished
992d62bc4baSyz147064 */
993da14cebeSEric Cheng if ((softmac->smac_hold_cnt != 0) ||
994da14cebeSEric Cheng (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) {
995d62bc4baSyz147064 softmac->smac_attached_left = softmac->smac_attachok_cnt;
996d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
997d62bc4baSyz147064 return (EBUSY);
998d62bc4baSyz147064 }
999d62bc4baSyz147064
1000d62bc4baSyz147064 /*
1001d62bc4baSyz147064 * Even if the predetach of one minor node has already failed
1002d62bc4baSyz147064 * (smac_attached_left is not 0), the DACF framework will continue
1003d62bc4baSyz147064 * to call the predetach routines of the other minor nodes,
1004d62bc4baSyz147064 * so we fail these calls here.
1005d62bc4baSyz147064 */
1006d62bc4baSyz147064 if (softmac->smac_attached_left != 0) {
1007d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
1008d62bc4baSyz147064 return (EBUSY);
1009d62bc4baSyz147064 }
1010d62bc4baSyz147064
1011da14cebeSEric Cheng smac_mh = softmac->smac_mh;
1012da14cebeSEric Cheng smac_flags = softmac->smac_flags;
1013da14cebeSEric Cheng softmac->smac_state = SOFTMAC_DETACH_INPROG;
1014da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
1015d62bc4baSyz147064
1016da14cebeSEric Cheng if (smac_mh != NULL) {
1017d62bc4baSyz147064 /*
1018da14cebeSEric Cheng * This is the first minor node that is being detached for this
1019da14cebeSEric Cheng * softmac.
1020d62bc4baSyz147064 */
1021da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
1022da14cebeSEric Cheng if (!(smac_flags & SOFTMAC_NOSUPP)) {
1023da14cebeSEric Cheng if ((err = dls_devnet_destroy(smac_mh, &linkid,
1024da14cebeSEric Cheng B_FALSE)) != 0) {
1025da14cebeSEric Cheng goto error;
1026d62bc4baSyz147064 }
1027d62bc4baSyz147064 }
1028d62bc4baSyz147064 /*
1029d62bc4baSyz147064 * If softmac_mac_register() succeeds in registering the mac
1030d62bc4baSyz147064 * of the legacy device, unregister it.
1031d62bc4baSyz147064 */
1032da14cebeSEric Cheng if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) {
1033da14cebeSEric Cheng if ((err = mac_disable_nowait(smac_mh)) != 0) {
10342b24ab6bSSebastien Roy (void) dls_devnet_create(smac_mh, linkid,
10352b24ab6bSSebastien Roy crgetzoneid(CRED()));
1036da14cebeSEric Cheng goto error;
1037d62bc4baSyz147064 }
1038da14cebeSEric Cheng /*
1039da14cebeSEric Cheng * Ask softmac_notify_thread to quit, and wait for
1040da14cebeSEric Cheng * that to be done.
1041da14cebeSEric Cheng */
1042da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex);
1043da14cebeSEric Cheng softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT;
1044da14cebeSEric Cheng cv_broadcast(&softmac->smac_cv);
1045da14cebeSEric Cheng while (softmac->smac_notify_thread != NULL) {
1046da14cebeSEric Cheng cv_wait(&softmac->smac_cv,
1047da14cebeSEric Cheng &softmac->smac_mutex);
1048da14cebeSEric Cheng }
1049da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
1050da14cebeSEric Cheng VERIFY(mac_unregister(smac_mh) == 0);
1051d62bc4baSyz147064 }
1052d62bc4baSyz147064 softmac->smac_mh = NULL;
1053d62bc4baSyz147064 }
1054d62bc4baSyz147064
1055d62bc4baSyz147064 /*
1056d62bc4baSyz147064 * Free softmac_dev
1057d62bc4baSyz147064 */
1058da14cebeSEric Cheng rw_enter(&softmac_hash_lock, RW_WRITER);
1059da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex);
1060da14cebeSEric Cheng
1061da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG &&
1062da14cebeSEric Cheng softmac->smac_attachok_cnt != 0);
1063da14cebeSEric Cheng softmac->smac_mh = NULL;
1064d62bc4baSyz147064 index = (getmajor(dev) == ddi_name_to_major("clone"));
1065d62bc4baSyz147064 softmac_dev = softmac->smac_softmac[index];
1066d62bc4baSyz147064 ASSERT(softmac_dev != NULL);
1067d62bc4baSyz147064 softmac->smac_softmac[index] = NULL;
1068d62bc4baSyz147064 kmem_free(softmac_dev, sizeof (softmac_dev_t));
1069d62bc4baSyz147064
1070d62bc4baSyz147064 if (--softmac->smac_attachok_cnt == 0) {
1071d62bc4baSyz147064 mod_hash_val_t hashval;
1072d62bc4baSyz147064
1073da14cebeSEric Cheng softmac->smac_state = SOFTMAC_UNINIT;
1074da14cebeSEric Cheng if (softmac->smac_hold_cnt != 0) {
1075da14cebeSEric Cheng /*
1076da14cebeSEric Cheng * Someone did a softmac_hold_device while we dropped
1077da14cebeSEric Cheng * the locks. Leave the softmac itself intact which
1078da14cebeSEric Cheng * will be reused by the reattach
1079da14cebeSEric Cheng */
1080da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
1081da14cebeSEric Cheng rw_exit(&softmac_hash_lock);
1082da14cebeSEric Cheng return (0);
1083da14cebeSEric Cheng }
1084d62bc4baSyz147064 err = mod_hash_remove(softmac_hash,
1085d62bc4baSyz147064 (mod_hash_key_t)devname,
1086d62bc4baSyz147064 (mod_hash_val_t *)&hashval);
1087d62bc4baSyz147064 ASSERT(err == 0);
1088d62bc4baSyz147064
1089d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
1090d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
10915d460eafSCathy Zhou ASSERT(softmac->smac_fp_disable_clients == 0);
10925d460eafSCathy Zhou softmac->smac_fastpath_admin_disabled = B_FALSE;
10935d460eafSCathy Zhou kmem_cache_free(softmac_cachep, softmac);
1094d62bc4baSyz147064 return (0);
1095d62bc4baSyz147064 }
1096d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
1097d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
1098da14cebeSEric Cheng return (0);
1099da14cebeSEric Cheng
1100da14cebeSEric Cheng error:
1101da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex);
1102da14cebeSEric Cheng softmac->smac_attached_left = softmac->smac_attachok_cnt;
1103da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE;
1104da14cebeSEric Cheng cv_broadcast(&softmac->smac_cv);
1105da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
1106d62bc4baSyz147064 return (err);
1107d62bc4baSyz147064 }
1108d62bc4baSyz147064
1109d62bc4baSyz147064 /*
1110d62bc4baSyz147064 * This function is called as the result of a newly started dlmgmtd daemon.
1111d62bc4baSyz147064 *
1112d62bc4baSyz147064 * We walk through every softmac that was created but failed to notify
1113d62bc4baSyz147064 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs
1114d62bc4baSyz147064 * when softmacs are created before dlmgmtd is ready. For example, during
1115d62bc4baSyz147064 * diskless boot, a network device is used (and therefore attached) before
1116d62bc4baSyz147064 * the datalink-management service starts dlmgmtd.
1117d62bc4baSyz147064 */
1118d62bc4baSyz147064 /* ARGSUSED */
1119d62bc4baSyz147064 static uint_t
softmac_mac_recreate(mod_hash_key_t key,mod_hash_val_t * val,void * arg)1120d62bc4baSyz147064 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1121d62bc4baSyz147064 {
1122d62bc4baSyz147064 softmac_t *softmac = (softmac_t *)val;
1123d62bc4baSyz147064 datalink_id_t linkid;
1124d62bc4baSyz147064 int err;
1125da14cebeSEric Cheng softmac_walk_t *smwp = arg;
1126d62bc4baSyz147064
1127d62bc4baSyz147064 /*
1128da14cebeSEric Cheng * The framework itself must not hold any locks across calls to the
1129da14cebeSEric Cheng * mac perimeter. Thus this function does not call any framework
1130da14cebeSEric Cheng * function that needs to grab the mac perimeter.
1131d62bc4baSyz147064 */
1132da14cebeSEric Cheng ASSERT(RW_READ_HELD(&softmac_hash_lock));
1133d62bc4baSyz147064
1134da14cebeSEric Cheng smwp->smw_retry = B_FALSE;
1135da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex);
1136da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac);
1137da14cebeSEric Cheng if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) {
1138da14cebeSEric Cheng /*
1139da14cebeSEric Cheng * Wait till softmac_create or softmac_mac_register finishes
1140da14cebeSEric Cheng * Hold the softmac to ensure it stays around. The wait itself
1141da14cebeSEric Cheng * is done in the caller, since we need to drop all locks
1142da14cebeSEric Cheng * including the mod hash's internal lock before calling
1143da14cebeSEric Cheng * cv_wait.
1144da14cebeSEric Cheng */
1145da14cebeSEric Cheng smwp->smw_retry = B_TRUE;
1146da14cebeSEric Cheng smwp->smw_softmac = softmac;
1147da14cebeSEric Cheng softmac->smac_hold_cnt++;
1148da14cebeSEric Cheng return (MH_WALK_TERMINATE);
1149da14cebeSEric Cheng }
1150da14cebeSEric Cheng
1151da14cebeSEric Cheng if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) ||
1152d62bc4baSyz147064 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) {
1153d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
1154d62bc4baSyz147064 return (MH_WALK_CONTINUE);
1155d62bc4baSyz147064 }
1156d62bc4baSyz147064
1157ae6aa22aSVenugopal Iyer /*
1158ae6aa22aSVenugopal Iyer * Bumping up the smac_hold_cnt allows us to drop the lock. It also
1159ae6aa22aSVenugopal Iyer * makes softmac_destroy() return failure on an attempted device detach.
1160ae6aa22aSVenugopal Iyer * We don't want to hold the lock across calls to other subsystems
1161ae6aa22aSVenugopal Iyer * like kstats, which will happen in the call to dls_devnet_recreate
1162ae6aa22aSVenugopal Iyer */
1163ae6aa22aSVenugopal Iyer softmac->smac_hold_cnt++;
1164ae6aa22aSVenugopal Iyer mutex_exit(&softmac->smac_mutex);
1165ae6aa22aSVenugopal Iyer
1166d62bc4baSyz147064 if (dls_mgmt_create(softmac->smac_devname,
1167d62bc4baSyz147064 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
1168d62bc4baSyz147064 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) {
1169ae6aa22aSVenugopal Iyer softmac_rele_device((dls_dev_handle_t)softmac);
1170d62bc4baSyz147064 return (MH_WALK_CONTINUE);
1171d62bc4baSyz147064 }
1172d62bc4baSyz147064
1173d62bc4baSyz147064 if ((err = softmac_update_info(softmac, &linkid)) != 0) {
1174d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s "
1175d62bc4baSyz147064 "failed (%d)", softmac->smac_devname, err);
1176ae6aa22aSVenugopal Iyer softmac_rele_device((dls_dev_handle_t)softmac);
1177d62bc4baSyz147064 return (MH_WALK_CONTINUE);
1178d62bc4baSyz147064 }
1179d62bc4baSyz147064
1180d62bc4baSyz147064 /*
1181d62bc4baSyz147064 * Create a link for this MAC. The link name will be the same
1182d62bc4baSyz147064 * as the MAC name.
1183d62bc4baSyz147064 */
1184d62bc4baSyz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
1185d62bc4baSyz147064 err = dls_devnet_recreate(softmac->smac_mh, linkid);
1186d62bc4baSyz147064 if (err != 0) {
1187d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for "
1188d62bc4baSyz147064 "%s (linkid %d) failed (%d)",
1189d62bc4baSyz147064 softmac->smac_devname, linkid, err);
1190d62bc4baSyz147064 }
1191d62bc4baSyz147064 }
1192d62bc4baSyz147064
1193ae6aa22aSVenugopal Iyer mutex_enter(&softmac->smac_mutex);
1194d62bc4baSyz147064 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE;
1195ae6aa22aSVenugopal Iyer ASSERT(softmac->smac_hold_cnt != 0);
1196ae6aa22aSVenugopal Iyer softmac->smac_hold_cnt--;
1197d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
1198d62bc4baSyz147064
1199d62bc4baSyz147064 return (MH_WALK_CONTINUE);
1200d62bc4baSyz147064 }
1201d62bc4baSyz147064
1202d62bc4baSyz147064 /*
1203d62bc4baSyz147064 * See comments above softmac_mac_recreate().
1204d62bc4baSyz147064 */
1205d62bc4baSyz147064 void
softmac_recreate()1206d62bc4baSyz147064 softmac_recreate()
1207d62bc4baSyz147064 {
1208da14cebeSEric Cheng softmac_walk_t smw;
1209da14cebeSEric Cheng softmac_t *softmac;
1210da14cebeSEric Cheng
1211d62bc4baSyz147064 /*
1212d62bc4baSyz147064 * Walk through the softmac_hash table. Request to create the
1213d62bc4baSyz147064 * [link name, linkid] mapping if we failed to do so.
1214d62bc4baSyz147064 */
1215da14cebeSEric Cheng do {
1216da14cebeSEric Cheng smw.smw_retry = B_FALSE;
1217d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_READER);
1218da14cebeSEric Cheng mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw);
1219d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
1220da14cebeSEric Cheng if (smw.smw_retry) {
1221da14cebeSEric Cheng /*
1222da14cebeSEric Cheng * softmac_create or softmac_mac_register hasn't yet
1223da14cebeSEric Cheng * finished and the softmac is not yet in the
1224da14cebeSEric Cheng * SOFTMAC_ATTACH_DONE state.
1225da14cebeSEric Cheng */
1226da14cebeSEric Cheng softmac = smw.smw_softmac;
1227da14cebeSEric Cheng cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
1228da14cebeSEric Cheng softmac->smac_hold_cnt--;
1229da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex);
1230da14cebeSEric Cheng }
1231da14cebeSEric Cheng } while (smw.smw_retry);
1232d62bc4baSyz147064 }
1233d62bc4baSyz147064
1234d62bc4baSyz147064 static int
softmac_m_start(void * arg)1235d62bc4baSyz147064 softmac_m_start(void *arg)
1236d62bc4baSyz147064 {
12375d460eafSCathy Zhou softmac_t *softmac = arg;
12385d460eafSCathy Zhou softmac_lower_t *slp = softmac->smac_lower;
12395d460eafSCathy Zhou int err;
12405d460eafSCathy Zhou
12415d460eafSCathy Zhou ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
12425d460eafSCathy Zhou /*
12435d460eafSCathy Zhou * Bind to SAP 2 on token ring, 0 on other interface types.
12445d460eafSCathy Zhou * (SAP 0 has special significance on token ring).
12455d460eafSCathy Zhou * Note that the receive-side packets could come anytime after bind.
12465d460eafSCathy Zhou */
12475d460eafSCathy Zhou err = softmac_send_bind_req(slp, softmac->smac_media == DL_TPR ? 2 : 0);
12485d460eafSCathy Zhou if (err != 0)
12495d460eafSCathy Zhou return (err);
12505d460eafSCathy Zhou
12515d460eafSCathy Zhou /*
12525d460eafSCathy Zhou * Put the lower stream to the DL_PROMISC_SAP mode in order to receive
12535d460eafSCathy Zhou * all packets of interest.
12545d460eafSCathy Zhou *
12555d460eafSCathy Zhou * some driver (e.g. the old legacy eri driver) incorrectly passes up
12565d460eafSCathy Zhou * packets to DL_PROMISC_SAP stream when the lower stream is not bound,
12575d460eafSCathy Zhou * so that we send DL_PROMISON_REQ after DL_BIND_REQ.
12585d460eafSCathy Zhou */
12595d460eafSCathy Zhou err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE);
12605d460eafSCathy Zhou if (err != 0) {
12615d460eafSCathy Zhou (void) softmac_send_unbind_req(slp);
12625d460eafSCathy Zhou return (err);
12635d460eafSCathy Zhou }
12645d460eafSCathy Zhou
12655d460eafSCathy Zhou /*
12665d460eafSCathy Zhou * Enable capabilities the underlying driver claims to support.
12675d460eafSCathy Zhou * Some driver requires this being called after the stream is bound.
12685d460eafSCathy Zhou */
12695d460eafSCathy Zhou if ((err = softmac_capab_enable(slp)) != 0) {
12705d460eafSCathy Zhou (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
12715d460eafSCathy Zhou (void) softmac_send_unbind_req(slp);
12725d460eafSCathy Zhou }
12735d460eafSCathy Zhou
12745d460eafSCathy Zhou return (err);
1275d62bc4baSyz147064 }
1276d62bc4baSyz147064
1277d62bc4baSyz147064 /* ARGSUSED */
1278d62bc4baSyz147064 static void
softmac_m_stop(void * arg)1279d62bc4baSyz147064 softmac_m_stop(void *arg)
1280d62bc4baSyz147064 {
12815d460eafSCathy Zhou softmac_t *softmac = arg;
12825d460eafSCathy Zhou softmac_lower_t *slp = softmac->smac_lower;
12835d460eafSCathy Zhou
12845d460eafSCathy Zhou ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
12855d460eafSCathy Zhou
12865d460eafSCathy Zhou /*
12875d460eafSCathy Zhou * It is not needed to reset zerocopy, MDT or HCKSUM capabilities.
12885d460eafSCathy Zhou */
12895d460eafSCathy Zhou (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
12905d460eafSCathy Zhou (void) softmac_send_unbind_req(slp);
1291d62bc4baSyz147064 }
1292d62bc4baSyz147064
1293d62bc4baSyz147064 /*
12945d460eafSCathy Zhou * Set up the lower stream above the legacy device. There are two different
12955d460eafSCathy Zhou * type of lower streams:
12965d460eafSCathy Zhou *
12975d460eafSCathy Zhou * - Shared lower-stream
12985d460eafSCathy Zhou *
12995d460eafSCathy Zhou * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW
13005d460eafSCathy Zhou * mode to send and receive the raw data. Further, put the lower stream into
1301d62bc4baSyz147064 * DL_PROMISC_SAP mode to receive all packets of interest.
13025d460eafSCathy Zhou *
13035d460eafSCathy Zhou * - Dedicated lower-stream
13045d460eafSCathy Zhou *
13055d460eafSCathy Zhou * The lower-stream which is dedicated to upper IP/ARP stream. This is used
13065d460eafSCathy Zhou * as fast-path for IP. In this case, the second argument is the pointer to
13075d460eafSCathy Zhou * the softmac upper-stream.
1308d62bc4baSyz147064 */
13095d460eafSCathy Zhou int
softmac_lower_setup(softmac_t * softmac,softmac_upper_t * sup,softmac_lower_t ** slpp)13105d460eafSCathy Zhou softmac_lower_setup(softmac_t *softmac, softmac_upper_t *sup,
13115d460eafSCathy Zhou softmac_lower_t **slpp)
1312d62bc4baSyz147064 {
1313d62bc4baSyz147064 ldi_ident_t li;
1314d62bc4baSyz147064 dev_t dev;
1315d62bc4baSyz147064 ldi_handle_t lh = NULL;
1316d62bc4baSyz147064 softmac_lower_t *slp = NULL;
1317d62bc4baSyz147064 smac_ioc_start_t start_arg;
1318d62bc4baSyz147064 struct strioctl strioc;
1319d62bc4baSyz147064 uint32_t notifications;
1320d62bc4baSyz147064 int err, rval;
1321d62bc4baSyz147064
1322d62bc4baSyz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0)
1323d62bc4baSyz147064 return (err);
1324d62bc4baSyz147064
13255d460eafSCathy Zhou /*
13265d460eafSCathy Zhou * The GLDv3 framework makes sure that mac_unregister(), mac_open(),
13275d460eafSCathy Zhou * and mac_close() cannot be called at the same time. So we don't
13285d460eafSCathy Zhou * need any protection to access softmac here.
13295d460eafSCathy Zhou */
1330d62bc4baSyz147064 dev = softmac->smac_dev;
13315d460eafSCathy Zhou
1332d62bc4baSyz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
1333d62bc4baSyz147064 ldi_ident_release(li);
1334d62bc4baSyz147064 if (err != 0)
1335d62bc4baSyz147064 goto done;
1336d62bc4baSyz147064
1337d62bc4baSyz147064 /*
1338d62bc4baSyz147064 * Pop all the intermediate modules. The autopushed modules will
1339d62bc4baSyz147064 * be pushed when the softmac node is opened.
1340d62bc4baSyz147064 */
1341d62bc4baSyz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
1342d62bc4baSyz147064 ;
1343d62bc4baSyz147064
1344d62bc4baSyz147064 if ((softmac->smac_style == DL_STYLE2) &&
1345d62bc4baSyz147064 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) {
1346d62bc4baSyz147064 goto done;
1347d62bc4baSyz147064 }
1348d62bc4baSyz147064
1349d62bc4baSyz147064 /*
13505d460eafSCathy Zhou * If this is the shared-lower-stream, put the lower stream to
13515d460eafSCathy Zhou * the DLIOCRAW mode to send/receive raw data.
1352d62bc4baSyz147064 */
13535d460eafSCathy Zhou if ((sup == NULL) && (err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL,
13545d460eafSCathy Zhou kcred, &rval)) != 0) {
1355d62bc4baSyz147064 goto done;
13565d460eafSCathy Zhou }
1357d62bc4baSyz147064
1358d62bc4baSyz147064 /*
1359d62bc4baSyz147064 * Then push the softmac shim layer atop the lower stream.
1360d62bc4baSyz147064 */
1361d62bc4baSyz147064 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL,
1362d62bc4baSyz147064 kcred, &rval)) != 0) {
1363d62bc4baSyz147064 goto done;
1364d62bc4baSyz147064 }
1365d62bc4baSyz147064
1366d62bc4baSyz147064 /*
1367d62bc4baSyz147064 * Send the ioctl to get the slp pointer.
1368d62bc4baSyz147064 */
1369d62bc4baSyz147064 strioc.ic_cmd = SMAC_IOC_START;
1370d62bc4baSyz147064 strioc.ic_timout = INFTIM;
1371d62bc4baSyz147064 strioc.ic_len = sizeof (start_arg);
1372d62bc4baSyz147064 strioc.ic_dp = (char *)&start_arg;
1373d62bc4baSyz147064
1374d62bc4baSyz147064 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL,
1375d62bc4baSyz147064 kcred, &rval)) != 0) {
1376d62bc4baSyz147064 goto done;
1377d62bc4baSyz147064 }
1378d62bc4baSyz147064 slp = start_arg.si_slp;
13795d460eafSCathy Zhou slp->sl_sup = sup;
1380d62bc4baSyz147064 slp->sl_lh = lh;
1381d62bc4baSyz147064 slp->sl_softmac = softmac;
1382d62bc4baSyz147064 *slpp = slp;
1383d62bc4baSyz147064
13845d460eafSCathy Zhou if (sup != NULL) {
13855d460eafSCathy Zhou slp->sl_rxinfo = &sup->su_rxinfo;
13865d460eafSCathy Zhou } else {
1387d62bc4baSyz147064 /*
13885d460eafSCathy Zhou * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND.
1389d62bc4baSyz147064 * We don't have to wait for the ack.
1390d62bc4baSyz147064 */
1391d62bc4baSyz147064 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP |
1392d62bc4baSyz147064 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS |
1393d62bc4baSyz147064 DL_NOTE_PROMISC_OFF_PHYS;
1394d62bc4baSyz147064
1395d62bc4baSyz147064 (void) softmac_send_notify_req(slp,
1396d62bc4baSyz147064 (notifications & softmac->smac_notifications));
13975d460eafSCathy Zhou }
1398d62bc4baSyz147064
1399d62bc4baSyz147064 done:
1400d62bc4baSyz147064 if (err != 0)
1401d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
1402d62bc4baSyz147064 return (err);
1403d62bc4baSyz147064 }
1404d62bc4baSyz147064
1405d62bc4baSyz147064 static int
softmac_m_open(void * arg)1406d62bc4baSyz147064 softmac_m_open(void *arg)
1407d62bc4baSyz147064 {
1408d62bc4baSyz147064 softmac_t *softmac = arg;
1409d62bc4baSyz147064 softmac_lower_t *slp;
1410d62bc4baSyz147064 int err;
1411d62bc4baSyz147064
1412da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1413d62bc4baSyz147064
14145d460eafSCathy Zhou if ((err = softmac_lower_setup(softmac, NULL, &slp)) != 0)
1415d62bc4baSyz147064 return (err);
1416d62bc4baSyz147064
1417d62bc4baSyz147064 softmac->smac_lower = slp;
1418d62bc4baSyz147064 return (0);
1419d62bc4baSyz147064 }
1420d62bc4baSyz147064
1421d62bc4baSyz147064 static void
softmac_m_close(void * arg)1422d62bc4baSyz147064 softmac_m_close(void *arg)
1423d62bc4baSyz147064 {
1424d62bc4baSyz147064 softmac_t *softmac = arg;
1425d62bc4baSyz147064 softmac_lower_t *slp;
1426d62bc4baSyz147064
1427da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
1428d62bc4baSyz147064 slp = softmac->smac_lower;
1429d62bc4baSyz147064 ASSERT(slp != NULL);
1430d62bc4baSyz147064
1431d62bc4baSyz147064 /*
1432d62bc4baSyz147064 * Note that slp is destroyed when lh is closed.
1433d62bc4baSyz147064 */
1434d62bc4baSyz147064 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred);
1435d62bc4baSyz147064 softmac->smac_lower = NULL;
1436d62bc4baSyz147064 }
1437d62bc4baSyz147064
14385d460eafSCathy Zhou /*
14395d460eafSCathy Zhou * Softmac supports two priviate link properteis:
14405d460eafSCathy Zhou *
14415d460eafSCathy Zhou * - "_fastpath"
14425d460eafSCathy Zhou *
14435d460eafSCathy Zhou * This is a read-only link property which points out the current data-path
14445d460eafSCathy Zhou * model of the given legacy link. The possible values are "disabled" and
14455d460eafSCathy Zhou * "enabled".
14465d460eafSCathy Zhou *
14475d460eafSCathy Zhou * - "_disable_fastpath"
14485d460eafSCathy Zhou *
14495d460eafSCathy Zhou * This is a read-write link property which can be used to disable or enable
14505d460eafSCathy Zhou * the fast-path of the given legacy link. The possible values are "true"
14515d460eafSCathy Zhou * and "false". Note that even when "_disable_fastpath" is set to be
14525d460eafSCathy Zhou * "false", the fast-path may still not be enabled since there may be
14535d460eafSCathy Zhou * other mac cleints that request the fast-path to be disabled.
14545d460eafSCathy Zhou */
14555d460eafSCathy Zhou /* ARGSUSED */
14565d460eafSCathy Zhou static int
softmac_m_setprop(void * arg,const char * name,mac_prop_id_t id,uint_t valsize,const void * val)14575d460eafSCathy Zhou softmac_m_setprop(void *arg, const char *name, mac_prop_id_t id,
14585d460eafSCathy Zhou uint_t valsize, const void *val)
14595d460eafSCathy Zhou {
14605d460eafSCathy Zhou softmac_t *softmac = arg;
14615d460eafSCathy Zhou
14625d460eafSCathy Zhou if (id != MAC_PROP_PRIVATE || strcmp(name, "_disable_fastpath") != 0)
14635d460eafSCathy Zhou return (ENOTSUP);
14645d460eafSCathy Zhou
14655d460eafSCathy Zhou if (strcmp(val, "true") == 0)
14665d460eafSCathy Zhou return (softmac_datapath_switch(softmac, B_TRUE, B_TRUE));
14675d460eafSCathy Zhou else if (strcmp(val, "false") == 0)
14685d460eafSCathy Zhou return (softmac_datapath_switch(softmac, B_FALSE, B_TRUE));
14695d460eafSCathy Zhou else
14705d460eafSCathy Zhou return (EINVAL);
14715d460eafSCathy Zhou }
14725d460eafSCathy Zhou
14735d460eafSCathy Zhou static int
softmac_m_getprop(void * arg,const char * name,mac_prop_id_t id,uint_t valsize,void * val)1474*0dc2366fSVenugopal Iyer softmac_m_getprop(void *arg, const char *name, mac_prop_id_t id,
1475*0dc2366fSVenugopal Iyer uint_t valsize, void *val)
14765d460eafSCathy Zhou {
14775d460eafSCathy Zhou softmac_t *softmac = arg;
14785d460eafSCathy Zhou char *fpstr;
14795d460eafSCathy Zhou
14805d460eafSCathy Zhou if (id != MAC_PROP_PRIVATE)
14815d460eafSCathy Zhou return (ENOTSUP);
14825d460eafSCathy Zhou
14835d460eafSCathy Zhou if (strcmp(name, "_fastpath") == 0) {
14845d460eafSCathy Zhou mutex_enter(&softmac->smac_fp_mutex);
14855d460eafSCathy Zhou fpstr = (DATAPATH_MODE(softmac) == SOFTMAC_SLOWPATH) ?
14865d460eafSCathy Zhou "disabled" : "enabled";
14875d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex);
14885d460eafSCathy Zhou } else if (strcmp(name, "_disable_fastpath") == 0) {
1489*0dc2366fSVenugopal Iyer fpstr = softmac->smac_fastpath_admin_disabled ?
1490*0dc2366fSVenugopal Iyer "true" : "false";
1491*0dc2366fSVenugopal Iyer } else if (strcmp(name, "_softmac") == 0) {
1492*0dc2366fSVenugopal Iyer fpstr = "true";
14935d460eafSCathy Zhou } else {
14945d460eafSCathy Zhou return (ENOTSUP);
14955d460eafSCathy Zhou }
14965d460eafSCathy Zhou
14975d460eafSCathy Zhou return (strlcpy(val, fpstr, valsize) >= valsize ? EINVAL : 0);
14985d460eafSCathy Zhou }
14995d460eafSCathy Zhou
1500*0dc2366fSVenugopal Iyer static void
softmac_m_propinfo(void * arg,const char * name,mac_prop_id_t id,mac_prop_info_handle_t prh)1501*0dc2366fSVenugopal Iyer softmac_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
1502*0dc2366fSVenugopal Iyer mac_prop_info_handle_t prh)
1503*0dc2366fSVenugopal Iyer {
1504*0dc2366fSVenugopal Iyer _NOTE(ARGUNUSED(arg));
1505*0dc2366fSVenugopal Iyer
1506*0dc2366fSVenugopal Iyer if (id != MAC_PROP_PRIVATE)
1507*0dc2366fSVenugopal Iyer return;
1508*0dc2366fSVenugopal Iyer
1509*0dc2366fSVenugopal Iyer if (strcmp(name, "_fastpath") == 0) {
1510*0dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1511*0dc2366fSVenugopal Iyer } else if (strcmp(name, "_disable_fastpath") == 0) {
1512*0dc2366fSVenugopal Iyer mac_prop_info_set_default_str(prh, "false");
1513*0dc2366fSVenugopal Iyer }
1514*0dc2366fSVenugopal Iyer
1515*0dc2366fSVenugopal Iyer }
1516*0dc2366fSVenugopal Iyer
1517d62bc4baSyz147064 int
softmac_hold_device(dev_t dev,dls_dev_handle_t * ddhp)1518d62bc4baSyz147064 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp)
1519d62bc4baSyz147064 {
1520d62bc4baSyz147064 dev_info_t *dip;
1521d62bc4baSyz147064 char devname[MAXNAMELEN];
1522d62bc4baSyz147064 softmac_t *softmac;
1523ee94b1c3SSebastien Roy major_t major;
1524ee94b1c3SSebastien Roy int ppa, err = 0, inst;
152561af1958SGarrett D'Amore
1526ee94b1c3SSebastien Roy major = getmajor(dev);
1527ee94b1c3SSebastien Roy ppa = getminor(dev) - 1;
152861af1958SGarrett D'Amore
152961af1958SGarrett D'Amore /*
1530ee94b1c3SSebastien Roy * For GLDv3 devices, look up the device instance using getinfo(9e).
1531ee94b1c3SSebastien Roy * Otherwise, fall back to the old assumption that inst == ppa. The
1532ee94b1c3SSebastien Roy * GLDV3_DRV() macro depends on the driver module being loaded, hence
1533ee94b1c3SSebastien Roy * the call to ddi_hold_driver().
153461af1958SGarrett D'Amore */
1535ee94b1c3SSebastien Roy if (ddi_hold_driver(major) == NULL)
1536ee94b1c3SSebastien Roy return (ENXIO);
1537ee94b1c3SSebastien Roy if (GLDV3_DRV(major)) {
1538ee94b1c3SSebastien Roy if ((inst = dev_to_instance(dev)) < 0)
1539ee94b1c3SSebastien Roy err = ENOENT;
1540ee94b1c3SSebastien Roy } else {
1541ee94b1c3SSebastien Roy inst = ppa;
1542ee94b1c3SSebastien Roy }
1543ee94b1c3SSebastien Roy ddi_rele_driver(major);
1544ee94b1c3SSebastien Roy if (err != 0)
1545ee94b1c3SSebastien Roy return (err);
1546d62bc4baSyz147064
1547d62bc4baSyz147064 /*
1548ee94b1c3SSebastien Roy * First try to hold this device instance to force device to attach
1549ee94b1c3SSebastien Roy * and ensure that the softmac entry gets created in net_postattach().
1550d62bc4baSyz147064 */
1551ee94b1c3SSebastien Roy if ((dip = ddi_hold_devi_by_instance(major, inst, 0)) == NULL)
1552d62bc4baSyz147064 return (ENOENT);
1553d62bc4baSyz147064
1554d62bc4baSyz147064 /*
15553ade6e84SGarrett D'Amore * Exclude non-physical network device instances, for example, aggr0.
15563ade6e84SGarrett D'Amore * Note: this check *must* occur after the dip is held, or else
1557ee94b1c3SSebastien Roy * NETWORK_PHYSDRV might return false incorrectly. The
1558ee94b1c3SSebastien Roy * DN_NETWORK_PHYSDRIVER flag used by NETWORK_PHYSDRV() gets set if
1559ee94b1c3SSebastien Roy * ddi_create_minor_node() is called during the device's attach
1560ee94b1c3SSebastien Roy * phase.
15613ade6e84SGarrett D'Amore */
1562ee94b1c3SSebastien Roy if (!NETWORK_PHYSDRV(major)) {
15633ade6e84SGarrett D'Amore ddi_release_devi(dip);
15643ade6e84SGarrett D'Amore return (ENOENT);
15653ade6e84SGarrett D'Amore }
15663ade6e84SGarrett D'Amore
1567ee94b1c3SSebastien Roy /* Now wait for its softmac to be created. */
1568ee94b1c3SSebastien Roy (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_major_to_name(major),
1569ee94b1c3SSebastien Roy ppa);
1570d62bc4baSyz147064 again:
1571d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_READER);
1572d62bc4baSyz147064
1573d62bc4baSyz147064 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
1574d62bc4baSyz147064 (mod_hash_val_t *)&softmac) != 0) {
1575d62bc4baSyz147064 /*
1576d62bc4baSyz147064 * This is rare but possible. It could happen when pre-detach
1577d62bc4baSyz147064 * routine of the device succeeds. But the softmac will then
1578d62bc4baSyz147064 * be recreated when device fails to detach (as this device
1579d62bc4baSyz147064 * is held).
1580d62bc4baSyz147064 */
1581da14cebeSEric Cheng mutex_enter(&smac_global_lock);
1582d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
1583da14cebeSEric Cheng cv_wait(&smac_global_cv, &smac_global_lock);
1584da14cebeSEric Cheng mutex_exit(&smac_global_lock);
1585d62bc4baSyz147064 goto again;
1586d62bc4baSyz147064 }
1587d62bc4baSyz147064
1588d62bc4baSyz147064 /*
1589d62bc4baSyz147064 * Bump smac_hold_cnt to prevent device detach.
1590d62bc4baSyz147064 */
1591d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex);
1592d62bc4baSyz147064 softmac->smac_hold_cnt++;
1593d62bc4baSyz147064 rw_exit(&softmac_hash_lock);
1594d62bc4baSyz147064
1595d62bc4baSyz147064 /*
1596d62bc4baSyz147064 * Wait till the device is fully attached.
1597d62bc4baSyz147064 */
1598da14cebeSEric Cheng while (softmac->smac_state != SOFTMAC_ATTACH_DONE)
1599d62bc4baSyz147064 cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
1600d62bc4baSyz147064
1601da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac);
1602da14cebeSEric Cheng
1603050fb016Syz147064 if ((err = softmac->smac_attacherr) != 0)
1604050fb016Syz147064 softmac->smac_hold_cnt--;
1605050fb016Syz147064 else
1606d62bc4baSyz147064 *ddhp = (dls_dev_handle_t)softmac;
1607d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
1608d62bc4baSyz147064
1609050fb016Syz147064 ddi_release_devi(dip);
1610d62bc4baSyz147064 return (err);
1611d62bc4baSyz147064 }
1612d62bc4baSyz147064
1613d62bc4baSyz147064 void
softmac_rele_device(dls_dev_handle_t ddh)1614d62bc4baSyz147064 softmac_rele_device(dls_dev_handle_t ddh)
1615d62bc4baSyz147064 {
16165d460eafSCathy Zhou if (ddh != NULL)
16175d460eafSCathy Zhou softmac_rele((softmac_t *)ddh);
16185d460eafSCathy Zhou }
16195d460eafSCathy Zhou
16205d460eafSCathy Zhou int
softmac_hold(dev_t dev,softmac_t ** softmacp)16215d460eafSCathy Zhou softmac_hold(dev_t dev, softmac_t **softmacp)
16225d460eafSCathy Zhou {
1623d62bc4baSyz147064 softmac_t *softmac;
16245d460eafSCathy Zhou char *drv;
16255d460eafSCathy Zhou mac_handle_t mh;
16265d460eafSCathy Zhou char mac[MAXNAMELEN];
16275d460eafSCathy Zhou int err;
1628d62bc4baSyz147064
16295d460eafSCathy Zhou if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
16305d460eafSCathy Zhou return (EINVAL);
1631d62bc4baSyz147064
16325d460eafSCathy Zhou (void) snprintf(mac, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1);
16335d460eafSCathy Zhou if ((err = mac_open(mac, &mh)) != 0)
16345d460eafSCathy Zhou return (err);
16355d460eafSCathy Zhou
16365d460eafSCathy Zhou softmac = (softmac_t *)mac_driver(mh);
16375d460eafSCathy Zhou
16385d460eafSCathy Zhou mutex_enter(&softmac->smac_mutex);
16395d460eafSCathy Zhou softmac->smac_hold_cnt++;
16405d460eafSCathy Zhou mutex_exit(&softmac->smac_mutex);
16415d460eafSCathy Zhou mac_close(mh);
16425d460eafSCathy Zhou *softmacp = softmac;
16435d460eafSCathy Zhou return (0);
16445d460eafSCathy Zhou }
16455d460eafSCathy Zhou
16465d460eafSCathy Zhou void
softmac_rele(softmac_t * softmac)16475d460eafSCathy Zhou softmac_rele(softmac_t *softmac)
16485d460eafSCathy Zhou {
1649d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex);
1650050fb016Syz147064 softmac->smac_hold_cnt--;
1651d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex);
1652d62bc4baSyz147064 }
1653