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 /*
225d460eafSCathy Zhou * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23d62bc4baSyz147064 * Use is subject to license terms.
24d62bc4baSyz147064 */
25d62bc4baSyz147064
2678a53e20SJohn Levon /*
2778a53e20SJohn Levon * Copyright 2019, Joyent, Inc.
28*9b664393SGarrett D'Amore * Copyright 2022 Garrett D'Amore
2978a53e20SJohn Levon */
30d62bc4baSyz147064
31d62bc4baSyz147064 #include <sys/types.h>
32d62bc4baSyz147064 #include <inet/common.h>
33d62bc4baSyz147064 #include <sys/stropts.h>
34d62bc4baSyz147064 #include <sys/modctl.h>
355d460eafSCathy Zhou #include <sys/dld.h>
36d62bc4baSyz147064 #include <sys/softmac_impl.h>
37d62bc4baSyz147064
38d62bc4baSyz147064 dev_info_t *softmac_dip = NULL;
395d460eafSCathy Zhou static kmem_cache_t *softmac_upper_cachep;
40d62bc4baSyz147064
415d460eafSCathy Zhou /*
425d460eafSCathy Zhou * This function is a generic open(9E) entry point into the softmac for
435d460eafSCathy Zhou * both the softmac module and the softmac driver.
445d460eafSCathy Zhou */
455d460eafSCathy Zhou static int softmac_cmn_open(queue_t *, dev_t *, int, int, cred_t *);
465d460eafSCathy Zhou
475d460eafSCathy Zhou /*
485d460eafSCathy Zhou * The following softmac_mod_xxx() functions are (9E) entry point functions for
495d460eafSCathy Zhou * the softmac module.
505d460eafSCathy Zhou */
515e1743f0SToomas Soome static int softmac_mod_close(queue_t *, int, cred_t *);
52a484bfa2SToomas Soome static int softmac_mod_rput(queue_t *, mblk_t *);
53a484bfa2SToomas Soome static int softmac_mod_wput(queue_t *, mblk_t *);
54a484bfa2SToomas Soome static int softmac_mod_wsrv(queue_t *);
555d460eafSCathy Zhou
565d460eafSCathy Zhou /*
575d460eafSCathy Zhou * The following softmac_drv_xxx() functions are (9E) entry point functions for
585d460eafSCathy Zhou * the softmac driver.
595d460eafSCathy Zhou */
605d460eafSCathy Zhou static int softmac_drv_open(queue_t *, dev_t *, int, int, cred_t *);
615e1743f0SToomas Soome static int softmac_drv_close(queue_t *, int, cred_t *);
62a484bfa2SToomas Soome static int softmac_drv_wput(queue_t *, mblk_t *);
63a484bfa2SToomas Soome static int softmac_drv_wsrv(queue_t *);
645d460eafSCathy Zhou
65d62bc4baSyz147064 static int softmac_attach(dev_info_t *, ddi_attach_cmd_t);
66d62bc4baSyz147064 static int softmac_detach(dev_info_t *, ddi_detach_cmd_t);
67d62bc4baSyz147064 static int softmac_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
68d62bc4baSyz147064
69d62bc4baSyz147064 static struct module_info softmac_modinfo = {
70d62bc4baSyz147064 0,
71d62bc4baSyz147064 SOFTMAC_DEV_NAME,
72d62bc4baSyz147064 0,
73d62bc4baSyz147064 INFPSZ,
74d62bc4baSyz147064 65536,
75d62bc4baSyz147064 1024
76d62bc4baSyz147064 };
77d62bc4baSyz147064
78d62bc4baSyz147064 /*
79d62bc4baSyz147064 * hi-water mark is 1 because of the flow control mechanism implemented in
80d62bc4baSyz147064 * dld. Refer to the comments in dld_str.c for details.
81d62bc4baSyz147064 */
82d62bc4baSyz147064 static struct module_info softmac_dld_modinfo = {
83d62bc4baSyz147064 0,
84d62bc4baSyz147064 SOFTMAC_DEV_NAME,
85d62bc4baSyz147064 0,
86d62bc4baSyz147064 INFPSZ,
87d62bc4baSyz147064 1,
88d62bc4baSyz147064 0
89d62bc4baSyz147064 };
90d62bc4baSyz147064
91d62bc4baSyz147064 static struct qinit softmac_urinit = {
92a484bfa2SToomas Soome softmac_mod_rput, /* qi_putp */
93a484bfa2SToomas Soome NULL, /* qi_srvp */
945d460eafSCathy Zhou softmac_cmn_open, /* qi_qopen */
955d460eafSCathy Zhou softmac_mod_close, /* qi_qclose */
96d62bc4baSyz147064 NULL, /* qi_qadmin */
97d62bc4baSyz147064 &softmac_modinfo /* qi_minfo */
98d62bc4baSyz147064 };
99d62bc4baSyz147064
100d62bc4baSyz147064 static struct qinit softmac_uwinit = {
101a484bfa2SToomas Soome softmac_mod_wput, /* qi_putp */
102a484bfa2SToomas Soome softmac_mod_wsrv, /* qi_srvp */
103d62bc4baSyz147064 NULL, /* qi_qopen */
104d62bc4baSyz147064 NULL, /* qi_qclose */
105d62bc4baSyz147064 NULL, /* qi_qadmin */
106d62bc4baSyz147064 &softmac_modinfo /* qi_minfo */
107d62bc4baSyz147064 };
108d62bc4baSyz147064
109d62bc4baSyz147064 static struct streamtab softmac_tab = {
110d62bc4baSyz147064 &softmac_urinit, /* st_rdinit */
111d62bc4baSyz147064 &softmac_uwinit /* st_wrinit */
112d62bc4baSyz147064 };
113d62bc4baSyz147064
114d62bc4baSyz147064 DDI_DEFINE_STREAM_OPS(softmac_ops, nulldev, nulldev, softmac_attach,
11519397407SSherry Moore softmac_detach, nodev, softmac_info, D_MP, &softmac_tab,
11619397407SSherry Moore ddi_quiesce_not_supported);
117d62bc4baSyz147064
118d62bc4baSyz147064 static struct qinit softmac_dld_r_qinit = {
1195d460eafSCathy Zhou NULL, NULL, softmac_drv_open, softmac_drv_close, NULL,
1205d460eafSCathy Zhou &softmac_dld_modinfo
121d62bc4baSyz147064 };
122d62bc4baSyz147064
123d62bc4baSyz147064 static struct qinit softmac_dld_w_qinit = {
124a484bfa2SToomas Soome softmac_drv_wput, softmac_drv_wsrv, NULL, NULL, NULL,
125d62bc4baSyz147064 &softmac_dld_modinfo
126d62bc4baSyz147064 };
127d62bc4baSyz147064
128d62bc4baSyz147064 static struct fmodsw softmac_fmodsw = {
129d62bc4baSyz147064 SOFTMAC_DEV_NAME,
130d62bc4baSyz147064 &softmac_tab,
131d62bc4baSyz147064 D_MP
132d62bc4baSyz147064 };
133d62bc4baSyz147064
134d62bc4baSyz147064 static struct modldrv softmac_modldrv = {
135d62bc4baSyz147064 &mod_driverops,
136d62bc4baSyz147064 "softmac driver",
137d62bc4baSyz147064 &softmac_ops
138d62bc4baSyz147064 };
139d62bc4baSyz147064
140d62bc4baSyz147064 static struct modlstrmod softmac_modlstrmod = {
141d62bc4baSyz147064 &mod_strmodops,
142d62bc4baSyz147064 "softmac module",
143d62bc4baSyz147064 &softmac_fmodsw
144d62bc4baSyz147064 };
145d62bc4baSyz147064
146d62bc4baSyz147064 static struct modlinkage softmac_modlinkage = {
147d62bc4baSyz147064 MODREV_1,
148d62bc4baSyz147064 &softmac_modlstrmod,
149d62bc4baSyz147064 &softmac_modldrv,
150d62bc4baSyz147064 NULL
151d62bc4baSyz147064 };
152d62bc4baSyz147064
153bd670b35SErik Nordmark static void softmac_dedicated_rx(void *, mac_resource_handle_t, mblk_t *,
154bd670b35SErik Nordmark mac_header_info_t *);
155bd670b35SErik Nordmark
1565d460eafSCathy Zhou /*ARGSUSED*/
1575d460eafSCathy Zhou static int
softmac_upper_constructor(void * buf,void * arg,int kmflag)1585d460eafSCathy Zhou softmac_upper_constructor(void *buf, void *arg, int kmflag)
1595d460eafSCathy Zhou {
1605d460eafSCathy Zhou softmac_upper_t *sup = buf;
1615d460eafSCathy Zhou
1625d460eafSCathy Zhou bzero(buf, sizeof (softmac_upper_t));
1635d460eafSCathy Zhou
1645d460eafSCathy Zhou mutex_init(&sup->su_mutex, NULL, MUTEX_DEFAULT, NULL);
1655d460eafSCathy Zhou cv_init(&sup->su_cv, NULL, CV_DEFAULT, NULL);
1665d460eafSCathy Zhou mutex_init(&sup->su_disp_mutex, NULL, MUTEX_DEFAULT, NULL);
1675d460eafSCathy Zhou cv_init(&sup->su_disp_cv, NULL, CV_DEFAULT, NULL);
1685d460eafSCathy Zhou list_create(&sup->su_req_list, sizeof (softmac_switch_req_t),
1695d460eafSCathy Zhou offsetof(softmac_switch_req_t, ssq_req_list_node));
1705d460eafSCathy Zhou return (0);
1715d460eafSCathy Zhou }
1725d460eafSCathy Zhou
1735d460eafSCathy Zhou /*ARGSUSED*/
1745d460eafSCathy Zhou static void
softmac_upper_destructor(void * buf,void * arg)1755d460eafSCathy Zhou softmac_upper_destructor(void *buf, void *arg)
1765d460eafSCathy Zhou {
1775d460eafSCathy Zhou softmac_upper_t *sup = buf;
1785d460eafSCathy Zhou
1795d460eafSCathy Zhou ASSERT(sup->su_slp == NULL);
1805d460eafSCathy Zhou ASSERT(sup->su_pending_head == NULL && sup->su_pending_tail == NULL);
1815d460eafSCathy Zhou ASSERT(!sup->su_dlpi_pending);
1825d460eafSCathy Zhou ASSERT(!sup->su_active);
1835d460eafSCathy Zhou ASSERT(!sup->su_closing);
1845d460eafSCathy Zhou ASSERT(sup->su_tx_flow_mp == NULL);
1855d460eafSCathy Zhou ASSERT(sup->su_tx_inprocess == 0);
1865d460eafSCathy Zhou ASSERT(sup->su_mode == SOFTMAC_UNKNOWN);
1875d460eafSCathy Zhou ASSERT(!sup->su_tx_busy);
1885d460eafSCathy Zhou ASSERT(!sup->su_bound);
1895d460eafSCathy Zhou ASSERT(!sup->su_taskq_scheduled);
19079eeb645SCathy Zhou ASSERT(sup->su_tx_notify_func == NULL);
19179eeb645SCathy Zhou ASSERT(sup->su_tx_notify_arg == NULL);
1925d460eafSCathy Zhou ASSERT(list_is_empty(&sup->su_req_list));
1935d460eafSCathy Zhou
1945d460eafSCathy Zhou list_destroy(&sup->su_req_list);
1955d460eafSCathy Zhou mutex_destroy(&sup->su_mutex);
1965d460eafSCathy Zhou cv_destroy(&sup->su_cv);
1975d460eafSCathy Zhou mutex_destroy(&sup->su_disp_mutex);
1985d460eafSCathy Zhou cv_destroy(&sup->su_disp_cv);
1995d460eafSCathy Zhou }
2005d460eafSCathy Zhou
201d62bc4baSyz147064 int
_init(void)202d62bc4baSyz147064 _init(void)
203d62bc4baSyz147064 {
204d62bc4baSyz147064 int err;
205d62bc4baSyz147064
206ee94b1c3SSebastien Roy mac_init_ops(NULL, SOFTMAC_DEV_NAME);
207d62bc4baSyz147064 softmac_init();
208d62bc4baSyz147064
2095d460eafSCathy Zhou softmac_upper_cachep = kmem_cache_create("softmac_upper_cache",
2105d460eafSCathy Zhou sizeof (softmac_upper_t), 0, softmac_upper_constructor,
2115d460eafSCathy Zhou softmac_upper_destructor, NULL, NULL, NULL, 0);
2125d460eafSCathy Zhou ASSERT(softmac_upper_cachep != NULL);
2135d460eafSCathy Zhou
214d62bc4baSyz147064 if ((err = mod_install(&softmac_modlinkage)) != 0) {
215d62bc4baSyz147064 softmac_fini();
216d62bc4baSyz147064 return (err);
217d62bc4baSyz147064 }
218d62bc4baSyz147064
219d62bc4baSyz147064 return (0);
220d62bc4baSyz147064 }
221d62bc4baSyz147064
222d62bc4baSyz147064 int
_fini(void)223d62bc4baSyz147064 _fini(void)
224d62bc4baSyz147064 {
225d62bc4baSyz147064 int err;
226d62bc4baSyz147064
227d62bc4baSyz147064 if (softmac_busy())
228d62bc4baSyz147064 return (EBUSY);
229d62bc4baSyz147064
230d62bc4baSyz147064 if ((err = mod_remove(&softmac_modlinkage)) != 0)
231d62bc4baSyz147064 return (err);
232d62bc4baSyz147064
2335d460eafSCathy Zhou kmem_cache_destroy(softmac_upper_cachep);
234d62bc4baSyz147064 softmac_fini();
235d62bc4baSyz147064
236d62bc4baSyz147064 return (0);
237d62bc4baSyz147064 }
238d62bc4baSyz147064
239d62bc4baSyz147064 int
_info(struct modinfo * modinfop)240d62bc4baSyz147064 _info(struct modinfo *modinfop)
241d62bc4baSyz147064 {
242d62bc4baSyz147064 return (mod_info(&softmac_modlinkage, modinfop));
243d62bc4baSyz147064 }
244d62bc4baSyz147064
245d62bc4baSyz147064 static int
softmac_cmn_open(queue_t * rq,dev_t * devp,int flag,int sflag,cred_t * credp)2465d460eafSCathy Zhou softmac_cmn_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
247d62bc4baSyz147064 {
248d62bc4baSyz147064 softmac_lower_t *slp;
249d62bc4baSyz147064 /*
250d62bc4baSyz147064 * This is a self-cloning driver so that each queue should only
251d62bc4baSyz147064 * get opened once.
252d62bc4baSyz147064 */
253d62bc4baSyz147064 if (rq->q_ptr != NULL)
254d62bc4baSyz147064 return (EBUSY);
255d62bc4baSyz147064
256d62bc4baSyz147064 if (sflag == MODOPEN) {
257d62bc4baSyz147064 /*
258d62bc4baSyz147064 * This is the softmac module pushed over an underlying
259d62bc4baSyz147064 * legacy device. Initialize the lower structure.
260d62bc4baSyz147064 */
261d62bc4baSyz147064 if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL)
262d62bc4baSyz147064 return (ENOMEM);
263d62bc4baSyz147064
264d62bc4baSyz147064 slp->sl_wq = WR(rq);
265d62bc4baSyz147064 cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL);
266d62bc4baSyz147064 mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL);
267d62bc4baSyz147064 slp->sl_pending_prim = DL_PRIM_INVAL;
268d62bc4baSyz147064 rq->q_ptr = WR(rq)->q_ptr = slp;
269d62bc4baSyz147064 qprocson(rq);
270d62bc4baSyz147064 return (0);
271d62bc4baSyz147064 }
272d62bc4baSyz147064
273d62bc4baSyz147064 /*
274d62bc4baSyz147064 * Regular device open of a softmac DLPI node. We modify
275d62bc4baSyz147064 * the queues' q_qinfo pointer such that all future STREAMS
2765d460eafSCathy Zhou * operations will go through another set of entry points
277d62bc4baSyz147064 */
278d62bc4baSyz147064 rq->q_qinfo = &softmac_dld_r_qinit;
279d62bc4baSyz147064 WR(rq)->q_qinfo = &softmac_dld_w_qinit;
2805d460eafSCathy Zhou return (softmac_drv_open(rq, devp, flag, sflag, credp));
281d62bc4baSyz147064 }
282d62bc4baSyz147064
2835e1743f0SToomas Soome /* ARGSUSED */
284d62bc4baSyz147064 static int
softmac_mod_close(queue_t * rq,int flags __unused,cred_t * credp __unused)2855e1743f0SToomas Soome softmac_mod_close(queue_t *rq, int flags __unused, cred_t *credp __unused)
286d62bc4baSyz147064 {
287d62bc4baSyz147064 softmac_lower_t *slp = rq->q_ptr;
288d62bc4baSyz147064
289d62bc4baSyz147064 /*
290d62bc4baSyz147064 * Call the appropriate delete routine depending on whether this is
291d62bc4baSyz147064 * a module or device.
292d62bc4baSyz147064 */
293d62bc4baSyz147064 ASSERT(WR(rq)->q_next != NULL);
294d62bc4baSyz147064
295d62bc4baSyz147064 qprocsoff(rq);
296d62bc4baSyz147064
297d62bc4baSyz147064 slp->sl_softmac = NULL;
298d62bc4baSyz147064 slp->sl_lh = NULL;
299d62bc4baSyz147064
300d62bc4baSyz147064 ASSERT(slp->sl_ack_mp == NULL);
301d62bc4baSyz147064 ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
302d62bc4baSyz147064 ASSERT(slp->sl_pending_ioctl == B_FALSE);
303d62bc4baSyz147064
304d62bc4baSyz147064 cv_destroy(&slp->sl_cv);
305d62bc4baSyz147064 mutex_destroy(&slp->sl_mutex);
306d62bc4baSyz147064
307d62bc4baSyz147064 kmem_free(slp, sizeof (*slp));
308d62bc4baSyz147064 return (0);
309d62bc4baSyz147064 }
310d62bc4baSyz147064
311a484bfa2SToomas Soome static int
softmac_mod_rput(queue_t * rq,mblk_t * mp)3125d460eafSCathy Zhou softmac_mod_rput(queue_t *rq, mblk_t *mp)
313d62bc4baSyz147064 {
314d62bc4baSyz147064 softmac_lower_t *slp = rq->q_ptr;
3155d460eafSCathy Zhou softmac_lower_rxinfo_t *rxinfo;
316d62bc4baSyz147064 union DL_primitives *dlp;
317d62bc4baSyz147064
318d62bc4baSyz147064 /*
319d62bc4baSyz147064 * This is the softmac module.
320d62bc4baSyz147064 */
321d62bc4baSyz147064 ASSERT(WR(rq)->q_next != NULL);
322d62bc4baSyz147064 ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL));
323d62bc4baSyz147064
324d62bc4baSyz147064 switch (DB_TYPE(mp)) {
3255d460eafSCathy Zhou case M_DATA: {
3265d460eafSCathy Zhou
327d62bc4baSyz147064 /*
3285d460eafSCathy Zhou * If sl_rxinfo is non-NULL. This is dedicated-lower-stream
3295d460eafSCathy Zhou * created for fastpath. Directly call the rx callback.
3305d460eafSCathy Zhou */
3315d460eafSCathy Zhou if ((rxinfo = slp->sl_rxinfo) != NULL) {
3325d460eafSCathy Zhou rxinfo->slr_rx(rxinfo->slr_arg, NULL, mp, NULL);
3335d460eafSCathy Zhou break;
3345d460eafSCathy Zhou }
3355d460eafSCathy Zhou
3365d460eafSCathy Zhou /*
3375d460eafSCathy Zhou * A shared-lower-stream. Some driver starts to send up
3385d460eafSCathy Zhou * packets even it not in the DL_IDLE state, where
3395d460eafSCathy Zhou * sl_softmac is not set yet. Drop the packet in this case.
340d62bc4baSyz147064 */
341d62bc4baSyz147064 if (slp->sl_softmac == NULL) {
342d62bc4baSyz147064 freemsg(mp);
343a484bfa2SToomas Soome return (0);
344d62bc4baSyz147064 }
345d62bc4baSyz147064
346d62bc4baSyz147064 /*
347da14cebeSEric Cheng * If this message is looped back from the legacy devices,
348da14cebeSEric Cheng * drop it as the Nemo framework will be responsible for
349da14cebeSEric Cheng * looping it back by the mac_txloop() function.
350da14cebeSEric Cheng */
351da14cebeSEric Cheng if (mp->b_flag & MSGNOLOOP) {
352da14cebeSEric Cheng freemsg(mp);
353a484bfa2SToomas Soome return (0);
354da14cebeSEric Cheng }
355da14cebeSEric Cheng
356da14cebeSEric Cheng /*
357d62bc4baSyz147064 * This is the most common case.
358d62bc4baSyz147064 */
359d62bc4baSyz147064 if (DB_REF(mp) == 1) {
360d62bc4baSyz147064 ASSERT(slp->sl_softmac != NULL);
361da14cebeSEric Cheng mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
362a484bfa2SToomas Soome return (0);
363d62bc4baSyz147064 } else {
364d62bc4baSyz147064 softmac_rput_process_data(slp, mp);
365d62bc4baSyz147064 }
366d62bc4baSyz147064 break;
3675d460eafSCathy Zhou }
368d62bc4baSyz147064 case M_PROTO:
369d62bc4baSyz147064 case M_PCPROTO:
370d62bc4baSyz147064 if (MBLKL(mp) < sizeof (dlp->dl_primitive)) {
371d62bc4baSyz147064 freemsg(mp);
372d62bc4baSyz147064 break;
373d62bc4baSyz147064 }
374d62bc4baSyz147064 dlp = (union DL_primitives *)mp->b_rptr;
375d62bc4baSyz147064 if (dlp->dl_primitive == DL_UNITDATA_IND) {
3765d460eafSCathy Zhou
3775d460eafSCathy Zhou if ((rxinfo = slp->sl_rxinfo) != NULL) {
378bd670b35SErik Nordmark softmac_dedicated_rx(slp->sl_sup, NULL, mp,
379bd670b35SErik Nordmark NULL);
3805d460eafSCathy Zhou break;
3815d460eafSCathy Zhou }
3825d460eafSCathy Zhou
383d62bc4baSyz147064 cmn_err(CE_WARN, "got unexpected %s message",
384d62bc4baSyz147064 dl_primstr(DL_UNITDATA_IND));
385d62bc4baSyz147064 freemsg(mp);
386d62bc4baSyz147064 break;
387d62bc4baSyz147064 }
388d62bc4baSyz147064 /*FALLTHROUGH*/
389d62bc4baSyz147064 default:
3905d460eafSCathy Zhou softmac_rput_process_notdata(rq, slp->sl_sup, mp);
391d62bc4baSyz147064 break;
392d62bc4baSyz147064 }
393a484bfa2SToomas Soome return (0);
394d62bc4baSyz147064 }
395d62bc4baSyz147064
396a484bfa2SToomas Soome static int
softmac_mod_wput(queue_t * wq,mblk_t * mp)3975d460eafSCathy Zhou softmac_mod_wput(queue_t *wq, mblk_t *mp)
398d62bc4baSyz147064 {
399d62bc4baSyz147064 /*
400d62bc4baSyz147064 * This is the softmac module
401d62bc4baSyz147064 */
402d62bc4baSyz147064 ASSERT(wq->q_next != NULL);
403d62bc4baSyz147064
404d62bc4baSyz147064 switch (DB_TYPE(mp)) {
405d62bc4baSyz147064 case M_IOCTL: {
406d62bc4baSyz147064 struct iocblk *ioc = (struct iocblk *)mp->b_rptr;
407d62bc4baSyz147064
408d62bc4baSyz147064 switch (ioc->ioc_cmd) {
409d62bc4baSyz147064 case SMAC_IOC_START: {
410d62bc4baSyz147064 softmac_lower_t *slp = wq->q_ptr;
411d62bc4baSyz147064 smac_ioc_start_t *arg;
412d62bc4baSyz147064
413d62bc4baSyz147064 if (ioc->ioc_count != sizeof (*arg)) {
414d62bc4baSyz147064 miocnak(wq, mp, 0, EINVAL);
415d62bc4baSyz147064 break;
416d62bc4baSyz147064 }
417d62bc4baSyz147064
418d62bc4baSyz147064 /*
419d62bc4baSyz147064 * Assign the devname and perstream handle of the
420d62bc4baSyz147064 * specific lower stream and return it as a part
421d62bc4baSyz147064 * of the ioctl.
422d62bc4baSyz147064 */
423d62bc4baSyz147064 arg = (smac_ioc_start_t *)mp->b_cont->b_rptr;
424d62bc4baSyz147064 arg->si_slp = slp;
425d62bc4baSyz147064 miocack(wq, mp, sizeof (*arg), 0);
426d62bc4baSyz147064 break;
427d62bc4baSyz147064 }
428d62bc4baSyz147064 default:
429d62bc4baSyz147064 miocnak(wq, mp, 0, EINVAL);
430d62bc4baSyz147064 break;
431d62bc4baSyz147064 }
432d62bc4baSyz147064 break;
433d62bc4baSyz147064 }
434d62bc4baSyz147064 default:
435d62bc4baSyz147064 freemsg(mp);
436d62bc4baSyz147064 break;
437d62bc4baSyz147064 }
438a484bfa2SToomas Soome return (0);
439d62bc4baSyz147064 }
440d62bc4baSyz147064
441a484bfa2SToomas Soome static int
softmac_mod_wsrv(queue_t * wq)4425d460eafSCathy Zhou softmac_mod_wsrv(queue_t *wq)
443d62bc4baSyz147064 {
444d62bc4baSyz147064 softmac_lower_t *slp = wq->q_ptr;
445d62bc4baSyz147064
446d62bc4baSyz147064 /*
447d62bc4baSyz147064 * This is the softmac module
448d62bc4baSyz147064 */
449d62bc4baSyz147064 ASSERT(wq->q_next != NULL);
450d62bc4baSyz147064
451d62bc4baSyz147064 /*
452d62bc4baSyz147064 * Inform that the tx resource is available; mac_tx_update() will
453d62bc4baSyz147064 * inform all the upper streams sharing this lower stream.
454d62bc4baSyz147064 */
4555d460eafSCathy Zhou if (slp->sl_sup != NULL)
4565d460eafSCathy Zhou qenable(slp->sl_sup->su_wq);
4575d460eafSCathy Zhou else if (slp->sl_softmac != NULL)
458d62bc4baSyz147064 mac_tx_update(slp->sl_softmac->smac_mh);
459a484bfa2SToomas Soome return (0);
460d62bc4baSyz147064 }
461d62bc4baSyz147064
462d62bc4baSyz147064 static int
softmac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)463d62bc4baSyz147064 softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
464d62bc4baSyz147064 {
465d62bc4baSyz147064 ASSERT(ddi_get_instance(dip) == 0);
466d62bc4baSyz147064
467d62bc4baSyz147064 if (cmd != DDI_ATTACH)
468d62bc4baSyz147064 return (DDI_FAILURE);
469d62bc4baSyz147064
470d62bc4baSyz147064 softmac_dip = dip;
471d62bc4baSyz147064
472d62bc4baSyz147064 return (DDI_SUCCESS);
473d62bc4baSyz147064 }
474d62bc4baSyz147064
475d62bc4baSyz147064 /* ARGSUSED */
476d62bc4baSyz147064 static int
softmac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)477d62bc4baSyz147064 softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
478d62bc4baSyz147064 {
479d62bc4baSyz147064 if (cmd != DDI_DETACH)
480d62bc4baSyz147064 return (DDI_FAILURE);
481d62bc4baSyz147064
482d62bc4baSyz147064 softmac_dip = NULL;
483d62bc4baSyz147064 return (DDI_SUCCESS);
484d62bc4baSyz147064 }
485d62bc4baSyz147064
486d62bc4baSyz147064 /* ARGSUSED */
487d62bc4baSyz147064 static int
softmac_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)488d62bc4baSyz147064 softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
489d62bc4baSyz147064 {
490d62bc4baSyz147064 switch (infocmd) {
491d62bc4baSyz147064 case DDI_INFO_DEVT2DEVINFO:
492d62bc4baSyz147064 if (softmac_dip != NULL) {
493d62bc4baSyz147064 *result = softmac_dip;
494d62bc4baSyz147064 return (DDI_SUCCESS);
495d62bc4baSyz147064 }
496d62bc4baSyz147064 break;
497d62bc4baSyz147064
498d62bc4baSyz147064 case DDI_INFO_DEVT2INSTANCE:
499d62bc4baSyz147064 *result = NULL;
500d62bc4baSyz147064 return (DDI_SUCCESS);
501d62bc4baSyz147064
502d62bc4baSyz147064 }
503d62bc4baSyz147064
504d62bc4baSyz147064 return (DDI_FAILURE);
505d62bc4baSyz147064 }
5065d460eafSCathy Zhou
5075d460eafSCathy Zhou /*ARGSUSED*/
5085d460eafSCathy Zhou static void
softmac_dedicated_rx(void * arg,mac_resource_handle_t mrh,mblk_t * mp,mac_header_info_t * mhip)5095d460eafSCathy Zhou softmac_dedicated_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
5105d460eafSCathy Zhou mac_header_info_t *mhip)
5115d460eafSCathy Zhou {
5125d460eafSCathy Zhou queue_t *rq = ((softmac_upper_t *)arg)->su_rq;
5135d460eafSCathy Zhou
5145d460eafSCathy Zhou if (canputnext(rq))
5155d460eafSCathy Zhou putnext(rq, mp);
5165d460eafSCathy Zhou else
5175d460eafSCathy Zhou freemsg(mp);
5185d460eafSCathy Zhou }
5195d460eafSCathy Zhou
5205d460eafSCathy Zhou /*ARGSUSED*/
5215d460eafSCathy Zhou static int
softmac_drv_open(queue_t * rq,dev_t * devp,int flag,int sflag,cred_t * credp)5225d460eafSCathy Zhou softmac_drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
5235d460eafSCathy Zhou {
5245d460eafSCathy Zhou softmac_upper_t *sup = NULL;
5255d460eafSCathy Zhou softmac_t *softmac;
5265d460eafSCathy Zhou int err = 0;
5275d460eafSCathy Zhou
5285d460eafSCathy Zhou /*
5295d460eafSCathy Zhou * This is a softmac device created for a legacy device, find the
5305d460eafSCathy Zhou * associated softmac and initialize the softmac_upper_t structure.
5315d460eafSCathy Zhou */
5325d460eafSCathy Zhou if ((err = softmac_hold(*devp, &softmac)) != 0)
5335d460eafSCathy Zhou return (err);
5345d460eafSCathy Zhou
5355d460eafSCathy Zhou sup = kmem_cache_alloc(softmac_upper_cachep, KM_NOSLEEP);
5365d460eafSCathy Zhou if (sup == NULL) {
5375d460eafSCathy Zhou err = ENOMEM;
5385d460eafSCathy Zhou goto fail;
5395d460eafSCathy Zhou }
5405d460eafSCathy Zhou
5415d460eafSCathy Zhou ASSERT(list_is_empty(&sup->su_req_list));
5425d460eafSCathy Zhou
5435d460eafSCathy Zhou if ((sup->su_tx_flow_mp = allocb(1, BPRI_HI)) == NULL) {
5445d460eafSCathy Zhou err = ENOMEM;
5455d460eafSCathy Zhou goto fail;
5465d460eafSCathy Zhou }
5475d460eafSCathy Zhou
5485d460eafSCathy Zhou sup->su_rq = rq;
5495d460eafSCathy Zhou sup->su_wq = WR(rq);
5505d460eafSCathy Zhou sup->su_softmac = softmac;
5515d460eafSCathy Zhou sup->su_mode = SOFTMAC_UNKNOWN;
5525d460eafSCathy Zhou
5535d460eafSCathy Zhou sup->su_rxinfo.slr_arg = sup;
5545d460eafSCathy Zhou sup->su_rxinfo.slr_rx = softmac_dedicated_rx;
5555d460eafSCathy Zhou sup->su_direct_rxinfo.slr_arg = sup;
5565d460eafSCathy Zhou sup->su_direct_rxinfo.slr_rx = softmac_dedicated_rx;
5575d460eafSCathy Zhou
5585d460eafSCathy Zhou if ((err = dld_str_open(rq, devp, sup)) != 0) {
5595d460eafSCathy Zhou freeb(sup->su_tx_flow_mp);
5605d460eafSCathy Zhou sup->su_tx_flow_mp = NULL;
5615d460eafSCathy Zhou goto fail;
5625d460eafSCathy Zhou }
5635d460eafSCathy Zhou
5645d460eafSCathy Zhou return (0);
5655d460eafSCathy Zhou
5665d460eafSCathy Zhou fail:
5675d460eafSCathy Zhou if (sup != NULL)
5685d460eafSCathy Zhou kmem_cache_free(softmac_upper_cachep, sup);
5695d460eafSCathy Zhou softmac_rele(softmac);
5705d460eafSCathy Zhou return (err);
5715d460eafSCathy Zhou }
5725d460eafSCathy Zhou
5735e1743f0SToomas Soome /* ARGSUSED */
5745d460eafSCathy Zhou static int
softmac_drv_close(queue_t * rq,int flags __unused,cred_t * credp __unused)5755e1743f0SToomas Soome softmac_drv_close(queue_t *rq, int flags __unused, cred_t *credp __unused)
5765d460eafSCathy Zhou {
5775d460eafSCathy Zhou softmac_upper_t *sup = dld_str_private(rq);
5785d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac;
5795d460eafSCathy Zhou
5805d460eafSCathy Zhou ASSERT(WR(rq)->q_next == NULL);
5815d460eafSCathy Zhou
5825d460eafSCathy Zhou qprocsoff(rq);
5835d460eafSCathy Zhou
5845d460eafSCathy Zhou ASSERT(sup->su_tx_inprocess == 0);
5855d460eafSCathy Zhou
5865d460eafSCathy Zhou /*
5875d460eafSCathy Zhou * Wait until the pending request are processed by the worker thread.
5885d460eafSCathy Zhou */
5895d460eafSCathy Zhou mutex_enter(&sup->su_disp_mutex);
5905d460eafSCathy Zhou sup->su_closing = B_TRUE;
5915d460eafSCathy Zhou while (sup->su_dlpi_pending)
5925d460eafSCathy Zhou cv_wait(&sup->su_disp_cv, &sup->su_disp_mutex);
5935d460eafSCathy Zhou mutex_exit(&sup->su_disp_mutex);
5945d460eafSCathy Zhou
5955d460eafSCathy Zhou softmac_upperstream_close(sup);
5965d460eafSCathy Zhou
5975d460eafSCathy Zhou if (sup->su_tx_flow_mp != NULL) {
5985d460eafSCathy Zhou freeb(sup->su_tx_flow_mp);
5995d460eafSCathy Zhou sup->su_tx_flow_mp = NULL;
6005d460eafSCathy Zhou }
6015d460eafSCathy Zhou
6025d460eafSCathy Zhou if (sup->su_active) {
6035d460eafSCathy Zhou mutex_enter(&softmac->smac_active_mutex);
6045d460eafSCathy Zhou softmac->smac_nactive--;
6055d460eafSCathy Zhou mutex_exit(&softmac->smac_active_mutex);
6065d460eafSCathy Zhou sup->su_active = B_FALSE;
6075d460eafSCathy Zhou }
6085d460eafSCathy Zhou
6095d460eafSCathy Zhou sup->su_bound = B_FALSE;
6105d460eafSCathy Zhou sup->su_softmac = NULL;
6115d460eafSCathy Zhou sup->su_closing = B_FALSE;
6125d460eafSCathy Zhou
6135d460eafSCathy Zhou kmem_cache_free(softmac_upper_cachep, sup);
6145d460eafSCathy Zhou
6155d460eafSCathy Zhou softmac_rele(softmac);
6165d460eafSCathy Zhou return (dld_str_close(rq));
6175d460eafSCathy Zhou }
6185d460eafSCathy Zhou
619a484bfa2SToomas Soome static int
softmac_drv_wput(queue_t * wq,mblk_t * mp)6205d460eafSCathy Zhou softmac_drv_wput(queue_t *wq, mblk_t *mp)
6215d460eafSCathy Zhou {
6225d460eafSCathy Zhou softmac_upper_t *sup = dld_str_private(wq);
6235d460eafSCathy Zhou t_uscalar_t prim;
6245d460eafSCathy Zhou
6255d460eafSCathy Zhou ASSERT(wq->q_next == NULL);
6265d460eafSCathy Zhou
6275d460eafSCathy Zhou switch (DB_TYPE(mp)) {
6285d460eafSCathy Zhou case M_DATA:
6295d460eafSCathy Zhou softmac_wput_data(sup, mp);
6305d460eafSCathy Zhou break;
6315d460eafSCathy Zhou case M_PROTO:
6325d460eafSCathy Zhou case M_PCPROTO:
6335d460eafSCathy Zhou
6345d460eafSCathy Zhou if (MBLKL(mp) < sizeof (t_uscalar_t)) {
6355d460eafSCathy Zhou freemsg(mp);
636a484bfa2SToomas Soome return (0);
6375d460eafSCathy Zhou }
6385d460eafSCathy Zhou
6395d460eafSCathy Zhou prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
6405d460eafSCathy Zhou if (prim == DL_UNITDATA_REQ) {
6415d460eafSCathy Zhou softmac_wput_data(sup, mp);
642a484bfa2SToomas Soome return (0);
6435d460eafSCathy Zhou }
6445d460eafSCathy Zhou
6455d460eafSCathy Zhou softmac_wput_nondata(sup, mp);
6465d460eafSCathy Zhou break;
6475d460eafSCathy Zhou default:
6485d460eafSCathy Zhou softmac_wput_nondata(sup, mp);
6495d460eafSCathy Zhou break;
6505d460eafSCathy Zhou }
651a484bfa2SToomas Soome return (0);
6525d460eafSCathy Zhou }
6535d460eafSCathy Zhou
654a484bfa2SToomas Soome static int
softmac_drv_wsrv(queue_t * wq)6555d460eafSCathy Zhou softmac_drv_wsrv(queue_t *wq)
6565d460eafSCathy Zhou {
6575d460eafSCathy Zhou softmac_upper_t *sup = dld_str_private(wq);
6585d460eafSCathy Zhou
6595d460eafSCathy Zhou ASSERT(wq->q_next == NULL);
6605d460eafSCathy Zhou
6615d460eafSCathy Zhou mutex_enter(&sup->su_mutex);
6625d460eafSCathy Zhou if (sup->su_mode != SOFTMAC_FASTPATH) {
6635d460eafSCathy Zhou /*
6645d460eafSCathy Zhou * Bump su_tx_inprocess so that su_mode won't change.
6655d460eafSCathy Zhou */
6665d460eafSCathy Zhou sup->su_tx_inprocess++;
6675d460eafSCathy Zhou mutex_exit(&sup->su_mutex);
66878a53e20SJohn Levon (void) dld_wsrv(wq);
6695d460eafSCathy Zhou mutex_enter(&sup->su_mutex);
6705d460eafSCathy Zhou if (--sup->su_tx_inprocess == 0)
6715d460eafSCathy Zhou cv_signal(&sup->su_cv);
6725d460eafSCathy Zhou } else if (sup->su_tx_busy && SOFTMAC_CANPUTNEXT(sup->su_slp->sl_wq)) {
6735d460eafSCathy Zhou /*
6745d460eafSCathy Zhou * The flow-conctol of the dedicated-lower-stream is
67579eeb645SCathy Zhou * relieved. If DLD_CAPAB_DIRECT is enabled, call tx_notify
67679eeb645SCathy Zhou * callback to relieve the flow-control of the specific client,
67779eeb645SCathy Zhou * otherwise relieve the flow-control of all the upper-stream
67879eeb645SCathy Zhou * using the traditional STREAM mechanism.
6795d460eafSCathy Zhou */
68079eeb645SCathy Zhou if (sup->su_tx_notify_func != NULL) {
68179eeb645SCathy Zhou sup->su_tx_inprocess++;
68279eeb645SCathy Zhou mutex_exit(&sup->su_mutex);
68379eeb645SCathy Zhou sup->su_tx_notify_func(sup->su_tx_notify_arg,
68479eeb645SCathy Zhou (mac_tx_cookie_t)sup);
68579eeb645SCathy Zhou mutex_enter(&sup->su_mutex);
68679eeb645SCathy Zhou if (--sup->su_tx_inprocess == 0)
68779eeb645SCathy Zhou cv_signal(&sup->su_cv);
68879eeb645SCathy Zhou }
68979eeb645SCathy Zhou ASSERT(sup->su_tx_flow_mp == NULL);
69079eeb645SCathy Zhou VERIFY((sup->su_tx_flow_mp = getq(wq)) != NULL);
6915d460eafSCathy Zhou sup->su_tx_busy = B_FALSE;
6925d460eafSCathy Zhou }
6935d460eafSCathy Zhou mutex_exit(&sup->su_mutex);
694a484bfa2SToomas Soome return (0);
6955d460eafSCathy Zhou }
696