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