19073SCathy.Zhou@Sun.COM /*
29073SCathy.Zhou@Sun.COM * CDDL HEADER START
39073SCathy.Zhou@Sun.COM *
49073SCathy.Zhou@Sun.COM * The contents of this file are subject to the terms of the
59073SCathy.Zhou@Sun.COM * Common Development and Distribution License (the "License").
69073SCathy.Zhou@Sun.COM * You may not use this file except in compliance with the License.
79073SCathy.Zhou@Sun.COM *
89073SCathy.Zhou@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99073SCathy.Zhou@Sun.COM * or http://www.opensolaris.org/os/licensing.
109073SCathy.Zhou@Sun.COM * See the License for the specific language governing permissions
119073SCathy.Zhou@Sun.COM * and limitations under the License.
129073SCathy.Zhou@Sun.COM *
139073SCathy.Zhou@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149073SCathy.Zhou@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159073SCathy.Zhou@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169073SCathy.Zhou@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179073SCathy.Zhou@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189073SCathy.Zhou@Sun.COM *
199073SCathy.Zhou@Sun.COM * CDDL HEADER END
209073SCathy.Zhou@Sun.COM */
219073SCathy.Zhou@Sun.COM /*
229073SCathy.Zhou@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
239073SCathy.Zhou@Sun.COM * Use is subject to license terms.
249073SCathy.Zhou@Sun.COM */
259073SCathy.Zhou@Sun.COM
269073SCathy.Zhou@Sun.COM /*
279073SCathy.Zhou@Sun.COM * Softmac data-path switching:
289073SCathy.Zhou@Sun.COM *
299073SCathy.Zhou@Sun.COM * - Fast-path model
309073SCathy.Zhou@Sun.COM *
319073SCathy.Zhou@Sun.COM * When the softmac fast-path is used, a dedicated lower-stream
329073SCathy.Zhou@Sun.COM * will be opened over the legacy device for each IP/ARP (upper-)stream
339073SCathy.Zhou@Sun.COM * over the softMAC, and all DLPI messages (including control messages
349073SCathy.Zhou@Sun.COM * and data messages) will be exchanged between the upper-stream and
359073SCathy.Zhou@Sun.COM * the corresponding lower-stream directly. Therefore, the data
369073SCathy.Zhou@Sun.COM * demultiplexing, filtering and classification processing will be done
379073SCathy.Zhou@Sun.COM * by the lower-stream, and the GLDv3 DLS/MAC layer processing will be
389073SCathy.Zhou@Sun.COM * no longer needed.
399073SCathy.Zhou@Sun.COM *
409073SCathy.Zhou@Sun.COM * - Slow-path model
419073SCathy.Zhou@Sun.COM *
429073SCathy.Zhou@Sun.COM * Some GLDv3 features requires the GLDv3 DLS/MAC layer processing to
439073SCathy.Zhou@Sun.COM * not be bypassed to assure its function correctness. For example,
449073SCathy.Zhou@Sun.COM * softmac fast-path must be disabled to support GLDv3 VNIC functionality.
459073SCathy.Zhou@Sun.COM * In this case, a shared lower-stream will be opened over the legacy
469073SCathy.Zhou@Sun.COM * device, which is responsible for implementing the GLDv3 callbacks
479073SCathy.Zhou@Sun.COM * and passing RAW data messages between the legacy devices and the GLDv3
489073SCathy.Zhou@Sun.COM * framework.
499073SCathy.Zhou@Sun.COM *
509073SCathy.Zhou@Sun.COM * By default, the softmac fast-path mode will be used to assure the
519073SCathy.Zhou@Sun.COM * performance; MAC clients will be able to request to disable the softmac
529073SCathy.Zhou@Sun.COM * fast-path mode to support certain features, and if that succeeds,
539073SCathy.Zhou@Sun.COM * the system will fallback to the slow-path softmac data-path model.
549073SCathy.Zhou@Sun.COM *
559073SCathy.Zhou@Sun.COM *
569073SCathy.Zhou@Sun.COM * The details of the softmac data fast-path model is stated as below
579073SCathy.Zhou@Sun.COM *
589073SCathy.Zhou@Sun.COM * 1. When a stream is opened on a softMAC, the softmac module will takes
599073SCathy.Zhou@Sun.COM * over the DLPI processing on this stream;
609073SCathy.Zhou@Sun.COM *
619073SCathy.Zhou@Sun.COM * 2. For IP/ARP streams over a softMAC, softmac data fast-path will be
629073SCathy.Zhou@Sun.COM * used by default, unless fast-path is disabled by any MAC client
639073SCathy.Zhou@Sun.COM * explicitly. The softmac module first identifies an IP/ARP stream
649073SCathy.Zhou@Sun.COM * by seeing whether there is a SIOCSLIFNAME ioctl sent from upstream,
659073SCathy.Zhou@Sun.COM * if there is one, this stream is either an IP or an ARP stream
669073SCathy.Zhou@Sun.COM * and will use fast-path potentially;
679073SCathy.Zhou@Sun.COM *
689073SCathy.Zhou@Sun.COM * 3. When the softmac fast-path is used, an dedicated lower-stream will
699073SCathy.Zhou@Sun.COM * be setup for each IP/ARP stream (1-1 mapping). From that point on,
709073SCathy.Zhou@Sun.COM * all control and data messages will be exchanged between the IP/ARP
719073SCathy.Zhou@Sun.COM * upper-stream and the legacy device through this dedicated
729073SCathy.Zhou@Sun.COM * lower-stream. As a result, the DLS/MAC layer processing in GLDv3
739073SCathy.Zhou@Sun.COM * will be skipped, and this greatly improves the performance;
749073SCathy.Zhou@Sun.COM *
759073SCathy.Zhou@Sun.COM * 4. When the softmac data fast-path is disabled by a MAC client (e.g.,
769073SCathy.Zhou@Sun.COM * by a VNIC), all the IP/ARP upper streams will try to switch from
779073SCathy.Zhou@Sun.COM * the fast-path to the slow-path. The dedicated lower-stream will be
789073SCathy.Zhou@Sun.COM * destroyed, and all the control and data-messages will go through the
799073SCathy.Zhou@Sun.COM * existing GLDv3 code path and (in the end) the shared lower-stream;
809073SCathy.Zhou@Sun.COM *
819073SCathy.Zhou@Sun.COM * 5. On the other hand, when the last MAC client cancels its fast-path
829073SCathy.Zhou@Sun.COM * disable request, all the IP/ARP streams will try to switch back to
839073SCathy.Zhou@Sun.COM * the fast-path mode;
849073SCathy.Zhou@Sun.COM *
859073SCathy.Zhou@Sun.COM * Step 5 and 6 both rely on the data-path mode switching process
869073SCathy.Zhou@Sun.COM * described below:
879073SCathy.Zhou@Sun.COM *
889073SCathy.Zhou@Sun.COM * 1) To switch the softmac data-path mode (between fast-path and slow-path),
899073SCathy.Zhou@Sun.COM * softmac will first send a DL_NOTE_REPLUMB DL_NOTIFY_IND message
909073SCathy.Zhou@Sun.COM * upstream over each IP/ARP streams that needs data-path mode switching;
919073SCathy.Zhou@Sun.COM *
929073SCathy.Zhou@Sun.COM * 2) When IP receives this DL_NOTE_REPLUMB message, it will bring down
939073SCathy.Zhou@Sun.COM * all the IP interfaces on the corresponding ill (IP Lower level
949073SCathy.Zhou@Sun.COM * structure), and bring up those interfaces over again; this will in
959073SCathy.Zhou@Sun.COM * turn cause the ARP to "replumb" the interface.
969073SCathy.Zhou@Sun.COM *
979073SCathy.Zhou@Sun.COM * During the replumb process, both IP and ARP will send downstream the
989073SCathy.Zhou@Sun.COM * necessary DL_DISABMULTI_REQ and DL_UNBIND_REQ messages and cleanup
999073SCathy.Zhou@Sun.COM * the old state of the underlying softMAC, following with the necessary
1009073SCathy.Zhou@Sun.COM * DL_BIND_REQ and DL_ENABMULTI_REQ messages to setup the new state.
1019073SCathy.Zhou@Sun.COM * Between the cleanup and re-setup process, IP/ARP will also send down
1029073SCathy.Zhou@Sun.COM * a DL_NOTE_REPLUMB_DONE DL_NOTIFY_CONF messages to the softMAC to
1039073SCathy.Zhou@Sun.COM * indicate the *switching point*;
1049073SCathy.Zhou@Sun.COM *
1059073SCathy.Zhou@Sun.COM * 3) When softmac receives the DL_NOTE_REPLUMB_DONE message, it either
1069073SCathy.Zhou@Sun.COM * creates or destroys the dedicated lower-stream (depending on which
1079073SCathy.Zhou@Sun.COM * data-path mode the softMAC switches to), and change the softmac
1089073SCathy.Zhou@Sun.COM * data-path mode. From then on, softmac will process all the succeeding
1099073SCathy.Zhou@Sun.COM * control messages (including the DL_BIND_REQ and DL_ENABMULTI_REQ
1109073SCathy.Zhou@Sun.COM * messages) and data messages based on new data-path mode.
1119073SCathy.Zhou@Sun.COM */
1129073SCathy.Zhou@Sun.COM
1139073SCathy.Zhou@Sun.COM #include <sys/types.h>
1149073SCathy.Zhou@Sun.COM #include <sys/disp.h>
1159073SCathy.Zhou@Sun.COM #include <sys/callb.h>
1169073SCathy.Zhou@Sun.COM #include <sys/sysmacros.h>
1179073SCathy.Zhou@Sun.COM #include <sys/file.h>
1189073SCathy.Zhou@Sun.COM #include <sys/vlan.h>
1199073SCathy.Zhou@Sun.COM #include <sys/dld.h>
1209073SCathy.Zhou@Sun.COM #include <sys/sockio.h>
1219073SCathy.Zhou@Sun.COM #include <sys/softmac_impl.h>
1229107Sjames.d.carlson@sun.com #include <net/if.h>
1239073SCathy.Zhou@Sun.COM
1249073SCathy.Zhou@Sun.COM static kmutex_t softmac_taskq_lock;
1259073SCathy.Zhou@Sun.COM static kcondvar_t softmac_taskq_cv;
1269073SCathy.Zhou@Sun.COM static list_t softmac_taskq_list; /* List of softmac_upper_t */
1279073SCathy.Zhou@Sun.COM boolean_t softmac_taskq_quit;
1289073SCathy.Zhou@Sun.COM boolean_t softmac_taskq_done;
1299073SCathy.Zhou@Sun.COM
1309073SCathy.Zhou@Sun.COM static void softmac_taskq_dispatch();
1319073SCathy.Zhou@Sun.COM static int softmac_fastpath_setup(softmac_upper_t *);
1329073SCathy.Zhou@Sun.COM static mac_tx_cookie_t softmac_fastpath_wput_data(softmac_upper_t *, mblk_t *,
1339073SCathy.Zhou@Sun.COM uintptr_t, uint16_t);
1349073SCathy.Zhou@Sun.COM static void softmac_datapath_switch_done(softmac_upper_t *);
1359073SCathy.Zhou@Sun.COM
1369073SCathy.Zhou@Sun.COM void
softmac_fp_init()1379073SCathy.Zhou@Sun.COM softmac_fp_init()
1389073SCathy.Zhou@Sun.COM {
1399073SCathy.Zhou@Sun.COM mutex_init(&softmac_taskq_lock, NULL, MUTEX_DRIVER, NULL);
1409073SCathy.Zhou@Sun.COM cv_init(&softmac_taskq_cv, NULL, CV_DRIVER, NULL);
1419073SCathy.Zhou@Sun.COM
1429073SCathy.Zhou@Sun.COM softmac_taskq_quit = B_FALSE;
1439073SCathy.Zhou@Sun.COM softmac_taskq_done = B_FALSE;
1449073SCathy.Zhou@Sun.COM list_create(&softmac_taskq_list, sizeof (softmac_upper_t),
1459073SCathy.Zhou@Sun.COM offsetof(softmac_upper_t, su_taskq_list_node));
1469073SCathy.Zhou@Sun.COM (void) thread_create(NULL, 0, softmac_taskq_dispatch, NULL, 0,
1479073SCathy.Zhou@Sun.COM &p0, TS_RUN, minclsyspri);
1489073SCathy.Zhou@Sun.COM }
1499073SCathy.Zhou@Sun.COM
1509073SCathy.Zhou@Sun.COM void
softmac_fp_fini()1519073SCathy.Zhou@Sun.COM softmac_fp_fini()
1529073SCathy.Zhou@Sun.COM {
1539073SCathy.Zhou@Sun.COM /*
1549073SCathy.Zhou@Sun.COM * Request the softmac_taskq thread to quit and wait for it to be done.
1559073SCathy.Zhou@Sun.COM */
1569073SCathy.Zhou@Sun.COM mutex_enter(&softmac_taskq_lock);
1579073SCathy.Zhou@Sun.COM softmac_taskq_quit = B_TRUE;
1589073SCathy.Zhou@Sun.COM cv_signal(&softmac_taskq_cv);
1599073SCathy.Zhou@Sun.COM while (!softmac_taskq_done)
1609073SCathy.Zhou@Sun.COM cv_wait(&softmac_taskq_cv, &softmac_taskq_lock);
1619073SCathy.Zhou@Sun.COM mutex_exit(&softmac_taskq_lock);
1629073SCathy.Zhou@Sun.COM list_destroy(&softmac_taskq_list);
1639073SCathy.Zhou@Sun.COM
1649073SCathy.Zhou@Sun.COM mutex_destroy(&softmac_taskq_lock);
1659073SCathy.Zhou@Sun.COM cv_destroy(&softmac_taskq_cv);
1669073SCathy.Zhou@Sun.COM }
1679073SCathy.Zhou@Sun.COM
1689073SCathy.Zhou@Sun.COM static boolean_t
check_ip_above(queue_t * q)1699073SCathy.Zhou@Sun.COM check_ip_above(queue_t *q)
1709073SCathy.Zhou@Sun.COM {
1719073SCathy.Zhou@Sun.COM queue_t *next_q;
1729073SCathy.Zhou@Sun.COM boolean_t ret = B_TRUE;
1739073SCathy.Zhou@Sun.COM
1749073SCathy.Zhou@Sun.COM claimstr(q);
1759073SCathy.Zhou@Sun.COM next_q = q->q_next;
1769073SCathy.Zhou@Sun.COM if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, "ip") != 0)
1779073SCathy.Zhou@Sun.COM ret = B_FALSE;
1789073SCathy.Zhou@Sun.COM releasestr(q);
1799073SCathy.Zhou@Sun.COM return (ret);
1809073SCathy.Zhou@Sun.COM }
1819073SCathy.Zhou@Sun.COM
1829073SCathy.Zhou@Sun.COM /* ARGSUSED */
1839073SCathy.Zhou@Sun.COM static int
softmac_capab_perim(softmac_upper_t * sup,void * data,uint_t flags)1849073SCathy.Zhou@Sun.COM softmac_capab_perim(softmac_upper_t *sup, void *data, uint_t flags)
1859073SCathy.Zhou@Sun.COM {
1869073SCathy.Zhou@Sun.COM switch (flags) {
1879073SCathy.Zhou@Sun.COM case DLD_ENABLE:
1889073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex);
1899073SCathy.Zhou@Sun.COM break;
1909073SCathy.Zhou@Sun.COM case DLD_DISABLE:
1919073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex);
1929073SCathy.Zhou@Sun.COM break;
1939073SCathy.Zhou@Sun.COM case DLD_QUERY:
1949073SCathy.Zhou@Sun.COM return (MUTEX_HELD(&sup->su_mutex));
1959073SCathy.Zhou@Sun.COM }
1969073SCathy.Zhou@Sun.COM return (0);
1979073SCathy.Zhou@Sun.COM }
1989073SCathy.Zhou@Sun.COM
1999073SCathy.Zhou@Sun.COM static mac_tx_notify_handle_t
softmac_client_tx_notify(softmac_upper_t * sup,mac_tx_notify_t func,void * arg)2009738SCathy.Zhou@Sun.COM softmac_client_tx_notify(softmac_upper_t *sup, mac_tx_notify_t func, void *arg)
2019073SCathy.Zhou@Sun.COM {
2029738SCathy.Zhou@Sun.COM ASSERT(MUTEX_HELD(&sup->su_mutex));
2039738SCathy.Zhou@Sun.COM
2049738SCathy.Zhou@Sun.COM if (func != NULL) {
2059738SCathy.Zhou@Sun.COM sup->su_tx_notify_func = func;
2069738SCathy.Zhou@Sun.COM sup->su_tx_notify_arg = arg;
2079738SCathy.Zhou@Sun.COM } else {
2089738SCathy.Zhou@Sun.COM /*
2099738SCathy.Zhou@Sun.COM * Wait for all tx_notify_func call to be done.
2109738SCathy.Zhou@Sun.COM */
2119738SCathy.Zhou@Sun.COM while (sup->su_tx_inprocess != 0)
2129738SCathy.Zhou@Sun.COM cv_wait(&sup->su_cv, &sup->su_mutex);
2139738SCathy.Zhou@Sun.COM
2149738SCathy.Zhou@Sun.COM sup->su_tx_notify_func = NULL;
2159738SCathy.Zhou@Sun.COM sup->su_tx_notify_arg = NULL;
2169738SCathy.Zhou@Sun.COM }
2179738SCathy.Zhou@Sun.COM return ((mac_tx_notify_handle_t)sup);
2189738SCathy.Zhou@Sun.COM }
2199738SCathy.Zhou@Sun.COM
2209738SCathy.Zhou@Sun.COM static boolean_t
softmac_tx_is_flow_blocked(softmac_upper_t * sup,mac_tx_cookie_t cookie)2219738SCathy.Zhou@Sun.COM softmac_tx_is_flow_blocked(softmac_upper_t *sup, mac_tx_cookie_t cookie)
2229738SCathy.Zhou@Sun.COM {
2239738SCathy.Zhou@Sun.COM ASSERT(cookie == (mac_tx_cookie_t)sup);
2249738SCathy.Zhou@Sun.COM return (sup->su_tx_busy);
2259073SCathy.Zhou@Sun.COM }
2269073SCathy.Zhou@Sun.COM
2279073SCathy.Zhou@Sun.COM static int
softmac_capab_direct(softmac_upper_t * sup,void * data,uint_t flags)2289073SCathy.Zhou@Sun.COM softmac_capab_direct(softmac_upper_t *sup, void *data, uint_t flags)
2299073SCathy.Zhou@Sun.COM {
2309073SCathy.Zhou@Sun.COM dld_capab_direct_t *direct = data;
2319073SCathy.Zhou@Sun.COM softmac_lower_t *slp = sup->su_slp;
2329073SCathy.Zhou@Sun.COM
2339073SCathy.Zhou@Sun.COM ASSERT(MUTEX_HELD(&sup->su_mutex));
2349073SCathy.Zhou@Sun.COM
2359073SCathy.Zhou@Sun.COM ASSERT(sup->su_mode == SOFTMAC_FASTPATH);
2369073SCathy.Zhou@Sun.COM
2379073SCathy.Zhou@Sun.COM switch (flags) {
2389073SCathy.Zhou@Sun.COM case DLD_ENABLE:
2399073SCathy.Zhou@Sun.COM if (sup->su_direct)
2409073SCathy.Zhou@Sun.COM return (0);
2419073SCathy.Zhou@Sun.COM
2429073SCathy.Zhou@Sun.COM sup->su_direct_rxinfo.slr_rx = (softmac_rx_t)direct->di_rx_cf;
2439073SCathy.Zhou@Sun.COM sup->su_direct_rxinfo.slr_arg = direct->di_rx_ch;
2449073SCathy.Zhou@Sun.COM slp->sl_rxinfo = &sup->su_direct_rxinfo;
2459073SCathy.Zhou@Sun.COM direct->di_tx_df = (uintptr_t)softmac_fastpath_wput_data;
2469073SCathy.Zhou@Sun.COM direct->di_tx_dh = sup;
2479738SCathy.Zhou@Sun.COM direct->di_tx_fctl_df = (uintptr_t)softmac_tx_is_flow_blocked;
2489738SCathy.Zhou@Sun.COM direct->di_tx_fctl_dh = sup;
2499073SCathy.Zhou@Sun.COM direct->di_tx_cb_df = (uintptr_t)softmac_client_tx_notify;
2509738SCathy.Zhou@Sun.COM direct->di_tx_cb_dh = sup;
2519073SCathy.Zhou@Sun.COM sup->su_direct = B_TRUE;
2529073SCathy.Zhou@Sun.COM return (0);
2539073SCathy.Zhou@Sun.COM
2549073SCathy.Zhou@Sun.COM case DLD_DISABLE:
2559073SCathy.Zhou@Sun.COM if (!sup->su_direct)
2569073SCathy.Zhou@Sun.COM return (0);
2579073SCathy.Zhou@Sun.COM
2589073SCathy.Zhou@Sun.COM slp->sl_rxinfo = &sup->su_rxinfo;
2599073SCathy.Zhou@Sun.COM sup->su_direct = B_FALSE;
2609073SCathy.Zhou@Sun.COM return (0);
2619073SCathy.Zhou@Sun.COM }
2629073SCathy.Zhou@Sun.COM return (ENOTSUP);
2639073SCathy.Zhou@Sun.COM }
2649073SCathy.Zhou@Sun.COM
2659073SCathy.Zhou@Sun.COM static int
softmac_dld_capab(softmac_upper_t * sup,uint_t type,void * data,uint_t flags)2669073SCathy.Zhou@Sun.COM softmac_dld_capab(softmac_upper_t *sup, uint_t type, void *data, uint_t flags)
2679073SCathy.Zhou@Sun.COM {
2689073SCathy.Zhou@Sun.COM int err;
2699073SCathy.Zhou@Sun.COM
2709073SCathy.Zhou@Sun.COM /*
2719073SCathy.Zhou@Sun.COM * Don't enable direct callback capabilities unless the caller is
2729073SCathy.Zhou@Sun.COM * the IP client. When a module is inserted in a stream (_I_INSERT)
2739073SCathy.Zhou@Sun.COM * the stack initiates capability disable, but due to races, the
2749073SCathy.Zhou@Sun.COM * module insertion may complete before the capability disable
2759073SCathy.Zhou@Sun.COM * completes. So we limit the check to DLD_ENABLE case.
2769073SCathy.Zhou@Sun.COM */
2779073SCathy.Zhou@Sun.COM if ((flags == DLD_ENABLE && type != DLD_CAPAB_PERIM) &&
2789073SCathy.Zhou@Sun.COM !check_ip_above(sup->su_rq)) {
2799073SCathy.Zhou@Sun.COM return (ENOTSUP);
2809073SCathy.Zhou@Sun.COM }
2819073SCathy.Zhou@Sun.COM
2829073SCathy.Zhou@Sun.COM switch (type) {
2839073SCathy.Zhou@Sun.COM case DLD_CAPAB_DIRECT:
2849073SCathy.Zhou@Sun.COM err = softmac_capab_direct(sup, data, flags);
2859073SCathy.Zhou@Sun.COM break;
2869073SCathy.Zhou@Sun.COM
2879073SCathy.Zhou@Sun.COM case DLD_CAPAB_PERIM:
2889073SCathy.Zhou@Sun.COM err = softmac_capab_perim(sup, data, flags);
2899073SCathy.Zhou@Sun.COM break;
2909073SCathy.Zhou@Sun.COM
2919073SCathy.Zhou@Sun.COM default:
2929073SCathy.Zhou@Sun.COM err = ENOTSUP;
2939073SCathy.Zhou@Sun.COM break;
2949073SCathy.Zhou@Sun.COM }
2959073SCathy.Zhou@Sun.COM return (err);
2969073SCathy.Zhou@Sun.COM }
2979073SCathy.Zhou@Sun.COM
2989073SCathy.Zhou@Sun.COM static void
softmac_capability_advertise(softmac_upper_t * sup,mblk_t * mp)2999073SCathy.Zhou@Sun.COM softmac_capability_advertise(softmac_upper_t *sup, mblk_t *mp)
3009073SCathy.Zhou@Sun.COM {
3019073SCathy.Zhou@Sun.COM dl_capability_ack_t *dlap;
3029073SCathy.Zhou@Sun.COM dl_capability_sub_t *dlsp;
3039073SCathy.Zhou@Sun.COM t_uscalar_t subsize;
3049073SCathy.Zhou@Sun.COM uint8_t *ptr;
3059073SCathy.Zhou@Sun.COM queue_t *q = sup->su_wq;
3069073SCathy.Zhou@Sun.COM mblk_t *mp1;
3079073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac;
3089073SCathy.Zhou@Sun.COM boolean_t dld_capable = B_FALSE;
3099073SCathy.Zhou@Sun.COM boolean_t hcksum_capable = B_FALSE;
3109073SCathy.Zhou@Sun.COM boolean_t zcopy_capable = B_FALSE;
3119073SCathy.Zhou@Sun.COM boolean_t mdt_capable = B_FALSE;
3129073SCathy.Zhou@Sun.COM
3139073SCathy.Zhou@Sun.COM ASSERT(sup->su_mode == SOFTMAC_FASTPATH);
3149073SCathy.Zhou@Sun.COM
3159073SCathy.Zhou@Sun.COM /*
3169073SCathy.Zhou@Sun.COM * Initially assume no capabilities.
3179073SCathy.Zhou@Sun.COM */
3189073SCathy.Zhou@Sun.COM subsize = 0;
3199073SCathy.Zhou@Sun.COM
3209073SCathy.Zhou@Sun.COM /*
3219073SCathy.Zhou@Sun.COM * Direct capability negotiation interface between IP and softmac
3229073SCathy.Zhou@Sun.COM */
3239073SCathy.Zhou@Sun.COM if (check_ip_above(sup->su_rq)) {
3249073SCathy.Zhou@Sun.COM dld_capable = B_TRUE;
3259073SCathy.Zhou@Sun.COM subsize += sizeof (dl_capability_sub_t) +
3269073SCathy.Zhou@Sun.COM sizeof (dl_capab_dld_t);
3279073SCathy.Zhou@Sun.COM }
3289073SCathy.Zhou@Sun.COM
3299073SCathy.Zhou@Sun.COM /*
3309073SCathy.Zhou@Sun.COM * Check if checksum offload is supported on this MAC.
3319073SCathy.Zhou@Sun.COM */
3329073SCathy.Zhou@Sun.COM if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) {
3339073SCathy.Zhou@Sun.COM hcksum_capable = B_TRUE;
3349073SCathy.Zhou@Sun.COM subsize += sizeof (dl_capability_sub_t) +
3359073SCathy.Zhou@Sun.COM sizeof (dl_capab_hcksum_t);
3369073SCathy.Zhou@Sun.COM }
3379073SCathy.Zhou@Sun.COM
3389073SCathy.Zhou@Sun.COM /*
3399073SCathy.Zhou@Sun.COM * Check if zerocopy is supported on this interface.
3409073SCathy.Zhou@Sun.COM */
3419073SCathy.Zhou@Sun.COM if (!(softmac->smac_capab_flags & MAC_CAPAB_NO_ZCOPY)) {
3429073SCathy.Zhou@Sun.COM zcopy_capable = B_TRUE;
3439073SCathy.Zhou@Sun.COM subsize += sizeof (dl_capability_sub_t) +
3449073SCathy.Zhou@Sun.COM sizeof (dl_capab_zerocopy_t);
3459073SCathy.Zhou@Sun.COM }
3469073SCathy.Zhou@Sun.COM
3479073SCathy.Zhou@Sun.COM if (softmac->smac_mdt) {
3489073SCathy.Zhou@Sun.COM mdt_capable = B_TRUE;
3499073SCathy.Zhou@Sun.COM subsize += sizeof (dl_capability_sub_t) +
3509073SCathy.Zhou@Sun.COM sizeof (dl_capab_mdt_t);
3519073SCathy.Zhou@Sun.COM }
3529073SCathy.Zhou@Sun.COM
3539073SCathy.Zhou@Sun.COM /*
3549073SCathy.Zhou@Sun.COM * If there are no capabilities to advertise or if we
3559073SCathy.Zhou@Sun.COM * can't allocate a response, send a DL_ERROR_ACK.
3569073SCathy.Zhou@Sun.COM */
3579073SCathy.Zhou@Sun.COM if ((subsize == 0) || (mp1 = reallocb(mp,
3589073SCathy.Zhou@Sun.COM sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) {
3599073SCathy.Zhou@Sun.COM dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0);
3609073SCathy.Zhou@Sun.COM return;
3619073SCathy.Zhou@Sun.COM }
3629073SCathy.Zhou@Sun.COM
3639073SCathy.Zhou@Sun.COM mp = mp1;
3649073SCathy.Zhou@Sun.COM DB_TYPE(mp) = M_PROTO;
3659073SCathy.Zhou@Sun.COM mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize;
3669073SCathy.Zhou@Sun.COM bzero(mp->b_rptr, MBLKL(mp));
3679073SCathy.Zhou@Sun.COM dlap = (dl_capability_ack_t *)mp->b_rptr;
3689073SCathy.Zhou@Sun.COM dlap->dl_primitive = DL_CAPABILITY_ACK;
3699073SCathy.Zhou@Sun.COM dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
3709073SCathy.Zhou@Sun.COM dlap->dl_sub_length = subsize;
3719073SCathy.Zhou@Sun.COM ptr = (uint8_t *)&dlap[1];
3729073SCathy.Zhou@Sun.COM
3739073SCathy.Zhou@Sun.COM /*
3749073SCathy.Zhou@Sun.COM * IP polling interface.
3759073SCathy.Zhou@Sun.COM */
3769073SCathy.Zhou@Sun.COM if (dld_capable) {
3779073SCathy.Zhou@Sun.COM dl_capab_dld_t dld;
3789073SCathy.Zhou@Sun.COM
3799073SCathy.Zhou@Sun.COM dlsp = (dl_capability_sub_t *)ptr;
3809073SCathy.Zhou@Sun.COM dlsp->dl_cap = DL_CAPAB_DLD;
3819073SCathy.Zhou@Sun.COM dlsp->dl_length = sizeof (dl_capab_dld_t);
3829073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capability_sub_t);
3839073SCathy.Zhou@Sun.COM
3849073SCathy.Zhou@Sun.COM bzero(&dld, sizeof (dl_capab_dld_t));
3859073SCathy.Zhou@Sun.COM dld.dld_version = DLD_CURRENT_VERSION;
3869073SCathy.Zhou@Sun.COM dld.dld_capab = (uintptr_t)softmac_dld_capab;
3879073SCathy.Zhou@Sun.COM dld.dld_capab_handle = (uintptr_t)sup;
3889073SCathy.Zhou@Sun.COM
3899073SCathy.Zhou@Sun.COM dlcapabsetqid(&(dld.dld_mid), sup->su_rq);
3909073SCathy.Zhou@Sun.COM bcopy(&dld, ptr, sizeof (dl_capab_dld_t));
3919073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capab_dld_t);
3929073SCathy.Zhou@Sun.COM }
3939073SCathy.Zhou@Sun.COM
3949073SCathy.Zhou@Sun.COM /*
3959073SCathy.Zhou@Sun.COM * TCP/IP checksum offload.
3969073SCathy.Zhou@Sun.COM */
3979073SCathy.Zhou@Sun.COM if (hcksum_capable) {
3989073SCathy.Zhou@Sun.COM dl_capab_hcksum_t hcksum;
3999073SCathy.Zhou@Sun.COM
4009073SCathy.Zhou@Sun.COM dlsp = (dl_capability_sub_t *)ptr;
4019073SCathy.Zhou@Sun.COM
4029073SCathy.Zhou@Sun.COM dlsp->dl_cap = DL_CAPAB_HCKSUM;
4039073SCathy.Zhou@Sun.COM dlsp->dl_length = sizeof (dl_capab_hcksum_t);
4049073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capability_sub_t);
4059073SCathy.Zhou@Sun.COM
4069073SCathy.Zhou@Sun.COM bzero(&hcksum, sizeof (dl_capab_hcksum_t));
4079073SCathy.Zhou@Sun.COM hcksum.hcksum_version = HCKSUM_VERSION_1;
4089073SCathy.Zhou@Sun.COM hcksum.hcksum_txflags = softmac->smac_hcksum_txflags;
4099073SCathy.Zhou@Sun.COM dlcapabsetqid(&(hcksum.hcksum_mid), sup->su_rq);
4109073SCathy.Zhou@Sun.COM bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
4119073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capab_hcksum_t);
4129073SCathy.Zhou@Sun.COM }
4139073SCathy.Zhou@Sun.COM
4149073SCathy.Zhou@Sun.COM /*
4159073SCathy.Zhou@Sun.COM * Zero copy
4169073SCathy.Zhou@Sun.COM */
4179073SCathy.Zhou@Sun.COM if (zcopy_capable) {
4189073SCathy.Zhou@Sun.COM dl_capab_zerocopy_t zcopy;
4199073SCathy.Zhou@Sun.COM
4209073SCathy.Zhou@Sun.COM dlsp = (dl_capability_sub_t *)ptr;
4219073SCathy.Zhou@Sun.COM
4229073SCathy.Zhou@Sun.COM dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
4239073SCathy.Zhou@Sun.COM dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
4249073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capability_sub_t);
4259073SCathy.Zhou@Sun.COM
4269073SCathy.Zhou@Sun.COM bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
4279073SCathy.Zhou@Sun.COM zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
4289073SCathy.Zhou@Sun.COM zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
4299073SCathy.Zhou@Sun.COM dlcapabsetqid(&(zcopy.zerocopy_mid), sup->su_rq);
4309073SCathy.Zhou@Sun.COM bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
4319073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capab_zerocopy_t);
4329073SCathy.Zhou@Sun.COM }
4339073SCathy.Zhou@Sun.COM
4349073SCathy.Zhou@Sun.COM /*
4359073SCathy.Zhou@Sun.COM * MDT
4369073SCathy.Zhou@Sun.COM */
4379073SCathy.Zhou@Sun.COM if (mdt_capable) {
4389073SCathy.Zhou@Sun.COM dl_capab_mdt_t mdt;
4399073SCathy.Zhou@Sun.COM
4409073SCathy.Zhou@Sun.COM dlsp = (dl_capability_sub_t *)ptr;
4419073SCathy.Zhou@Sun.COM
4429073SCathy.Zhou@Sun.COM dlsp->dl_cap = DL_CAPAB_MDT;
4439073SCathy.Zhou@Sun.COM dlsp->dl_length = sizeof (dl_capab_mdt_t);
4449073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capability_sub_t);
4459073SCathy.Zhou@Sun.COM
4469073SCathy.Zhou@Sun.COM bzero(&mdt, sizeof (dl_capab_mdt_t));
4479073SCathy.Zhou@Sun.COM mdt.mdt_version = MDT_VERSION_2;
4489073SCathy.Zhou@Sun.COM mdt.mdt_flags = DL_CAPAB_MDT_ENABLE;
4499073SCathy.Zhou@Sun.COM mdt.mdt_hdr_head = softmac->smac_mdt_capab.mdt_hdr_head;
4509073SCathy.Zhou@Sun.COM mdt.mdt_hdr_tail = softmac->smac_mdt_capab.mdt_hdr_tail;
4519073SCathy.Zhou@Sun.COM mdt.mdt_max_pld = softmac->smac_mdt_capab.mdt_max_pld;
4529073SCathy.Zhou@Sun.COM mdt.mdt_span_limit = softmac->smac_mdt_capab.mdt_span_limit;
4539073SCathy.Zhou@Sun.COM dlcapabsetqid(&(mdt.mdt_mid), sup->su_rq);
4549073SCathy.Zhou@Sun.COM bcopy(&mdt, ptr, sizeof (dl_capab_mdt_t));
4559073SCathy.Zhou@Sun.COM ptr += sizeof (dl_capab_mdt_t);
4569073SCathy.Zhou@Sun.COM }
4579073SCathy.Zhou@Sun.COM
4589073SCathy.Zhou@Sun.COM ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
4599073SCathy.Zhou@Sun.COM qreply(q, mp);
4609073SCathy.Zhou@Sun.COM }
4619073SCathy.Zhou@Sun.COM
4629073SCathy.Zhou@Sun.COM static void
softmac_capability_req(softmac_upper_t * sup,mblk_t * mp)4639073SCathy.Zhou@Sun.COM softmac_capability_req(softmac_upper_t *sup, mblk_t *mp)
4649073SCathy.Zhou@Sun.COM {
4659073SCathy.Zhou@Sun.COM dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
4669073SCathy.Zhou@Sun.COM dl_capability_sub_t *sp;
4679073SCathy.Zhou@Sun.COM size_t size, len;
4689073SCathy.Zhou@Sun.COM offset_t off, end;
4699073SCathy.Zhou@Sun.COM t_uscalar_t dl_err;
4709073SCathy.Zhou@Sun.COM queue_t *q = sup->su_wq;
4719073SCathy.Zhou@Sun.COM
4729073SCathy.Zhou@Sun.COM ASSERT(sup->su_mode == SOFTMAC_FASTPATH);
4739073SCathy.Zhou@Sun.COM if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
4749073SCathy.Zhou@Sun.COM dl_err = DL_BADPRIM;
4759073SCathy.Zhou@Sun.COM goto failed;
4769073SCathy.Zhou@Sun.COM }
4779073SCathy.Zhou@Sun.COM
4789073SCathy.Zhou@Sun.COM if (!sup->su_bound) {
4799073SCathy.Zhou@Sun.COM dl_err = DL_OUTSTATE;
4809073SCathy.Zhou@Sun.COM goto failed;
4819073SCathy.Zhou@Sun.COM }
4829073SCathy.Zhou@Sun.COM
4839073SCathy.Zhou@Sun.COM /*
4849073SCathy.Zhou@Sun.COM * This request is overloaded. If there are no requested capabilities
4859073SCathy.Zhou@Sun.COM * then we just want to acknowledge with all the capabilities we
4869073SCathy.Zhou@Sun.COM * support. Otherwise we enable the set of capabilities requested.
4879073SCathy.Zhou@Sun.COM */
4889073SCathy.Zhou@Sun.COM if (dlp->dl_sub_length == 0) {
4899073SCathy.Zhou@Sun.COM softmac_capability_advertise(sup, mp);
4909073SCathy.Zhou@Sun.COM return;
4919073SCathy.Zhou@Sun.COM }
4929073SCathy.Zhou@Sun.COM
4939073SCathy.Zhou@Sun.COM if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
4949073SCathy.Zhou@Sun.COM dl_err = DL_BADPRIM;
4959073SCathy.Zhou@Sun.COM goto failed;
4969073SCathy.Zhou@Sun.COM }
4979073SCathy.Zhou@Sun.COM
4989073SCathy.Zhou@Sun.COM dlp->dl_primitive = DL_CAPABILITY_ACK;
4999073SCathy.Zhou@Sun.COM
5009073SCathy.Zhou@Sun.COM off = dlp->dl_sub_offset;
5019073SCathy.Zhou@Sun.COM len = dlp->dl_sub_length;
5029073SCathy.Zhou@Sun.COM
5039073SCathy.Zhou@Sun.COM /*
5049073SCathy.Zhou@Sun.COM * Walk the list of capabilities to be enabled.
5059073SCathy.Zhou@Sun.COM */
5069073SCathy.Zhou@Sun.COM for (end = off + len; off < end; ) {
5079073SCathy.Zhou@Sun.COM sp = (dl_capability_sub_t *)(mp->b_rptr + off);
5089073SCathy.Zhou@Sun.COM size = sizeof (dl_capability_sub_t) + sp->dl_length;
5099073SCathy.Zhou@Sun.COM
5109073SCathy.Zhou@Sun.COM if (off + size > end ||
5119073SCathy.Zhou@Sun.COM !IS_P2ALIGNED(off, sizeof (uint32_t))) {
5129073SCathy.Zhou@Sun.COM dl_err = DL_BADPRIM;
5139073SCathy.Zhou@Sun.COM goto failed;
5149073SCathy.Zhou@Sun.COM }
5159073SCathy.Zhou@Sun.COM
5169073SCathy.Zhou@Sun.COM switch (sp->dl_cap) {
5179073SCathy.Zhou@Sun.COM /*
5189073SCathy.Zhou@Sun.COM * TCP/IP checksum offload to hardware.
5199073SCathy.Zhou@Sun.COM */
5209073SCathy.Zhou@Sun.COM case DL_CAPAB_HCKSUM: {
5219073SCathy.Zhou@Sun.COM dl_capab_hcksum_t *hcksump;
5229073SCathy.Zhou@Sun.COM dl_capab_hcksum_t hcksum;
5239073SCathy.Zhou@Sun.COM
5249073SCathy.Zhou@Sun.COM hcksump = (dl_capab_hcksum_t *)&sp[1];
5259073SCathy.Zhou@Sun.COM /*
5269073SCathy.Zhou@Sun.COM * Copy for alignment.
5279073SCathy.Zhou@Sun.COM */
5289073SCathy.Zhou@Sun.COM bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
5299073SCathy.Zhou@Sun.COM dlcapabsetqid(&(hcksum.hcksum_mid), sup->su_rq);
5309073SCathy.Zhou@Sun.COM bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
5319073SCathy.Zhou@Sun.COM break;
5329073SCathy.Zhou@Sun.COM }
5339073SCathy.Zhou@Sun.COM
5349073SCathy.Zhou@Sun.COM default:
5359073SCathy.Zhou@Sun.COM break;
5369073SCathy.Zhou@Sun.COM }
5379073SCathy.Zhou@Sun.COM
5389073SCathy.Zhou@Sun.COM off += size;
5399073SCathy.Zhou@Sun.COM }
5409073SCathy.Zhou@Sun.COM qreply(q, mp);
5419073SCathy.Zhou@Sun.COM return;
5429073SCathy.Zhou@Sun.COM failed:
5439073SCathy.Zhou@Sun.COM dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0);
5449073SCathy.Zhou@Sun.COM }
5459073SCathy.Zhou@Sun.COM
5469073SCathy.Zhou@Sun.COM static void
softmac_bind_req(softmac_upper_t * sup,mblk_t * mp)5479073SCathy.Zhou@Sun.COM softmac_bind_req(softmac_upper_t *sup, mblk_t *mp)
5489073SCathy.Zhou@Sun.COM {
5499073SCathy.Zhou@Sun.COM softmac_lower_t *slp = sup->su_slp;
5509073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac;
5519073SCathy.Zhou@Sun.COM mblk_t *ackmp, *mp1;
5529073SCathy.Zhou@Sun.COM int err;
5539073SCathy.Zhou@Sun.COM
5549073SCathy.Zhou@Sun.COM if (MBLKL(mp) < DL_BIND_REQ_SIZE) {
5559073SCathy.Zhou@Sun.COM freemsg(mp);
5569073SCathy.Zhou@Sun.COM return;
5579073SCathy.Zhou@Sun.COM }
5589073SCathy.Zhou@Sun.COM
5599073SCathy.Zhou@Sun.COM /*
5609073SCathy.Zhou@Sun.COM * Allocate ackmp incase the underlying driver does not ack timely.
5619073SCathy.Zhou@Sun.COM */
5629073SCathy.Zhou@Sun.COM if ((mp1 = allocb(sizeof (dl_error_ack_t), BPRI_HI)) == NULL) {
5639073SCathy.Zhou@Sun.COM dlerrorack(sup->su_wq, mp, DL_BIND_REQ, DL_SYSERR, ENOMEM);
5649073SCathy.Zhou@Sun.COM return;
5659073SCathy.Zhou@Sun.COM }
5669073SCathy.Zhou@Sun.COM
5679073SCathy.Zhou@Sun.COM err = softmac_output(slp, mp, DL_BIND_REQ, DL_BIND_ACK, &ackmp);
5689073SCathy.Zhou@Sun.COM if (ackmp != NULL) {
5699073SCathy.Zhou@Sun.COM freemsg(mp1);
5709073SCathy.Zhou@Sun.COM } else {
5719073SCathy.Zhou@Sun.COM /*
5729073SCathy.Zhou@Sun.COM * The driver does not ack timely.
5739073SCathy.Zhou@Sun.COM */
5749073SCathy.Zhou@Sun.COM ASSERT(err == ENOMSG);
5759073SCathy.Zhou@Sun.COM ackmp = mp1;
5769073SCathy.Zhou@Sun.COM }
5779073SCathy.Zhou@Sun.COM if (err != 0)
5789073SCathy.Zhou@Sun.COM goto failed;
5799073SCathy.Zhou@Sun.COM
5809073SCathy.Zhou@Sun.COM /*
5819073SCathy.Zhou@Sun.COM * Enable capabilities the underlying driver claims to support.
5829073SCathy.Zhou@Sun.COM */
5839073SCathy.Zhou@Sun.COM if ((err = softmac_capab_enable(slp)) != 0)
5849073SCathy.Zhou@Sun.COM goto failed;
5859073SCathy.Zhou@Sun.COM
5869073SCathy.Zhou@Sun.COM /*
5879073SCathy.Zhou@Sun.COM * Check whether this softmac is already marked as exclusively used,
5889073SCathy.Zhou@Sun.COM * e.g., an aggregation is created over it. Fail the BIND_REQ if so.
5899073SCathy.Zhou@Sun.COM */
5909073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_active_mutex);
5919073SCathy.Zhou@Sun.COM if (softmac->smac_active) {
5929073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex);
5939073SCathy.Zhou@Sun.COM err = EBUSY;
5949073SCathy.Zhou@Sun.COM goto failed;
5959073SCathy.Zhou@Sun.COM }
5969073SCathy.Zhou@Sun.COM softmac->smac_nactive++;
5979073SCathy.Zhou@Sun.COM sup->su_active = B_TRUE;
5989073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex);
5999073SCathy.Zhou@Sun.COM sup->su_bound = B_TRUE;
6009073SCathy.Zhou@Sun.COM
6019073SCathy.Zhou@Sun.COM qreply(sup->su_wq, ackmp);
6029073SCathy.Zhou@Sun.COM return;
6039073SCathy.Zhou@Sun.COM failed:
6049073SCathy.Zhou@Sun.COM if (err != 0) {
6059073SCathy.Zhou@Sun.COM dlerrorack(sup->su_wq, ackmp, DL_BIND_REQ, DL_SYSERR, err);
6069073SCathy.Zhou@Sun.COM return;
6079073SCathy.Zhou@Sun.COM }
6089073SCathy.Zhou@Sun.COM }
6099073SCathy.Zhou@Sun.COM
6109073SCathy.Zhou@Sun.COM static void
softmac_unbind_req(softmac_upper_t * sup,mblk_t * mp)6119073SCathy.Zhou@Sun.COM softmac_unbind_req(softmac_upper_t *sup, mblk_t *mp)
6129073SCathy.Zhou@Sun.COM {
6139073SCathy.Zhou@Sun.COM softmac_lower_t *slp = sup->su_slp;
6149073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac;
6159073SCathy.Zhou@Sun.COM mblk_t *ackmp, *mp1;
6169073SCathy.Zhou@Sun.COM int err;
6179073SCathy.Zhou@Sun.COM
6189073SCathy.Zhou@Sun.COM if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) {
6199073SCathy.Zhou@Sun.COM freemsg(mp);
6209073SCathy.Zhou@Sun.COM return;
6219073SCathy.Zhou@Sun.COM }
6229073SCathy.Zhou@Sun.COM
6239073SCathy.Zhou@Sun.COM if (!sup->su_bound) {
6249073SCathy.Zhou@Sun.COM dlerrorack(sup->su_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
6259073SCathy.Zhou@Sun.COM return;
6269073SCathy.Zhou@Sun.COM }
6279073SCathy.Zhou@Sun.COM
6289073SCathy.Zhou@Sun.COM /*
6299073SCathy.Zhou@Sun.COM * Allocate ackmp incase the underlying driver does not ack timely.
6309073SCathy.Zhou@Sun.COM */
6319073SCathy.Zhou@Sun.COM if ((mp1 = allocb(sizeof (dl_error_ack_t), BPRI_HI)) == NULL) {
6329073SCathy.Zhou@Sun.COM dlerrorack(sup->su_wq, mp, DL_UNBIND_REQ, DL_SYSERR, ENOMEM);
6339073SCathy.Zhou@Sun.COM return;
6349073SCathy.Zhou@Sun.COM }
6359073SCathy.Zhou@Sun.COM
6369073SCathy.Zhou@Sun.COM err = softmac_output(slp, mp, DL_UNBIND_REQ, DL_OK_ACK, &ackmp);
6379073SCathy.Zhou@Sun.COM if (ackmp != NULL) {
6389073SCathy.Zhou@Sun.COM freemsg(mp1);
6399073SCathy.Zhou@Sun.COM } else {
6409073SCathy.Zhou@Sun.COM /*
6419073SCathy.Zhou@Sun.COM * The driver does not ack timely.
6429073SCathy.Zhou@Sun.COM */
6439073SCathy.Zhou@Sun.COM ASSERT(err == ENOMSG);
6449073SCathy.Zhou@Sun.COM ackmp = mp1;
6459073SCathy.Zhou@Sun.COM }
6469073SCathy.Zhou@Sun.COM if (err != 0) {
6479073SCathy.Zhou@Sun.COM dlerrorack(sup->su_wq, ackmp, DL_UNBIND_REQ, DL_SYSERR, err);
6489073SCathy.Zhou@Sun.COM return;
6499073SCathy.Zhou@Sun.COM }
6509073SCathy.Zhou@Sun.COM
6519073SCathy.Zhou@Sun.COM sup->su_bound = B_FALSE;
6529073SCathy.Zhou@Sun.COM
6539073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_active_mutex);
6549073SCathy.Zhou@Sun.COM if (sup->su_active) {
6559073SCathy.Zhou@Sun.COM ASSERT(!softmac->smac_active);
6569073SCathy.Zhou@Sun.COM softmac->smac_nactive--;
6579073SCathy.Zhou@Sun.COM sup->su_active = B_FALSE;
6589073SCathy.Zhou@Sun.COM }
6599073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex);
6609073SCathy.Zhou@Sun.COM
6619073SCathy.Zhou@Sun.COM done:
6629073SCathy.Zhou@Sun.COM qreply(sup->su_wq, ackmp);
6639073SCathy.Zhou@Sun.COM }
6649073SCathy.Zhou@Sun.COM
6659073SCathy.Zhou@Sun.COM /*
6669073SCathy.Zhou@Sun.COM * Process the non-data mblk.
6679073SCathy.Zhou@Sun.COM */
6689073SCathy.Zhou@Sun.COM static void
softmac_wput_single_nondata(softmac_upper_t * sup,mblk_t * mp)6699073SCathy.Zhou@Sun.COM softmac_wput_single_nondata(softmac_upper_t *sup, mblk_t *mp)
6709073SCathy.Zhou@Sun.COM {
6719073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac;
6729073SCathy.Zhou@Sun.COM softmac_lower_t *slp = sup->su_slp;
6739073SCathy.Zhou@Sun.COM unsigned char dbtype;
6749073SCathy.Zhou@Sun.COM t_uscalar_t prim;
6759073SCathy.Zhou@Sun.COM
6769073SCathy.Zhou@Sun.COM dbtype = DB_TYPE(mp);
677*11042SErik.Nordmark@Sun.COM sup->su_is_arp = 0;
6789073SCathy.Zhou@Sun.COM switch (dbtype) {
679*11042SErik.Nordmark@Sun.COM case M_CTL:
680*11042SErik.Nordmark@Sun.COM sup->su_is_arp = 1;
681*11042SErik.Nordmark@Sun.COM /* FALLTHROUGH */
682*11042SErik.Nordmark@Sun.COM case M_IOCTL: {
6839073SCathy.Zhou@Sun.COM uint32_t expected_mode;
6849073SCathy.Zhou@Sun.COM
6859073SCathy.Zhou@Sun.COM if (((struct iocblk *)(mp->b_rptr))->ioc_cmd != SIOCSLIFNAME)
6869073SCathy.Zhou@Sun.COM break;
6879073SCathy.Zhou@Sun.COM
6889073SCathy.Zhou@Sun.COM /*
6899073SCathy.Zhou@Sun.COM * Nak the M_IOCTL based on the STREAMS specification.
6909073SCathy.Zhou@Sun.COM */
6919073SCathy.Zhou@Sun.COM if (dbtype == M_IOCTL)
6929073SCathy.Zhou@Sun.COM miocnak(sup->su_wq, mp, 0, EINVAL);
6939682SCathy.Zhou@Sun.COM else
6949682SCathy.Zhou@Sun.COM freemsg(mp);
6959073SCathy.Zhou@Sun.COM
6969073SCathy.Zhou@Sun.COM /*
6979073SCathy.Zhou@Sun.COM * This stream is either IP or ARP. See whether
6989073SCathy.Zhou@Sun.COM * we need to setup a dedicated-lower-stream for it.
6999073SCathy.Zhou@Sun.COM */
7009073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_fp_mutex);
7019073SCathy.Zhou@Sun.COM
7029073SCathy.Zhou@Sun.COM expected_mode = DATAPATH_MODE(softmac);
7039073SCathy.Zhou@Sun.COM if (expected_mode == SOFTMAC_SLOWPATH)
7049073SCathy.Zhou@Sun.COM sup->su_mode = SOFTMAC_SLOWPATH;
7059073SCathy.Zhou@Sun.COM list_insert_head(&softmac->smac_sup_list, sup);
7069073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
7079073SCathy.Zhou@Sun.COM
7089073SCathy.Zhou@Sun.COM /*
7099073SCathy.Zhou@Sun.COM * Setup the fast-path dedicated lower stream if fast-path
7109073SCathy.Zhou@Sun.COM * is expected. Note that no lock is held here, and if
7119073SCathy.Zhou@Sun.COM * smac_expected_mode is changed from SOFTMAC_FASTPATH to
7129073SCathy.Zhou@Sun.COM * SOFTMAC_SLOWPATH, the DL_NOTE_REPLUMB message used for
7139073SCathy.Zhou@Sun.COM * data-path switching would already be queued and will
7149073SCathy.Zhou@Sun.COM * be processed by softmac_wput_single_nondata() later.
7159073SCathy.Zhou@Sun.COM */
7169073SCathy.Zhou@Sun.COM if (expected_mode == SOFTMAC_FASTPATH)
7179073SCathy.Zhou@Sun.COM (void) softmac_fastpath_setup(sup);
7189073SCathy.Zhou@Sun.COM return;
7199073SCathy.Zhou@Sun.COM }
7209073SCathy.Zhou@Sun.COM case M_PROTO:
7219073SCathy.Zhou@Sun.COM case M_PCPROTO:
7229073SCathy.Zhou@Sun.COM if (MBLKL(mp) < sizeof (t_uscalar_t)) {
7239073SCathy.Zhou@Sun.COM freemsg(mp);
7249073SCathy.Zhou@Sun.COM return;
7259073SCathy.Zhou@Sun.COM }
7269073SCathy.Zhou@Sun.COM prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
7279073SCathy.Zhou@Sun.COM switch (prim) {
7289073SCathy.Zhou@Sun.COM case DL_NOTIFY_IND:
7299073SCathy.Zhou@Sun.COM if (MBLKL(mp) < sizeof (dl_notify_ind_t) ||
7309073SCathy.Zhou@Sun.COM ((dl_notify_ind_t *)mp->b_rptr)->dl_notification !=
7319073SCathy.Zhou@Sun.COM DL_NOTE_REPLUMB) {
7329073SCathy.Zhou@Sun.COM freemsg(mp);
7339073SCathy.Zhou@Sun.COM return;
7349073SCathy.Zhou@Sun.COM }
7359073SCathy.Zhou@Sun.COM /*
7369073SCathy.Zhou@Sun.COM * This DL_NOTE_REPLUMB message is initiated
7379073SCathy.Zhou@Sun.COM * and queued by the softmac itself, when the
7389073SCathy.Zhou@Sun.COM * sup is trying to switching its datapath mode
7399073SCathy.Zhou@Sun.COM * between SOFTMAC_SLOWPATH and SOFTMAC_FASTPATH.
7409073SCathy.Zhou@Sun.COM * Send this message upstream.
7419073SCathy.Zhou@Sun.COM */
7429073SCathy.Zhou@Sun.COM qreply(sup->su_wq, mp);
7439073SCathy.Zhou@Sun.COM return;
7449073SCathy.Zhou@Sun.COM case DL_NOTIFY_CONF:
7459073SCathy.Zhou@Sun.COM if (MBLKL(mp) < sizeof (dl_notify_conf_t) ||
7469073SCathy.Zhou@Sun.COM ((dl_notify_conf_t *)mp->b_rptr)->dl_notification !=
7479073SCathy.Zhou@Sun.COM DL_NOTE_REPLUMB_DONE) {
7489073SCathy.Zhou@Sun.COM freemsg(mp);
7499073SCathy.Zhou@Sun.COM return;
7509073SCathy.Zhou@Sun.COM }
7519073SCathy.Zhou@Sun.COM /*
7529073SCathy.Zhou@Sun.COM * This is an indication from IP/ARP that the
7539073SCathy.Zhou@Sun.COM * fastpath->slowpath switch is done.
7549073SCathy.Zhou@Sun.COM */
7559073SCathy.Zhou@Sun.COM freemsg(mp);
7569073SCathy.Zhou@Sun.COM softmac_datapath_switch_done(sup);
7579073SCathy.Zhou@Sun.COM return;
7589073SCathy.Zhou@Sun.COM }
7599073SCathy.Zhou@Sun.COM break;
7609073SCathy.Zhou@Sun.COM }
7619073SCathy.Zhou@Sun.COM
7629073SCathy.Zhou@Sun.COM /*
7639073SCathy.Zhou@Sun.COM * No need to hold lock to check su_mode, since su_mode updating only
7649073SCathy.Zhou@Sun.COM * operation is is serialized by softmac_wput_nondata_task().
7659073SCathy.Zhou@Sun.COM */
7669073SCathy.Zhou@Sun.COM if (sup->su_mode != SOFTMAC_FASTPATH) {
7679073SCathy.Zhou@Sun.COM dld_wput(sup->su_wq, mp);
7689073SCathy.Zhou@Sun.COM return;
7699073SCathy.Zhou@Sun.COM }
7709073SCathy.Zhou@Sun.COM
7719073SCathy.Zhou@Sun.COM /*
7729073SCathy.Zhou@Sun.COM * Fastpath non-data message processing. Most of non-data messages
7739073SCathy.Zhou@Sun.COM * can be directly passed down to the dedicated-lower-stream, aside
7749073SCathy.Zhou@Sun.COM * from the following M_PROTO/M_PCPROTO messages.
7759073SCathy.Zhou@Sun.COM */
7769073SCathy.Zhou@Sun.COM switch (dbtype) {
7779073SCathy.Zhou@Sun.COM case M_PROTO:
7789073SCathy.Zhou@Sun.COM case M_PCPROTO:
7799073SCathy.Zhou@Sun.COM switch (prim) {
7809073SCathy.Zhou@Sun.COM case DL_BIND_REQ:
7819073SCathy.Zhou@Sun.COM softmac_bind_req(sup, mp);
7829073SCathy.Zhou@Sun.COM break;
7839073SCathy.Zhou@Sun.COM case DL_UNBIND_REQ:
7849073SCathy.Zhou@Sun.COM softmac_unbind_req(sup, mp);
7859073SCathy.Zhou@Sun.COM break;
7869073SCathy.Zhou@Sun.COM case DL_CAPABILITY_REQ:
7879073SCathy.Zhou@Sun.COM softmac_capability_req(sup, mp);
7889073SCathy.Zhou@Sun.COM break;
7899073SCathy.Zhou@Sun.COM default:
7909073SCathy.Zhou@Sun.COM putnext(slp->sl_wq, mp);
7919073SCathy.Zhou@Sun.COM break;
7929073SCathy.Zhou@Sun.COM }
7939073SCathy.Zhou@Sun.COM break;
7949073SCathy.Zhou@Sun.COM default:
7959073SCathy.Zhou@Sun.COM putnext(slp->sl_wq, mp);
7969073SCathy.Zhou@Sun.COM break;
7979073SCathy.Zhou@Sun.COM }
7989073SCathy.Zhou@Sun.COM }
7999073SCathy.Zhou@Sun.COM
8009073SCathy.Zhou@Sun.COM /*
8019073SCathy.Zhou@Sun.COM * The worker thread which processes non-data messages. Note we only process
8029073SCathy.Zhou@Sun.COM * one message at one time in order to be able to "flush" the queued message
8039073SCathy.Zhou@Sun.COM * and serialize the processing.
8049073SCathy.Zhou@Sun.COM */
8059073SCathy.Zhou@Sun.COM static void
softmac_wput_nondata_task(void * arg)8069073SCathy.Zhou@Sun.COM softmac_wput_nondata_task(void *arg)
8079073SCathy.Zhou@Sun.COM {
8089073SCathy.Zhou@Sun.COM softmac_upper_t *sup = arg;
8099073SCathy.Zhou@Sun.COM mblk_t *mp;
8109073SCathy.Zhou@Sun.COM
8119073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_disp_mutex);
8129073SCathy.Zhou@Sun.COM
8139073SCathy.Zhou@Sun.COM while (sup->su_pending_head != NULL) {
8149073SCathy.Zhou@Sun.COM if (sup->su_closing)
8159073SCathy.Zhou@Sun.COM break;
8169073SCathy.Zhou@Sun.COM
8179073SCathy.Zhou@Sun.COM SOFTMAC_DQ_PENDING(sup, &mp);
8189073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_disp_mutex);
8199073SCathy.Zhou@Sun.COM softmac_wput_single_nondata(sup, mp);
8209073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_disp_mutex);
8219073SCathy.Zhou@Sun.COM }
8229073SCathy.Zhou@Sun.COM
8239073SCathy.Zhou@Sun.COM /*
8249073SCathy.Zhou@Sun.COM * If the stream is closing, flush all queued messages and inform
8259073SCathy.Zhou@Sun.COM * the stream to be closed.
8269073SCathy.Zhou@Sun.COM */
8279073SCathy.Zhou@Sun.COM freemsgchain(sup->su_pending_head);
8289073SCathy.Zhou@Sun.COM sup->su_pending_head = sup->su_pending_tail = NULL;
8299073SCathy.Zhou@Sun.COM sup->su_dlpi_pending = B_FALSE;
8309073SCathy.Zhou@Sun.COM cv_signal(&sup->su_disp_cv);
8319073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_disp_mutex);
8329073SCathy.Zhou@Sun.COM }
8339073SCathy.Zhou@Sun.COM
8349073SCathy.Zhou@Sun.COM /*
8359073SCathy.Zhou@Sun.COM * Kernel thread to handle taskq dispatch failures in softmac_wput_nondata().
8369073SCathy.Zhou@Sun.COM * This thread is started when the softmac module is first loaded.
8379073SCathy.Zhou@Sun.COM */
8389073SCathy.Zhou@Sun.COM static void
softmac_taskq_dispatch(void)8399073SCathy.Zhou@Sun.COM softmac_taskq_dispatch(void)
8409073SCathy.Zhou@Sun.COM {
8419073SCathy.Zhou@Sun.COM callb_cpr_t cprinfo;
8429073SCathy.Zhou@Sun.COM softmac_upper_t *sup;
8439073SCathy.Zhou@Sun.COM
8449073SCathy.Zhou@Sun.COM CALLB_CPR_INIT(&cprinfo, &softmac_taskq_lock, callb_generic_cpr,
8459073SCathy.Zhou@Sun.COM "softmac_taskq_dispatch");
8469073SCathy.Zhou@Sun.COM mutex_enter(&softmac_taskq_lock);
8479073SCathy.Zhou@Sun.COM
8489073SCathy.Zhou@Sun.COM while (!softmac_taskq_quit) {
8499073SCathy.Zhou@Sun.COM sup = list_head(&softmac_taskq_list);
8509073SCathy.Zhou@Sun.COM while (sup != NULL) {
8519073SCathy.Zhou@Sun.COM list_remove(&softmac_taskq_list, sup);
8529073SCathy.Zhou@Sun.COM sup->su_taskq_scheduled = B_FALSE;
8539073SCathy.Zhou@Sun.COM mutex_exit(&softmac_taskq_lock);
8549073SCathy.Zhou@Sun.COM VERIFY(taskq_dispatch(system_taskq,
8559073SCathy.Zhou@Sun.COM softmac_wput_nondata_task, sup, TQ_SLEEP) != NULL);
8569073SCathy.Zhou@Sun.COM mutex_enter(&softmac_taskq_lock);
8579073SCathy.Zhou@Sun.COM sup = list_head(&softmac_taskq_list);
8589073SCathy.Zhou@Sun.COM }
8599073SCathy.Zhou@Sun.COM
8609073SCathy.Zhou@Sun.COM CALLB_CPR_SAFE_BEGIN(&cprinfo);
8619073SCathy.Zhou@Sun.COM cv_wait(&softmac_taskq_cv, &softmac_taskq_lock);
8629073SCathy.Zhou@Sun.COM CALLB_CPR_SAFE_END(&cprinfo, &softmac_taskq_lock);
8639073SCathy.Zhou@Sun.COM }
8649073SCathy.Zhou@Sun.COM
8659073SCathy.Zhou@Sun.COM softmac_taskq_done = B_TRUE;
8669073SCathy.Zhou@Sun.COM cv_signal(&softmac_taskq_cv);
8679073SCathy.Zhou@Sun.COM CALLB_CPR_EXIT(&cprinfo);
8689073SCathy.Zhou@Sun.COM thread_exit();
8699073SCathy.Zhou@Sun.COM }
8709073SCathy.Zhou@Sun.COM
8719073SCathy.Zhou@Sun.COM void
softmac_wput_nondata(softmac_upper_t * sup,mblk_t * mp)8729073SCathy.Zhou@Sun.COM softmac_wput_nondata(softmac_upper_t *sup, mblk_t *mp)
8739073SCathy.Zhou@Sun.COM {
8749073SCathy.Zhou@Sun.COM /*
8759073SCathy.Zhou@Sun.COM * The processing of the message might block. Enqueue the
8769073SCathy.Zhou@Sun.COM * message for later processing.
8779073SCathy.Zhou@Sun.COM */
8789073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_disp_mutex);
8799073SCathy.Zhou@Sun.COM
8809073SCathy.Zhou@Sun.COM if (sup->su_closing) {
8819073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_disp_mutex);
8829073SCathy.Zhou@Sun.COM freemsg(mp);
8839073SCathy.Zhou@Sun.COM return;
8849073SCathy.Zhou@Sun.COM }
8859073SCathy.Zhou@Sun.COM
8869073SCathy.Zhou@Sun.COM SOFTMAC_EQ_PENDING(sup, mp);
8879073SCathy.Zhou@Sun.COM
8889073SCathy.Zhou@Sun.COM if (sup->su_dlpi_pending) {
8899073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_disp_mutex);
8909073SCathy.Zhou@Sun.COM return;
8919073SCathy.Zhou@Sun.COM }
8929073SCathy.Zhou@Sun.COM sup->su_dlpi_pending = B_TRUE;
8939073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_disp_mutex);
8949073SCathy.Zhou@Sun.COM
8959073SCathy.Zhou@Sun.COM if (taskq_dispatch(system_taskq, softmac_wput_nondata_task,
8969073SCathy.Zhou@Sun.COM sup, TQ_NOSLEEP) != NULL) {
8979073SCathy.Zhou@Sun.COM return;
8989073SCathy.Zhou@Sun.COM }
8999073SCathy.Zhou@Sun.COM
9009073SCathy.Zhou@Sun.COM mutex_enter(&softmac_taskq_lock);
9019073SCathy.Zhou@Sun.COM if (!sup->su_taskq_scheduled) {
9029073SCathy.Zhou@Sun.COM list_insert_tail(&softmac_taskq_list, sup);
9039073SCathy.Zhou@Sun.COM cv_signal(&softmac_taskq_cv);
9049073SCathy.Zhou@Sun.COM }
9059073SCathy.Zhou@Sun.COM sup->su_taskq_scheduled = B_TRUE;
9069073SCathy.Zhou@Sun.COM mutex_exit(&softmac_taskq_lock);
9079073SCathy.Zhou@Sun.COM }
9089073SCathy.Zhou@Sun.COM
9099073SCathy.Zhou@Sun.COM /*
9109073SCathy.Zhou@Sun.COM * Setup the dedicated-lower-stream (fast-path) for the IP/ARP upperstream.
9119073SCathy.Zhou@Sun.COM */
9129073SCathy.Zhou@Sun.COM static int
softmac_fastpath_setup(softmac_upper_t * sup)9139073SCathy.Zhou@Sun.COM softmac_fastpath_setup(softmac_upper_t *sup)
9149073SCathy.Zhou@Sun.COM {
9159073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac;
9169073SCathy.Zhou@Sun.COM softmac_lower_t *slp;
9179073SCathy.Zhou@Sun.COM int err;
9189073SCathy.Zhou@Sun.COM
9199073SCathy.Zhou@Sun.COM err = softmac_lower_setup(softmac, sup, &slp);
9209073SCathy.Zhou@Sun.COM
9219073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex);
9229073SCathy.Zhou@Sun.COM /*
9239073SCathy.Zhou@Sun.COM * Wait for all data messages to be processed so that we can change
9249073SCathy.Zhou@Sun.COM * the su_mode.
9259073SCathy.Zhou@Sun.COM */
9269073SCathy.Zhou@Sun.COM while (sup->su_tx_inprocess != 0)
9279073SCathy.Zhou@Sun.COM cv_wait(&sup->su_cv, &sup->su_mutex);
9289073SCathy.Zhou@Sun.COM
9299073SCathy.Zhou@Sun.COM ASSERT(sup->su_mode != SOFTMAC_FASTPATH);
9309073SCathy.Zhou@Sun.COM ASSERT(sup->su_slp == NULL);
9319073SCathy.Zhou@Sun.COM if (err != 0) {
9329073SCathy.Zhou@Sun.COM sup->su_mode = SOFTMAC_SLOWPATH;
9339073SCathy.Zhou@Sun.COM } else {
9349073SCathy.Zhou@Sun.COM sup->su_slp = slp;
9359073SCathy.Zhou@Sun.COM sup->su_mode = SOFTMAC_FASTPATH;
9369073SCathy.Zhou@Sun.COM }
9379073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex);
9389073SCathy.Zhou@Sun.COM return (err);
9399073SCathy.Zhou@Sun.COM }
9409073SCathy.Zhou@Sun.COM
9419073SCathy.Zhou@Sun.COM /*
9429073SCathy.Zhou@Sun.COM * Tear down the dedicated-lower-stream (fast-path) for the IP/ARP upperstream.
9439073SCathy.Zhou@Sun.COM */
9449073SCathy.Zhou@Sun.COM static void
softmac_fastpath_tear(softmac_upper_t * sup)9459073SCathy.Zhou@Sun.COM softmac_fastpath_tear(softmac_upper_t *sup)
9469073SCathy.Zhou@Sun.COM {
9479073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex);
9489073SCathy.Zhou@Sun.COM /*
9499073SCathy.Zhou@Sun.COM * Wait for all data messages in the dedicated-lower-stream
9509073SCathy.Zhou@Sun.COM * to be processed.
9519073SCathy.Zhou@Sun.COM */
9529073SCathy.Zhou@Sun.COM while (sup->su_tx_inprocess != 0)
9539073SCathy.Zhou@Sun.COM cv_wait(&sup->su_cv, &sup->su_mutex);
9549073SCathy.Zhou@Sun.COM
9559738SCathy.Zhou@Sun.COM /*
9569738SCathy.Zhou@Sun.COM * Note that this function is called either when the stream is closed,
9579738SCathy.Zhou@Sun.COM * or the stream is unbound (fastpath-slowpath-switch). Therefore,
9589738SCathy.Zhou@Sun.COM * No need to call the tx_notify callback.
9599738SCathy.Zhou@Sun.COM */
9609738SCathy.Zhou@Sun.COM sup->su_tx_notify_func = NULL;
9619738SCathy.Zhou@Sun.COM sup->su_tx_notify_arg = NULL;
9629073SCathy.Zhou@Sun.COM if (sup->su_tx_busy) {
9639073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_flow_mp == NULL);
9649738SCathy.Zhou@Sun.COM VERIFY((sup->su_tx_flow_mp = getq(sup->su_wq)) != NULL);
9659073SCathy.Zhou@Sun.COM sup->su_tx_busy = B_FALSE;
9669073SCathy.Zhou@Sun.COM }
9679073SCathy.Zhou@Sun.COM
9689073SCathy.Zhou@Sun.COM sup->su_mode = SOFTMAC_SLOWPATH;
9699073SCathy.Zhou@Sun.COM
9709073SCathy.Zhou@Sun.COM /*
9719073SCathy.Zhou@Sun.COM * Destroy the dedicated-lower-stream. Note that slp is destroyed
9729073SCathy.Zhou@Sun.COM * when lh is closed.
9739073SCathy.Zhou@Sun.COM */
9749073SCathy.Zhou@Sun.COM (void) ldi_close(sup->su_slp->sl_lh, FREAD|FWRITE, kcred);
9759073SCathy.Zhou@Sun.COM sup->su_slp = NULL;
9769073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex);
9779073SCathy.Zhou@Sun.COM }
9789073SCathy.Zhou@Sun.COM
9799073SCathy.Zhou@Sun.COM void
softmac_wput_data(softmac_upper_t * sup,mblk_t * mp)9809073SCathy.Zhou@Sun.COM softmac_wput_data(softmac_upper_t *sup, mblk_t *mp)
9819073SCathy.Zhou@Sun.COM {
9829073SCathy.Zhou@Sun.COM /*
9839073SCathy.Zhou@Sun.COM * No lock is required to access the su_mode field since the data
9849073SCathy.Zhou@Sun.COM * traffic is quiesce by IP when the data-path mode is in the
9859073SCathy.Zhou@Sun.COM * process of switching.
9869073SCathy.Zhou@Sun.COM */
9879073SCathy.Zhou@Sun.COM if (sup->su_mode != SOFTMAC_FASTPATH)
9889073SCathy.Zhou@Sun.COM dld_wput(sup->su_wq, mp);
9899073SCathy.Zhou@Sun.COM else
9909073SCathy.Zhou@Sun.COM (void) softmac_fastpath_wput_data(sup, mp, NULL, 0);
9919073SCathy.Zhou@Sun.COM }
9929073SCathy.Zhou@Sun.COM
9939073SCathy.Zhou@Sun.COM /*ARGSUSED*/
9949073SCathy.Zhou@Sun.COM static mac_tx_cookie_t
softmac_fastpath_wput_data(softmac_upper_t * sup,mblk_t * mp,uintptr_t f_hint,uint16_t flag)9959073SCathy.Zhou@Sun.COM softmac_fastpath_wput_data(softmac_upper_t *sup, mblk_t *mp, uintptr_t f_hint,
9969073SCathy.Zhou@Sun.COM uint16_t flag)
9979073SCathy.Zhou@Sun.COM {
9989073SCathy.Zhou@Sun.COM queue_t *wq = sup->su_slp->sl_wq;
9999073SCathy.Zhou@Sun.COM
10009073SCathy.Zhou@Sun.COM /*
10019073SCathy.Zhou@Sun.COM * This function is called from IP, only the MAC_DROP_ON_NO_DESC
10029073SCathy.Zhou@Sun.COM * flag can be specified.
10039073SCathy.Zhou@Sun.COM */
10049073SCathy.Zhou@Sun.COM ASSERT((flag & ~MAC_DROP_ON_NO_DESC) == 0);
10059073SCathy.Zhou@Sun.COM ASSERT(mp->b_next == NULL);
10069073SCathy.Zhou@Sun.COM
10079073SCathy.Zhou@Sun.COM /*
10089073SCathy.Zhou@Sun.COM * Check wether the dedicated-lower-stream is able to handle more
10099073SCathy.Zhou@Sun.COM * messages, and enable the flow-control if it is not.
10109073SCathy.Zhou@Sun.COM *
10119073SCathy.Zhou@Sun.COM * Note that in order not to introduce any packet reordering, we
10129073SCathy.Zhou@Sun.COM * always send the message down to the dedicated-lower-stream:
10139073SCathy.Zhou@Sun.COM *
10149073SCathy.Zhou@Sun.COM * If the flow-control is already enabled, but we still get
10159073SCathy.Zhou@Sun.COM * the messages from the upper-stream, it means that the upper
10169073SCathy.Zhou@Sun.COM * stream does not respect STREAMS flow-control (e.g., TCP). Simply
10179073SCathy.Zhou@Sun.COM * pass the message down to the lower-stream in that case.
10189073SCathy.Zhou@Sun.COM */
10199073SCathy.Zhou@Sun.COM if (SOFTMAC_CANPUTNEXT(wq)) {
10209073SCathy.Zhou@Sun.COM putnext(wq, mp);
10219073SCathy.Zhou@Sun.COM return (NULL);
10229073SCathy.Zhou@Sun.COM }
10239073SCathy.Zhou@Sun.COM
10249073SCathy.Zhou@Sun.COM if (sup->su_tx_busy) {
10259738SCathy.Zhou@Sun.COM if ((flag & MAC_DROP_ON_NO_DESC) != 0)
10269738SCathy.Zhou@Sun.COM freemsg(mp);
10279738SCathy.Zhou@Sun.COM else
10289738SCathy.Zhou@Sun.COM putnext(wq, mp);
10299738SCathy.Zhou@Sun.COM return ((mac_tx_cookie_t)sup);
10309073SCathy.Zhou@Sun.COM }
10319073SCathy.Zhou@Sun.COM
10329073SCathy.Zhou@Sun.COM mutex_enter(&sup->su_mutex);
10339073SCathy.Zhou@Sun.COM if (!sup->su_tx_busy) {
10349738SCathy.Zhou@Sun.COM /*
10359738SCathy.Zhou@Sun.COM * If DLD_CAPAB_DIRECT is enabled, the notify callback will be
10369738SCathy.Zhou@Sun.COM * called when the flow control can be disabled. Otherwise,
10379738SCathy.Zhou@Sun.COM * put the tx_flow_mp into the wq to make use of the old
10389738SCathy.Zhou@Sun.COM * streams flow control.
10399738SCathy.Zhou@Sun.COM */
10409073SCathy.Zhou@Sun.COM ASSERT(sup->su_tx_flow_mp != NULL);
10419073SCathy.Zhou@Sun.COM (void) putq(sup->su_wq, sup->su_tx_flow_mp);
10429073SCathy.Zhou@Sun.COM sup->su_tx_flow_mp = NULL;
10439073SCathy.Zhou@Sun.COM sup->su_tx_busy = B_TRUE;
10449073SCathy.Zhou@Sun.COM qenable(wq);
10459073SCathy.Zhou@Sun.COM }
10469073SCathy.Zhou@Sun.COM mutex_exit(&sup->su_mutex);
10479738SCathy.Zhou@Sun.COM
10489738SCathy.Zhou@Sun.COM if ((flag & MAC_DROP_ON_NO_DESC) != 0)
10499738SCathy.Zhou@Sun.COM freemsg(mp);
10509738SCathy.Zhou@Sun.COM else
10519738SCathy.Zhou@Sun.COM putnext(wq, mp);
10529738SCathy.Zhou@Sun.COM return ((mac_tx_cookie_t)sup);
10539073SCathy.Zhou@Sun.COM }
10549073SCathy.Zhou@Sun.COM
10559073SCathy.Zhou@Sun.COM boolean_t
softmac_active_set(void * arg)10569073SCathy.Zhou@Sun.COM softmac_active_set(void *arg)
10579073SCathy.Zhou@Sun.COM {
10589073SCathy.Zhou@Sun.COM softmac_t *softmac = arg;
10599073SCathy.Zhou@Sun.COM
10609073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_active_mutex);
10619073SCathy.Zhou@Sun.COM if (softmac->smac_nactive != 0) {
10629073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex);
10639073SCathy.Zhou@Sun.COM return (B_FALSE);
10649073SCathy.Zhou@Sun.COM }
10659073SCathy.Zhou@Sun.COM softmac->smac_active = B_TRUE;
10669073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex);
10679073SCathy.Zhou@Sun.COM return (B_TRUE);
10689073SCathy.Zhou@Sun.COM }
10699073SCathy.Zhou@Sun.COM
10709073SCathy.Zhou@Sun.COM void
softmac_active_clear(void * arg)10719073SCathy.Zhou@Sun.COM softmac_active_clear(void *arg)
10729073SCathy.Zhou@Sun.COM {
10739073SCathy.Zhou@Sun.COM softmac_t *softmac = arg;
10749073SCathy.Zhou@Sun.COM
10759073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_active_mutex);
10769073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_active && (softmac->smac_nactive == 0));
10779073SCathy.Zhou@Sun.COM softmac->smac_active = B_FALSE;
10789073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_active_mutex);
10799073SCathy.Zhou@Sun.COM }
10809073SCathy.Zhou@Sun.COM
10819073SCathy.Zhou@Sun.COM /*
10829073SCathy.Zhou@Sun.COM * Disable/reenable fastpath on given softmac. This request could come from a
10839073SCathy.Zhou@Sun.COM * MAC client or directly from administrators.
10849073SCathy.Zhou@Sun.COM */
10859073SCathy.Zhou@Sun.COM int
softmac_datapath_switch(softmac_t * softmac,boolean_t disable,boolean_t admin)10869073SCathy.Zhou@Sun.COM softmac_datapath_switch(softmac_t *softmac, boolean_t disable, boolean_t admin)
10879073SCathy.Zhou@Sun.COM {
10889073SCathy.Zhou@Sun.COM softmac_upper_t *sup;
10899073SCathy.Zhou@Sun.COM mblk_t *head = NULL, *tail = NULL, *mp;
10909073SCathy.Zhou@Sun.COM list_t reqlist;
10919073SCathy.Zhou@Sun.COM softmac_switch_req_t *req;
10929073SCathy.Zhou@Sun.COM uint32_t current_mode, expected_mode;
10939073SCathy.Zhou@Sun.COM int err = 0;
10949073SCathy.Zhou@Sun.COM
10959073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_fp_mutex);
10969073SCathy.Zhou@Sun.COM
10979073SCathy.Zhou@Sun.COM current_mode = DATAPATH_MODE(softmac);
10989073SCathy.Zhou@Sun.COM if (admin) {
10999073SCathy.Zhou@Sun.COM if (softmac->smac_fastpath_admin_disabled == disable) {
11009073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
11019073SCathy.Zhou@Sun.COM return (0);
11029073SCathy.Zhou@Sun.COM }
11039073SCathy.Zhou@Sun.COM softmac->smac_fastpath_admin_disabled = disable;
11049073SCathy.Zhou@Sun.COM } else if (disable) {
11059073SCathy.Zhou@Sun.COM softmac->smac_fp_disable_clients++;
11069073SCathy.Zhou@Sun.COM } else {
11079073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_fp_disable_clients != 0);
11089073SCathy.Zhou@Sun.COM softmac->smac_fp_disable_clients--;
11099073SCathy.Zhou@Sun.COM }
11109073SCathy.Zhou@Sun.COM
11119073SCathy.Zhou@Sun.COM expected_mode = DATAPATH_MODE(softmac);
11129073SCathy.Zhou@Sun.COM if (current_mode == expected_mode) {
11139073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
11149073SCathy.Zhou@Sun.COM return (0);
11159073SCathy.Zhou@Sun.COM }
11169073SCathy.Zhou@Sun.COM
11179073SCathy.Zhou@Sun.COM /*
11189073SCathy.Zhou@Sun.COM * The expected mode is different from whatever datapath mode
11199073SCathy.Zhou@Sun.COM * this softmac is expected from last request, enqueue the data-path
11209073SCathy.Zhou@Sun.COM * switch request.
11219073SCathy.Zhou@Sun.COM */
11229073SCathy.Zhou@Sun.COM list_create(&reqlist, sizeof (softmac_switch_req_t),
11239073SCathy.Zhou@Sun.COM offsetof(softmac_switch_req_t, ssq_req_list_node));
11249073SCathy.Zhou@Sun.COM
11259073SCathy.Zhou@Sun.COM /*
11269073SCathy.Zhou@Sun.COM * Allocate all DL_NOTIFY_IND messages and request structures that
11279073SCathy.Zhou@Sun.COM * are required to switch each IP/ARP stream to the expected mode.
11289073SCathy.Zhou@Sun.COM */
11299073SCathy.Zhou@Sun.COM for (sup = list_head(&softmac->smac_sup_list); sup != NULL;
11309073SCathy.Zhou@Sun.COM sup = list_next(&softmac->smac_sup_list, sup)) {
11319073SCathy.Zhou@Sun.COM dl_notify_ind_t *dlip;
11329073SCathy.Zhou@Sun.COM
11339073SCathy.Zhou@Sun.COM req = kmem_alloc(sizeof (softmac_switch_req_t), KM_NOSLEEP);
11349073SCathy.Zhou@Sun.COM if (req == NULL)
11359073SCathy.Zhou@Sun.COM break;
11369073SCathy.Zhou@Sun.COM
11379073SCathy.Zhou@Sun.COM req->ssq_expected_mode = expected_mode;
1138*11042SErik.Nordmark@Sun.COM if (sup->su_is_arp) {
1139*11042SErik.Nordmark@Sun.COM list_insert_tail(&reqlist, req);
1140*11042SErik.Nordmark@Sun.COM continue;
1141*11042SErik.Nordmark@Sun.COM }
11429073SCathy.Zhou@Sun.COM /*
11439073SCathy.Zhou@Sun.COM * Allocate the DL_NOTE_REPLUMB message.
11449073SCathy.Zhou@Sun.COM */
11459073SCathy.Zhou@Sun.COM if ((mp = allocb(sizeof (dl_notify_ind_t), BPRI_LO)) == NULL) {
11469073SCathy.Zhou@Sun.COM kmem_free(req, sizeof (softmac_switch_req_t));
11479073SCathy.Zhou@Sun.COM break;
11489073SCathy.Zhou@Sun.COM }
11499073SCathy.Zhou@Sun.COM
11509073SCathy.Zhou@Sun.COM list_insert_tail(&reqlist, req);
11519073SCathy.Zhou@Sun.COM
11529073SCathy.Zhou@Sun.COM mp->b_wptr = mp->b_rptr + sizeof (dl_notify_ind_t);
11539073SCathy.Zhou@Sun.COM mp->b_datap->db_type = M_PROTO;
11549073SCathy.Zhou@Sun.COM bzero(mp->b_rptr, sizeof (dl_notify_ind_t));
11559073SCathy.Zhou@Sun.COM dlip = (dl_notify_ind_t *)mp->b_rptr;
11569073SCathy.Zhou@Sun.COM dlip->dl_primitive = DL_NOTIFY_IND;
11579073SCathy.Zhou@Sun.COM dlip->dl_notification = DL_NOTE_REPLUMB;
11589073SCathy.Zhou@Sun.COM if (head == NULL) {
11599073SCathy.Zhou@Sun.COM head = tail = mp;
11609073SCathy.Zhou@Sun.COM } else {
11619073SCathy.Zhou@Sun.COM tail->b_next = mp;
11629073SCathy.Zhou@Sun.COM tail = mp;
11639073SCathy.Zhou@Sun.COM }
11649073SCathy.Zhou@Sun.COM }
11659073SCathy.Zhou@Sun.COM
11669073SCathy.Zhou@Sun.COM /*
11679073SCathy.Zhou@Sun.COM * Note that it is fine if the expected data-path mode is fast-path
11689073SCathy.Zhou@Sun.COM * and some of streams fails to switch. Only return failure if we
11699073SCathy.Zhou@Sun.COM * are expected to switch to the slow-path.
11709073SCathy.Zhou@Sun.COM */
11719073SCathy.Zhou@Sun.COM if (sup != NULL && expected_mode == SOFTMAC_SLOWPATH) {
11729073SCathy.Zhou@Sun.COM err = ENOMEM;
11739073SCathy.Zhou@Sun.COM goto fail;
11749073SCathy.Zhou@Sun.COM }
11759073SCathy.Zhou@Sun.COM
11769073SCathy.Zhou@Sun.COM /*
11779073SCathy.Zhou@Sun.COM * Start switching for each IP/ARP stream. The switching operation
11789073SCathy.Zhou@Sun.COM * will eventually succeed and there is no need to wait for it
11799073SCathy.Zhou@Sun.COM * to finish.
11809073SCathy.Zhou@Sun.COM */
11819073SCathy.Zhou@Sun.COM for (sup = list_head(&softmac->smac_sup_list); sup != NULL;
11829073SCathy.Zhou@Sun.COM sup = list_next(&softmac->smac_sup_list, sup)) {
1183*11042SErik.Nordmark@Sun.COM if (!sup->su_is_arp) {
1184*11042SErik.Nordmark@Sun.COM mp = head->b_next;
1185*11042SErik.Nordmark@Sun.COM head->b_next = NULL;
1186*11042SErik.Nordmark@Sun.COM softmac_wput_nondata(sup, head);
1187*11042SErik.Nordmark@Sun.COM head = mp;
1188*11042SErik.Nordmark@Sun.COM }
11899073SCathy.Zhou@Sun.COM /*
1190*11042SErik.Nordmark@Sun.COM * Add the switch request to the requests list of the stream.
11919073SCathy.Zhou@Sun.COM */
11929073SCathy.Zhou@Sun.COM req = list_head(&reqlist);
11939073SCathy.Zhou@Sun.COM ASSERT(req != NULL);
11949073SCathy.Zhou@Sun.COM list_remove(&reqlist, req);
11959073SCathy.Zhou@Sun.COM list_insert_tail(&sup->su_req_list, req);
11969073SCathy.Zhou@Sun.COM }
11979073SCathy.Zhou@Sun.COM
11989073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
11999073SCathy.Zhou@Sun.COM ASSERT(list_is_empty(&reqlist));
12009073SCathy.Zhou@Sun.COM list_destroy(&reqlist);
12019073SCathy.Zhou@Sun.COM return (0);
12029073SCathy.Zhou@Sun.COM fail:
12039073SCathy.Zhou@Sun.COM if (admin) {
12049073SCathy.Zhou@Sun.COM softmac->smac_fastpath_admin_disabled = !disable;
12059073SCathy.Zhou@Sun.COM } else if (disable) {
12069073SCathy.Zhou@Sun.COM softmac->smac_fp_disable_clients--;
12079073SCathy.Zhou@Sun.COM } else {
12089073SCathy.Zhou@Sun.COM softmac->smac_fp_disable_clients++;
12099073SCathy.Zhou@Sun.COM }
12109073SCathy.Zhou@Sun.COM
12119073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
12129073SCathy.Zhou@Sun.COM while ((req = list_head(&reqlist)) != NULL) {
12139073SCathy.Zhou@Sun.COM list_remove(&reqlist, req);
12149073SCathy.Zhou@Sun.COM kmem_free(req, sizeof (softmac_switch_req_t));
12159073SCathy.Zhou@Sun.COM }
12169073SCathy.Zhou@Sun.COM freemsgchain(head);
12179073SCathy.Zhou@Sun.COM list_destroy(&reqlist);
12189073SCathy.Zhou@Sun.COM return (err);
12199073SCathy.Zhou@Sun.COM }
12209073SCathy.Zhou@Sun.COM
12219073SCathy.Zhou@Sun.COM int
softmac_fastpath_disable(void * arg)12229073SCathy.Zhou@Sun.COM softmac_fastpath_disable(void *arg)
12239073SCathy.Zhou@Sun.COM {
12249073SCathy.Zhou@Sun.COM return (softmac_datapath_switch((softmac_t *)arg, B_TRUE, B_FALSE));
12259073SCathy.Zhou@Sun.COM }
12269073SCathy.Zhou@Sun.COM
12279073SCathy.Zhou@Sun.COM void
softmac_fastpath_enable(void * arg)12289073SCathy.Zhou@Sun.COM softmac_fastpath_enable(void *arg)
12299073SCathy.Zhou@Sun.COM {
12309073SCathy.Zhou@Sun.COM VERIFY(softmac_datapath_switch((softmac_t *)arg, B_FALSE,
12319073SCathy.Zhou@Sun.COM B_FALSE) == 0);
12329073SCathy.Zhou@Sun.COM }
12339073SCathy.Zhou@Sun.COM
12349073SCathy.Zhou@Sun.COM void
softmac_upperstream_close(softmac_upper_t * sup)12359073SCathy.Zhou@Sun.COM softmac_upperstream_close(softmac_upper_t *sup)
12369073SCathy.Zhou@Sun.COM {
12379073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac;
12389073SCathy.Zhou@Sun.COM softmac_switch_req_t *req;
12399073SCathy.Zhou@Sun.COM
12409073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_fp_mutex);
12419073SCathy.Zhou@Sun.COM
12429073SCathy.Zhou@Sun.COM if (sup->su_mode == SOFTMAC_FASTPATH)
12439073SCathy.Zhou@Sun.COM softmac_fastpath_tear(sup);
12449073SCathy.Zhou@Sun.COM
12459073SCathy.Zhou@Sun.COM if (sup->su_mode != SOFTMAC_UNKNOWN) {
12469073SCathy.Zhou@Sun.COM list_remove(&softmac->smac_sup_list, sup);
12479073SCathy.Zhou@Sun.COM sup->su_mode = SOFTMAC_UNKNOWN;
12489073SCathy.Zhou@Sun.COM }
12499073SCathy.Zhou@Sun.COM
12509073SCathy.Zhou@Sun.COM /*
12519073SCathy.Zhou@Sun.COM * Cleanup all the switch requests queueed on this stream.
12529073SCathy.Zhou@Sun.COM */
12539073SCathy.Zhou@Sun.COM while ((req = list_head(&sup->su_req_list)) != NULL) {
12549073SCathy.Zhou@Sun.COM list_remove(&sup->su_req_list, req);
12559073SCathy.Zhou@Sun.COM kmem_free(req, sizeof (softmac_switch_req_t));
12569073SCathy.Zhou@Sun.COM }
12579073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
12589073SCathy.Zhou@Sun.COM }
12599073SCathy.Zhou@Sun.COM
12609073SCathy.Zhou@Sun.COM /*
12619073SCathy.Zhou@Sun.COM * Handle the DL_NOTE_REPLUMB_DONE indication from IP/ARP. Change the upper
12629073SCathy.Zhou@Sun.COM * stream from the fastpath mode to the slowpath mode.
12639073SCathy.Zhou@Sun.COM */
12649073SCathy.Zhou@Sun.COM static void
softmac_datapath_switch_done(softmac_upper_t * sup)12659073SCathy.Zhou@Sun.COM softmac_datapath_switch_done(softmac_upper_t *sup)
12669073SCathy.Zhou@Sun.COM {
12679073SCathy.Zhou@Sun.COM softmac_t *softmac = sup->su_softmac;
12689073SCathy.Zhou@Sun.COM softmac_switch_req_t *req;
12699073SCathy.Zhou@Sun.COM uint32_t expected_mode;
12709073SCathy.Zhou@Sun.COM
12719073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_fp_mutex);
12729073SCathy.Zhou@Sun.COM req = list_head(&sup->su_req_list);
12739073SCathy.Zhou@Sun.COM list_remove(&sup->su_req_list, req);
12749073SCathy.Zhou@Sun.COM expected_mode = req->ssq_expected_mode;
12759073SCathy.Zhou@Sun.COM kmem_free(req, sizeof (softmac_switch_req_t));
12769073SCathy.Zhou@Sun.COM
12779073SCathy.Zhou@Sun.COM if (expected_mode == sup->su_mode) {
12789073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
12799073SCathy.Zhou@Sun.COM return;
12809073SCathy.Zhou@Sun.COM }
12819073SCathy.Zhou@Sun.COM
12829073SCathy.Zhou@Sun.COM ASSERT(!sup->su_bound);
12839073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_fp_mutex);
12849073SCathy.Zhou@Sun.COM
12859073SCathy.Zhou@Sun.COM /*
12869073SCathy.Zhou@Sun.COM * It is fine if the expected mode is fast-path and we fail
12879073SCathy.Zhou@Sun.COM * to enable fastpath on this stream.
12889073SCathy.Zhou@Sun.COM */
12899073SCathy.Zhou@Sun.COM if (expected_mode == SOFTMAC_SLOWPATH)
12909073SCathy.Zhou@Sun.COM softmac_fastpath_tear(sup);
12919073SCathy.Zhou@Sun.COM else
12929073SCathy.Zhou@Sun.COM (void) softmac_fastpath_setup(sup);
12939073SCathy.Zhou@Sun.COM }
1294