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 /* 22*9073SCathy.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> 31*9073SCathy.Zhou@Sun.COM #include <sys/dld.h> 325895Syz147064 #include <sys/softmac_impl.h> 335895Syz147064 345895Syz147064 dev_info_t *softmac_dip = NULL; 35*9073SCathy.Zhou@Sun.COM static kmem_cache_t *softmac_upper_cachep; 365895Syz147064 37*9073SCathy.Zhou@Sun.COM /* 38*9073SCathy.Zhou@Sun.COM * This function is a generic open(9E) entry point into the softmac for 39*9073SCathy.Zhou@Sun.COM * both the softmac module and the softmac driver. 40*9073SCathy.Zhou@Sun.COM */ 41*9073SCathy.Zhou@Sun.COM static int softmac_cmn_open(queue_t *, dev_t *, int, int, cred_t *); 42*9073SCathy.Zhou@Sun.COM 43*9073SCathy.Zhou@Sun.COM /* 44*9073SCathy.Zhou@Sun.COM * The following softmac_mod_xxx() functions are (9E) entry point functions for 45*9073SCathy.Zhou@Sun.COM * the softmac module. 46*9073SCathy.Zhou@Sun.COM */ 47*9073SCathy.Zhou@Sun.COM static int softmac_mod_close(queue_t *); 48*9073SCathy.Zhou@Sun.COM static void softmac_mod_rput(queue_t *, mblk_t *); 49*9073SCathy.Zhou@Sun.COM static void softmac_mod_wput(queue_t *, mblk_t *); 50*9073SCathy.Zhou@Sun.COM static void softmac_mod_wsrv(queue_t *); 51*9073SCathy.Zhou@Sun.COM 52*9073SCathy.Zhou@Sun.COM /* 53*9073SCathy.Zhou@Sun.COM * The following softmac_drv_xxx() functions are (9E) entry point functions for 54*9073SCathy.Zhou@Sun.COM * the softmac driver. 55*9073SCathy.Zhou@Sun.COM */ 56*9073SCathy.Zhou@Sun.COM static int softmac_drv_open(queue_t *, dev_t *, int, int, cred_t *); 57*9073SCathy.Zhou@Sun.COM static int softmac_drv_close(queue_t *); 58*9073SCathy.Zhou@Sun.COM static void softmac_drv_wput(queue_t *, mblk_t *); 59*9073SCathy.Zhou@Sun.COM static void softmac_drv_wsrv(queue_t *); 60*9073SCathy.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 = { 88*9073SCathy.Zhou@Sun.COM (pfi_t)softmac_mod_rput, /* qi_putp */ 89*9073SCathy.Zhou@Sun.COM (pfi_t)NULL, /* qi_srvp */ 90*9073SCathy.Zhou@Sun.COM softmac_cmn_open, /* qi_qopen */ 91*9073SCathy.Zhou@Sun.COM softmac_mod_close, /* qi_qclose */ 92*9073SCathy.Zhou@Sun.COM NULL, /* qi_qadmin */ 93*9073SCathy.Zhou@Sun.COM &softmac_modinfo /* qi_minfo */ 945895Syz147064 }; 955895Syz147064 965895Syz147064 static struct qinit softmac_uwinit = { 97*9073SCathy.Zhou@Sun.COM (pfi_t)softmac_mod_wput, /* qi_putp */ 98*9073SCathy.Zhou@Sun.COM (pfi_t)softmac_mod_wsrv, /* qi_srvp */ 99*9073SCathy.Zhou@Sun.COM NULL, /* qi_qopen */ 100*9073SCathy.Zhou@Sun.COM NULL, /* qi_qclose */ 101*9073SCathy.Zhou@Sun.COM NULL, /* qi_qadmin */ 102*9073SCathy.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 = { 115*9073SCathy.Zhou@Sun.COM NULL, NULL, softmac_drv_open, softmac_drv_close, NULL, 116*9073SCathy.Zhou@Sun.COM &softmac_dld_modinfo 1175895Syz147064 }; 1185895Syz147064 1195895Syz147064 static struct qinit softmac_dld_w_qinit = { 120*9073SCathy.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*9073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 150*9073SCathy.Zhou@Sun.COM static int 151*9073SCathy.Zhou@Sun.COM softmac_upper_constructor(void *buf, void *arg, int kmflag) 152*9073SCathy.Zhou@Sun.COM { 153*9073SCathy.Zhou@Sun.COM softmac_upper_t *sup = buf; 154*9073SCathy.Zhou@Sun.COM 155*9073SCathy.Zhou@Sun.COM bzero(buf, sizeof (softmac_upper_t)); 156*9073SCathy.Zhou@Sun.COM 157*9073SCathy.Zhou@Sun.COM mutex_init(&sup->su_mutex, NULL, MUTEX_DEFAULT, NULL); 158*9073SCathy.Zhou@Sun.COM cv_init(&sup->su_cv, NULL, CV_DEFAULT, NULL); 159*9073SCathy.Zhou@Sun.COM mutex_init(&sup->su_disp_mutex, NULL, MUTEX_DEFAULT, NULL); 160*9073SCathy.Zhou@Sun.COM cv_init(&sup->su_disp_cv, NULL, CV_DEFAULT, NULL); 161*9073SCathy.Zhou@Sun.COM list_create(&sup->su_req_list, sizeof (softmac_switch_req_t), 162*9073SCathy.Zhou@Sun.COM offsetof(softmac_switch_req_t, ssq_req_list_node)); 163*9073SCathy.Zhou@Sun.COM return (0); 164*9073SCathy.Zhou@Sun.COM } 165*9073SCathy.Zhou@Sun.COM 166*9073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 167*9073SCathy.Zhou@Sun.COM static void 168*9073SCathy.Zhou@Sun.COM softmac_upper_destructor(void *buf, void *arg) 169*9073SCathy.Zhou@Sun.COM { 170*9073SCathy.Zhou@Sun.COM softmac_upper_t *sup = buf; 171*9073SCathy.Zhou@Sun.COM 172*9073SCathy.Zhou@Sun.COM ASSERT(sup->su_slp == NULL); 173*9073SCathy.Zhou@Sun.COM ASSERT(sup->su_pending_head == NULL && sup->su_pending_tail == NULL); 174*9073SCathy.Zhou@Sun.COM ASSERT(!sup->su_dlpi_pending); 175*9073SCathy.Zhou@Sun.COM ASSERT(!sup->su_active); 176*9073SCathy.Zhou@Sun.COM ASSERT(!sup->su_closing); 177*9073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_flow_mp == NULL); 178*9073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_inprocess == 0); 179*9073SCathy.Zhou@Sun.COM ASSERT(sup->su_mode == SOFTMAC_UNKNOWN); 180*9073SCathy.Zhou@Sun.COM ASSERT(!sup->su_tx_busy); 181*9073SCathy.Zhou@Sun.COM ASSERT(!sup->su_bound); 182*9073SCathy.Zhou@Sun.COM ASSERT(!sup->su_taskq_scheduled); 183*9073SCathy.Zhou@Sun.COM ASSERT(list_is_empty(&sup->su_req_list)); 184*9073SCathy.Zhou@Sun.COM 185*9073SCathy.Zhou@Sun.COM list_destroy(&sup->su_req_list); 186*9073SCathy.Zhou@Sun.COM mutex_destroy(&sup->su_mutex); 187*9073SCathy.Zhou@Sun.COM cv_destroy(&sup->su_cv); 188*9073SCathy.Zhou@Sun.COM mutex_destroy(&sup->su_disp_mutex); 189*9073SCathy.Zhou@Sun.COM cv_destroy(&sup->su_disp_cv); 190*9073SCathy.Zhou@Sun.COM } 191*9073SCathy.Zhou@Sun.COM 1925895Syz147064 int 1935895Syz147064 _init(void) 1945895Syz147064 { 1955895Syz147064 int err; 1965895Syz147064 1975895Syz147064 softmac_init(); 1985895Syz147064 199*9073SCathy.Zhou@Sun.COM softmac_upper_cachep = kmem_cache_create("softmac_upper_cache", 200*9073SCathy.Zhou@Sun.COM sizeof (softmac_upper_t), 0, softmac_upper_constructor, 201*9073SCathy.Zhou@Sun.COM softmac_upper_destructor, NULL, NULL, NULL, 0); 202*9073SCathy.Zhou@Sun.COM ASSERT(softmac_upper_cachep != NULL); 203*9073SCathy.Zhou@Sun.COM 2045895Syz147064 if ((err = mod_install(&softmac_modlinkage)) != 0) { 2055895Syz147064 softmac_fini(); 2065895Syz147064 return (err); 2075895Syz147064 } 2085895Syz147064 2095895Syz147064 return (0); 2105895Syz147064 } 2115895Syz147064 2125895Syz147064 int 2135895Syz147064 _fini(void) 2145895Syz147064 { 2155895Syz147064 int err; 2165895Syz147064 2175895Syz147064 if (softmac_busy()) 2185895Syz147064 return (EBUSY); 2195895Syz147064 2205895Syz147064 if ((err = mod_remove(&softmac_modlinkage)) != 0) 2215895Syz147064 return (err); 2225895Syz147064 223*9073SCathy.Zhou@Sun.COM kmem_cache_destroy(softmac_upper_cachep); 2245895Syz147064 softmac_fini(); 2255895Syz147064 2265895Syz147064 return (0); 2275895Syz147064 } 2285895Syz147064 2295895Syz147064 int 2305895Syz147064 _info(struct modinfo *modinfop) 2315895Syz147064 { 2325895Syz147064 return (mod_info(&softmac_modlinkage, modinfop)); 2335895Syz147064 } 2345895Syz147064 2355895Syz147064 static int 236*9073SCathy.Zhou@Sun.COM softmac_cmn_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 2375895Syz147064 { 2385895Syz147064 softmac_lower_t *slp; 2395895Syz147064 /* 2405895Syz147064 * This is a self-cloning driver so that each queue should only 2415895Syz147064 * get opened once. 2425895Syz147064 */ 2435895Syz147064 if (rq->q_ptr != NULL) 2445895Syz147064 return (EBUSY); 2455895Syz147064 2465895Syz147064 if (sflag == MODOPEN) { 2475895Syz147064 /* 2485895Syz147064 * This is the softmac module pushed over an underlying 2495895Syz147064 * legacy device. Initialize the lower structure. 2505895Syz147064 */ 2515895Syz147064 if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL) 2525895Syz147064 return (ENOMEM); 2535895Syz147064 2545895Syz147064 slp->sl_wq = WR(rq); 2555895Syz147064 cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL); 2565895Syz147064 mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL); 2575895Syz147064 cv_init(&slp->sl_ctl_cv, NULL, CV_DRIVER, NULL); 2585895Syz147064 mutex_init(&slp->sl_ctl_mutex, NULL, MUTEX_DRIVER, NULL); 2595895Syz147064 slp->sl_pending_prim = DL_PRIM_INVAL; 2605895Syz147064 rq->q_ptr = WR(rq)->q_ptr = slp; 2615895Syz147064 qprocson(rq); 2625895Syz147064 return (0); 2635895Syz147064 } 2645895Syz147064 2655895Syz147064 /* 2665895Syz147064 * Regular device open of a softmac DLPI node. We modify 2675895Syz147064 * the queues' q_qinfo pointer such that all future STREAMS 268*9073SCathy.Zhou@Sun.COM * operations will go through another set of entry points 2695895Syz147064 */ 2705895Syz147064 rq->q_qinfo = &softmac_dld_r_qinit; 2715895Syz147064 WR(rq)->q_qinfo = &softmac_dld_w_qinit; 272*9073SCathy.Zhou@Sun.COM return (softmac_drv_open(rq, devp, flag, sflag, credp)); 2735895Syz147064 } 2745895Syz147064 2755895Syz147064 static int 276*9073SCathy.Zhou@Sun.COM softmac_mod_close(queue_t *rq) 2775895Syz147064 { 2785895Syz147064 softmac_lower_t *slp = rq->q_ptr; 2795895Syz147064 2805895Syz147064 /* 2815895Syz147064 * Call the appropriate delete routine depending on whether this is 2825895Syz147064 * a module or device. 2835895Syz147064 */ 2845895Syz147064 ASSERT(WR(rq)->q_next != NULL); 2855895Syz147064 2865895Syz147064 qprocsoff(rq); 2875895Syz147064 2885895Syz147064 slp->sl_softmac = NULL; 2895895Syz147064 slp->sl_lh = NULL; 2905895Syz147064 2915895Syz147064 ASSERT(slp->sl_ack_mp == NULL); 2925895Syz147064 ASSERT(slp->sl_ctl_inprogress == B_FALSE); 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 cv_destroy(&slp->sl_ctl_cv); 2995895Syz147064 mutex_destroy(&slp->sl_ctl_mutex); 3005895Syz147064 3015895Syz147064 kmem_free(slp, sizeof (*slp)); 3025895Syz147064 return (0); 3035895Syz147064 } 3045895Syz147064 3055895Syz147064 static void 306*9073SCathy.Zhou@Sun.COM softmac_mod_rput(queue_t *rq, mblk_t *mp) 3075895Syz147064 { 308*9073SCathy.Zhou@Sun.COM softmac_lower_t *slp = rq->q_ptr; 309*9073SCathy.Zhou@Sun.COM softmac_lower_rxinfo_t *rxinfo; 310*9073SCathy.Zhou@Sun.COM union DL_primitives *dlp; 3115895Syz147064 3125895Syz147064 /* 3135895Syz147064 * This is the softmac module. 3145895Syz147064 */ 3155895Syz147064 ASSERT(WR(rq)->q_next != NULL); 3165895Syz147064 ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL)); 3175895Syz147064 3185895Syz147064 switch (DB_TYPE(mp)) { 319*9073SCathy.Zhou@Sun.COM case M_DATA: { 320*9073SCathy.Zhou@Sun.COM 3215895Syz147064 /* 322*9073SCathy.Zhou@Sun.COM * If sl_rxinfo is non-NULL. This is dedicated-lower-stream 323*9073SCathy.Zhou@Sun.COM * created for fastpath. Directly call the rx callback. 324*9073SCathy.Zhou@Sun.COM */ 325*9073SCathy.Zhou@Sun.COM if ((rxinfo = slp->sl_rxinfo) != NULL) { 326*9073SCathy.Zhou@Sun.COM rxinfo->slr_rx(rxinfo->slr_arg, NULL, mp, NULL); 327*9073SCathy.Zhou@Sun.COM break; 328*9073SCathy.Zhou@Sun.COM } 329*9073SCathy.Zhou@Sun.COM 330*9073SCathy.Zhou@Sun.COM /* 331*9073SCathy.Zhou@Sun.COM * A shared-lower-stream. Some driver starts to send up 332*9073SCathy.Zhou@Sun.COM * packets even it not in the DL_IDLE state, where 333*9073SCathy.Zhou@Sun.COM * sl_softmac is not set yet. Drop the packet in this case. 3345895Syz147064 */ 3355895Syz147064 if (slp->sl_softmac == NULL) { 3365895Syz147064 freemsg(mp); 3375895Syz147064 return; 3385895Syz147064 } 3395895Syz147064 3405895Syz147064 /* 3418275SEric Cheng * If this message is looped back from the legacy devices, 3428275SEric Cheng * drop it as the Nemo framework will be responsible for 3438275SEric Cheng * looping it back by the mac_txloop() function. 3448275SEric Cheng */ 3458275SEric Cheng if (mp->b_flag & MSGNOLOOP) { 3468275SEric Cheng freemsg(mp); 3478275SEric Cheng return; 3488275SEric Cheng } 3498275SEric Cheng 3508275SEric Cheng /* 3515895Syz147064 * This is the most common case. 3525895Syz147064 */ 3535895Syz147064 if (DB_REF(mp) == 1) { 3545895Syz147064 ASSERT(slp->sl_softmac != NULL); 3558275SEric Cheng mac_rx(slp->sl_softmac->smac_mh, NULL, mp); 3565895Syz147064 return; 3575895Syz147064 } else { 3585895Syz147064 softmac_rput_process_data(slp, mp); 3595895Syz147064 } 3605895Syz147064 break; 361*9073SCathy.Zhou@Sun.COM } 3625895Syz147064 case M_PROTO: 3635895Syz147064 case M_PCPROTO: 3645895Syz147064 if (MBLKL(mp) < sizeof (dlp->dl_primitive)) { 3655895Syz147064 freemsg(mp); 3665895Syz147064 break; 3675895Syz147064 } 3685895Syz147064 dlp = (union DL_primitives *)mp->b_rptr; 3695895Syz147064 if (dlp->dl_primitive == DL_UNITDATA_IND) { 370*9073SCathy.Zhou@Sun.COM 371*9073SCathy.Zhou@Sun.COM if ((rxinfo = slp->sl_rxinfo) != NULL) { 372*9073SCathy.Zhou@Sun.COM rxinfo->slr_rx(rxinfo->slr_arg, NULL, mp, NULL); 373*9073SCathy.Zhou@Sun.COM break; 374*9073SCathy.Zhou@Sun.COM } 375*9073SCathy.Zhou@Sun.COM 3765895Syz147064 cmn_err(CE_WARN, "got unexpected %s message", 3775895Syz147064 dl_primstr(DL_UNITDATA_IND)); 3785895Syz147064 freemsg(mp); 3795895Syz147064 break; 3805895Syz147064 } 3815895Syz147064 /*FALLTHROUGH*/ 3825895Syz147064 default: 383*9073SCathy.Zhou@Sun.COM softmac_rput_process_notdata(rq, slp->sl_sup, mp); 3845895Syz147064 break; 3855895Syz147064 } 3865895Syz147064 } 3875895Syz147064 3885895Syz147064 static void 389*9073SCathy.Zhou@Sun.COM softmac_mod_wput(queue_t *wq, mblk_t *mp) 3905895Syz147064 { 3915895Syz147064 /* 3925895Syz147064 * This is the softmac module 3935895Syz147064 */ 3945895Syz147064 ASSERT(wq->q_next != NULL); 3955895Syz147064 3965895Syz147064 switch (DB_TYPE(mp)) { 3975895Syz147064 case M_IOCTL: { 3985895Syz147064 struct iocblk *ioc = (struct iocblk *)mp->b_rptr; 3995895Syz147064 4005895Syz147064 switch (ioc->ioc_cmd) { 4015895Syz147064 case SMAC_IOC_START: { 4025895Syz147064 softmac_lower_t *slp = wq->q_ptr; 4035895Syz147064 smac_ioc_start_t *arg; 4045895Syz147064 4055895Syz147064 if (ioc->ioc_count != sizeof (*arg)) { 4065895Syz147064 miocnak(wq, mp, 0, EINVAL); 4075895Syz147064 break; 4085895Syz147064 } 4095895Syz147064 4105895Syz147064 /* 4115895Syz147064 * Assign the devname and perstream handle of the 4125895Syz147064 * specific lower stream and return it as a part 4135895Syz147064 * of the ioctl. 4145895Syz147064 */ 4155895Syz147064 arg = (smac_ioc_start_t *)mp->b_cont->b_rptr; 4165895Syz147064 arg->si_slp = slp; 4175895Syz147064 miocack(wq, mp, sizeof (*arg), 0); 4185895Syz147064 break; 4195895Syz147064 } 4205895Syz147064 default: 4215895Syz147064 miocnak(wq, mp, 0, EINVAL); 4225895Syz147064 break; 4235895Syz147064 } 4245895Syz147064 break; 4255895Syz147064 } 4265895Syz147064 default: 4275895Syz147064 freemsg(mp); 4285895Syz147064 break; 4295895Syz147064 } 4305895Syz147064 } 4315895Syz147064 4325895Syz147064 static void 433*9073SCathy.Zhou@Sun.COM softmac_mod_wsrv(queue_t *wq) 4345895Syz147064 { 4355895Syz147064 softmac_lower_t *slp = wq->q_ptr; 4365895Syz147064 4375895Syz147064 /* 4385895Syz147064 * This is the softmac module 4395895Syz147064 */ 4405895Syz147064 ASSERT(wq->q_next != NULL); 4415895Syz147064 4425895Syz147064 /* 4435895Syz147064 * Inform that the tx resource is available; mac_tx_update() will 4445895Syz147064 * inform all the upper streams sharing this lower stream. 4455895Syz147064 */ 446*9073SCathy.Zhou@Sun.COM if (slp->sl_sup != NULL) 447*9073SCathy.Zhou@Sun.COM qenable(slp->sl_sup->su_wq); 448*9073SCathy.Zhou@Sun.COM else if (slp->sl_softmac != NULL) 4495895Syz147064 mac_tx_update(slp->sl_softmac->smac_mh); 4505895Syz147064 } 4515895Syz147064 4525895Syz147064 static int 4535895Syz147064 softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4545895Syz147064 { 4555895Syz147064 ASSERT(ddi_get_instance(dip) == 0); 4565895Syz147064 4575895Syz147064 if (cmd != DDI_ATTACH) 4585895Syz147064 return (DDI_FAILURE); 4595895Syz147064 4605895Syz147064 softmac_dip = dip; 4615895Syz147064 4625895Syz147064 return (DDI_SUCCESS); 4635895Syz147064 } 4645895Syz147064 4655895Syz147064 /* ARGSUSED */ 4665895Syz147064 static int 4675895Syz147064 softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4685895Syz147064 { 4695895Syz147064 if (cmd != DDI_DETACH) 4705895Syz147064 return (DDI_FAILURE); 4715895Syz147064 4725895Syz147064 softmac_dip = NULL; 4735895Syz147064 return (DDI_SUCCESS); 4745895Syz147064 } 4755895Syz147064 4765895Syz147064 /* ARGSUSED */ 4775895Syz147064 static int 4785895Syz147064 softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 4795895Syz147064 { 4805895Syz147064 switch (infocmd) { 4815895Syz147064 case DDI_INFO_DEVT2DEVINFO: 4825895Syz147064 if (softmac_dip != NULL) { 4835895Syz147064 *result = softmac_dip; 4845895Syz147064 return (DDI_SUCCESS); 4855895Syz147064 } 4865895Syz147064 break; 4875895Syz147064 4885895Syz147064 case DDI_INFO_DEVT2INSTANCE: 4895895Syz147064 *result = NULL; 4905895Syz147064 return (DDI_SUCCESS); 4915895Syz147064 4925895Syz147064 } 4935895Syz147064 4945895Syz147064 return (DDI_FAILURE); 4955895Syz147064 } 496*9073SCathy.Zhou@Sun.COM 497*9073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 498*9073SCathy.Zhou@Sun.COM static void 499*9073SCathy.Zhou@Sun.COM softmac_dedicated_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 500*9073SCathy.Zhou@Sun.COM mac_header_info_t *mhip) 501*9073SCathy.Zhou@Sun.COM { 502*9073SCathy.Zhou@Sun.COM queue_t *rq = ((softmac_upper_t *)arg)->su_rq; 503*9073SCathy.Zhou@Sun.COM 504*9073SCathy.Zhou@Sun.COM if (canputnext(rq)) 505*9073SCathy.Zhou@Sun.COM putnext(rq, mp); 506*9073SCathy.Zhou@Sun.COM else 507*9073SCathy.Zhou@Sun.COM freemsg(mp); 508*9073SCathy.Zhou@Sun.COM } 509*9073SCathy.Zhou@Sun.COM 510*9073SCathy.Zhou@Sun.COM /*ARGSUSED*/ 511*9073SCathy.Zhou@Sun.COM static int 512*9073SCathy.Zhou@Sun.COM softmac_drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 513*9073SCathy.Zhou@Sun.COM { 514*9073SCathy.Zhou@Sun.COM softmac_upper_t *sup = NULL; 515*9073SCathy.Zhou@Sun.COM softmac_t *softmac; 516*9073SCathy.Zhou@Sun.COM int err = 0; 517*9073SCathy.Zhou@Sun.COM 518*9073SCathy.Zhou@Sun.COM /* 519*9073SCathy.Zhou@Sun.COM * This is a softmac device created for a legacy device, find the 520*9073SCathy.Zhou@Sun.COM * associated softmac and initialize the softmac_upper_t structure. 521*9073SCathy.Zhou@Sun.COM */ 522*9073SCathy.Zhou@Sun.COM if ((err = softmac_hold(*devp, &softmac)) != 0) 523*9073SCathy.Zhou@Sun.COM return (err); 524*9073SCathy.Zhou@Sun.COM 525*9073SCathy.Zhou@Sun.COM sup = kmem_cache_alloc(softmac_upper_cachep, KM_NOSLEEP); 526*9073SCathy.Zhou@Sun.COM if (sup == NULL) { 527*9073SCathy.Zhou@Sun.COM err = ENOMEM; 528*9073SCathy.Zhou@Sun.COM goto fail; 529*9073SCathy.Zhou@Sun.COM } 530*9073SCathy.Zhou@Sun.COM 531*9073SCathy.Zhou@Sun.COM ASSERT(list_is_empty(&sup->su_req_list)); 532*9073SCathy.Zhou@Sun.COM 533*9073SCathy.Zhou@Sun.COM if ((sup->su_tx_flow_mp = allocb(1, BPRI_HI)) == NULL) { 534*9073SCathy.Zhou@Sun.COM err = ENOMEM; 535*9073SCathy.Zhou@Sun.COM goto fail; 536*9073SCathy.Zhou@Sun.COM } 537*9073SCathy.Zhou@Sun.COM 538*9073SCathy.Zhou@Sun.COM sup->su_rq = rq; 539*9073SCathy.Zhou@Sun.COM sup->su_wq = WR(rq); 540*9073SCathy.Zhou@Sun.COM sup->su_softmac = softmac; 541*9073SCathy.Zhou@Sun.COM sup->su_mode = SOFTMAC_UNKNOWN; 542*9073SCathy.Zhou@Sun.COM 543*9073SCathy.Zhou@Sun.COM sup->su_rxinfo.slr_arg = sup; 544*9073SCathy.Zhou@Sun.COM sup->su_rxinfo.slr_rx = softmac_dedicated_rx; 545*9073SCathy.Zhou@Sun.COM sup->su_direct_rxinfo.slr_arg = sup; 546*9073SCathy.Zhou@Sun.COM sup->su_direct_rxinfo.slr_rx = softmac_dedicated_rx; 547*9073SCathy.Zhou@Sun.COM 548*9073SCathy.Zhou@Sun.COM if ((err = dld_str_open(rq, devp, sup)) != 0) { 549*9073SCathy.Zhou@Sun.COM freeb(sup->su_tx_flow_mp); 550*9073SCathy.Zhou@Sun.COM sup->su_tx_flow_mp = NULL; 551*9073SCathy.Zhou@Sun.COM goto fail; 552*9073SCathy.Zhou@Sun.COM } 553*9073SCathy.Zhou@Sun.COM 554*9073SCathy.Zhou@Sun.COM return (0); 555*9073SCathy.Zhou@Sun.COM 556*9073SCathy.Zhou@Sun.COM fail: 557*9073SCathy.Zhou@Sun.COM if (sup != NULL) 558*9073SCathy.Zhou@Sun.COM kmem_cache_free(softmac_upper_cachep, sup); 559*9073SCathy.Zhou@Sun.COM softmac_rele(softmac); 560*9073SCathy.Zhou@Sun.COM return (err); 561*9073SCathy.Zhou@Sun.COM } 562*9073SCathy.Zhou@Sun.COM 563*9073SCathy.Zhou@Sun.COM static int 564*9073SCathy.Zhou@Sun.COM softmac_drv_close(queue_t *rq) 565*9073SCathy.Zhou@Sun.COM { 566*9073SCathy.Zhou@Sun.COM softmac_upper_t *sup = dld_str_private(rq); 567*9073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac; 568*9073SCathy.Zhou@Sun.COM 569*9073SCathy.Zhou@Sun.COM ASSERT(WR(rq)->q_next == NULL); 570*9073SCathy.Zhou@Sun.COM 571*9073SCathy.Zhou@Sun.COM qprocsoff(rq); 572*9073SCathy.Zhou@Sun.COM 573*9073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_inprocess == 0); 574*9073SCathy.Zhou@Sun.COM 575*9073SCathy.Zhou@Sun.COM /* 576*9073SCathy.Zhou@Sun.COM * Wait until the pending request are processed by the worker thread. 577*9073SCathy.Zhou@Sun.COM */ 578*9073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_disp_mutex); 579*9073SCathy.Zhou@Sun.COM sup->su_closing = B_TRUE; 580*9073SCathy.Zhou@Sun.COM while (sup->su_dlpi_pending) 581*9073SCathy.Zhou@Sun.COM cv_wait(&sup->su_disp_cv, &sup->su_disp_mutex); 582*9073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_disp_mutex); 583*9073SCathy.Zhou@Sun.COM 584*9073SCathy.Zhou@Sun.COM softmac_upperstream_close(sup); 585*9073SCathy.Zhou@Sun.COM 586*9073SCathy.Zhou@Sun.COM if (sup->su_tx_flow_mp != NULL) { 587*9073SCathy.Zhou@Sun.COM freeb(sup->su_tx_flow_mp); 588*9073SCathy.Zhou@Sun.COM sup->su_tx_flow_mp = NULL; 589*9073SCathy.Zhou@Sun.COM } 590*9073SCathy.Zhou@Sun.COM 591*9073SCathy.Zhou@Sun.COM if (sup->su_active) { 592*9073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_active_mutex); 593*9073SCathy.Zhou@Sun.COM softmac->smac_nactive--; 594*9073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex); 595*9073SCathy.Zhou@Sun.COM sup->su_active = B_FALSE; 596*9073SCathy.Zhou@Sun.COM } 597*9073SCathy.Zhou@Sun.COM 598*9073SCathy.Zhou@Sun.COM sup->su_bound = B_FALSE; 599*9073SCathy.Zhou@Sun.COM sup->su_softmac = NULL; 600*9073SCathy.Zhou@Sun.COM sup->su_closing = B_FALSE; 601*9073SCathy.Zhou@Sun.COM 602*9073SCathy.Zhou@Sun.COM kmem_cache_free(softmac_upper_cachep, sup); 603*9073SCathy.Zhou@Sun.COM 604*9073SCathy.Zhou@Sun.COM softmac_rele(softmac); 605*9073SCathy.Zhou@Sun.COM return (dld_str_close(rq)); 606*9073SCathy.Zhou@Sun.COM } 607*9073SCathy.Zhou@Sun.COM 608*9073SCathy.Zhou@Sun.COM static void 609*9073SCathy.Zhou@Sun.COM softmac_drv_wput(queue_t *wq, mblk_t *mp) 610*9073SCathy.Zhou@Sun.COM { 611*9073SCathy.Zhou@Sun.COM softmac_upper_t *sup = dld_str_private(wq); 612*9073SCathy.Zhou@Sun.COM t_uscalar_t prim; 613*9073SCathy.Zhou@Sun.COM 614*9073SCathy.Zhou@Sun.COM ASSERT(wq->q_next == NULL); 615*9073SCathy.Zhou@Sun.COM 616*9073SCathy.Zhou@Sun.COM switch (DB_TYPE(mp)) { 617*9073SCathy.Zhou@Sun.COM case M_DATA: 618*9073SCathy.Zhou@Sun.COM case M_MULTIDATA: 619*9073SCathy.Zhou@Sun.COM softmac_wput_data(sup, mp); 620*9073SCathy.Zhou@Sun.COM break; 621*9073SCathy.Zhou@Sun.COM case M_PROTO: 622*9073SCathy.Zhou@Sun.COM case M_PCPROTO: 623*9073SCathy.Zhou@Sun.COM 624*9073SCathy.Zhou@Sun.COM if (MBLKL(mp) < sizeof (t_uscalar_t)) { 625*9073SCathy.Zhou@Sun.COM freemsg(mp); 626*9073SCathy.Zhou@Sun.COM return; 627*9073SCathy.Zhou@Sun.COM } 628*9073SCathy.Zhou@Sun.COM 629*9073SCathy.Zhou@Sun.COM prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; 630*9073SCathy.Zhou@Sun.COM if (prim == DL_UNITDATA_REQ) { 631*9073SCathy.Zhou@Sun.COM softmac_wput_data(sup, mp); 632*9073SCathy.Zhou@Sun.COM return; 633*9073SCathy.Zhou@Sun.COM } 634*9073SCathy.Zhou@Sun.COM 635*9073SCathy.Zhou@Sun.COM softmac_wput_nondata(sup, mp); 636*9073SCathy.Zhou@Sun.COM break; 637*9073SCathy.Zhou@Sun.COM default: 638*9073SCathy.Zhou@Sun.COM softmac_wput_nondata(sup, mp); 639*9073SCathy.Zhou@Sun.COM break; 640*9073SCathy.Zhou@Sun.COM } 641*9073SCathy.Zhou@Sun.COM } 642*9073SCathy.Zhou@Sun.COM 643*9073SCathy.Zhou@Sun.COM static void 644*9073SCathy.Zhou@Sun.COM softmac_drv_wsrv(queue_t *wq) 645*9073SCathy.Zhou@Sun.COM { 646*9073SCathy.Zhou@Sun.COM softmac_upper_t *sup = dld_str_private(wq); 647*9073SCathy.Zhou@Sun.COM 648*9073SCathy.Zhou@Sun.COM ASSERT(wq->q_next == NULL); 649*9073SCathy.Zhou@Sun.COM 650*9073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex); 651*9073SCathy.Zhou@Sun.COM if (sup->su_mode != SOFTMAC_FASTPATH) { 652*9073SCathy.Zhou@Sun.COM /* 653*9073SCathy.Zhou@Sun.COM * Bump su_tx_inprocess so that su_mode won't change. 654*9073SCathy.Zhou@Sun.COM */ 655*9073SCathy.Zhou@Sun.COM sup->su_tx_inprocess++; 656*9073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex); 657*9073SCathy.Zhou@Sun.COM dld_wsrv(wq); 658*9073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex); 659*9073SCathy.Zhou@Sun.COM if (--sup->su_tx_inprocess == 0) 660*9073SCathy.Zhou@Sun.COM cv_signal(&sup->su_cv); 661*9073SCathy.Zhou@Sun.COM } else if (sup->su_tx_busy && SOFTMAC_CANPUTNEXT(sup->su_slp->sl_wq)) { 662*9073SCathy.Zhou@Sun.COM /* 663*9073SCathy.Zhou@Sun.COM * The flow-conctol of the dedicated-lower-stream is 664*9073SCathy.Zhou@Sun.COM * relieved, relieve the flow-control of the 665*9073SCathy.Zhou@Sun.COM * upper-stream too. 666*9073SCathy.Zhou@Sun.COM */ 667*9073SCathy.Zhou@Sun.COM sup->su_tx_flow_mp = getq(wq); 668*9073SCathy.Zhou@Sun.COM sup->su_tx_busy = B_FALSE; 669*9073SCathy.Zhou@Sun.COM } 670*9073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex); 671*9073SCathy.Zhou@Sun.COM } 672