xref: /titanic_51/usr/src/uts/common/io/softmac/softmac_dev.c (revision bd670b35a010421b6e1a5536c34453a827007c81)
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 
26d62bc4baSyz147064 
27d62bc4baSyz147064 #include <sys/types.h>
28d62bc4baSyz147064 #include <inet/common.h>
29d62bc4baSyz147064 #include <sys/stropts.h>
30d62bc4baSyz147064 #include <sys/modctl.h>
315d460eafSCathy Zhou #include <sys/dld.h>
32d62bc4baSyz147064 #include <sys/softmac_impl.h>
33d62bc4baSyz147064 
34d62bc4baSyz147064 dev_info_t		*softmac_dip = NULL;
355d460eafSCathy Zhou static kmem_cache_t	*softmac_upper_cachep;
36d62bc4baSyz147064 
375d460eafSCathy Zhou /*
385d460eafSCathy Zhou  * This function is a generic open(9E) entry point into the softmac for
395d460eafSCathy Zhou  * both the softmac module and the softmac driver.
405d460eafSCathy Zhou  */
415d460eafSCathy Zhou static int softmac_cmn_open(queue_t *, dev_t *, int, int, cred_t *);
425d460eafSCathy Zhou 
435d460eafSCathy Zhou /*
445d460eafSCathy Zhou  * The following softmac_mod_xxx() functions are (9E) entry point functions for
455d460eafSCathy Zhou  * the softmac module.
465d460eafSCathy Zhou  */
475d460eafSCathy Zhou static int softmac_mod_close(queue_t *);
485d460eafSCathy Zhou static void softmac_mod_rput(queue_t *, mblk_t *);
495d460eafSCathy Zhou static void softmac_mod_wput(queue_t *, mblk_t *);
505d460eafSCathy Zhou static void softmac_mod_wsrv(queue_t *);
515d460eafSCathy Zhou 
525d460eafSCathy Zhou /*
535d460eafSCathy Zhou  * The following softmac_drv_xxx() functions are (9E) entry point functions for
545d460eafSCathy Zhou  * the softmac driver.
555d460eafSCathy Zhou  */
565d460eafSCathy Zhou static int softmac_drv_open(queue_t *, dev_t *, int, int, cred_t *);
575d460eafSCathy Zhou static int softmac_drv_close(queue_t *);
585d460eafSCathy Zhou static void softmac_drv_wput(queue_t *, mblk_t *);
595d460eafSCathy Zhou static void softmac_drv_wsrv(queue_t *);
605d460eafSCathy Zhou 
61d62bc4baSyz147064 static int softmac_attach(dev_info_t *, ddi_attach_cmd_t);
62d62bc4baSyz147064 static int softmac_detach(dev_info_t *, ddi_detach_cmd_t);
63d62bc4baSyz147064 static int softmac_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
64d62bc4baSyz147064 
65d62bc4baSyz147064 static struct module_info softmac_modinfo = {
66d62bc4baSyz147064 	0,
67d62bc4baSyz147064 	SOFTMAC_DEV_NAME,
68d62bc4baSyz147064 	0,
69d62bc4baSyz147064 	INFPSZ,
70d62bc4baSyz147064 	65536,
71d62bc4baSyz147064 	1024
72d62bc4baSyz147064 };
73d62bc4baSyz147064 
74d62bc4baSyz147064 /*
75d62bc4baSyz147064  * hi-water mark is 1 because of the flow control mechanism implemented in
76d62bc4baSyz147064  * dld.  Refer to the comments in dld_str.c for details.
77d62bc4baSyz147064  */
78d62bc4baSyz147064 static struct module_info softmac_dld_modinfo = {
79d62bc4baSyz147064 	0,
80d62bc4baSyz147064 	SOFTMAC_DEV_NAME,
81d62bc4baSyz147064 	0,
82d62bc4baSyz147064 	INFPSZ,
83d62bc4baSyz147064 	1,
84d62bc4baSyz147064 	0
85d62bc4baSyz147064 };
86d62bc4baSyz147064 
87d62bc4baSyz147064 static struct qinit softmac_urinit = {
885d460eafSCathy Zhou 	(pfi_t)softmac_mod_rput,	/* qi_putp */
895d460eafSCathy Zhou 	(pfi_t)NULL,			/* qi_srvp */
905d460eafSCathy Zhou 	softmac_cmn_open,		/* qi_qopen */
915d460eafSCathy Zhou 	softmac_mod_close,		/* qi_qclose */
92d62bc4baSyz147064 	NULL,				/* qi_qadmin */
93d62bc4baSyz147064 	&softmac_modinfo		/* qi_minfo */
94d62bc4baSyz147064 };
95d62bc4baSyz147064 
96d62bc4baSyz147064 static struct qinit softmac_uwinit = {
975d460eafSCathy Zhou 	(pfi_t)softmac_mod_wput,	/* qi_putp */
985d460eafSCathy Zhou 	(pfi_t)softmac_mod_wsrv,	/* qi_srvp */
99d62bc4baSyz147064 	NULL,				/* qi_qopen */
100d62bc4baSyz147064 	NULL,				/* qi_qclose */
101d62bc4baSyz147064 	NULL,				/* qi_qadmin */
102d62bc4baSyz147064 	&softmac_modinfo		/* qi_minfo */
103d62bc4baSyz147064 };
104d62bc4baSyz147064 
105d62bc4baSyz147064 static struct streamtab softmac_tab = {
106d62bc4baSyz147064 	&softmac_urinit,	/* st_rdinit */
107d62bc4baSyz147064 	&softmac_uwinit		/* st_wrinit */
108d62bc4baSyz147064 };
109d62bc4baSyz147064 
110d62bc4baSyz147064 DDI_DEFINE_STREAM_OPS(softmac_ops, nulldev, nulldev, softmac_attach,
11119397407SSherry Moore     softmac_detach, nodev, softmac_info, D_MP, &softmac_tab,
11219397407SSherry Moore     ddi_quiesce_not_supported);
113d62bc4baSyz147064 
114d62bc4baSyz147064 static struct qinit softmac_dld_r_qinit = {
1155d460eafSCathy Zhou 	NULL, NULL, softmac_drv_open, softmac_drv_close, NULL,
1165d460eafSCathy Zhou 	&softmac_dld_modinfo
117d62bc4baSyz147064 };
118d62bc4baSyz147064 
119d62bc4baSyz147064 static struct qinit softmac_dld_w_qinit = {
1205d460eafSCathy Zhou 	(pfi_t)softmac_drv_wput, (pfi_t)softmac_drv_wsrv, NULL, NULL, NULL,
121d62bc4baSyz147064 	&softmac_dld_modinfo
122d62bc4baSyz147064 };
123d62bc4baSyz147064 
124d62bc4baSyz147064 static struct fmodsw softmac_fmodsw = {
125d62bc4baSyz147064 	SOFTMAC_DEV_NAME,
126d62bc4baSyz147064 	&softmac_tab,
127d62bc4baSyz147064 	D_MP
128d62bc4baSyz147064 };
129d62bc4baSyz147064 
130d62bc4baSyz147064 static struct modldrv softmac_modldrv = {
131d62bc4baSyz147064 	&mod_driverops,
132d62bc4baSyz147064 	"softmac driver",
133d62bc4baSyz147064 	&softmac_ops
134d62bc4baSyz147064 };
135d62bc4baSyz147064 
136d62bc4baSyz147064 static struct modlstrmod softmac_modlstrmod = {
137d62bc4baSyz147064 	&mod_strmodops,
138d62bc4baSyz147064 	"softmac module",
139d62bc4baSyz147064 	&softmac_fmodsw
140d62bc4baSyz147064 };
141d62bc4baSyz147064 
142d62bc4baSyz147064 static struct modlinkage softmac_modlinkage = {
143d62bc4baSyz147064 	MODREV_1,
144d62bc4baSyz147064 	&softmac_modlstrmod,
145d62bc4baSyz147064 	&softmac_modldrv,
146d62bc4baSyz147064 	NULL
147d62bc4baSyz147064 };
148d62bc4baSyz147064 
149*bd670b35SErik Nordmark static void softmac_dedicated_rx(void *, mac_resource_handle_t, mblk_t *,
150*bd670b35SErik Nordmark     mac_header_info_t *);
151*bd670b35SErik Nordmark 
1525d460eafSCathy Zhou /*ARGSUSED*/
1535d460eafSCathy Zhou static int
1545d460eafSCathy Zhou softmac_upper_constructor(void *buf, void *arg, int kmflag)
1555d460eafSCathy Zhou {
1565d460eafSCathy Zhou 	softmac_upper_t	*sup = buf;
1575d460eafSCathy Zhou 
1585d460eafSCathy Zhou 	bzero(buf, sizeof (softmac_upper_t));
1595d460eafSCathy Zhou 
1605d460eafSCathy Zhou 	mutex_init(&sup->su_mutex, NULL, MUTEX_DEFAULT, NULL);
1615d460eafSCathy Zhou 	cv_init(&sup->su_cv, NULL, CV_DEFAULT, NULL);
1625d460eafSCathy Zhou 	mutex_init(&sup->su_disp_mutex, NULL, MUTEX_DEFAULT, NULL);
1635d460eafSCathy Zhou 	cv_init(&sup->su_disp_cv, NULL, CV_DEFAULT, NULL);
1645d460eafSCathy Zhou 	list_create(&sup->su_req_list, sizeof (softmac_switch_req_t),
1655d460eafSCathy Zhou 	    offsetof(softmac_switch_req_t, ssq_req_list_node));
1665d460eafSCathy Zhou 	return (0);
1675d460eafSCathy Zhou }
1685d460eafSCathy Zhou 
1695d460eafSCathy Zhou /*ARGSUSED*/
1705d460eafSCathy Zhou static void
1715d460eafSCathy Zhou softmac_upper_destructor(void *buf, void *arg)
1725d460eafSCathy Zhou {
1735d460eafSCathy Zhou 	softmac_upper_t	*sup = buf;
1745d460eafSCathy Zhou 
1755d460eafSCathy Zhou 	ASSERT(sup->su_slp == NULL);
1765d460eafSCathy Zhou 	ASSERT(sup->su_pending_head == NULL && sup->su_pending_tail == NULL);
1775d460eafSCathy Zhou 	ASSERT(!sup->su_dlpi_pending);
1785d460eafSCathy Zhou 	ASSERT(!sup->su_active);
1795d460eafSCathy Zhou 	ASSERT(!sup->su_closing);
1805d460eafSCathy Zhou 	ASSERT(sup->su_tx_flow_mp == NULL);
1815d460eafSCathy Zhou 	ASSERT(sup->su_tx_inprocess == 0);
1825d460eafSCathy Zhou 	ASSERT(sup->su_mode == SOFTMAC_UNKNOWN);
1835d460eafSCathy Zhou 	ASSERT(!sup->su_tx_busy);
1845d460eafSCathy Zhou 	ASSERT(!sup->su_bound);
1855d460eafSCathy Zhou 	ASSERT(!sup->su_taskq_scheduled);
18679eeb645SCathy Zhou 	ASSERT(sup->su_tx_notify_func == NULL);
18779eeb645SCathy Zhou 	ASSERT(sup->su_tx_notify_arg == NULL);
1885d460eafSCathy Zhou 	ASSERT(list_is_empty(&sup->su_req_list));
1895d460eafSCathy Zhou 
1905d460eafSCathy Zhou 	list_destroy(&sup->su_req_list);
1915d460eafSCathy Zhou 	mutex_destroy(&sup->su_mutex);
1925d460eafSCathy Zhou 	cv_destroy(&sup->su_cv);
1935d460eafSCathy Zhou 	mutex_destroy(&sup->su_disp_mutex);
1945d460eafSCathy Zhou 	cv_destroy(&sup->su_disp_cv);
1955d460eafSCathy Zhou }
1965d460eafSCathy Zhou 
197d62bc4baSyz147064 int
198d62bc4baSyz147064 _init(void)
199d62bc4baSyz147064 {
200d62bc4baSyz147064 	int	err;
201d62bc4baSyz147064 
202ee94b1c3SSebastien Roy 	mac_init_ops(NULL, SOFTMAC_DEV_NAME);
203d62bc4baSyz147064 	softmac_init();
204d62bc4baSyz147064 
2055d460eafSCathy Zhou 	softmac_upper_cachep = kmem_cache_create("softmac_upper_cache",
2065d460eafSCathy Zhou 	    sizeof (softmac_upper_t), 0, softmac_upper_constructor,
2075d460eafSCathy Zhou 	    softmac_upper_destructor, NULL, NULL, NULL, 0);
2085d460eafSCathy Zhou 	ASSERT(softmac_upper_cachep != NULL);
2095d460eafSCathy Zhou 
210d62bc4baSyz147064 	if ((err = mod_install(&softmac_modlinkage)) != 0) {
211d62bc4baSyz147064 		softmac_fini();
212d62bc4baSyz147064 		return (err);
213d62bc4baSyz147064 	}
214d62bc4baSyz147064 
215d62bc4baSyz147064 	return (0);
216d62bc4baSyz147064 }
217d62bc4baSyz147064 
218d62bc4baSyz147064 int
219d62bc4baSyz147064 _fini(void)
220d62bc4baSyz147064 {
221d62bc4baSyz147064 	int err;
222d62bc4baSyz147064 
223d62bc4baSyz147064 	if (softmac_busy())
224d62bc4baSyz147064 		return (EBUSY);
225d62bc4baSyz147064 
226d62bc4baSyz147064 	if ((err = mod_remove(&softmac_modlinkage)) != 0)
227d62bc4baSyz147064 		return (err);
228d62bc4baSyz147064 
2295d460eafSCathy Zhou 	kmem_cache_destroy(softmac_upper_cachep);
230d62bc4baSyz147064 	softmac_fini();
231d62bc4baSyz147064 
232d62bc4baSyz147064 	return (0);
233d62bc4baSyz147064 }
234d62bc4baSyz147064 
235d62bc4baSyz147064 int
236d62bc4baSyz147064 _info(struct modinfo *modinfop)
237d62bc4baSyz147064 {
238d62bc4baSyz147064 	return (mod_info(&softmac_modlinkage, modinfop));
239d62bc4baSyz147064 }
240d62bc4baSyz147064 
241d62bc4baSyz147064 static int
2425d460eafSCathy Zhou softmac_cmn_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
243d62bc4baSyz147064 {
244d62bc4baSyz147064 	softmac_lower_t	*slp;
245d62bc4baSyz147064 	/*
246d62bc4baSyz147064 	 * This is a self-cloning driver so that each queue should only
247d62bc4baSyz147064 	 * get opened once.
248d62bc4baSyz147064 	 */
249d62bc4baSyz147064 	if (rq->q_ptr != NULL)
250d62bc4baSyz147064 		return (EBUSY);
251d62bc4baSyz147064 
252d62bc4baSyz147064 	if (sflag == MODOPEN) {
253d62bc4baSyz147064 		/*
254d62bc4baSyz147064 		 * This is the softmac module pushed over an underlying
255d62bc4baSyz147064 		 * legacy device.  Initialize the lower structure.
256d62bc4baSyz147064 		 */
257d62bc4baSyz147064 		if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL)
258d62bc4baSyz147064 			return (ENOMEM);
259d62bc4baSyz147064 
260d62bc4baSyz147064 		slp->sl_wq = WR(rq);
261d62bc4baSyz147064 		cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL);
262d62bc4baSyz147064 		mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL);
263d62bc4baSyz147064 		slp->sl_pending_prim = DL_PRIM_INVAL;
264d62bc4baSyz147064 		rq->q_ptr = WR(rq)->q_ptr = slp;
265d62bc4baSyz147064 		qprocson(rq);
266d62bc4baSyz147064 		return (0);
267d62bc4baSyz147064 	}
268d62bc4baSyz147064 
269d62bc4baSyz147064 	/*
270d62bc4baSyz147064 	 * Regular device open of a softmac DLPI node.  We modify
271d62bc4baSyz147064 	 * the queues' q_qinfo pointer such that all future STREAMS
2725d460eafSCathy Zhou 	 * operations will go through another set of entry points
273d62bc4baSyz147064 	 */
274d62bc4baSyz147064 	rq->q_qinfo = &softmac_dld_r_qinit;
275d62bc4baSyz147064 	WR(rq)->q_qinfo = &softmac_dld_w_qinit;
2765d460eafSCathy Zhou 	return (softmac_drv_open(rq, devp, flag, sflag, credp));
277d62bc4baSyz147064 }
278d62bc4baSyz147064 
279d62bc4baSyz147064 static int
2805d460eafSCathy Zhou softmac_mod_close(queue_t *rq)
281d62bc4baSyz147064 {
282d62bc4baSyz147064 	softmac_lower_t	*slp = rq->q_ptr;
283d62bc4baSyz147064 
284d62bc4baSyz147064 	/*
285d62bc4baSyz147064 	 * Call the appropriate delete routine depending on whether this is
286d62bc4baSyz147064 	 * a module or device.
287d62bc4baSyz147064 	 */
288d62bc4baSyz147064 	ASSERT(WR(rq)->q_next != NULL);
289d62bc4baSyz147064 
290d62bc4baSyz147064 	qprocsoff(rq);
291d62bc4baSyz147064 
292d62bc4baSyz147064 	slp->sl_softmac = NULL;
293d62bc4baSyz147064 	slp->sl_lh = NULL;
294d62bc4baSyz147064 
295d62bc4baSyz147064 	ASSERT(slp->sl_ack_mp == NULL);
296d62bc4baSyz147064 	ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
297d62bc4baSyz147064 	ASSERT(slp->sl_pending_ioctl == B_FALSE);
298d62bc4baSyz147064 
299d62bc4baSyz147064 	cv_destroy(&slp->sl_cv);
300d62bc4baSyz147064 	mutex_destroy(&slp->sl_mutex);
301d62bc4baSyz147064 
302d62bc4baSyz147064 	kmem_free(slp, sizeof (*slp));
303d62bc4baSyz147064 	return (0);
304d62bc4baSyz147064 }
305d62bc4baSyz147064 
306d62bc4baSyz147064 static void
3075d460eafSCathy Zhou softmac_mod_rput(queue_t *rq, mblk_t *mp)
308d62bc4baSyz147064 {
309d62bc4baSyz147064 	softmac_lower_t		*slp = rq->q_ptr;
3105d460eafSCathy Zhou 	softmac_lower_rxinfo_t	*rxinfo;
311d62bc4baSyz147064 	union DL_primitives	*dlp;
312d62bc4baSyz147064 
313d62bc4baSyz147064 	/*
314d62bc4baSyz147064 	 * This is the softmac module.
315d62bc4baSyz147064 	 */
316d62bc4baSyz147064 	ASSERT(WR(rq)->q_next != NULL);
317d62bc4baSyz147064 	ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL));
318d62bc4baSyz147064 
319d62bc4baSyz147064 	switch (DB_TYPE(mp)) {
3205d460eafSCathy Zhou 	case M_DATA: {
3215d460eafSCathy Zhou 
322d62bc4baSyz147064 		/*
3235d460eafSCathy Zhou 		 * If sl_rxinfo is non-NULL. This is dedicated-lower-stream
3245d460eafSCathy Zhou 		 * created for fastpath. Directly call the rx callback.
3255d460eafSCathy Zhou 		 */
3265d460eafSCathy Zhou 		if ((rxinfo = slp->sl_rxinfo) != NULL) {
3275d460eafSCathy Zhou 			rxinfo->slr_rx(rxinfo->slr_arg, NULL, mp, NULL);
3285d460eafSCathy Zhou 			break;
3295d460eafSCathy Zhou 		}
3305d460eafSCathy Zhou 
3315d460eafSCathy Zhou 		/*
3325d460eafSCathy Zhou 		 * A shared-lower-stream. Some driver starts to send up
3335d460eafSCathy Zhou 		 * packets even it not in the DL_IDLE state, where
3345d460eafSCathy Zhou 		 * sl_softmac is not set yet. Drop the packet in this case.
335d62bc4baSyz147064 		 */
336d62bc4baSyz147064 		if (slp->sl_softmac == NULL) {
337d62bc4baSyz147064 			freemsg(mp);
338d62bc4baSyz147064 			return;
339d62bc4baSyz147064 		}
340d62bc4baSyz147064 
341d62bc4baSyz147064 		/*
342da14cebeSEric Cheng 		 * If this message is looped back from the legacy devices,
343da14cebeSEric Cheng 		 * drop it as the Nemo framework will be responsible for
344da14cebeSEric Cheng 		 * looping it back by the mac_txloop() function.
345da14cebeSEric Cheng 		 */
346da14cebeSEric Cheng 		if (mp->b_flag & MSGNOLOOP) {
347da14cebeSEric Cheng 			freemsg(mp);
348da14cebeSEric Cheng 			return;
349da14cebeSEric Cheng 		}
350da14cebeSEric Cheng 
351da14cebeSEric Cheng 		/*
352d62bc4baSyz147064 		 * This is the most common case.
353d62bc4baSyz147064 		 */
354d62bc4baSyz147064 		if (DB_REF(mp) == 1) {
355d62bc4baSyz147064 			ASSERT(slp->sl_softmac != NULL);
356da14cebeSEric Cheng 			mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
357d62bc4baSyz147064 			return;
358d62bc4baSyz147064 		} else {
359d62bc4baSyz147064 			softmac_rput_process_data(slp, mp);
360d62bc4baSyz147064 		}
361d62bc4baSyz147064 		break;
3625d460eafSCathy Zhou 	}
363d62bc4baSyz147064 	case M_PROTO:
364d62bc4baSyz147064 	case M_PCPROTO:
365d62bc4baSyz147064 		if (MBLKL(mp) < sizeof (dlp->dl_primitive)) {
366d62bc4baSyz147064 			freemsg(mp);
367d62bc4baSyz147064 			break;
368d62bc4baSyz147064 		}
369d62bc4baSyz147064 		dlp = (union DL_primitives *)mp->b_rptr;
370d62bc4baSyz147064 		if (dlp->dl_primitive == DL_UNITDATA_IND) {
3715d460eafSCathy Zhou 
3725d460eafSCathy Zhou 			if ((rxinfo = slp->sl_rxinfo) != NULL) {
373*bd670b35SErik Nordmark 				softmac_dedicated_rx(slp->sl_sup, NULL, mp,
374*bd670b35SErik Nordmark 				    NULL);
3755d460eafSCathy Zhou 				break;
3765d460eafSCathy Zhou 			}
3775d460eafSCathy Zhou 
378d62bc4baSyz147064 			cmn_err(CE_WARN, "got unexpected %s message",
379d62bc4baSyz147064 			    dl_primstr(DL_UNITDATA_IND));
380d62bc4baSyz147064 			freemsg(mp);
381d62bc4baSyz147064 			break;
382d62bc4baSyz147064 		}
383d62bc4baSyz147064 		/*FALLTHROUGH*/
384d62bc4baSyz147064 	default:
3855d460eafSCathy Zhou 		softmac_rput_process_notdata(rq, slp->sl_sup, mp);
386d62bc4baSyz147064 		break;
387d62bc4baSyz147064 	}
388d62bc4baSyz147064 }
389d62bc4baSyz147064 
390d62bc4baSyz147064 static void
3915d460eafSCathy Zhou softmac_mod_wput(queue_t *wq, mblk_t *mp)
392d62bc4baSyz147064 {
393d62bc4baSyz147064 	/*
394d62bc4baSyz147064 	 * This is the softmac module
395d62bc4baSyz147064 	 */
396d62bc4baSyz147064 	ASSERT(wq->q_next != NULL);
397d62bc4baSyz147064 
398d62bc4baSyz147064 	switch (DB_TYPE(mp)) {
399d62bc4baSyz147064 	case M_IOCTL: {
400d62bc4baSyz147064 		struct iocblk		*ioc = (struct iocblk *)mp->b_rptr;
401d62bc4baSyz147064 
402d62bc4baSyz147064 		switch (ioc->ioc_cmd) {
403d62bc4baSyz147064 		case SMAC_IOC_START: {
404d62bc4baSyz147064 			softmac_lower_t		*slp = wq->q_ptr;
405d62bc4baSyz147064 			smac_ioc_start_t	*arg;
406d62bc4baSyz147064 
407d62bc4baSyz147064 			if (ioc->ioc_count != sizeof (*arg)) {
408d62bc4baSyz147064 				miocnak(wq, mp, 0, EINVAL);
409d62bc4baSyz147064 				break;
410d62bc4baSyz147064 			}
411d62bc4baSyz147064 
412d62bc4baSyz147064 			/*
413d62bc4baSyz147064 			 * Assign the devname and perstream handle of the
414d62bc4baSyz147064 			 * specific lower stream and return it as a part
415d62bc4baSyz147064 			 * of the ioctl.
416d62bc4baSyz147064 			 */
417d62bc4baSyz147064 			arg = (smac_ioc_start_t *)mp->b_cont->b_rptr;
418d62bc4baSyz147064 			arg->si_slp = slp;
419d62bc4baSyz147064 			miocack(wq, mp, sizeof (*arg), 0);
420d62bc4baSyz147064 			break;
421d62bc4baSyz147064 		}
422d62bc4baSyz147064 		default:
423d62bc4baSyz147064 			miocnak(wq, mp, 0, EINVAL);
424d62bc4baSyz147064 			break;
425d62bc4baSyz147064 		}
426d62bc4baSyz147064 		break;
427d62bc4baSyz147064 	}
428d62bc4baSyz147064 	default:
429d62bc4baSyz147064 		freemsg(mp);
430d62bc4baSyz147064 		break;
431d62bc4baSyz147064 	}
432d62bc4baSyz147064 }
433d62bc4baSyz147064 
434d62bc4baSyz147064 static void
4355d460eafSCathy Zhou softmac_mod_wsrv(queue_t *wq)
436d62bc4baSyz147064 {
437d62bc4baSyz147064 	softmac_lower_t *slp = wq->q_ptr;
438d62bc4baSyz147064 
439d62bc4baSyz147064 	/*
440d62bc4baSyz147064 	 * This is the softmac module
441d62bc4baSyz147064 	 */
442d62bc4baSyz147064 	ASSERT(wq->q_next != NULL);
443d62bc4baSyz147064 
444d62bc4baSyz147064 	/*
445d62bc4baSyz147064 	 * Inform that the tx resource is available; mac_tx_update() will
446d62bc4baSyz147064 	 * inform all the upper streams sharing this lower stream.
447d62bc4baSyz147064 	 */
4485d460eafSCathy Zhou 	if (slp->sl_sup != NULL)
4495d460eafSCathy Zhou 		qenable(slp->sl_sup->su_wq);
4505d460eafSCathy Zhou 	else if (slp->sl_softmac != NULL)
451d62bc4baSyz147064 		mac_tx_update(slp->sl_softmac->smac_mh);
452d62bc4baSyz147064 }
453d62bc4baSyz147064 
454d62bc4baSyz147064 static int
455d62bc4baSyz147064 softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
456d62bc4baSyz147064 {
457d62bc4baSyz147064 	ASSERT(ddi_get_instance(dip) == 0);
458d62bc4baSyz147064 
459d62bc4baSyz147064 	if (cmd != DDI_ATTACH)
460d62bc4baSyz147064 		return (DDI_FAILURE);
461d62bc4baSyz147064 
462d62bc4baSyz147064 	softmac_dip = dip;
463d62bc4baSyz147064 
464d62bc4baSyz147064 	return (DDI_SUCCESS);
465d62bc4baSyz147064 }
466d62bc4baSyz147064 
467d62bc4baSyz147064 /* ARGSUSED */
468d62bc4baSyz147064 static int
469d62bc4baSyz147064 softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
470d62bc4baSyz147064 {
471d62bc4baSyz147064 	if (cmd != DDI_DETACH)
472d62bc4baSyz147064 		return (DDI_FAILURE);
473d62bc4baSyz147064 
474d62bc4baSyz147064 	softmac_dip = NULL;
475d62bc4baSyz147064 	return (DDI_SUCCESS);
476d62bc4baSyz147064 }
477d62bc4baSyz147064 
478d62bc4baSyz147064 /* ARGSUSED */
479d62bc4baSyz147064 static int
480d62bc4baSyz147064 softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
481d62bc4baSyz147064 {
482d62bc4baSyz147064 	switch (infocmd) {
483d62bc4baSyz147064 	case DDI_INFO_DEVT2DEVINFO:
484d62bc4baSyz147064 		if (softmac_dip != NULL) {
485d62bc4baSyz147064 			*result = softmac_dip;
486d62bc4baSyz147064 			return (DDI_SUCCESS);
487d62bc4baSyz147064 		}
488d62bc4baSyz147064 		break;
489d62bc4baSyz147064 
490d62bc4baSyz147064 	case DDI_INFO_DEVT2INSTANCE:
491d62bc4baSyz147064 		*result = NULL;
492d62bc4baSyz147064 		return (DDI_SUCCESS);
493d62bc4baSyz147064 
494d62bc4baSyz147064 	}
495d62bc4baSyz147064 
496d62bc4baSyz147064 	return (DDI_FAILURE);
497d62bc4baSyz147064 }
4985d460eafSCathy Zhou 
4995d460eafSCathy Zhou /*ARGSUSED*/
5005d460eafSCathy Zhou static void
5015d460eafSCathy Zhou softmac_dedicated_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
5025d460eafSCathy Zhou     mac_header_info_t *mhip)
5035d460eafSCathy Zhou {
5045d460eafSCathy Zhou 	queue_t *rq = ((softmac_upper_t *)arg)->su_rq;
5055d460eafSCathy Zhou 
5065d460eafSCathy Zhou 	if (canputnext(rq))
5075d460eafSCathy Zhou 		putnext(rq, mp);
5085d460eafSCathy Zhou 	else
5095d460eafSCathy Zhou 		freemsg(mp);
5105d460eafSCathy Zhou }
5115d460eafSCathy Zhou 
5125d460eafSCathy Zhou /*ARGSUSED*/
5135d460eafSCathy Zhou static int
5145d460eafSCathy Zhou softmac_drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
5155d460eafSCathy Zhou {
5165d460eafSCathy Zhou 	softmac_upper_t	*sup = NULL;
5175d460eafSCathy Zhou 	softmac_t	*softmac;
5185d460eafSCathy Zhou 	int		err = 0;
5195d460eafSCathy Zhou 
5205d460eafSCathy Zhou 	/*
5215d460eafSCathy Zhou 	 * This is a softmac device created for a legacy device, find the
5225d460eafSCathy Zhou 	 * associated softmac and initialize the softmac_upper_t structure.
5235d460eafSCathy Zhou 	 */
5245d460eafSCathy Zhou 	if ((err = softmac_hold(*devp, &softmac)) != 0)
5255d460eafSCathy Zhou 		return (err);
5265d460eafSCathy Zhou 
5275d460eafSCathy Zhou 	sup = kmem_cache_alloc(softmac_upper_cachep, KM_NOSLEEP);
5285d460eafSCathy Zhou 	if (sup == NULL) {
5295d460eafSCathy Zhou 		err = ENOMEM;
5305d460eafSCathy Zhou 		goto fail;
5315d460eafSCathy Zhou 	}
5325d460eafSCathy Zhou 
5335d460eafSCathy Zhou 	ASSERT(list_is_empty(&sup->su_req_list));
5345d460eafSCathy Zhou 
5355d460eafSCathy Zhou 	if ((sup->su_tx_flow_mp = allocb(1, BPRI_HI)) == NULL) {
5365d460eafSCathy Zhou 		err = ENOMEM;
5375d460eafSCathy Zhou 		goto fail;
5385d460eafSCathy Zhou 	}
5395d460eafSCathy Zhou 
5405d460eafSCathy Zhou 	sup->su_rq = rq;
5415d460eafSCathy Zhou 	sup->su_wq = WR(rq);
5425d460eafSCathy Zhou 	sup->su_softmac = softmac;
5435d460eafSCathy Zhou 	sup->su_mode = SOFTMAC_UNKNOWN;
5445d460eafSCathy Zhou 
5455d460eafSCathy Zhou 	sup->su_rxinfo.slr_arg = sup;
5465d460eafSCathy Zhou 	sup->su_rxinfo.slr_rx = softmac_dedicated_rx;
5475d460eafSCathy Zhou 	sup->su_direct_rxinfo.slr_arg = sup;
5485d460eafSCathy Zhou 	sup->su_direct_rxinfo.slr_rx = softmac_dedicated_rx;
5495d460eafSCathy Zhou 
5505d460eafSCathy Zhou 	if ((err = dld_str_open(rq, devp, sup)) != 0) {
5515d460eafSCathy Zhou 		freeb(sup->su_tx_flow_mp);
5525d460eafSCathy Zhou 		sup->su_tx_flow_mp = NULL;
5535d460eafSCathy Zhou 		goto fail;
5545d460eafSCathy Zhou 	}
5555d460eafSCathy Zhou 
5565d460eafSCathy Zhou 	return (0);
5575d460eafSCathy Zhou 
5585d460eafSCathy Zhou fail:
5595d460eafSCathy Zhou 	if (sup != NULL)
5605d460eafSCathy Zhou 		kmem_cache_free(softmac_upper_cachep, sup);
5615d460eafSCathy Zhou 	softmac_rele(softmac);
5625d460eafSCathy Zhou 	return (err);
5635d460eafSCathy Zhou }
5645d460eafSCathy Zhou 
5655d460eafSCathy Zhou static int
5665d460eafSCathy Zhou softmac_drv_close(queue_t *rq)
5675d460eafSCathy Zhou {
5685d460eafSCathy Zhou 	softmac_upper_t	*sup = dld_str_private(rq);
5695d460eafSCathy Zhou 	softmac_t	*softmac = sup->su_softmac;
5705d460eafSCathy Zhou 
5715d460eafSCathy Zhou 	ASSERT(WR(rq)->q_next == NULL);
5725d460eafSCathy Zhou 
5735d460eafSCathy Zhou 	qprocsoff(rq);
5745d460eafSCathy Zhou 
5755d460eafSCathy Zhou 	ASSERT(sup->su_tx_inprocess == 0);
5765d460eafSCathy Zhou 
5775d460eafSCathy Zhou 	/*
5785d460eafSCathy Zhou 	 * Wait until the pending request are processed by the worker thread.
5795d460eafSCathy Zhou 	 */
5805d460eafSCathy Zhou 	mutex_enter(&sup->su_disp_mutex);
5815d460eafSCathy Zhou 	sup->su_closing = B_TRUE;
5825d460eafSCathy Zhou 	while (sup->su_dlpi_pending)
5835d460eafSCathy Zhou 		cv_wait(&sup->su_disp_cv, &sup->su_disp_mutex);
5845d460eafSCathy Zhou 	mutex_exit(&sup->su_disp_mutex);
5855d460eafSCathy Zhou 
5865d460eafSCathy Zhou 	softmac_upperstream_close(sup);
5875d460eafSCathy Zhou 
5885d460eafSCathy Zhou 	if (sup->su_tx_flow_mp != NULL) {
5895d460eafSCathy Zhou 		freeb(sup->su_tx_flow_mp);
5905d460eafSCathy Zhou 		sup->su_tx_flow_mp = NULL;
5915d460eafSCathy Zhou 	}
5925d460eafSCathy Zhou 
5935d460eafSCathy Zhou 	if (sup->su_active) {
5945d460eafSCathy Zhou 		mutex_enter(&softmac->smac_active_mutex);
5955d460eafSCathy Zhou 		softmac->smac_nactive--;
5965d460eafSCathy Zhou 		mutex_exit(&softmac->smac_active_mutex);
5975d460eafSCathy Zhou 		sup->su_active = B_FALSE;
5985d460eafSCathy Zhou 	}
5995d460eafSCathy Zhou 
6005d460eafSCathy Zhou 	sup->su_bound = B_FALSE;
6015d460eafSCathy Zhou 	sup->su_softmac = NULL;
6025d460eafSCathy Zhou 	sup->su_closing = B_FALSE;
6035d460eafSCathy Zhou 
6045d460eafSCathy Zhou 	kmem_cache_free(softmac_upper_cachep, sup);
6055d460eafSCathy Zhou 
6065d460eafSCathy Zhou 	softmac_rele(softmac);
6075d460eafSCathy Zhou 	return (dld_str_close(rq));
6085d460eafSCathy Zhou }
6095d460eafSCathy Zhou 
6105d460eafSCathy Zhou static void
6115d460eafSCathy Zhou softmac_drv_wput(queue_t *wq, mblk_t *mp)
6125d460eafSCathy Zhou {
6135d460eafSCathy Zhou 	softmac_upper_t	*sup = dld_str_private(wq);
6145d460eafSCathy Zhou 	t_uscalar_t	prim;
6155d460eafSCathy Zhou 
6165d460eafSCathy Zhou 	ASSERT(wq->q_next == NULL);
6175d460eafSCathy Zhou 
6185d460eafSCathy Zhou 	switch (DB_TYPE(mp)) {
6195d460eafSCathy Zhou 	case M_DATA:
6205d460eafSCathy Zhou 	case M_MULTIDATA:
6215d460eafSCathy Zhou 		softmac_wput_data(sup, mp);
6225d460eafSCathy Zhou 		break;
6235d460eafSCathy Zhou 	case M_PROTO:
6245d460eafSCathy Zhou 	case M_PCPROTO:
6255d460eafSCathy Zhou 
6265d460eafSCathy Zhou 		if (MBLKL(mp) < sizeof (t_uscalar_t)) {
6275d460eafSCathy Zhou 			freemsg(mp);
6285d460eafSCathy Zhou 			return;
6295d460eafSCathy Zhou 		}
6305d460eafSCathy Zhou 
6315d460eafSCathy Zhou 		prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
6325d460eafSCathy Zhou 		if (prim == DL_UNITDATA_REQ) {
6335d460eafSCathy Zhou 			softmac_wput_data(sup, mp);
6345d460eafSCathy Zhou 			return;
6355d460eafSCathy Zhou 		}
6365d460eafSCathy Zhou 
6375d460eafSCathy Zhou 		softmac_wput_nondata(sup, mp);
6385d460eafSCathy Zhou 		break;
6395d460eafSCathy Zhou 	default:
6405d460eafSCathy Zhou 		softmac_wput_nondata(sup, mp);
6415d460eafSCathy Zhou 		break;
6425d460eafSCathy Zhou 	}
6435d460eafSCathy Zhou }
6445d460eafSCathy Zhou 
6455d460eafSCathy Zhou static void
6465d460eafSCathy Zhou softmac_drv_wsrv(queue_t *wq)
6475d460eafSCathy Zhou {
6485d460eafSCathy Zhou 	softmac_upper_t	*sup = dld_str_private(wq);
6495d460eafSCathy Zhou 
6505d460eafSCathy Zhou 	ASSERT(wq->q_next == NULL);
6515d460eafSCathy Zhou 
6525d460eafSCathy Zhou 	mutex_enter(&sup->su_mutex);
6535d460eafSCathy Zhou 	if (sup->su_mode != SOFTMAC_FASTPATH) {
6545d460eafSCathy Zhou 		/*
6555d460eafSCathy Zhou 		 * Bump su_tx_inprocess so that su_mode won't change.
6565d460eafSCathy Zhou 		 */
6575d460eafSCathy Zhou 		sup->su_tx_inprocess++;
6585d460eafSCathy Zhou 		mutex_exit(&sup->su_mutex);
6595d460eafSCathy Zhou 		dld_wsrv(wq);
6605d460eafSCathy Zhou 		mutex_enter(&sup->su_mutex);
6615d460eafSCathy Zhou 		if (--sup->su_tx_inprocess == 0)
6625d460eafSCathy Zhou 			cv_signal(&sup->su_cv);
6635d460eafSCathy Zhou 	} else if (sup->su_tx_busy && SOFTMAC_CANPUTNEXT(sup->su_slp->sl_wq)) {
6645d460eafSCathy Zhou 		/*
6655d460eafSCathy Zhou 		 * The flow-conctol of the dedicated-lower-stream is
66679eeb645SCathy Zhou 		 * relieved. If DLD_CAPAB_DIRECT is enabled, call tx_notify
66779eeb645SCathy Zhou 		 * callback to relieve the flow-control of the specific client,
66879eeb645SCathy Zhou 		 * otherwise relieve the flow-control of all the upper-stream
66979eeb645SCathy Zhou 		 * using the traditional STREAM mechanism.
6705d460eafSCathy Zhou 		 */
67179eeb645SCathy Zhou 		if (sup->su_tx_notify_func != NULL) {
67279eeb645SCathy Zhou 			sup->su_tx_inprocess++;
67379eeb645SCathy Zhou 			mutex_exit(&sup->su_mutex);
67479eeb645SCathy Zhou 			sup->su_tx_notify_func(sup->su_tx_notify_arg,
67579eeb645SCathy Zhou 			    (mac_tx_cookie_t)sup);
67679eeb645SCathy Zhou 			mutex_enter(&sup->su_mutex);
67779eeb645SCathy Zhou 			if (--sup->su_tx_inprocess == 0)
67879eeb645SCathy Zhou 				cv_signal(&sup->su_cv);
67979eeb645SCathy Zhou 		}
68079eeb645SCathy Zhou 		ASSERT(sup->su_tx_flow_mp == NULL);
68179eeb645SCathy Zhou 		VERIFY((sup->su_tx_flow_mp = getq(wq)) != NULL);
6825d460eafSCathy Zhou 		sup->su_tx_busy = B_FALSE;
6835d460eafSCathy Zhou 	}
6845d460eafSCathy Zhou 	mutex_exit(&sup->su_mutex);
6855d460eafSCathy Zhou }
686