xref: /onnv-gate/usr/src/uts/common/io/softmac/softmac_dev.c (revision 11042:2d6e217af1b4)
15895Syz147064 /*
25895Syz147064  * CDDL HEADER START
35895Syz147064  *
45895Syz147064  * The contents of this file are subject to the terms of the
55895Syz147064  * Common Development and Distribution License (the "License").
65895Syz147064  * You may not use this file except in compliance with the License.
75895Syz147064  *
85895Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95895Syz147064  * or http://www.opensolaris.org/os/licensing.
105895Syz147064  * See the License for the specific language governing permissions
115895Syz147064  * and limitations under the License.
125895Syz147064  *
135895Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
145895Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155895Syz147064  * If applicable, add the following below this CDDL HEADER, with the
165895Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
175895Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
185895Syz147064  *
195895Syz147064  * CDDL HEADER END
205895Syz147064  */
215895Syz147064 /*
229073SCathy.Zhou@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235895Syz147064  * Use is subject to license terms.
245895Syz147064  */
255895Syz147064 
265895Syz147064 
275895Syz147064 #include <sys/types.h>
285895Syz147064 #include <inet/common.h>
295895Syz147064 #include <sys/stropts.h>
305895Syz147064 #include <sys/modctl.h>
319073SCathy.Zhou@Sun.COM #include <sys/dld.h>
325895Syz147064 #include <sys/softmac_impl.h>
335895Syz147064 
345895Syz147064 dev_info_t		*softmac_dip = NULL;
359073SCathy.Zhou@Sun.COM static kmem_cache_t	*softmac_upper_cachep;
365895Syz147064 
379073SCathy.Zhou@Sun.COM /*
389073SCathy.Zhou@Sun.COM  * This function is a generic open(9E) entry point into the softmac for
399073SCathy.Zhou@Sun.COM  * both the softmac module and the softmac driver.
409073SCathy.Zhou@Sun.COM  */
419073SCathy.Zhou@Sun.COM static int softmac_cmn_open(queue_t *, dev_t *, int, int, cred_t *);
429073SCathy.Zhou@Sun.COM 
439073SCathy.Zhou@Sun.COM /*
449073SCathy.Zhou@Sun.COM  * The following softmac_mod_xxx() functions are (9E) entry point functions for
459073SCathy.Zhou@Sun.COM  * the softmac module.
469073SCathy.Zhou@Sun.COM  */
479073SCathy.Zhou@Sun.COM static int softmac_mod_close(queue_t *);
489073SCathy.Zhou@Sun.COM static void softmac_mod_rput(queue_t *, mblk_t *);
499073SCathy.Zhou@Sun.COM static void softmac_mod_wput(queue_t *, mblk_t *);
509073SCathy.Zhou@Sun.COM static void softmac_mod_wsrv(queue_t *);
519073SCathy.Zhou@Sun.COM 
529073SCathy.Zhou@Sun.COM /*
539073SCathy.Zhou@Sun.COM  * The following softmac_drv_xxx() functions are (9E) entry point functions for
549073SCathy.Zhou@Sun.COM  * the softmac driver.
559073SCathy.Zhou@Sun.COM  */
569073SCathy.Zhou@Sun.COM static int softmac_drv_open(queue_t *, dev_t *, int, int, cred_t *);
579073SCathy.Zhou@Sun.COM static int softmac_drv_close(queue_t *);
589073SCathy.Zhou@Sun.COM static void softmac_drv_wput(queue_t *, mblk_t *);
599073SCathy.Zhou@Sun.COM static void softmac_drv_wsrv(queue_t *);
609073SCathy.Zhou@Sun.COM 
615895Syz147064 static int softmac_attach(dev_info_t *, ddi_attach_cmd_t);
625895Syz147064 static int softmac_detach(dev_info_t *, ddi_detach_cmd_t);
635895Syz147064 static int softmac_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
645895Syz147064 
655895Syz147064 static struct module_info softmac_modinfo = {
665895Syz147064 	0,
675895Syz147064 	SOFTMAC_DEV_NAME,
685895Syz147064 	0,
695895Syz147064 	INFPSZ,
705895Syz147064 	65536,
715895Syz147064 	1024
725895Syz147064 };
735895Syz147064 
745895Syz147064 /*
755895Syz147064  * hi-water mark is 1 because of the flow control mechanism implemented in
765895Syz147064  * dld.  Refer to the comments in dld_str.c for details.
775895Syz147064  */
785895Syz147064 static struct module_info softmac_dld_modinfo = {
795895Syz147064 	0,
805895Syz147064 	SOFTMAC_DEV_NAME,
815895Syz147064 	0,
825895Syz147064 	INFPSZ,
835895Syz147064 	1,
845895Syz147064 	0
855895Syz147064 };
865895Syz147064 
875895Syz147064 static struct qinit softmac_urinit = {
889073SCathy.Zhou@Sun.COM 	(pfi_t)softmac_mod_rput,	/* qi_putp */
899073SCathy.Zhou@Sun.COM 	(pfi_t)NULL,			/* qi_srvp */
909073SCathy.Zhou@Sun.COM 	softmac_cmn_open,		/* qi_qopen */
919073SCathy.Zhou@Sun.COM 	softmac_mod_close,		/* qi_qclose */
929073SCathy.Zhou@Sun.COM 	NULL,				/* qi_qadmin */
939073SCathy.Zhou@Sun.COM 	&softmac_modinfo		/* qi_minfo */
945895Syz147064 };
955895Syz147064 
965895Syz147064 static struct qinit softmac_uwinit = {
979073SCathy.Zhou@Sun.COM 	(pfi_t)softmac_mod_wput,	/* qi_putp */
989073SCathy.Zhou@Sun.COM 	(pfi_t)softmac_mod_wsrv,	/* qi_srvp */
999073SCathy.Zhou@Sun.COM 	NULL,				/* qi_qopen */
1009073SCathy.Zhou@Sun.COM 	NULL,				/* qi_qclose */
1019073SCathy.Zhou@Sun.COM 	NULL,				/* qi_qadmin */
1029073SCathy.Zhou@Sun.COM 	&softmac_modinfo		/* qi_minfo */
1035895Syz147064 };
1045895Syz147064 
1055895Syz147064 static struct streamtab softmac_tab = {
1065895Syz147064 	&softmac_urinit,	/* st_rdinit */
1075895Syz147064 	&softmac_uwinit		/* st_wrinit */
1085895Syz147064 };
1095895Syz147064 
1105895Syz147064 DDI_DEFINE_STREAM_OPS(softmac_ops, nulldev, nulldev, softmac_attach,
1117656SSherry.Moore@Sun.COM     softmac_detach, nodev, softmac_info, D_MP, &softmac_tab,
1127656SSherry.Moore@Sun.COM     ddi_quiesce_not_supported);
1135895Syz147064 
1145895Syz147064 static struct qinit softmac_dld_r_qinit = {
1159073SCathy.Zhou@Sun.COM 	NULL, NULL, softmac_drv_open, softmac_drv_close, NULL,
1169073SCathy.Zhou@Sun.COM 	&softmac_dld_modinfo
1175895Syz147064 };
1185895Syz147064 
1195895Syz147064 static struct qinit softmac_dld_w_qinit = {
1209073SCathy.Zhou@Sun.COM 	(pfi_t)softmac_drv_wput, (pfi_t)softmac_drv_wsrv, NULL, NULL, NULL,
1215895Syz147064 	&softmac_dld_modinfo
1225895Syz147064 };
1235895Syz147064 
1245895Syz147064 static struct fmodsw softmac_fmodsw = {
1255895Syz147064 	SOFTMAC_DEV_NAME,
1265895Syz147064 	&softmac_tab,
1275895Syz147064 	D_MP
1285895Syz147064 };
1295895Syz147064 
1305895Syz147064 static struct modldrv softmac_modldrv = {
1315895Syz147064 	&mod_driverops,
1325895Syz147064 	"softmac driver",
1335895Syz147064 	&softmac_ops
1345895Syz147064 };
1355895Syz147064 
1365895Syz147064 static struct modlstrmod softmac_modlstrmod = {
1375895Syz147064 	&mod_strmodops,
1385895Syz147064 	"softmac module",
1395895Syz147064 	&softmac_fmodsw
1405895Syz147064 };
1415895Syz147064 
1425895Syz147064 static struct modlinkage softmac_modlinkage = {
1435895Syz147064 	MODREV_1,
1445895Syz147064 	&softmac_modlstrmod,
1455895Syz147064 	&softmac_modldrv,
1465895Syz147064 	NULL
1475895Syz147064 };
1485895Syz147064 
149*11042SErik.Nordmark@Sun.COM static void softmac_dedicated_rx(void *, mac_resource_handle_t, mblk_t *,
150*11042SErik.Nordmark@Sun.COM     mac_header_info_t *);
151*11042SErik.Nordmark@Sun.COM 
1529073SCathy.Zhou@Sun.COM /*ARGSUSED*/
1539073SCathy.Zhou@Sun.COM static int
softmac_upper_constructor(void * buf,void * arg,int kmflag)1549073SCathy.Zhou@Sun.COM softmac_upper_constructor(void *buf, void *arg, int kmflag)
1559073SCathy.Zhou@Sun.COM {
1569073SCathy.Zhou@Sun.COM 	softmac_upper_t	*sup = buf;
1579073SCathy.Zhou@Sun.COM 
1589073SCathy.Zhou@Sun.COM 	bzero(buf, sizeof (softmac_upper_t));
1599073SCathy.Zhou@Sun.COM 
1609073SCathy.Zhou@Sun.COM 	mutex_init(&sup->su_mutex, NULL, MUTEX_DEFAULT, NULL);
1619073SCathy.Zhou@Sun.COM 	cv_init(&sup->su_cv, NULL, CV_DEFAULT, NULL);
1629073SCathy.Zhou@Sun.COM 	mutex_init(&sup->su_disp_mutex, NULL, MUTEX_DEFAULT, NULL);
1639073SCathy.Zhou@Sun.COM 	cv_init(&sup->su_disp_cv, NULL, CV_DEFAULT, NULL);
1649073SCathy.Zhou@Sun.COM 	list_create(&sup->su_req_list, sizeof (softmac_switch_req_t),
1659073SCathy.Zhou@Sun.COM 	    offsetof(softmac_switch_req_t, ssq_req_list_node));
1669073SCathy.Zhou@Sun.COM 	return (0);
1679073SCathy.Zhou@Sun.COM }
1689073SCathy.Zhou@Sun.COM 
1699073SCathy.Zhou@Sun.COM /*ARGSUSED*/
1709073SCathy.Zhou@Sun.COM static void
softmac_upper_destructor(void * buf,void * arg)1719073SCathy.Zhou@Sun.COM softmac_upper_destructor(void *buf, void *arg)
1729073SCathy.Zhou@Sun.COM {
1739073SCathy.Zhou@Sun.COM 	softmac_upper_t	*sup = buf;
1749073SCathy.Zhou@Sun.COM 
1759073SCathy.Zhou@Sun.COM 	ASSERT(sup->su_slp == NULL);
1769073SCathy.Zhou@Sun.COM 	ASSERT(sup->su_pending_head == NULL && sup->su_pending_tail == NULL);
1779073SCathy.Zhou@Sun.COM 	ASSERT(!sup->su_dlpi_pending);
1789073SCathy.Zhou@Sun.COM 	ASSERT(!sup->su_active);
1799073SCathy.Zhou@Sun.COM 	ASSERT(!sup->su_closing);
1809073SCathy.Zhou@Sun.COM 	ASSERT(sup->su_tx_flow_mp == NULL);
1819073SCathy.Zhou@Sun.COM 	ASSERT(sup->su_tx_inprocess == 0);
1829073SCathy.Zhou@Sun.COM 	ASSERT(sup->su_mode == SOFTMAC_UNKNOWN);
1839073SCathy.Zhou@Sun.COM 	ASSERT(!sup->su_tx_busy);
1849073SCathy.Zhou@Sun.COM 	ASSERT(!sup->su_bound);
1859073SCathy.Zhou@Sun.COM 	ASSERT(!sup->su_taskq_scheduled);
1869738SCathy.Zhou@Sun.COM 	ASSERT(sup->su_tx_notify_func == NULL);
1879738SCathy.Zhou@Sun.COM 	ASSERT(sup->su_tx_notify_arg == NULL);
1889073SCathy.Zhou@Sun.COM 	ASSERT(list_is_empty(&sup->su_req_list));
1899073SCathy.Zhou@Sun.COM 
1909073SCathy.Zhou@Sun.COM 	list_destroy(&sup->su_req_list);
1919073SCathy.Zhou@Sun.COM 	mutex_destroy(&sup->su_mutex);
1929073SCathy.Zhou@Sun.COM 	cv_destroy(&sup->su_cv);
1939073SCathy.Zhou@Sun.COM 	mutex_destroy(&sup->su_disp_mutex);
1949073SCathy.Zhou@Sun.COM 	cv_destroy(&sup->su_disp_cv);
1959073SCathy.Zhou@Sun.COM }
1969073SCathy.Zhou@Sun.COM 
1975895Syz147064 int
_init(void)1985895Syz147064 _init(void)
1995895Syz147064 {
2005895Syz147064 	int	err;
2015895Syz147064 
20210986SSebastien.Roy@Sun.COM 	mac_init_ops(NULL, SOFTMAC_DEV_NAME);
2035895Syz147064 	softmac_init();
2045895Syz147064 
2059073SCathy.Zhou@Sun.COM 	softmac_upper_cachep = kmem_cache_create("softmac_upper_cache",
2069073SCathy.Zhou@Sun.COM 	    sizeof (softmac_upper_t), 0, softmac_upper_constructor,
2079073SCathy.Zhou@Sun.COM 	    softmac_upper_destructor, NULL, NULL, NULL, 0);
2089073SCathy.Zhou@Sun.COM 	ASSERT(softmac_upper_cachep != NULL);
2099073SCathy.Zhou@Sun.COM 
2105895Syz147064 	if ((err = mod_install(&softmac_modlinkage)) != 0) {
2115895Syz147064 		softmac_fini();
2125895Syz147064 		return (err);
2135895Syz147064 	}
2145895Syz147064 
2155895Syz147064 	return (0);
2165895Syz147064 }
2175895Syz147064 
2185895Syz147064 int
_fini(void)2195895Syz147064 _fini(void)
2205895Syz147064 {
2215895Syz147064 	int err;
2225895Syz147064 
2235895Syz147064 	if (softmac_busy())
2245895Syz147064 		return (EBUSY);
2255895Syz147064 
2265895Syz147064 	if ((err = mod_remove(&softmac_modlinkage)) != 0)
2275895Syz147064 		return (err);
2285895Syz147064 
2299073SCathy.Zhou@Sun.COM 	kmem_cache_destroy(softmac_upper_cachep);
2305895Syz147064 	softmac_fini();
2315895Syz147064 
2325895Syz147064 	return (0);
2335895Syz147064 }
2345895Syz147064 
2355895Syz147064 int
_info(struct modinfo * modinfop)2365895Syz147064 _info(struct modinfo *modinfop)
2375895Syz147064 {
2385895Syz147064 	return (mod_info(&softmac_modlinkage, modinfop));
2395895Syz147064 }
2405895Syz147064 
2415895Syz147064 static int
softmac_cmn_open(queue_t * rq,dev_t * devp,int flag,int sflag,cred_t * credp)2429073SCathy.Zhou@Sun.COM softmac_cmn_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
2435895Syz147064 {
2445895Syz147064 	softmac_lower_t	*slp;
2455895Syz147064 	/*
2465895Syz147064 	 * This is a self-cloning driver so that each queue should only
2475895Syz147064 	 * get opened once.
2485895Syz147064 	 */
2495895Syz147064 	if (rq->q_ptr != NULL)
2505895Syz147064 		return (EBUSY);
2515895Syz147064 
2525895Syz147064 	if (sflag == MODOPEN) {
2535895Syz147064 		/*
2545895Syz147064 		 * This is the softmac module pushed over an underlying
2555895Syz147064 		 * legacy device.  Initialize the lower structure.
2565895Syz147064 		 */
2575895Syz147064 		if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL)
2585895Syz147064 			return (ENOMEM);
2595895Syz147064 
2605895Syz147064 		slp->sl_wq = WR(rq);
2615895Syz147064 		cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL);
2625895Syz147064 		mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL);
2635895Syz147064 		slp->sl_pending_prim = DL_PRIM_INVAL;
2645895Syz147064 		rq->q_ptr = WR(rq)->q_ptr = slp;
2655895Syz147064 		qprocson(rq);
2665895Syz147064 		return (0);
2675895Syz147064 	}
2685895Syz147064 
2695895Syz147064 	/*
2705895Syz147064 	 * Regular device open of a softmac DLPI node.  We modify
2715895Syz147064 	 * the queues' q_qinfo pointer such that all future STREAMS
2729073SCathy.Zhou@Sun.COM 	 * operations will go through another set of entry points
2735895Syz147064 	 */
2745895Syz147064 	rq->q_qinfo = &softmac_dld_r_qinit;
2755895Syz147064 	WR(rq)->q_qinfo = &softmac_dld_w_qinit;
2769073SCathy.Zhou@Sun.COM 	return (softmac_drv_open(rq, devp, flag, sflag, credp));
2775895Syz147064 }
2785895Syz147064 
2795895Syz147064 static int
softmac_mod_close(queue_t * rq)2809073SCathy.Zhou@Sun.COM softmac_mod_close(queue_t *rq)
2815895Syz147064 {
2825895Syz147064 	softmac_lower_t	*slp = rq->q_ptr;
2835895Syz147064 
2845895Syz147064 	/*
2855895Syz147064 	 * Call the appropriate delete routine depending on whether this is
2865895Syz147064 	 * a module or device.
2875895Syz147064 	 */
2885895Syz147064 	ASSERT(WR(rq)->q_next != NULL);
2895895Syz147064 
2905895Syz147064 	qprocsoff(rq);
2915895Syz147064 
2925895Syz147064 	slp->sl_softmac = NULL;
2935895Syz147064 	slp->sl_lh = NULL;
2945895Syz147064 
2955895Syz147064 	ASSERT(slp->sl_ack_mp == NULL);
2965895Syz147064 	ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
2975895Syz147064 	ASSERT(slp->sl_pending_ioctl == B_FALSE);
2985895Syz147064 
2995895Syz147064 	cv_destroy(&slp->sl_cv);
3005895Syz147064 	mutex_destroy(&slp->sl_mutex);
3015895Syz147064 
3025895Syz147064 	kmem_free(slp, sizeof (*slp));
3035895Syz147064 	return (0);
3045895Syz147064 }
3055895Syz147064 
3065895Syz147064 static void
softmac_mod_rput(queue_t * rq,mblk_t * mp)3079073SCathy.Zhou@Sun.COM softmac_mod_rput(queue_t *rq, mblk_t *mp)
3085895Syz147064 {
3099073SCathy.Zhou@Sun.COM 	softmac_lower_t		*slp = rq->q_ptr;
3109073SCathy.Zhou@Sun.COM 	softmac_lower_rxinfo_t	*rxinfo;
3119073SCathy.Zhou@Sun.COM 	union DL_primitives	*dlp;
3125895Syz147064 
3135895Syz147064 	/*
3145895Syz147064 	 * This is the softmac module.
3155895Syz147064 	 */
3165895Syz147064 	ASSERT(WR(rq)->q_next != NULL);
3175895Syz147064 	ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL));
3185895Syz147064 
3195895Syz147064 	switch (DB_TYPE(mp)) {
3209073SCathy.Zhou@Sun.COM 	case M_DATA: {
3219073SCathy.Zhou@Sun.COM 
3225895Syz147064 		/*
3239073SCathy.Zhou@Sun.COM 		 * If sl_rxinfo is non-NULL. This is dedicated-lower-stream
3249073SCathy.Zhou@Sun.COM 		 * created for fastpath. Directly call the rx callback.
3259073SCathy.Zhou@Sun.COM 		 */
3269073SCathy.Zhou@Sun.COM 		if ((rxinfo = slp->sl_rxinfo) != NULL) {
3279073SCathy.Zhou@Sun.COM 			rxinfo->slr_rx(rxinfo->slr_arg, NULL, mp, NULL);
3289073SCathy.Zhou@Sun.COM 			break;
3299073SCathy.Zhou@Sun.COM 		}
3309073SCathy.Zhou@Sun.COM 
3319073SCathy.Zhou@Sun.COM 		/*
3329073SCathy.Zhou@Sun.COM 		 * A shared-lower-stream. Some driver starts to send up
3339073SCathy.Zhou@Sun.COM 		 * packets even it not in the DL_IDLE state, where
3349073SCathy.Zhou@Sun.COM 		 * sl_softmac is not set yet. Drop the packet in this case.
3355895Syz147064 		 */
3365895Syz147064 		if (slp->sl_softmac == NULL) {
3375895Syz147064 			freemsg(mp);
3385895Syz147064 			return;
3395895Syz147064 		}
3405895Syz147064 
3415895Syz147064 		/*
3428275SEric Cheng 		 * If this message is looped back from the legacy devices,
3438275SEric Cheng 		 * drop it as the Nemo framework will be responsible for
3448275SEric Cheng 		 * looping it back by the mac_txloop() function.
3458275SEric Cheng 		 */
3468275SEric Cheng 		if (mp->b_flag & MSGNOLOOP) {
3478275SEric Cheng 			freemsg(mp);
3488275SEric Cheng 			return;
3498275SEric Cheng 		}
3508275SEric Cheng 
3518275SEric Cheng 		/*
3525895Syz147064 		 * This is the most common case.
3535895Syz147064 		 */
3545895Syz147064 		if (DB_REF(mp) == 1) {
3555895Syz147064 			ASSERT(slp->sl_softmac != NULL);
3568275SEric Cheng 			mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
3575895Syz147064 			return;
3585895Syz147064 		} else {
3595895Syz147064 			softmac_rput_process_data(slp, mp);
3605895Syz147064 		}
3615895Syz147064 		break;
3629073SCathy.Zhou@Sun.COM 	}
3635895Syz147064 	case M_PROTO:
3645895Syz147064 	case M_PCPROTO:
3655895Syz147064 		if (MBLKL(mp) < sizeof (dlp->dl_primitive)) {
3665895Syz147064 			freemsg(mp);
3675895Syz147064 			break;
3685895Syz147064 		}
3695895Syz147064 		dlp = (union DL_primitives *)mp->b_rptr;
3705895Syz147064 		if (dlp->dl_primitive == DL_UNITDATA_IND) {
3719073SCathy.Zhou@Sun.COM 
3729073SCathy.Zhou@Sun.COM 			if ((rxinfo = slp->sl_rxinfo) != NULL) {
373*11042SErik.Nordmark@Sun.COM 				softmac_dedicated_rx(slp->sl_sup, NULL, mp,
374*11042SErik.Nordmark@Sun.COM 				    NULL);
3759073SCathy.Zhou@Sun.COM 				break;
3769073SCathy.Zhou@Sun.COM 			}
3779073SCathy.Zhou@Sun.COM 
3785895Syz147064 			cmn_err(CE_WARN, "got unexpected %s message",
3795895Syz147064 			    dl_primstr(DL_UNITDATA_IND));
3805895Syz147064 			freemsg(mp);
3815895Syz147064 			break;
3825895Syz147064 		}
3835895Syz147064 		/*FALLTHROUGH*/
3845895Syz147064 	default:
3859073SCathy.Zhou@Sun.COM 		softmac_rput_process_notdata(rq, slp->sl_sup, mp);
3865895Syz147064 		break;
3875895Syz147064 	}
3885895Syz147064 }
3895895Syz147064 
3905895Syz147064 static void
softmac_mod_wput(queue_t * wq,mblk_t * mp)3919073SCathy.Zhou@Sun.COM softmac_mod_wput(queue_t *wq, mblk_t *mp)
3925895Syz147064 {
3935895Syz147064 	/*
3945895Syz147064 	 * This is the softmac module
3955895Syz147064 	 */
3965895Syz147064 	ASSERT(wq->q_next != NULL);
3975895Syz147064 
3985895Syz147064 	switch (DB_TYPE(mp)) {
3995895Syz147064 	case M_IOCTL: {
4005895Syz147064 		struct iocblk		*ioc = (struct iocblk *)mp->b_rptr;
4015895Syz147064 
4025895Syz147064 		switch (ioc->ioc_cmd) {
4035895Syz147064 		case SMAC_IOC_START: {
4045895Syz147064 			softmac_lower_t		*slp = wq->q_ptr;
4055895Syz147064 			smac_ioc_start_t	*arg;
4065895Syz147064 
4075895Syz147064 			if (ioc->ioc_count != sizeof (*arg)) {
4085895Syz147064 				miocnak(wq, mp, 0, EINVAL);
4095895Syz147064 				break;
4105895Syz147064 			}
4115895Syz147064 
4125895Syz147064 			/*
4135895Syz147064 			 * Assign the devname and perstream handle of the
4145895Syz147064 			 * specific lower stream and return it as a part
4155895Syz147064 			 * of the ioctl.
4165895Syz147064 			 */
4175895Syz147064 			arg = (smac_ioc_start_t *)mp->b_cont->b_rptr;
4185895Syz147064 			arg->si_slp = slp;
4195895Syz147064 			miocack(wq, mp, sizeof (*arg), 0);
4205895Syz147064 			break;
4215895Syz147064 		}
4225895Syz147064 		default:
4235895Syz147064 			miocnak(wq, mp, 0, EINVAL);
4245895Syz147064 			break;
4255895Syz147064 		}
4265895Syz147064 		break;
4275895Syz147064 	}
4285895Syz147064 	default:
4295895Syz147064 		freemsg(mp);
4305895Syz147064 		break;
4315895Syz147064 	}
4325895Syz147064 }
4335895Syz147064 
4345895Syz147064 static void
softmac_mod_wsrv(queue_t * wq)4359073SCathy.Zhou@Sun.COM softmac_mod_wsrv(queue_t *wq)
4365895Syz147064 {
4375895Syz147064 	softmac_lower_t *slp = wq->q_ptr;
4385895Syz147064 
4395895Syz147064 	/*
4405895Syz147064 	 * This is the softmac module
4415895Syz147064 	 */
4425895Syz147064 	ASSERT(wq->q_next != NULL);
4435895Syz147064 
4445895Syz147064 	/*
4455895Syz147064 	 * Inform that the tx resource is available; mac_tx_update() will
4465895Syz147064 	 * inform all the upper streams sharing this lower stream.
4475895Syz147064 	 */
4489073SCathy.Zhou@Sun.COM 	if (slp->sl_sup != NULL)
4499073SCathy.Zhou@Sun.COM 		qenable(slp->sl_sup->su_wq);
4509073SCathy.Zhou@Sun.COM 	else if (slp->sl_softmac != NULL)
4515895Syz147064 		mac_tx_update(slp->sl_softmac->smac_mh);
4525895Syz147064 }
4535895Syz147064 
4545895Syz147064 static int
softmac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)4555895Syz147064 softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4565895Syz147064 {
4575895Syz147064 	ASSERT(ddi_get_instance(dip) == 0);
4585895Syz147064 
4595895Syz147064 	if (cmd != DDI_ATTACH)
4605895Syz147064 		return (DDI_FAILURE);
4615895Syz147064 
4625895Syz147064 	softmac_dip = dip;
4635895Syz147064 
4645895Syz147064 	return (DDI_SUCCESS);
4655895Syz147064 }
4665895Syz147064 
4675895Syz147064 /* ARGSUSED */
4685895Syz147064 static int
softmac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4695895Syz147064 softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4705895Syz147064 {
4715895Syz147064 	if (cmd != DDI_DETACH)
4725895Syz147064 		return (DDI_FAILURE);
4735895Syz147064 
4745895Syz147064 	softmac_dip = NULL;
4755895Syz147064 	return (DDI_SUCCESS);
4765895Syz147064 }
4775895Syz147064 
4785895Syz147064 /* ARGSUSED */
4795895Syz147064 static int
softmac_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4805895Syz147064 softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
4815895Syz147064 {
4825895Syz147064 	switch (infocmd) {
4835895Syz147064 	case DDI_INFO_DEVT2DEVINFO:
4845895Syz147064 		if (softmac_dip != NULL) {
4855895Syz147064 			*result = softmac_dip;
4865895Syz147064 			return (DDI_SUCCESS);
4875895Syz147064 		}
4885895Syz147064 		break;
4895895Syz147064 
4905895Syz147064 	case DDI_INFO_DEVT2INSTANCE:
4915895Syz147064 		*result = NULL;
4925895Syz147064 		return (DDI_SUCCESS);
4935895Syz147064 
4945895Syz147064 	}
4955895Syz147064 
4965895Syz147064 	return (DDI_FAILURE);
4975895Syz147064 }
4989073SCathy.Zhou@Sun.COM 
4999073SCathy.Zhou@Sun.COM /*ARGSUSED*/
5009073SCathy.Zhou@Sun.COM static void
softmac_dedicated_rx(void * arg,mac_resource_handle_t mrh,mblk_t * mp,mac_header_info_t * mhip)5019073SCathy.Zhou@Sun.COM softmac_dedicated_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
5029073SCathy.Zhou@Sun.COM     mac_header_info_t *mhip)
5039073SCathy.Zhou@Sun.COM {
5049073SCathy.Zhou@Sun.COM 	queue_t *rq = ((softmac_upper_t *)arg)->su_rq;
5059073SCathy.Zhou@Sun.COM 
5069073SCathy.Zhou@Sun.COM 	if (canputnext(rq))
5079073SCathy.Zhou@Sun.COM 		putnext(rq, mp);
5089073SCathy.Zhou@Sun.COM 	else
5099073SCathy.Zhou@Sun.COM 		freemsg(mp);
5109073SCathy.Zhou@Sun.COM }
5119073SCathy.Zhou@Sun.COM 
5129073SCathy.Zhou@Sun.COM /*ARGSUSED*/
5139073SCathy.Zhou@Sun.COM static int
softmac_drv_open(queue_t * rq,dev_t * devp,int flag,int sflag,cred_t * credp)5149073SCathy.Zhou@Sun.COM softmac_drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
5159073SCathy.Zhou@Sun.COM {
5169073SCathy.Zhou@Sun.COM 	softmac_upper_t	*sup = NULL;
5179073SCathy.Zhou@Sun.COM 	softmac_t	*softmac;
5189073SCathy.Zhou@Sun.COM 	int		err = 0;
5199073SCathy.Zhou@Sun.COM 
5209073SCathy.Zhou@Sun.COM 	/*
5219073SCathy.Zhou@Sun.COM 	 * This is a softmac device created for a legacy device, find the
5229073SCathy.Zhou@Sun.COM 	 * associated softmac and initialize the softmac_upper_t structure.
5239073SCathy.Zhou@Sun.COM 	 */
5249073SCathy.Zhou@Sun.COM 	if ((err = softmac_hold(*devp, &softmac)) != 0)
5259073SCathy.Zhou@Sun.COM 		return (err);
5269073SCathy.Zhou@Sun.COM 
5279073SCathy.Zhou@Sun.COM 	sup = kmem_cache_alloc(softmac_upper_cachep, KM_NOSLEEP);
5289073SCathy.Zhou@Sun.COM 	if (sup == NULL) {
5299073SCathy.Zhou@Sun.COM 		err = ENOMEM;
5309073SCathy.Zhou@Sun.COM 		goto fail;
5319073SCathy.Zhou@Sun.COM 	}
5329073SCathy.Zhou@Sun.COM 
5339073SCathy.Zhou@Sun.COM 	ASSERT(list_is_empty(&sup->su_req_list));
5349073SCathy.Zhou@Sun.COM 
5359073SCathy.Zhou@Sun.COM 	if ((sup->su_tx_flow_mp = allocb(1, BPRI_HI)) == NULL) {
5369073SCathy.Zhou@Sun.COM 		err = ENOMEM;
5379073SCathy.Zhou@Sun.COM 		goto fail;
5389073SCathy.Zhou@Sun.COM 	}
5399073SCathy.Zhou@Sun.COM 
5409073SCathy.Zhou@Sun.COM 	sup->su_rq = rq;
5419073SCathy.Zhou@Sun.COM 	sup->su_wq = WR(rq);
5429073SCathy.Zhou@Sun.COM 	sup->su_softmac = softmac;
5439073SCathy.Zhou@Sun.COM 	sup->su_mode = SOFTMAC_UNKNOWN;
5449073SCathy.Zhou@Sun.COM 
5459073SCathy.Zhou@Sun.COM 	sup->su_rxinfo.slr_arg = sup;
5469073SCathy.Zhou@Sun.COM 	sup->su_rxinfo.slr_rx = softmac_dedicated_rx;
5479073SCathy.Zhou@Sun.COM 	sup->su_direct_rxinfo.slr_arg = sup;
5489073SCathy.Zhou@Sun.COM 	sup->su_direct_rxinfo.slr_rx = softmac_dedicated_rx;
5499073SCathy.Zhou@Sun.COM 
5509073SCathy.Zhou@Sun.COM 	if ((err = dld_str_open(rq, devp, sup)) != 0) {
5519073SCathy.Zhou@Sun.COM 		freeb(sup->su_tx_flow_mp);
5529073SCathy.Zhou@Sun.COM 		sup->su_tx_flow_mp = NULL;
5539073SCathy.Zhou@Sun.COM 		goto fail;
5549073SCathy.Zhou@Sun.COM 	}
5559073SCathy.Zhou@Sun.COM 
5569073SCathy.Zhou@Sun.COM 	return (0);
5579073SCathy.Zhou@Sun.COM 
5589073SCathy.Zhou@Sun.COM fail:
5599073SCathy.Zhou@Sun.COM 	if (sup != NULL)
5609073SCathy.Zhou@Sun.COM 		kmem_cache_free(softmac_upper_cachep, sup);
5619073SCathy.Zhou@Sun.COM 	softmac_rele(softmac);
5629073SCathy.Zhou@Sun.COM 	return (err);
5639073SCathy.Zhou@Sun.COM }
5649073SCathy.Zhou@Sun.COM 
5659073SCathy.Zhou@Sun.COM static int
softmac_drv_close(queue_t * rq)5669073SCathy.Zhou@Sun.COM softmac_drv_close(queue_t *rq)
5679073SCathy.Zhou@Sun.COM {
5689073SCathy.Zhou@Sun.COM 	softmac_upper_t	*sup = dld_str_private(rq);
5699073SCathy.Zhou@Sun.COM 	softmac_t	*softmac = sup->su_softmac;
5709073SCathy.Zhou@Sun.COM 
5719073SCathy.Zhou@Sun.COM 	ASSERT(WR(rq)->q_next == NULL);
5729073SCathy.Zhou@Sun.COM 
5739073SCathy.Zhou@Sun.COM 	qprocsoff(rq);
5749073SCathy.Zhou@Sun.COM 
5759073SCathy.Zhou@Sun.COM 	ASSERT(sup->su_tx_inprocess == 0);
5769073SCathy.Zhou@Sun.COM 
5779073SCathy.Zhou@Sun.COM 	/*
5789073SCathy.Zhou@Sun.COM 	 * Wait until the pending request are processed by the worker thread.
5799073SCathy.Zhou@Sun.COM 	 */
5809073SCathy.Zhou@Sun.COM 	mutex_enter(&sup->su_disp_mutex);
5819073SCathy.Zhou@Sun.COM 	sup->su_closing = B_TRUE;
5829073SCathy.Zhou@Sun.COM 	while (sup->su_dlpi_pending)
5839073SCathy.Zhou@Sun.COM 		cv_wait(&sup->su_disp_cv, &sup->su_disp_mutex);
5849073SCathy.Zhou@Sun.COM 	mutex_exit(&sup->su_disp_mutex);
5859073SCathy.Zhou@Sun.COM 
5869073SCathy.Zhou@Sun.COM 	softmac_upperstream_close(sup);
5879073SCathy.Zhou@Sun.COM 
5889073SCathy.Zhou@Sun.COM 	if (sup->su_tx_flow_mp != NULL) {
5899073SCathy.Zhou@Sun.COM 		freeb(sup->su_tx_flow_mp);
5909073SCathy.Zhou@Sun.COM 		sup->su_tx_flow_mp = NULL;
5919073SCathy.Zhou@Sun.COM 	}
5929073SCathy.Zhou@Sun.COM 
5939073SCathy.Zhou@Sun.COM 	if (sup->su_active) {
5949073SCathy.Zhou@Sun.COM 		mutex_enter(&softmac->smac_active_mutex);
5959073SCathy.Zhou@Sun.COM 		softmac->smac_nactive--;
5969073SCathy.Zhou@Sun.COM 		mutex_exit(&softmac->smac_active_mutex);
5979073SCathy.Zhou@Sun.COM 		sup->su_active = B_FALSE;
5989073SCathy.Zhou@Sun.COM 	}
5999073SCathy.Zhou@Sun.COM 
6009073SCathy.Zhou@Sun.COM 	sup->su_bound = B_FALSE;
6019073SCathy.Zhou@Sun.COM 	sup->su_softmac = NULL;
6029073SCathy.Zhou@Sun.COM 	sup->su_closing = B_FALSE;
6039073SCathy.Zhou@Sun.COM 
6049073SCathy.Zhou@Sun.COM 	kmem_cache_free(softmac_upper_cachep, sup);
6059073SCathy.Zhou@Sun.COM 
6069073SCathy.Zhou@Sun.COM 	softmac_rele(softmac);
6079073SCathy.Zhou@Sun.COM 	return (dld_str_close(rq));
6089073SCathy.Zhou@Sun.COM }
6099073SCathy.Zhou@Sun.COM 
6109073SCathy.Zhou@Sun.COM static void
softmac_drv_wput(queue_t * wq,mblk_t * mp)6119073SCathy.Zhou@Sun.COM softmac_drv_wput(queue_t *wq, mblk_t *mp)
6129073SCathy.Zhou@Sun.COM {
6139073SCathy.Zhou@Sun.COM 	softmac_upper_t	*sup = dld_str_private(wq);
6149073SCathy.Zhou@Sun.COM 	t_uscalar_t	prim;
6159073SCathy.Zhou@Sun.COM 
6169073SCathy.Zhou@Sun.COM 	ASSERT(wq->q_next == NULL);
6179073SCathy.Zhou@Sun.COM 
6189073SCathy.Zhou@Sun.COM 	switch (DB_TYPE(mp)) {
6199073SCathy.Zhou@Sun.COM 	case M_DATA:
6209073SCathy.Zhou@Sun.COM 	case M_MULTIDATA:
6219073SCathy.Zhou@Sun.COM 		softmac_wput_data(sup, mp);
6229073SCathy.Zhou@Sun.COM 		break;
6239073SCathy.Zhou@Sun.COM 	case M_PROTO:
6249073SCathy.Zhou@Sun.COM 	case M_PCPROTO:
6259073SCathy.Zhou@Sun.COM 
6269073SCathy.Zhou@Sun.COM 		if (MBLKL(mp) < sizeof (t_uscalar_t)) {
6279073SCathy.Zhou@Sun.COM 			freemsg(mp);
6289073SCathy.Zhou@Sun.COM 			return;
6299073SCathy.Zhou@Sun.COM 		}
6309073SCathy.Zhou@Sun.COM 
6319073SCathy.Zhou@Sun.COM 		prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
6329073SCathy.Zhou@Sun.COM 		if (prim == DL_UNITDATA_REQ) {
6339073SCathy.Zhou@Sun.COM 			softmac_wput_data(sup, mp);
6349073SCathy.Zhou@Sun.COM 			return;
6359073SCathy.Zhou@Sun.COM 		}
6369073SCathy.Zhou@Sun.COM 
6379073SCathy.Zhou@Sun.COM 		softmac_wput_nondata(sup, mp);
6389073SCathy.Zhou@Sun.COM 		break;
6399073SCathy.Zhou@Sun.COM 	default:
6409073SCathy.Zhou@Sun.COM 		softmac_wput_nondata(sup, mp);
6419073SCathy.Zhou@Sun.COM 		break;
6429073SCathy.Zhou@Sun.COM 	}
6439073SCathy.Zhou@Sun.COM }
6449073SCathy.Zhou@Sun.COM 
6459073SCathy.Zhou@Sun.COM static void
softmac_drv_wsrv(queue_t * wq)6469073SCathy.Zhou@Sun.COM softmac_drv_wsrv(queue_t *wq)
6479073SCathy.Zhou@Sun.COM {
6489073SCathy.Zhou@Sun.COM 	softmac_upper_t	*sup = dld_str_private(wq);
6499073SCathy.Zhou@Sun.COM 
6509073SCathy.Zhou@Sun.COM 	ASSERT(wq->q_next == NULL);
6519073SCathy.Zhou@Sun.COM 
6529073SCathy.Zhou@Sun.COM 	mutex_enter(&sup->su_mutex);
6539073SCathy.Zhou@Sun.COM 	if (sup->su_mode != SOFTMAC_FASTPATH) {
6549073SCathy.Zhou@Sun.COM 		/*
6559073SCathy.Zhou@Sun.COM 		 * Bump su_tx_inprocess so that su_mode won't change.
6569073SCathy.Zhou@Sun.COM 		 */
6579073SCathy.Zhou@Sun.COM 		sup->su_tx_inprocess++;
6589073SCathy.Zhou@Sun.COM 		mutex_exit(&sup->su_mutex);
6599073SCathy.Zhou@Sun.COM 		dld_wsrv(wq);
6609073SCathy.Zhou@Sun.COM 		mutex_enter(&sup->su_mutex);
6619073SCathy.Zhou@Sun.COM 		if (--sup->su_tx_inprocess == 0)
6629073SCathy.Zhou@Sun.COM 			cv_signal(&sup->su_cv);
6639073SCathy.Zhou@Sun.COM 	} else if (sup->su_tx_busy && SOFTMAC_CANPUTNEXT(sup->su_slp->sl_wq)) {
6649073SCathy.Zhou@Sun.COM 		/*
6659073SCathy.Zhou@Sun.COM 		 * The flow-conctol of the dedicated-lower-stream is
6669738SCathy.Zhou@Sun.COM 		 * relieved. If DLD_CAPAB_DIRECT is enabled, call tx_notify
6679738SCathy.Zhou@Sun.COM 		 * callback to relieve the flow-control of the specific client,
6689738SCathy.Zhou@Sun.COM 		 * otherwise relieve the flow-control of all the upper-stream
6699738SCathy.Zhou@Sun.COM 		 * using the traditional STREAM mechanism.
6709073SCathy.Zhou@Sun.COM 		 */
6719738SCathy.Zhou@Sun.COM 		if (sup->su_tx_notify_func != NULL) {
6729738SCathy.Zhou@Sun.COM 			sup->su_tx_inprocess++;
6739738SCathy.Zhou@Sun.COM 			mutex_exit(&sup->su_mutex);
6749738SCathy.Zhou@Sun.COM 			sup->su_tx_notify_func(sup->su_tx_notify_arg,
6759738SCathy.Zhou@Sun.COM 			    (mac_tx_cookie_t)sup);
6769738SCathy.Zhou@Sun.COM 			mutex_enter(&sup->su_mutex);
6779738SCathy.Zhou@Sun.COM 			if (--sup->su_tx_inprocess == 0)
6789738SCathy.Zhou@Sun.COM 				cv_signal(&sup->su_cv);
6799738SCathy.Zhou@Sun.COM 		}
6809738SCathy.Zhou@Sun.COM 		ASSERT(sup->su_tx_flow_mp == NULL);
6819738SCathy.Zhou@Sun.COM 		VERIFY((sup->su_tx_flow_mp = getq(wq)) != NULL);
6829073SCathy.Zhou@Sun.COM 		sup->su_tx_busy = B_FALSE;
6839073SCathy.Zhou@Sun.COM 	}
6849073SCathy.Zhou@Sun.COM 	mutex_exit(&sup->su_mutex);
6859073SCathy.Zhou@Sun.COM }
686