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 1499073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 1509073SCathy.Zhou@Sun.COM static int 1519073SCathy.Zhou@Sun.COM softmac_upper_constructor(void *buf, void *arg, int kmflag) 1529073SCathy.Zhou@Sun.COM { 1539073SCathy.Zhou@Sun.COM softmac_upper_t *sup = buf; 1549073SCathy.Zhou@Sun.COM 1559073SCathy.Zhou@Sun.COM bzero(buf, sizeof (softmac_upper_t)); 1569073SCathy.Zhou@Sun.COM 1579073SCathy.Zhou@Sun.COM mutex_init(&sup->su_mutex, NULL, MUTEX_DEFAULT, NULL); 1589073SCathy.Zhou@Sun.COM cv_init(&sup->su_cv, NULL, CV_DEFAULT, NULL); 1599073SCathy.Zhou@Sun.COM mutex_init(&sup->su_disp_mutex, NULL, MUTEX_DEFAULT, NULL); 1609073SCathy.Zhou@Sun.COM cv_init(&sup->su_disp_cv, NULL, CV_DEFAULT, NULL); 1619073SCathy.Zhou@Sun.COM list_create(&sup->su_req_list, sizeof (softmac_switch_req_t), 1629073SCathy.Zhou@Sun.COM offsetof(softmac_switch_req_t, ssq_req_list_node)); 1639073SCathy.Zhou@Sun.COM return (0); 1649073SCathy.Zhou@Sun.COM } 1659073SCathy.Zhou@Sun.COM 1669073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 1679073SCathy.Zhou@Sun.COM static void 1689073SCathy.Zhou@Sun.COM softmac_upper_destructor(void *buf, void *arg) 1699073SCathy.Zhou@Sun.COM { 1709073SCathy.Zhou@Sun.COM softmac_upper_t *sup = buf; 1719073SCathy.Zhou@Sun.COM 1729073SCathy.Zhou@Sun.COM ASSERT(sup->su_slp == NULL); 1739073SCathy.Zhou@Sun.COM ASSERT(sup->su_pending_head == NULL && sup->su_pending_tail == NULL); 1749073SCathy.Zhou@Sun.COM ASSERT(!sup->su_dlpi_pending); 1759073SCathy.Zhou@Sun.COM ASSERT(!sup->su_active); 1769073SCathy.Zhou@Sun.COM ASSERT(!sup->su_closing); 1779073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_flow_mp == NULL); 1789073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_inprocess == 0); 1799073SCathy.Zhou@Sun.COM ASSERT(sup->su_mode == SOFTMAC_UNKNOWN); 1809073SCathy.Zhou@Sun.COM ASSERT(!sup->su_tx_busy); 1819073SCathy.Zhou@Sun.COM ASSERT(!sup->su_bound); 1829073SCathy.Zhou@Sun.COM ASSERT(!sup->su_taskq_scheduled); 1839738SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_notify_func == NULL); 1849738SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_notify_arg == NULL); 1859073SCathy.Zhou@Sun.COM ASSERT(list_is_empty(&sup->su_req_list)); 1869073SCathy.Zhou@Sun.COM 1879073SCathy.Zhou@Sun.COM list_destroy(&sup->su_req_list); 1889073SCathy.Zhou@Sun.COM mutex_destroy(&sup->su_mutex); 1899073SCathy.Zhou@Sun.COM cv_destroy(&sup->su_cv); 1909073SCathy.Zhou@Sun.COM mutex_destroy(&sup->su_disp_mutex); 1919073SCathy.Zhou@Sun.COM cv_destroy(&sup->su_disp_cv); 1929073SCathy.Zhou@Sun.COM } 1939073SCathy.Zhou@Sun.COM 1945895Syz147064 int 1955895Syz147064 _init(void) 1965895Syz147064 { 1975895Syz147064 int err; 1985895Syz147064 199*10986SSebastien.Roy@Sun.COM mac_init_ops(NULL, SOFTMAC_DEV_NAME); 2005895Syz147064 softmac_init(); 2015895Syz147064 2029073SCathy.Zhou@Sun.COM softmac_upper_cachep = kmem_cache_create("softmac_upper_cache", 2039073SCathy.Zhou@Sun.COM sizeof (softmac_upper_t), 0, softmac_upper_constructor, 2049073SCathy.Zhou@Sun.COM softmac_upper_destructor, NULL, NULL, NULL, 0); 2059073SCathy.Zhou@Sun.COM ASSERT(softmac_upper_cachep != NULL); 2069073SCathy.Zhou@Sun.COM 2075895Syz147064 if ((err = mod_install(&softmac_modlinkage)) != 0) { 2085895Syz147064 softmac_fini(); 2095895Syz147064 return (err); 2105895Syz147064 } 2115895Syz147064 2125895Syz147064 return (0); 2135895Syz147064 } 2145895Syz147064 2155895Syz147064 int 2165895Syz147064 _fini(void) 2175895Syz147064 { 2185895Syz147064 int err; 2195895Syz147064 2205895Syz147064 if (softmac_busy()) 2215895Syz147064 return (EBUSY); 2225895Syz147064 2235895Syz147064 if ((err = mod_remove(&softmac_modlinkage)) != 0) 2245895Syz147064 return (err); 2255895Syz147064 2269073SCathy.Zhou@Sun.COM kmem_cache_destroy(softmac_upper_cachep); 2275895Syz147064 softmac_fini(); 2285895Syz147064 2295895Syz147064 return (0); 2305895Syz147064 } 2315895Syz147064 2325895Syz147064 int 2335895Syz147064 _info(struct modinfo *modinfop) 2345895Syz147064 { 2355895Syz147064 return (mod_info(&softmac_modlinkage, modinfop)); 2365895Syz147064 } 2375895Syz147064 2385895Syz147064 static int 2399073SCathy.Zhou@Sun.COM softmac_cmn_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 2405895Syz147064 { 2415895Syz147064 softmac_lower_t *slp; 2425895Syz147064 /* 2435895Syz147064 * This is a self-cloning driver so that each queue should only 2445895Syz147064 * get opened once. 2455895Syz147064 */ 2465895Syz147064 if (rq->q_ptr != NULL) 2475895Syz147064 return (EBUSY); 2485895Syz147064 2495895Syz147064 if (sflag == MODOPEN) { 2505895Syz147064 /* 2515895Syz147064 * This is the softmac module pushed over an underlying 2525895Syz147064 * legacy device. Initialize the lower structure. 2535895Syz147064 */ 2545895Syz147064 if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL) 2555895Syz147064 return (ENOMEM); 2565895Syz147064 2575895Syz147064 slp->sl_wq = WR(rq); 2585895Syz147064 cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL); 2595895Syz147064 mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL); 2605895Syz147064 slp->sl_pending_prim = DL_PRIM_INVAL; 2615895Syz147064 rq->q_ptr = WR(rq)->q_ptr = slp; 2625895Syz147064 qprocson(rq); 2635895Syz147064 return (0); 2645895Syz147064 } 2655895Syz147064 2665895Syz147064 /* 2675895Syz147064 * Regular device open of a softmac DLPI node. We modify 2685895Syz147064 * the queues' q_qinfo pointer such that all future STREAMS 2699073SCathy.Zhou@Sun.COM * operations will go through another set of entry points 2705895Syz147064 */ 2715895Syz147064 rq->q_qinfo = &softmac_dld_r_qinit; 2725895Syz147064 WR(rq)->q_qinfo = &softmac_dld_w_qinit; 2739073SCathy.Zhou@Sun.COM return (softmac_drv_open(rq, devp, flag, sflag, credp)); 2745895Syz147064 } 2755895Syz147064 2765895Syz147064 static int 2779073SCathy.Zhou@Sun.COM softmac_mod_close(queue_t *rq) 2785895Syz147064 { 2795895Syz147064 softmac_lower_t *slp = rq->q_ptr; 2805895Syz147064 2815895Syz147064 /* 2825895Syz147064 * Call the appropriate delete routine depending on whether this is 2835895Syz147064 * a module or device. 2845895Syz147064 */ 2855895Syz147064 ASSERT(WR(rq)->q_next != NULL); 2865895Syz147064 2875895Syz147064 qprocsoff(rq); 2885895Syz147064 2895895Syz147064 slp->sl_softmac = NULL; 2905895Syz147064 slp->sl_lh = NULL; 2915895Syz147064 2925895Syz147064 ASSERT(slp->sl_ack_mp == NULL); 2935895Syz147064 ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL); 2945895Syz147064 ASSERT(slp->sl_pending_ioctl == B_FALSE); 2955895Syz147064 2965895Syz147064 cv_destroy(&slp->sl_cv); 2975895Syz147064 mutex_destroy(&slp->sl_mutex); 2985895Syz147064 2995895Syz147064 kmem_free(slp, sizeof (*slp)); 3005895Syz147064 return (0); 3015895Syz147064 } 3025895Syz147064 3035895Syz147064 static void 3049073SCathy.Zhou@Sun.COM softmac_mod_rput(queue_t *rq, mblk_t *mp) 3055895Syz147064 { 3069073SCathy.Zhou@Sun.COM softmac_lower_t *slp = rq->q_ptr; 3079073SCathy.Zhou@Sun.COM softmac_lower_rxinfo_t *rxinfo; 3089073SCathy.Zhou@Sun.COM union DL_primitives *dlp; 3095895Syz147064 3105895Syz147064 /* 3115895Syz147064 * This is the softmac module. 3125895Syz147064 */ 3135895Syz147064 ASSERT(WR(rq)->q_next != NULL); 3145895Syz147064 ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL)); 3155895Syz147064 3165895Syz147064 switch (DB_TYPE(mp)) { 3179073SCathy.Zhou@Sun.COM case M_DATA: { 3189073SCathy.Zhou@Sun.COM 3195895Syz147064 /* 3209073SCathy.Zhou@Sun.COM * If sl_rxinfo is non-NULL. This is dedicated-lower-stream 3219073SCathy.Zhou@Sun.COM * created for fastpath. Directly call the rx callback. 3229073SCathy.Zhou@Sun.COM */ 3239073SCathy.Zhou@Sun.COM if ((rxinfo = slp->sl_rxinfo) != NULL) { 3249073SCathy.Zhou@Sun.COM rxinfo->slr_rx(rxinfo->slr_arg, NULL, mp, NULL); 3259073SCathy.Zhou@Sun.COM break; 3269073SCathy.Zhou@Sun.COM } 3279073SCathy.Zhou@Sun.COM 3289073SCathy.Zhou@Sun.COM /* 3299073SCathy.Zhou@Sun.COM * A shared-lower-stream. Some driver starts to send up 3309073SCathy.Zhou@Sun.COM * packets even it not in the DL_IDLE state, where 3319073SCathy.Zhou@Sun.COM * sl_softmac is not set yet. Drop the packet in this case. 3325895Syz147064 */ 3335895Syz147064 if (slp->sl_softmac == NULL) { 3345895Syz147064 freemsg(mp); 3355895Syz147064 return; 3365895Syz147064 } 3375895Syz147064 3385895Syz147064 /* 3398275SEric Cheng * If this message is looped back from the legacy devices, 3408275SEric Cheng * drop it as the Nemo framework will be responsible for 3418275SEric Cheng * looping it back by the mac_txloop() function. 3428275SEric Cheng */ 3438275SEric Cheng if (mp->b_flag & MSGNOLOOP) { 3448275SEric Cheng freemsg(mp); 3458275SEric Cheng return; 3468275SEric Cheng } 3478275SEric Cheng 3488275SEric Cheng /* 3495895Syz147064 * This is the most common case. 3505895Syz147064 */ 3515895Syz147064 if (DB_REF(mp) == 1) { 3525895Syz147064 ASSERT(slp->sl_softmac != NULL); 3538275SEric Cheng mac_rx(slp->sl_softmac->smac_mh, NULL, mp); 3545895Syz147064 return; 3555895Syz147064 } else { 3565895Syz147064 softmac_rput_process_data(slp, mp); 3575895Syz147064 } 3585895Syz147064 break; 3599073SCathy.Zhou@Sun.COM } 3605895Syz147064 case M_PROTO: 3615895Syz147064 case M_PCPROTO: 3625895Syz147064 if (MBLKL(mp) < sizeof (dlp->dl_primitive)) { 3635895Syz147064 freemsg(mp); 3645895Syz147064 break; 3655895Syz147064 } 3665895Syz147064 dlp = (union DL_primitives *)mp->b_rptr; 3675895Syz147064 if (dlp->dl_primitive == DL_UNITDATA_IND) { 3689073SCathy.Zhou@Sun.COM 3699073SCathy.Zhou@Sun.COM if ((rxinfo = slp->sl_rxinfo) != NULL) { 3709073SCathy.Zhou@Sun.COM rxinfo->slr_rx(rxinfo->slr_arg, NULL, mp, NULL); 3719073SCathy.Zhou@Sun.COM break; 3729073SCathy.Zhou@Sun.COM } 3739073SCathy.Zhou@Sun.COM 3745895Syz147064 cmn_err(CE_WARN, "got unexpected %s message", 3755895Syz147064 dl_primstr(DL_UNITDATA_IND)); 3765895Syz147064 freemsg(mp); 3775895Syz147064 break; 3785895Syz147064 } 3795895Syz147064 /*FALLTHROUGH*/ 3805895Syz147064 default: 3819073SCathy.Zhou@Sun.COM softmac_rput_process_notdata(rq, slp->sl_sup, mp); 3825895Syz147064 break; 3835895Syz147064 } 3845895Syz147064 } 3855895Syz147064 3865895Syz147064 static void 3879073SCathy.Zhou@Sun.COM softmac_mod_wput(queue_t *wq, mblk_t *mp) 3885895Syz147064 { 3895895Syz147064 /* 3905895Syz147064 * This is the softmac module 3915895Syz147064 */ 3925895Syz147064 ASSERT(wq->q_next != NULL); 3935895Syz147064 3945895Syz147064 switch (DB_TYPE(mp)) { 3955895Syz147064 case M_IOCTL: { 3965895Syz147064 struct iocblk *ioc = (struct iocblk *)mp->b_rptr; 3975895Syz147064 3985895Syz147064 switch (ioc->ioc_cmd) { 3995895Syz147064 case SMAC_IOC_START: { 4005895Syz147064 softmac_lower_t *slp = wq->q_ptr; 4015895Syz147064 smac_ioc_start_t *arg; 4025895Syz147064 4035895Syz147064 if (ioc->ioc_count != sizeof (*arg)) { 4045895Syz147064 miocnak(wq, mp, 0, EINVAL); 4055895Syz147064 break; 4065895Syz147064 } 4075895Syz147064 4085895Syz147064 /* 4095895Syz147064 * Assign the devname and perstream handle of the 4105895Syz147064 * specific lower stream and return it as a part 4115895Syz147064 * of the ioctl. 4125895Syz147064 */ 4135895Syz147064 arg = (smac_ioc_start_t *)mp->b_cont->b_rptr; 4145895Syz147064 arg->si_slp = slp; 4155895Syz147064 miocack(wq, mp, sizeof (*arg), 0); 4165895Syz147064 break; 4175895Syz147064 } 4185895Syz147064 default: 4195895Syz147064 miocnak(wq, mp, 0, EINVAL); 4205895Syz147064 break; 4215895Syz147064 } 4225895Syz147064 break; 4235895Syz147064 } 4245895Syz147064 default: 4255895Syz147064 freemsg(mp); 4265895Syz147064 break; 4275895Syz147064 } 4285895Syz147064 } 4295895Syz147064 4305895Syz147064 static void 4319073SCathy.Zhou@Sun.COM softmac_mod_wsrv(queue_t *wq) 4325895Syz147064 { 4335895Syz147064 softmac_lower_t *slp = wq->q_ptr; 4345895Syz147064 4355895Syz147064 /* 4365895Syz147064 * This is the softmac module 4375895Syz147064 */ 4385895Syz147064 ASSERT(wq->q_next != NULL); 4395895Syz147064 4405895Syz147064 /* 4415895Syz147064 * Inform that the tx resource is available; mac_tx_update() will 4425895Syz147064 * inform all the upper streams sharing this lower stream. 4435895Syz147064 */ 4449073SCathy.Zhou@Sun.COM if (slp->sl_sup != NULL) 4459073SCathy.Zhou@Sun.COM qenable(slp->sl_sup->su_wq); 4469073SCathy.Zhou@Sun.COM else if (slp->sl_softmac != NULL) 4475895Syz147064 mac_tx_update(slp->sl_softmac->smac_mh); 4485895Syz147064 } 4495895Syz147064 4505895Syz147064 static int 4515895Syz147064 softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4525895Syz147064 { 4535895Syz147064 ASSERT(ddi_get_instance(dip) == 0); 4545895Syz147064 4555895Syz147064 if (cmd != DDI_ATTACH) 4565895Syz147064 return (DDI_FAILURE); 4575895Syz147064 4585895Syz147064 softmac_dip = dip; 4595895Syz147064 4605895Syz147064 return (DDI_SUCCESS); 4615895Syz147064 } 4625895Syz147064 4635895Syz147064 /* ARGSUSED */ 4645895Syz147064 static int 4655895Syz147064 softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4665895Syz147064 { 4675895Syz147064 if (cmd != DDI_DETACH) 4685895Syz147064 return (DDI_FAILURE); 4695895Syz147064 4705895Syz147064 softmac_dip = NULL; 4715895Syz147064 return (DDI_SUCCESS); 4725895Syz147064 } 4735895Syz147064 4745895Syz147064 /* ARGSUSED */ 4755895Syz147064 static int 4765895Syz147064 softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 4775895Syz147064 { 4785895Syz147064 switch (infocmd) { 4795895Syz147064 case DDI_INFO_DEVT2DEVINFO: 4805895Syz147064 if (softmac_dip != NULL) { 4815895Syz147064 *result = softmac_dip; 4825895Syz147064 return (DDI_SUCCESS); 4835895Syz147064 } 4845895Syz147064 break; 4855895Syz147064 4865895Syz147064 case DDI_INFO_DEVT2INSTANCE: 4875895Syz147064 *result = NULL; 4885895Syz147064 return (DDI_SUCCESS); 4895895Syz147064 4905895Syz147064 } 4915895Syz147064 4925895Syz147064 return (DDI_FAILURE); 4935895Syz147064 } 4949073SCathy.Zhou@Sun.COM 4959073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 4969073SCathy.Zhou@Sun.COM static void 4979073SCathy.Zhou@Sun.COM softmac_dedicated_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 4989073SCathy.Zhou@Sun.COM mac_header_info_t *mhip) 4999073SCathy.Zhou@Sun.COM { 5009073SCathy.Zhou@Sun.COM queue_t *rq = ((softmac_upper_t *)arg)->su_rq; 5019073SCathy.Zhou@Sun.COM 5029073SCathy.Zhou@Sun.COM if (canputnext(rq)) 5039073SCathy.Zhou@Sun.COM putnext(rq, mp); 5049073SCathy.Zhou@Sun.COM else 5059073SCathy.Zhou@Sun.COM freemsg(mp); 5069073SCathy.Zhou@Sun.COM } 5079073SCathy.Zhou@Sun.COM 5089073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 5099073SCathy.Zhou@Sun.COM static int 5109073SCathy.Zhou@Sun.COM softmac_drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 5119073SCathy.Zhou@Sun.COM { 5129073SCathy.Zhou@Sun.COM softmac_upper_t *sup = NULL; 5139073SCathy.Zhou@Sun.COM softmac_t *softmac; 5149073SCathy.Zhou@Sun.COM int err = 0; 5159073SCathy.Zhou@Sun.COM 5169073SCathy.Zhou@Sun.COM /* 5179073SCathy.Zhou@Sun.COM * This is a softmac device created for a legacy device, find the 5189073SCathy.Zhou@Sun.COM * associated softmac and initialize the softmac_upper_t structure. 5199073SCathy.Zhou@Sun.COM */ 5209073SCathy.Zhou@Sun.COM if ((err = softmac_hold(*devp, &softmac)) != 0) 5219073SCathy.Zhou@Sun.COM return (err); 5229073SCathy.Zhou@Sun.COM 5239073SCathy.Zhou@Sun.COM sup = kmem_cache_alloc(softmac_upper_cachep, KM_NOSLEEP); 5249073SCathy.Zhou@Sun.COM if (sup == NULL) { 5259073SCathy.Zhou@Sun.COM err = ENOMEM; 5269073SCathy.Zhou@Sun.COM goto fail; 5279073SCathy.Zhou@Sun.COM } 5289073SCathy.Zhou@Sun.COM 5299073SCathy.Zhou@Sun.COM ASSERT(list_is_empty(&sup->su_req_list)); 5309073SCathy.Zhou@Sun.COM 5319073SCathy.Zhou@Sun.COM if ((sup->su_tx_flow_mp = allocb(1, BPRI_HI)) == NULL) { 5329073SCathy.Zhou@Sun.COM err = ENOMEM; 5339073SCathy.Zhou@Sun.COM goto fail; 5349073SCathy.Zhou@Sun.COM } 5359073SCathy.Zhou@Sun.COM 5369073SCathy.Zhou@Sun.COM sup->su_rq = rq; 5379073SCathy.Zhou@Sun.COM sup->su_wq = WR(rq); 5389073SCathy.Zhou@Sun.COM sup->su_softmac = softmac; 5399073SCathy.Zhou@Sun.COM sup->su_mode = SOFTMAC_UNKNOWN; 5409073SCathy.Zhou@Sun.COM 5419073SCathy.Zhou@Sun.COM sup->su_rxinfo.slr_arg = sup; 5429073SCathy.Zhou@Sun.COM sup->su_rxinfo.slr_rx = softmac_dedicated_rx; 5439073SCathy.Zhou@Sun.COM sup->su_direct_rxinfo.slr_arg = sup; 5449073SCathy.Zhou@Sun.COM sup->su_direct_rxinfo.slr_rx = softmac_dedicated_rx; 5459073SCathy.Zhou@Sun.COM 5469073SCathy.Zhou@Sun.COM if ((err = dld_str_open(rq, devp, sup)) != 0) { 5479073SCathy.Zhou@Sun.COM freeb(sup->su_tx_flow_mp); 5489073SCathy.Zhou@Sun.COM sup->su_tx_flow_mp = NULL; 5499073SCathy.Zhou@Sun.COM goto fail; 5509073SCathy.Zhou@Sun.COM } 5519073SCathy.Zhou@Sun.COM 5529073SCathy.Zhou@Sun.COM return (0); 5539073SCathy.Zhou@Sun.COM 5549073SCathy.Zhou@Sun.COM fail: 5559073SCathy.Zhou@Sun.COM if (sup != NULL) 5569073SCathy.Zhou@Sun.COM kmem_cache_free(softmac_upper_cachep, sup); 5579073SCathy.Zhou@Sun.COM softmac_rele(softmac); 5589073SCathy.Zhou@Sun.COM return (err); 5599073SCathy.Zhou@Sun.COM } 5609073SCathy.Zhou@Sun.COM 5619073SCathy.Zhou@Sun.COM static int 5629073SCathy.Zhou@Sun.COM softmac_drv_close(queue_t *rq) 5639073SCathy.Zhou@Sun.COM { 5649073SCathy.Zhou@Sun.COM softmac_upper_t *sup = dld_str_private(rq); 5659073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac; 5669073SCathy.Zhou@Sun.COM 5679073SCathy.Zhou@Sun.COM ASSERT(WR(rq)->q_next == NULL); 5689073SCathy.Zhou@Sun.COM 5699073SCathy.Zhou@Sun.COM qprocsoff(rq); 5709073SCathy.Zhou@Sun.COM 5719073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_inprocess == 0); 5729073SCathy.Zhou@Sun.COM 5739073SCathy.Zhou@Sun.COM /* 5749073SCathy.Zhou@Sun.COM * Wait until the pending request are processed by the worker thread. 5759073SCathy.Zhou@Sun.COM */ 5769073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_disp_mutex); 5779073SCathy.Zhou@Sun.COM sup->su_closing = B_TRUE; 5789073SCathy.Zhou@Sun.COM while (sup->su_dlpi_pending) 5799073SCathy.Zhou@Sun.COM cv_wait(&sup->su_disp_cv, &sup->su_disp_mutex); 5809073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_disp_mutex); 5819073SCathy.Zhou@Sun.COM 5829073SCathy.Zhou@Sun.COM softmac_upperstream_close(sup); 5839073SCathy.Zhou@Sun.COM 5849073SCathy.Zhou@Sun.COM if (sup->su_tx_flow_mp != NULL) { 5859073SCathy.Zhou@Sun.COM freeb(sup->su_tx_flow_mp); 5869073SCathy.Zhou@Sun.COM sup->su_tx_flow_mp = NULL; 5879073SCathy.Zhou@Sun.COM } 5889073SCathy.Zhou@Sun.COM 5899073SCathy.Zhou@Sun.COM if (sup->su_active) { 5909073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_active_mutex); 5919073SCathy.Zhou@Sun.COM softmac->smac_nactive--; 5929073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex); 5939073SCathy.Zhou@Sun.COM sup->su_active = B_FALSE; 5949073SCathy.Zhou@Sun.COM } 5959073SCathy.Zhou@Sun.COM 5969073SCathy.Zhou@Sun.COM sup->su_bound = B_FALSE; 5979073SCathy.Zhou@Sun.COM sup->su_softmac = NULL; 5989073SCathy.Zhou@Sun.COM sup->su_closing = B_FALSE; 5999073SCathy.Zhou@Sun.COM 6009073SCathy.Zhou@Sun.COM kmem_cache_free(softmac_upper_cachep, sup); 6019073SCathy.Zhou@Sun.COM 6029073SCathy.Zhou@Sun.COM softmac_rele(softmac); 6039073SCathy.Zhou@Sun.COM return (dld_str_close(rq)); 6049073SCathy.Zhou@Sun.COM } 6059073SCathy.Zhou@Sun.COM 6069073SCathy.Zhou@Sun.COM static void 6079073SCathy.Zhou@Sun.COM softmac_drv_wput(queue_t *wq, mblk_t *mp) 6089073SCathy.Zhou@Sun.COM { 6099073SCathy.Zhou@Sun.COM softmac_upper_t *sup = dld_str_private(wq); 6109073SCathy.Zhou@Sun.COM t_uscalar_t prim; 6119073SCathy.Zhou@Sun.COM 6129073SCathy.Zhou@Sun.COM ASSERT(wq->q_next == NULL); 6139073SCathy.Zhou@Sun.COM 6149073SCathy.Zhou@Sun.COM switch (DB_TYPE(mp)) { 6159073SCathy.Zhou@Sun.COM case M_DATA: 6169073SCathy.Zhou@Sun.COM case M_MULTIDATA: 6179073SCathy.Zhou@Sun.COM softmac_wput_data(sup, mp); 6189073SCathy.Zhou@Sun.COM break; 6199073SCathy.Zhou@Sun.COM case M_PROTO: 6209073SCathy.Zhou@Sun.COM case M_PCPROTO: 6219073SCathy.Zhou@Sun.COM 6229073SCathy.Zhou@Sun.COM if (MBLKL(mp) < sizeof (t_uscalar_t)) { 6239073SCathy.Zhou@Sun.COM freemsg(mp); 6249073SCathy.Zhou@Sun.COM return; 6259073SCathy.Zhou@Sun.COM } 6269073SCathy.Zhou@Sun.COM 6279073SCathy.Zhou@Sun.COM prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; 6289073SCathy.Zhou@Sun.COM if (prim == DL_UNITDATA_REQ) { 6299073SCathy.Zhou@Sun.COM softmac_wput_data(sup, mp); 6309073SCathy.Zhou@Sun.COM return; 6319073SCathy.Zhou@Sun.COM } 6329073SCathy.Zhou@Sun.COM 6339073SCathy.Zhou@Sun.COM softmac_wput_nondata(sup, mp); 6349073SCathy.Zhou@Sun.COM break; 6359073SCathy.Zhou@Sun.COM default: 6369073SCathy.Zhou@Sun.COM softmac_wput_nondata(sup, mp); 6379073SCathy.Zhou@Sun.COM break; 6389073SCathy.Zhou@Sun.COM } 6399073SCathy.Zhou@Sun.COM } 6409073SCathy.Zhou@Sun.COM 6419073SCathy.Zhou@Sun.COM static void 6429073SCathy.Zhou@Sun.COM softmac_drv_wsrv(queue_t *wq) 6439073SCathy.Zhou@Sun.COM { 6449073SCathy.Zhou@Sun.COM softmac_upper_t *sup = dld_str_private(wq); 6459073SCathy.Zhou@Sun.COM 6469073SCathy.Zhou@Sun.COM ASSERT(wq->q_next == NULL); 6479073SCathy.Zhou@Sun.COM 6489073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex); 6499073SCathy.Zhou@Sun.COM if (sup->su_mode != SOFTMAC_FASTPATH) { 6509073SCathy.Zhou@Sun.COM /* 6519073SCathy.Zhou@Sun.COM * Bump su_tx_inprocess so that su_mode won't change. 6529073SCathy.Zhou@Sun.COM */ 6539073SCathy.Zhou@Sun.COM sup->su_tx_inprocess++; 6549073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex); 6559073SCathy.Zhou@Sun.COM dld_wsrv(wq); 6569073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex); 6579073SCathy.Zhou@Sun.COM if (--sup->su_tx_inprocess == 0) 6589073SCathy.Zhou@Sun.COM cv_signal(&sup->su_cv); 6599073SCathy.Zhou@Sun.COM } else if (sup->su_tx_busy && SOFTMAC_CANPUTNEXT(sup->su_slp->sl_wq)) { 6609073SCathy.Zhou@Sun.COM /* 6619073SCathy.Zhou@Sun.COM * The flow-conctol of the dedicated-lower-stream is 6629738SCathy.Zhou@Sun.COM * relieved. If DLD_CAPAB_DIRECT is enabled, call tx_notify 6639738SCathy.Zhou@Sun.COM * callback to relieve the flow-control of the specific client, 6649738SCathy.Zhou@Sun.COM * otherwise relieve the flow-control of all the upper-stream 6659738SCathy.Zhou@Sun.COM * using the traditional STREAM mechanism. 6669073SCathy.Zhou@Sun.COM */ 6679738SCathy.Zhou@Sun.COM if (sup->su_tx_notify_func != NULL) { 6689738SCathy.Zhou@Sun.COM sup->su_tx_inprocess++; 6699738SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex); 6709738SCathy.Zhou@Sun.COM sup->su_tx_notify_func(sup->su_tx_notify_arg, 6719738SCathy.Zhou@Sun.COM (mac_tx_cookie_t)sup); 6729738SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex); 6739738SCathy.Zhou@Sun.COM if (--sup->su_tx_inprocess == 0) 6749738SCathy.Zhou@Sun.COM cv_signal(&sup->su_cv); 6759738SCathy.Zhou@Sun.COM } 6769738SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_flow_mp == NULL); 6779738SCathy.Zhou@Sun.COM VERIFY((sup->su_tx_flow_mp = getq(wq)) != NULL); 6789073SCathy.Zhou@Sun.COM sup->su_tx_busy = B_FALSE; 6799073SCathy.Zhou@Sun.COM } 6809073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex); 6819073SCathy.Zhou@Sun.COM } 682