xref: /illumos-gate/usr/src/uts/common/io/mac/mac.c (revision 67cac09c10b30f6cb8b54321a2b35560d4d1642a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5490ed22dSyz147064  * Common Development and Distribution License (the "License").
6490ed22dSyz147064  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21843e1988Sjohnlev 
227c478bd9Sstevel@tonic-gate /*
230591ddd0SPrakash Jalan  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2484de666eSRyan Zezeski  * Copyright 2020 Joyent, Inc.
253bc4925dSGarrett D'Amore  * Copyright 2015 Garrett D'Amore <garrett@damore.org>
26d77e6e0fSPaul Winder  * Copyright 2020 RackTop Systems, Inc.
27*67cac09cSKyle Simpson  * Copyright 2024 Oxide Computer Company
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * MAC Services Module
32da14cebeSEric Cheng  *
33da14cebeSEric Cheng  * The GLDv3 framework locking -  The MAC layer
34da14cebeSEric Cheng  * --------------------------------------------
35da14cebeSEric Cheng  *
36da14cebeSEric Cheng  * The MAC layer is central to the GLD framework and can provide the locking
37da14cebeSEric Cheng  * framework needed for itself and for the use of MAC clients. MAC end points
38da14cebeSEric Cheng  * are fairly disjoint and don't share a lot of state. So a coarse grained
39da14cebeSEric Cheng  * multi-threading scheme is to single thread all create/modify/delete or set
40da14cebeSEric Cheng  * type of control operations on a per mac end point while allowing data threads
41da14cebeSEric Cheng  * concurrently.
42da14cebeSEric Cheng  *
43da14cebeSEric Cheng  * Control operations (set) that modify a mac end point are always serialized on
44da14cebeSEric Cheng  * a per mac end point basis, We have at most 1 such thread per mac end point
45da14cebeSEric Cheng  * at a time.
46da14cebeSEric Cheng  *
47da14cebeSEric Cheng  * All other operations that are not serialized are essentially multi-threaded.
48da14cebeSEric Cheng  * For example a control operation (get) like getting statistics which may not
49da14cebeSEric Cheng  * care about reading values atomically or data threads sending or receiving
50da14cebeSEric Cheng  * data. Mostly these type of operations don't modify the control state. Any
51da14cebeSEric Cheng  * state these operations care about are protected using traditional locks.
52da14cebeSEric Cheng  *
53da14cebeSEric Cheng  * The perimeter only serializes serial operations. It does not imply there
54da14cebeSEric Cheng  * aren't any other concurrent operations. However a serialized operation may
55da14cebeSEric Cheng  * sometimes need to make sure it is the only thread. In this case it needs
56da14cebeSEric Cheng  * to use reference counting mechanisms to cv_wait until any current data
57da14cebeSEric Cheng  * threads are done.
58da14cebeSEric Cheng  *
59da14cebeSEric Cheng  * The mac layer itself does not hold any locks across a call to another layer.
60da14cebeSEric Cheng  * The perimeter is however held across a down call to the driver to make the
61da14cebeSEric Cheng  * whole control operation atomic with respect to other control operations.
62da14cebeSEric Cheng  * Also the data path and get type control operations may proceed concurrently.
63da14cebeSEric Cheng  * These operations synchronize with the single serial operation on a given mac
64da14cebeSEric Cheng  * end point using regular locks. The perimeter ensures that conflicting
65da14cebeSEric Cheng  * operations like say a mac_multicast_add and a mac_multicast_remove on the
66da14cebeSEric Cheng  * same mac end point don't interfere with each other and also ensures that the
67da14cebeSEric Cheng  * changes in the mac layer and the call to the underlying driver to say add a
68da14cebeSEric Cheng  * multicast address are done atomically without interference from a thread
69da14cebeSEric Cheng  * trying to delete the same address.
70da14cebeSEric Cheng  *
71da14cebeSEric Cheng  * For example, consider
72da14cebeSEric Cheng  * mac_multicst_add()
73da14cebeSEric Cheng  * {
74da14cebeSEric Cheng  *	mac_perimeter_enter();	serialize all control operations
75da14cebeSEric Cheng  *
76da14cebeSEric Cheng  *	grab list lock		protect against access by data threads
77da14cebeSEric Cheng  *	add to list
78da14cebeSEric Cheng  *	drop list lock
79da14cebeSEric Cheng  *
80da14cebeSEric Cheng  *	call driver's mi_multicst
81da14cebeSEric Cheng  *
82da14cebeSEric Cheng  *	mac_perimeter_exit();
83da14cebeSEric Cheng  * }
84da14cebeSEric Cheng  *
85da14cebeSEric Cheng  * To lessen the number of serialization locks and simplify the lock hierarchy,
86da14cebeSEric Cheng  * we serialize all the control operations on a per mac end point by using a
87da14cebeSEric Cheng  * single serialization lock called the perimeter. We allow recursive entry into
88da14cebeSEric Cheng  * the perimeter to facilitate use of this mechanism by both the mac client and
89da14cebeSEric Cheng  * the MAC layer itself.
90da14cebeSEric Cheng  *
91da14cebeSEric Cheng  * MAC client means an entity that does an operation on a mac handle
92da14cebeSEric Cheng  * obtained from a mac_open/mac_client_open. Similarly MAC driver means
93da14cebeSEric Cheng  * an entity that does an operation on a mac handle obtained from a
94da14cebeSEric Cheng  * mac_register. An entity could be both client and driver but on different
95da14cebeSEric Cheng  * handles eg. aggr. and should only make the corresponding mac interface calls
96da14cebeSEric Cheng  * i.e. mac driver interface or mac client interface as appropriate for that
97da14cebeSEric Cheng  * mac handle.
98da14cebeSEric Cheng  *
99da14cebeSEric Cheng  * General rules.
100da14cebeSEric Cheng  * -------------
101da14cebeSEric Cheng  *
102da14cebeSEric Cheng  * R1. The lock order of upcall threads is natually opposite to downcall
103da14cebeSEric Cheng  * threads. Hence upcalls must not hold any locks across layers for fear of
104da14cebeSEric Cheng  * recursive lock enter and lock order violation. This applies to all layers.
105da14cebeSEric Cheng  *
106da14cebeSEric Cheng  * R2. The perimeter is just another lock. Since it is held in the down
107da14cebeSEric Cheng  * direction, acquiring the perimeter in an upcall is prohibited as it would
108da14cebeSEric Cheng  * cause a deadlock. This applies to all layers.
109da14cebeSEric Cheng  *
110da14cebeSEric Cheng  * Note that upcalls that need to grab the mac perimeter (for example
111da14cebeSEric Cheng  * mac_notify upcalls) can still achieve that by posting the request to a
112da14cebeSEric Cheng  * thread, which can then grab all the required perimeters and locks in the
113da14cebeSEric Cheng  * right global order. Note that in the above example the mac layer iself
114da14cebeSEric Cheng  * won't grab the mac perimeter in the mac_notify upcall, instead the upcall
115da14cebeSEric Cheng  * to the client must do that. Please see the aggr code for an example.
116da14cebeSEric Cheng  *
117da14cebeSEric Cheng  * MAC client rules
118da14cebeSEric Cheng  * ----------------
119da14cebeSEric Cheng  *
120da14cebeSEric Cheng  * R3. A MAC client may use the MAC provided perimeter facility to serialize
121da14cebeSEric Cheng  * control operations on a per mac end point. It does this by by acquring
122da14cebeSEric Cheng  * and holding the perimeter across a sequence of calls to the mac layer.
123da14cebeSEric Cheng  * This ensures atomicity across the entire block of mac calls. In this
124da14cebeSEric Cheng  * model the MAC client must not hold any client locks across the calls to
125da14cebeSEric Cheng  * the mac layer. This model is the preferred solution.
126da14cebeSEric Cheng  *
127da14cebeSEric Cheng  * R4. However if a MAC client has a lot of global state across all mac end
128da14cebeSEric Cheng  * points the per mac end point serialization may not be sufficient. In this
129da14cebeSEric Cheng  * case the client may choose to use global locks or use its own serialization.
130da14cebeSEric Cheng  * To avoid deadlocks, these client layer locks held across the mac calls
131da14cebeSEric Cheng  * in the control path must never be acquired by the data path for the reason
132da14cebeSEric Cheng  * mentioned below.
133da14cebeSEric Cheng  *
134da14cebeSEric Cheng  * (Assume that a control operation that holds a client lock blocks in the
135da14cebeSEric Cheng  * mac layer waiting for upcall reference counts to drop to zero. If an upcall
136da14cebeSEric Cheng  * data thread that holds this reference count, tries to acquire the same
137da14cebeSEric Cheng  * client lock subsequently it will deadlock).
138da14cebeSEric Cheng  *
139da14cebeSEric Cheng  * A MAC client may follow either the R3 model or the R4 model, but can't
140da14cebeSEric Cheng  * mix both. In the former, the hierarchy is Perim -> client locks, but in
141da14cebeSEric Cheng  * the latter it is client locks -> Perim.
142da14cebeSEric Cheng  *
143da14cebeSEric Cheng  * R5. MAC clients must make MAC calls (excluding data calls) in a cv_wait'able
144da14cebeSEric Cheng  * context since they may block while trying to acquire the perimeter.
145da14cebeSEric Cheng  * In addition some calls may block waiting for upcall refcnts to come down to
146da14cebeSEric Cheng  * zero.
147da14cebeSEric Cheng  *
148da14cebeSEric Cheng  * R6. MAC clients must make sure that they are single threaded and all threads
149da14cebeSEric Cheng  * from the top (in particular data threads) have finished before calling
150da14cebeSEric Cheng  * mac_client_close. The MAC framework does not track the number of client
151da14cebeSEric Cheng  * threads using the mac client handle. Also mac clients must make sure
152da14cebeSEric Cheng  * they have undone all the control operations before calling mac_client_close.
153da14cebeSEric Cheng  * For example mac_unicast_remove/mac_multicast_remove to undo the corresponding
154da14cebeSEric Cheng  * mac_unicast_add/mac_multicast_add.
155da14cebeSEric Cheng  *
156da14cebeSEric Cheng  * MAC framework rules
157da14cebeSEric Cheng  * -------------------
158da14cebeSEric Cheng  *
159da14cebeSEric Cheng  * R7. The mac layer itself must not hold any mac layer locks (except the mac
160da14cebeSEric Cheng  * perimeter) across a call to any other layer from the mac layer. The call to
161da14cebeSEric Cheng  * any other layer could be via mi_* entry points, classifier entry points into
162da14cebeSEric Cheng  * the driver or via upcall pointers into layers above. The mac perimeter may
163da14cebeSEric Cheng  * be acquired or held only in the down direction, for e.g. when calling into
164da14cebeSEric Cheng  * a mi_* driver enty point to provide atomicity of the operation.
165da14cebeSEric Cheng  *
166da14cebeSEric Cheng  * R8. Since it is not guaranteed (see R14) that drivers won't hold locks across
167da14cebeSEric Cheng  * mac driver interfaces, the MAC layer must provide a cut out for control
168da14cebeSEric Cheng  * interfaces like upcall notifications and start them in a separate thread.
169da14cebeSEric Cheng  *
170da14cebeSEric Cheng  * R9. Note that locking order also implies a plumbing order. For example
171da14cebeSEric Cheng  * VNICs are allowed to be created over aggrs, but not vice-versa. An attempt
172da14cebeSEric Cheng  * to plumb in any other order must be failed at mac_open time, otherwise it
173da14cebeSEric Cheng  * could lead to deadlocks due to inverse locking order.
174da14cebeSEric Cheng  *
175da14cebeSEric Cheng  * R10. MAC driver interfaces must not block since the driver could call them
176da14cebeSEric Cheng  * in interrupt context.
177da14cebeSEric Cheng  *
178da14cebeSEric Cheng  * R11. Walkers must preferably not hold any locks while calling walker
179da14cebeSEric Cheng  * callbacks. Instead these can operate on reference counts. In simple
180da14cebeSEric Cheng  * callbacks it may be ok to hold a lock and call the callbacks, but this is
181da14cebeSEric Cheng  * harder to maintain in the general case of arbitrary callbacks.
182da14cebeSEric Cheng  *
183da14cebeSEric Cheng  * R12. The MAC layer must protect upcall notification callbacks using reference
184da14cebeSEric Cheng  * counts rather than holding locks across the callbacks.
185da14cebeSEric Cheng  *
186da14cebeSEric Cheng  * R13. Given the variety of drivers, it is preferable if the MAC layer can make
187da14cebeSEric Cheng  * sure that any pointers (such as mac ring pointers) it passes to the driver
188da14cebeSEric Cheng  * remain valid until mac unregister time. Currently the mac layer achieves
189da14cebeSEric Cheng  * this by using generation numbers for rings and freeing the mac rings only
190da14cebeSEric Cheng  * at unregister time.  The MAC layer must provide a layer of indirection and
191da14cebeSEric Cheng  * must not expose underlying driver rings or driver data structures/pointers
192da14cebeSEric Cheng  * directly to MAC clients.
193da14cebeSEric Cheng  *
194da14cebeSEric Cheng  * MAC driver rules
195da14cebeSEric Cheng  * ----------------
196da14cebeSEric Cheng  *
197da14cebeSEric Cheng  * R14. It would be preferable if MAC drivers don't hold any locks across any
198da14cebeSEric Cheng  * mac call. However at a minimum they must not hold any locks across data
199da14cebeSEric Cheng  * upcalls. They must also make sure that all references to mac data structures
200da14cebeSEric Cheng  * are cleaned up and that it is single threaded at mac_unregister time.
201da14cebeSEric Cheng  *
202da14cebeSEric Cheng  * R15. MAC driver interfaces don't block and so the action may be done
203da14cebeSEric Cheng  * asynchronously in a separate thread as for example handling notifications.
204da14cebeSEric Cheng  * The driver must not assume that the action is complete when the call
205da14cebeSEric Cheng  * returns.
206da14cebeSEric Cheng  *
207da14cebeSEric Cheng  * R16. Drivers must maintain a generation number per Rx ring, and pass it
208da14cebeSEric Cheng  * back to mac_rx_ring(); They are expected to increment the generation
209da14cebeSEric Cheng  * number whenever the ring's stop routine is invoked.
210da14cebeSEric Cheng  * See comments in mac_rx_ring();
211da14cebeSEric Cheng  *
212da14cebeSEric Cheng  * R17 Similarly mi_stop is another synchronization point and the driver must
213da14cebeSEric Cheng  * ensure that all upcalls are done and there won't be any future upcall
214da14cebeSEric Cheng  * before returning from mi_stop.
215da14cebeSEric Cheng  *
216da14cebeSEric Cheng  * R18. The driver may assume that all set/modify control operations via
217da14cebeSEric Cheng  * the mi_* entry points are single threaded on a per mac end point.
218da14cebeSEric Cheng  *
219da14cebeSEric Cheng  * Lock and Perimeter hierarchy scenarios
220da14cebeSEric Cheng  * ---------------------------------------
221da14cebeSEric Cheng  *
222da14cebeSEric Cheng  * i_mac_impl_lock -> mi_rw_lock -> srs_lock -> s_ring_lock[i_mac_tx_srs_notify]
223da14cebeSEric Cheng  *
224da14cebeSEric Cheng  * ft_lock -> fe_lock [mac_flow_lookup]
225da14cebeSEric Cheng  *
226da14cebeSEric Cheng  * mi_rw_lock -> fe_lock [mac_bcast_send]
227da14cebeSEric Cheng  *
228da14cebeSEric Cheng  * srs_lock -> mac_bw_lock [mac_rx_srs_drain_bw]
229da14cebeSEric Cheng  *
230da14cebeSEric Cheng  * cpu_lock -> mac_srs_g_lock -> srs_lock -> s_ring_lock [mac_walk_srs_and_bind]
231da14cebeSEric Cheng  *
232da14cebeSEric Cheng  * i_dls_devnet_lock -> mac layer locks [dls_devnet_rename]
233da14cebeSEric Cheng  *
234da14cebeSEric Cheng  * Perimeters are ordered P1 -> P2 -> P3 from top to bottom in order of mac
235da14cebeSEric Cheng  * client to driver. In the case of clients that explictly use the mac provided
236da14cebeSEric Cheng  * perimeter mechanism for its serialization, the hierarchy is
237da14cebeSEric Cheng  * Perimeter -> mac layer locks, since the client never holds any locks across
238da14cebeSEric Cheng  * the mac calls. In the case of clients that use its own locks the hierarchy
239da14cebeSEric Cheng  * is Client locks -> Mac Perim -> Mac layer locks. The client never explicitly
240da14cebeSEric Cheng  * calls mac_perim_enter/exit in this case.
241da14cebeSEric Cheng  *
242da14cebeSEric Cheng  * Subflow creation rules
243da14cebeSEric Cheng  * ---------------------------
244da14cebeSEric Cheng  * o In case of a user specified cpulist present on underlying link and flows,
245da14cebeSEric Cheng  * the flows cpulist must be a subset of the underlying link.
246da14cebeSEric Cheng  * o In case of a user specified fanout mode present on link and flow, the
247da14cebeSEric Cheng  * subflow fanout count has to be less than or equal to that of the
248da14cebeSEric Cheng  * underlying link. The cpu-bindings for the subflows will be a subset of
249da14cebeSEric Cheng  * the underlying link.
250da14cebeSEric Cheng  * o In case if no cpulist specified on both underlying link and flow, the
251da14cebeSEric Cheng  * underlying link relies on a  MAC tunable to provide out of box fanout.
252da14cebeSEric Cheng  * The subflow will have no cpulist (the subflow will be unbound)
253da14cebeSEric Cheng  * o In case if no cpulist is specified on the underlying link, a subflow can
254da14cebeSEric Cheng  * carry  either a user-specified cpulist or fanout count. The cpu-bindings
255da14cebeSEric Cheng  * for the subflow will not adhere to restriction that they need to be subset
256da14cebeSEric Cheng  * of the underlying link.
257da14cebeSEric Cheng  * o In case where the underlying link is carrying either a user specified
258da14cebeSEric Cheng  * cpulist or fanout mode and for a unspecified subflow, the subflow will be
259da14cebeSEric Cheng  * created unbound.
260da14cebeSEric Cheng  * o While creating unbound subflows, bandwidth mode changes attempt to
261da14cebeSEric Cheng  * figure a right fanout count. In such cases the fanout count will override
262da14cebeSEric Cheng  * the unbound cpu-binding behavior.
263da14cebeSEric Cheng  * o In addition to this, while cycling between flow and link properties, we
264da14cebeSEric Cheng  * impose a restriction that if a link property has a subflow with
265da14cebeSEric Cheng  * user-specified attributes, we will not allow changing the link property.
266da14cebeSEric Cheng  * The administrator needs to reset all the user specified properties for the
267da14cebeSEric Cheng  * subflows before attempting a link property change.
268da14cebeSEric Cheng  * Some of the above rules can be overridden by specifying additional command
269da14cebeSEric Cheng  * line options while creating or modifying link or subflow properties.
270bc44a933SRobert Mustacchi  *
271bc44a933SRobert Mustacchi  * Datapath
272bc44a933SRobert Mustacchi  * --------
273bc44a933SRobert Mustacchi  *
274bc44a933SRobert Mustacchi  * For information on the datapath, the world of soft rings, hardware rings, how
275bc44a933SRobert Mustacchi  * it is structured, and the path of an mblk_t between a driver and a mac
276bc44a933SRobert Mustacchi  * client, see mac_sched.c.
2777c478bd9Sstevel@tonic-gate  */
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate #include <sys/types.h>
2807c478bd9Sstevel@tonic-gate #include <sys/conf.h>
281d62bc4baSyz147064 #include <sys/id_space.h>
2828de9d095Syz147064 #include <sys/esunddi.h>
2837c478bd9Sstevel@tonic-gate #include <sys/stat.h>
284d62bc4baSyz147064 #include <sys/mkdev.h>
2857c478bd9Sstevel@tonic-gate #include <sys/stream.h>
2867c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
2877c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
2887c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
289c228408bSMichael Lim #include <sys/list.h>
290210db224Sericheng #include <sys/modhash.h>
291da14cebeSEric Cheng #include <sys/mac_provider.h>
292da14cebeSEric Cheng #include <sys/mac_client_impl.h>
293da14cebeSEric Cheng #include <sys/mac_soft_ring.h>
2940dc2366fSVenugopal Iyer #include <sys/mac_stat.h>
2957c478bd9Sstevel@tonic-gate #include <sys/mac_impl.h>
296da14cebeSEric Cheng #include <sys/mac.h>
297da14cebeSEric Cheng #include <sys/dls.h>
298210db224Sericheng #include <sys/dld.h>
299ba2e4443Sseb #include <sys/modctl.h>
300f4b3ec61Sdh155122 #include <sys/fs/dv_node.h>
3010487e2c9Sgd78059 #include <sys/thread.h>
3020487e2c9Sgd78059 #include <sys/proc.h>
3030487e2c9Sgd78059 #include <sys/callb.h>
3040487e2c9Sgd78059 #include <sys/cpuvar.h>
305bd7f69f6Sseb #include <sys/atomic.h>
306da14cebeSEric Cheng #include <sys/bitmap.h>
3071f8aaf0dSethindra #include <sys/sdt.h>
308da14cebeSEric Cheng #include <sys/mac_flow.h>
309da14cebeSEric Cheng #include <sys/ddi_intr_impl.h>
310da14cebeSEric Cheng #include <sys/disp.h>
311da14cebeSEric Cheng #include <sys/sdt.h>
312da14cebeSEric Cheng #include <sys/vnic.h>
313da14cebeSEric Cheng #include <sys/vnic_impl.h>
314da14cebeSEric Cheng #include <sys/vlan.h>
315da14cebeSEric Cheng #include <inet/ip.h>
316da14cebeSEric Cheng #include <inet/ip6.h>
317da14cebeSEric Cheng #include <sys/exacct.h>
318da14cebeSEric Cheng #include <sys/exacct_impl.h>
319e7801d59Ssowmini #include <inet/nd.h>
3204045d941Ssowmini #include <sys/ethernet.h>
3210dc2366fSVenugopal Iyer #include <sys/pool.h>
3220dc2366fSVenugopal Iyer #include <sys/pool_pset.h>
3230dc2366fSVenugopal Iyer #include <sys/cpupart.h>
3240dc2366fSVenugopal Iyer #include <inet/wifi_ioctl.h>
3250dc2366fSVenugopal Iyer #include <net/wpa.h>
326dd72704bSRobert Mustacchi #include <sys/mac_ether.h>
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
3297c478bd9Sstevel@tonic-gate 
330da14cebeSEric Cheng kmem_cache_t		*i_mac_impl_cachep;
331da14cebeSEric Cheng mod_hash_t		*i_mac_impl_hash;
332210db224Sericheng krwlock_t		i_mac_impl_lock;
333210db224Sericheng uint_t			i_mac_impl_count;
334da14cebeSEric Cheng static kmem_cache_t	*mac_ring_cache;
335d62bc4baSyz147064 static id_space_t	*minor_ids;
336d62bc4baSyz147064 static uint32_t		minor_count;
3370dc2366fSVenugopal Iyer static pool_event_cb_t	mac_pool_event_reg;
3387c478bd9Sstevel@tonic-gate 
339da14cebeSEric Cheng /*
340da14cebeSEric Cheng  * Logging stuff. Perhaps mac_logging_interval could be broken into
341da14cebeSEric Cheng  * mac_flow_log_interval and mac_link_log_interval if we want to be
342da14cebeSEric Cheng  * able to schedule them differently.
343da14cebeSEric Cheng  */
344da14cebeSEric Cheng uint_t			mac_logging_interval;
345da14cebeSEric Cheng boolean_t		mac_flow_log_enable;
346da14cebeSEric Cheng boolean_t		mac_link_log_enable;
347da14cebeSEric Cheng timeout_id_t		mac_logging_timer;
348da14cebeSEric Cheng 
349ba2e4443Sseb #define	MACTYPE_KMODDIR	"mac"
350ba2e4443Sseb #define	MACTYPE_HASHSZ	67
351ba2e4443Sseb static mod_hash_t	*i_mactype_hash;
352bd7f69f6Sseb /*
353bd7f69f6Sseb  * i_mactype_lock synchronizes threads that obtain references to mactype_t
354bd7f69f6Sseb  * structures through i_mactype_getplugin().
355bd7f69f6Sseb  */
356bd7f69f6Sseb static kmutex_t		i_mactype_lock;
357ba2e4443Sseb 
3587c478bd9Sstevel@tonic-gate /*
359da14cebeSEric Cheng  * mac_tx_percpu_cnt
360da14cebeSEric Cheng  *
361da14cebeSEric Cheng  * Number of per cpu locks per mac_client_impl_t. Used by the transmit side
362da14cebeSEric Cheng  * in mac_tx to reduce lock contention. This is sized at boot time in mac_init.
363da14cebeSEric Cheng  * mac_tx_percpu_cnt_max is settable in /etc/system and must be a power of 2.
364da14cebeSEric Cheng  * Per cpu locks may be disabled by setting mac_tx_percpu_cnt_max to 1.
3657c478bd9Sstevel@tonic-gate  */
366da14cebeSEric Cheng int mac_tx_percpu_cnt;
367da14cebeSEric Cheng int mac_tx_percpu_cnt_max = 128;
3687c478bd9Sstevel@tonic-gate 
3694eaa4710SRishi Srivatsavai /*
3704eaa4710SRishi Srivatsavai  * Call back functions for the bridge module.  These are guaranteed to be valid
3714eaa4710SRishi Srivatsavai  * when holding a reference on a link or when holding mip->mi_bridge_lock and
3724eaa4710SRishi Srivatsavai  * mi_bridge_link is non-NULL.
3734eaa4710SRishi Srivatsavai  */
3744eaa4710SRishi Srivatsavai mac_bridge_tx_t mac_bridge_tx_cb;
3754eaa4710SRishi Srivatsavai mac_bridge_rx_t mac_bridge_rx_cb;
3764eaa4710SRishi Srivatsavai mac_bridge_ref_t mac_bridge_ref_cb;
3774eaa4710SRishi Srivatsavai mac_bridge_ls_t mac_bridge_ls_cb;
3784eaa4710SRishi Srivatsavai 
379da14cebeSEric Cheng static int i_mac_constructor(void *, void *, int);
380da14cebeSEric Cheng static void i_mac_destructor(void *, void *);
381da14cebeSEric Cheng static int i_mac_ring_ctor(void *, void *, int);
382da14cebeSEric Cheng static void i_mac_ring_dtor(void *, void *);
383*67cac09cSKyle Simpson static flow_entry_t *mac_rx_classify(mac_impl_t *, mac_resource_handle_t,
384*67cac09cSKyle Simpson     mblk_t *);
385da14cebeSEric Cheng void mac_tx_client_flush(mac_client_impl_t *);
386da14cebeSEric Cheng void mac_tx_client_block(mac_client_impl_t *);
387da14cebeSEric Cheng static void mac_rx_ring_quiesce(mac_ring_t *, uint_t);
388da14cebeSEric Cheng static int mac_start_group_and_rings(mac_group_t *);
389da14cebeSEric Cheng static void mac_stop_group_and_rings(mac_group_t *);
3900dc2366fSVenugopal Iyer static void mac_pool_event_cb(pool_event_t, int, void *);
391ba2e4443Sseb 
392c228408bSMichael Lim typedef struct netinfo_s {
393c228408bSMichael Lim 	list_node_t	ni_link;
394c228408bSMichael Lim 	void		*ni_record;
395c228408bSMichael Lim 	int		ni_size;
396c228408bSMichael Lim 	int		ni_type;
397c228408bSMichael Lim } netinfo_t;
398c228408bSMichael Lim 
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate  * Module initialization functions.
4017c478bd9Sstevel@tonic-gate  */
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate void
mac_init(void)4047c478bd9Sstevel@tonic-gate mac_init(void)
4057c478bd9Sstevel@tonic-gate {
406da14cebeSEric Cheng 	mac_tx_percpu_cnt = ((boot_max_ncpus == -1) ? max_ncpus :
407da14cebeSEric Cheng 	    boot_max_ncpus);
408da14cebeSEric Cheng 
409da14cebeSEric Cheng 	/* Upper bound is mac_tx_percpu_cnt_max */
410da14cebeSEric Cheng 	if (mac_tx_percpu_cnt > mac_tx_percpu_cnt_max)
411da14cebeSEric Cheng 		mac_tx_percpu_cnt = mac_tx_percpu_cnt_max;
412da14cebeSEric Cheng 
413da14cebeSEric Cheng 	if (mac_tx_percpu_cnt < 1) {
414da14cebeSEric Cheng 		/* Someone set max_tx_percpu_cnt_max to 0 or less */
415da14cebeSEric Cheng 		mac_tx_percpu_cnt = 1;
416da14cebeSEric Cheng 	}
417da14cebeSEric Cheng 
418da14cebeSEric Cheng 	ASSERT(mac_tx_percpu_cnt >= 1);
419da14cebeSEric Cheng 	mac_tx_percpu_cnt = (1 << highbit(mac_tx_percpu_cnt - 1));
420da14cebeSEric Cheng 	/*
421da14cebeSEric Cheng 	 * Make it of the form 2**N - 1 in the range
422da14cebeSEric Cheng 	 * [0 .. mac_tx_percpu_cnt_max - 1]
423da14cebeSEric Cheng 	 */
424da14cebeSEric Cheng 	mac_tx_percpu_cnt--;
425da14cebeSEric Cheng 
4267c478bd9Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
427ba2e4443Sseb 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
428ba2e4443Sseb 	    NULL, NULL, NULL, 0);
4297c478bd9Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
4307c478bd9Sstevel@tonic-gate 
431da14cebeSEric Cheng 	mac_ring_cache = kmem_cache_create("mac_ring_cache",
432da14cebeSEric Cheng 	    sizeof (mac_ring_t), 0, i_mac_ring_ctor, i_mac_ring_dtor, NULL,
433da14cebeSEric Cheng 	    NULL, NULL, 0);
434da14cebeSEric Cheng 	ASSERT(mac_ring_cache != NULL);
435843e1988Sjohnlev 
436210db224Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
437210db224Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
438210db224Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
439210db224Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
440da14cebeSEric Cheng 
441da14cebeSEric Cheng 	mac_flow_init();
442da14cebeSEric Cheng 	mac_soft_ring_init();
443da14cebeSEric Cheng 	mac_bcast_init();
444da14cebeSEric Cheng 	mac_client_init();
445da14cebeSEric Cheng 
446210db224Sericheng 	i_mac_impl_count = 0;
447ba2e4443Sseb 
448ba2e4443Sseb 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
449ba2e4443Sseb 	    MACTYPE_HASHSZ,
450ba2e4443Sseb 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
451ba2e4443Sseb 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
452d62bc4baSyz147064 
453d62bc4baSyz147064 	/*
454d62bc4baSyz147064 	 * Allocate an id space to manage minor numbers. The range of the
45593a61d92SGarrett D'Amore 	 * space will be from MAC_MAX_MINOR+1 to MAC_PRIVATE_MINOR-1.  This
45693a61d92SGarrett D'Amore 	 * leaves half of the 32-bit minors available for driver private use.
457d62bc4baSyz147064 	 */
45893a61d92SGarrett D'Amore 	minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1,
45993a61d92SGarrett D'Amore 	    MAC_PRIVATE_MINOR-1);
460d62bc4baSyz147064 	ASSERT(minor_ids != NULL);
461d62bc4baSyz147064 	minor_count = 0;
462da14cebeSEric Cheng 
463da14cebeSEric Cheng 	/* Let's default to 20 seconds */
464da14cebeSEric Cheng 	mac_logging_interval = 20;
465da14cebeSEric Cheng 	mac_flow_log_enable = B_FALSE;
466da14cebeSEric Cheng 	mac_link_log_enable = B_FALSE;
46784de666eSRyan Zezeski 	mac_logging_timer = NULL;
4680dc2366fSVenugopal Iyer 
4690dc2366fSVenugopal Iyer 	/* Register to be notified of noteworthy pools events */
4700dc2366fSVenugopal Iyer 	mac_pool_event_reg.pec_func =  mac_pool_event_cb;
4710dc2366fSVenugopal Iyer 	mac_pool_event_reg.pec_arg = NULL;
4720dc2366fSVenugopal Iyer 	pool_event_cb_register(&mac_pool_event_reg);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate int
mac_fini(void)4767c478bd9Sstevel@tonic-gate mac_fini(void)
4777c478bd9Sstevel@tonic-gate {
4780dc2366fSVenugopal Iyer 
479d62bc4baSyz147064 	if (i_mac_impl_count > 0 || minor_count > 0)
480210db224Sericheng 		return (EBUSY);
4817c478bd9Sstevel@tonic-gate 
4820dc2366fSVenugopal Iyer 	pool_event_cb_unregister(&mac_pool_event_reg);
4830dc2366fSVenugopal Iyer 
484d62bc4baSyz147064 	id_space_destroy(minor_ids);
485da14cebeSEric Cheng 	mac_flow_fini();
486d62bc4baSyz147064 
487210db224Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
488210db224Sericheng 	rw_destroy(&i_mac_impl_lock);
4897c478bd9Sstevel@tonic-gate 
490da14cebeSEric Cheng 	mac_client_fini();
491da14cebeSEric Cheng 	kmem_cache_destroy(mac_ring_cache);
492ba2e4443Sseb 
493ba2e4443Sseb 	mod_hash_destroy_hash(i_mactype_hash);
494da14cebeSEric Cheng 	mac_soft_ring_finish();
4950dc2366fSVenugopal Iyer 
4960dc2366fSVenugopal Iyer 
4977c478bd9Sstevel@tonic-gate 	return (0);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
500ee94b1c3SSebastien Roy /*
501ee94b1c3SSebastien Roy  * Initialize a GLDv3 driver's device ops.  A driver that manages its own ops
502ee94b1c3SSebastien Roy  * (e.g. softmac) may pass in a NULL ops argument.
503ee94b1c3SSebastien Roy  */
504da14cebeSEric Cheng void
mac_init_ops(struct dev_ops * ops,const char * name)505da14cebeSEric Cheng mac_init_ops(struct dev_ops *ops, const char *name)
506da14cebeSEric Cheng {
507ee94b1c3SSebastien Roy 	major_t major = ddi_name_to_major((char *)name);
508ee94b1c3SSebastien Roy 
509ee94b1c3SSebastien Roy 	/*
510ee94b1c3SSebastien Roy 	 * By returning on error below, we are not letting the driver continue
511ee94b1c3SSebastien Roy 	 * in an undefined context.  The mac_register() function will faill if
512ee94b1c3SSebastien Roy 	 * DN_GLDV3_DRIVER isn't set.
513ee94b1c3SSebastien Roy 	 */
514ee94b1c3SSebastien Roy 	if (major == DDI_MAJOR_T_NONE)
515ee94b1c3SSebastien Roy 		return;
516ee94b1c3SSebastien Roy 	LOCK_DEV_OPS(&devnamesp[major].dn_lock);
517ee94b1c3SSebastien Roy 	devnamesp[major].dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER);
518ee94b1c3SSebastien Roy 	UNLOCK_DEV_OPS(&devnamesp[major].dn_lock);
519ee94b1c3SSebastien Roy 	if (ops != NULL)
520da14cebeSEric Cheng 		dld_init_ops(ops, name);
521da14cebeSEric Cheng }
5227c478bd9Sstevel@tonic-gate 
523da14cebeSEric Cheng void
mac_fini_ops(struct dev_ops * ops)524da14cebeSEric Cheng mac_fini_ops(struct dev_ops *ops)
525da14cebeSEric Cheng {
526da14cebeSEric Cheng 	dld_fini_ops(ops);
527da14cebeSEric Cheng }
528da14cebeSEric Cheng 
529da14cebeSEric Cheng /*ARGSUSED*/
530d62bc4baSyz147064 static int
i_mac_constructor(void * buf,void * arg,int kmflag)531da14cebeSEric Cheng i_mac_constructor(void *buf, void *arg, int kmflag)
532da14cebeSEric Cheng {
533da14cebeSEric Cheng 	mac_impl_t	*mip = buf;
534da14cebeSEric Cheng 
535da14cebeSEric Cheng 	bzero(buf, sizeof (mac_impl_t));
536da14cebeSEric Cheng 
537da14cebeSEric Cheng 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
538da14cebeSEric Cheng 
539da14cebeSEric Cheng 	rw_init(&mip->mi_rw_lock, NULL, RW_DRIVER, NULL);
540da14cebeSEric Cheng 	mutex_init(&mip->mi_notify_lock, NULL, MUTEX_DRIVER, NULL);
541da14cebeSEric Cheng 	mutex_init(&mip->mi_promisc_lock, NULL, MUTEX_DRIVER, NULL);
542da14cebeSEric Cheng 	mutex_init(&mip->mi_ring_lock, NULL, MUTEX_DEFAULT, NULL);
543da14cebeSEric Cheng 
544da14cebeSEric Cheng 	mip->mi_notify_cb_info.mcbi_lockp = &mip->mi_notify_lock;
545da14cebeSEric Cheng 	cv_init(&mip->mi_notify_cb_info.mcbi_cv, NULL, CV_DRIVER, NULL);
546da14cebeSEric Cheng 	mip->mi_promisc_cb_info.mcbi_lockp = &mip->mi_promisc_lock;
547da14cebeSEric Cheng 	cv_init(&mip->mi_promisc_cb_info.mcbi_cv, NULL, CV_DRIVER, NULL);
5484eaa4710SRishi Srivatsavai 
5494eaa4710SRishi Srivatsavai 	mutex_init(&mip->mi_bridge_lock, NULL, MUTEX_DEFAULT, NULL);
5504eaa4710SRishi Srivatsavai 
551da14cebeSEric Cheng 	return (0);
552da14cebeSEric Cheng }
553da14cebeSEric Cheng 
554da14cebeSEric Cheng /*ARGSUSED*/
555da14cebeSEric Cheng static void
i_mac_destructor(void * buf,void * arg)556da14cebeSEric Cheng i_mac_destructor(void *buf, void *arg)
557da14cebeSEric Cheng {
558da14cebeSEric Cheng 	mac_impl_t	*mip = buf;
559da14cebeSEric Cheng 	mac_cb_info_t	*mcbi;
560da14cebeSEric Cheng 
561da14cebeSEric Cheng 	ASSERT(mip->mi_ref == 0);
562da14cebeSEric Cheng 	ASSERT(mip->mi_active == 0);
563da14cebeSEric Cheng 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
564da14cebeSEric Cheng 	ASSERT(mip->mi_devpromisc == 0);
565da14cebeSEric Cheng 	ASSERT(mip->mi_ksp == NULL);
566da14cebeSEric Cheng 	ASSERT(mip->mi_kstat_count == 0);
567da14cebeSEric Cheng 	ASSERT(mip->mi_nclients == 0);
568da14cebeSEric Cheng 	ASSERT(mip->mi_nactiveclients == 0);
569ae6aa22aSVenugopal Iyer 	ASSERT(mip->mi_single_active_client == NULL);
570da14cebeSEric Cheng 	ASSERT(mip->mi_state_flags == 0);
571da14cebeSEric Cheng 	ASSERT(mip->mi_factory_addr == NULL);
572da14cebeSEric Cheng 	ASSERT(mip->mi_factory_addr_num == 0);
573da14cebeSEric Cheng 	ASSERT(mip->mi_default_tx_ring == NULL);
574da14cebeSEric Cheng 
575da14cebeSEric Cheng 	mcbi = &mip->mi_notify_cb_info;
576da14cebeSEric Cheng 	ASSERT(mcbi->mcbi_del_cnt == 0 && mcbi->mcbi_walker_cnt == 0);
577da14cebeSEric Cheng 	ASSERT(mip->mi_notify_bits == 0);
578da14cebeSEric Cheng 	ASSERT(mip->mi_notify_thread == NULL);
579da14cebeSEric Cheng 	ASSERT(mcbi->mcbi_lockp == &mip->mi_notify_lock);
580da14cebeSEric Cheng 	mcbi->mcbi_lockp = NULL;
581da14cebeSEric Cheng 
582da14cebeSEric Cheng 	mcbi = &mip->mi_promisc_cb_info;
583da14cebeSEric Cheng 	ASSERT(mcbi->mcbi_del_cnt == 0 && mip->mi_promisc_list == NULL);
584da14cebeSEric Cheng 	ASSERT(mip->mi_promisc_list == NULL);
585da14cebeSEric Cheng 	ASSERT(mcbi->mcbi_lockp == &mip->mi_promisc_lock);
586da14cebeSEric Cheng 	mcbi->mcbi_lockp = NULL;
587da14cebeSEric Cheng 
588da14cebeSEric Cheng 	ASSERT(mip->mi_bcast_ngrps == 0 && mip->mi_bcast_grp == NULL);
589da14cebeSEric Cheng 	ASSERT(mip->mi_perim_owner == NULL && mip->mi_perim_ocnt == 0);
590da14cebeSEric Cheng 
591da14cebeSEric Cheng 	rw_destroy(&mip->mi_rw_lock);
592da14cebeSEric Cheng 
593da14cebeSEric Cheng 	mutex_destroy(&mip->mi_promisc_lock);
594da14cebeSEric Cheng 	cv_destroy(&mip->mi_promisc_cb_info.mcbi_cv);
595da14cebeSEric Cheng 	mutex_destroy(&mip->mi_notify_lock);
596da14cebeSEric Cheng 	cv_destroy(&mip->mi_notify_cb_info.mcbi_cv);
597da14cebeSEric Cheng 	mutex_destroy(&mip->mi_ring_lock);
5984eaa4710SRishi Srivatsavai 
5994eaa4710SRishi Srivatsavai 	ASSERT(mip->mi_bridge_link == NULL);
600da14cebeSEric Cheng }
601da14cebeSEric Cheng 
602da14cebeSEric Cheng /* ARGSUSED */
603da14cebeSEric Cheng static int
i_mac_ring_ctor(void * buf,void * arg,int kmflag)604da14cebeSEric Cheng i_mac_ring_ctor(void *buf, void *arg, int kmflag)
605da14cebeSEric Cheng {
606da14cebeSEric Cheng 	mac_ring_t *ring = (mac_ring_t *)buf;
607da14cebeSEric Cheng 
608da14cebeSEric Cheng 	bzero(ring, sizeof (mac_ring_t));
609da14cebeSEric Cheng 	cv_init(&ring->mr_cv, NULL, CV_DEFAULT, NULL);
610da14cebeSEric Cheng 	mutex_init(&ring->mr_lock, NULL, MUTEX_DEFAULT, NULL);
611da14cebeSEric Cheng 	ring->mr_state = MR_FREE;
612da14cebeSEric Cheng 	return (0);
613da14cebeSEric Cheng }
614da14cebeSEric Cheng 
615da14cebeSEric Cheng /* ARGSUSED */
616da14cebeSEric Cheng static void
i_mac_ring_dtor(void * buf,void * arg)617da14cebeSEric Cheng i_mac_ring_dtor(void *buf, void *arg)
618da14cebeSEric Cheng {
619da14cebeSEric Cheng 	mac_ring_t *ring = (mac_ring_t *)buf;
620da14cebeSEric Cheng 
621da14cebeSEric Cheng 	cv_destroy(&ring->mr_cv);
622da14cebeSEric Cheng 	mutex_destroy(&ring->mr_lock);
623da14cebeSEric Cheng }
624da14cebeSEric Cheng 
625da14cebeSEric Cheng /*
626da14cebeSEric Cheng  * Common functions to do mac callback addition and deletion. Currently this is
627da14cebeSEric Cheng  * used by promisc callbacks and notify callbacks. List addition and deletion
628da14cebeSEric Cheng  * need to take care of list walkers. List walkers in general, can't hold list
629da14cebeSEric Cheng  * locks and make upcall callbacks due to potential lock order and recursive
630da14cebeSEric Cheng  * reentry issues. Instead list walkers increment the list walker count to mark
631da14cebeSEric Cheng  * the presence of a walker thread. Addition can be carefully done to ensure
632da14cebeSEric Cheng  * that the list walker always sees either the old list or the new list.
633da14cebeSEric Cheng  * However the deletion can't be done while the walker is active, instead the
634da14cebeSEric Cheng  * deleting thread simply marks the entry as logically deleted. The last walker
635da14cebeSEric Cheng  * physically deletes and frees up the logically deleted entries when the walk
636da14cebeSEric Cheng  * is complete.
637da14cebeSEric Cheng  */
638da14cebeSEric Cheng void
mac_callback_add(mac_cb_info_t * mcbi,mac_cb_t ** mcb_head,mac_cb_t * mcb_elem)639da14cebeSEric Cheng mac_callback_add(mac_cb_info_t *mcbi, mac_cb_t **mcb_head,
640da14cebeSEric Cheng     mac_cb_t *mcb_elem)
641da14cebeSEric Cheng {
642da14cebeSEric Cheng 	mac_cb_t	*p;
643da14cebeSEric Cheng 	mac_cb_t	**pp;
644da14cebeSEric Cheng 
645da14cebeSEric Cheng 	/* Verify it is not already in the list */
646da14cebeSEric Cheng 	for (pp = mcb_head; (p = *pp) != NULL; pp = &p->mcb_nextp) {
647da14cebeSEric Cheng 		if (p == mcb_elem)
648da14cebeSEric Cheng 			break;
649da14cebeSEric Cheng 	}
650da14cebeSEric Cheng 	VERIFY(p == NULL);
651da14cebeSEric Cheng 
652da14cebeSEric Cheng 	/*
653da14cebeSEric Cheng 	 * Add it to the head of the callback list. The membar ensures that
654da14cebeSEric Cheng 	 * the following list pointer manipulations reach global visibility
655da14cebeSEric Cheng 	 * in exactly the program order below.
656da14cebeSEric Cheng 	 */
657da14cebeSEric Cheng 	ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
658da14cebeSEric Cheng 
659da14cebeSEric Cheng 	mcb_elem->mcb_nextp = *mcb_head;
660da14cebeSEric Cheng 	membar_producer();
661da14cebeSEric Cheng 	*mcb_head = mcb_elem;
662da14cebeSEric Cheng }
663da14cebeSEric Cheng 
664da14cebeSEric Cheng /*
665da14cebeSEric Cheng  * Mark the entry as logically deleted. If there aren't any walkers unlink
666da14cebeSEric Cheng  * from the list. In either case return the corresponding status.
667da14cebeSEric Cheng  */
668da14cebeSEric Cheng boolean_t
mac_callback_remove(mac_cb_info_t * mcbi,mac_cb_t ** mcb_head,mac_cb_t * mcb_elem)669da14cebeSEric Cheng mac_callback_remove(mac_cb_info_t *mcbi, mac_cb_t **mcb_head,
670da14cebeSEric Cheng     mac_cb_t *mcb_elem)
671da14cebeSEric Cheng {
672da14cebeSEric Cheng 	mac_cb_t	*p;
673da14cebeSEric Cheng 	mac_cb_t	**pp;
674da14cebeSEric Cheng 
675da14cebeSEric Cheng 	ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
676da14cebeSEric Cheng 	/*
677da14cebeSEric Cheng 	 * Search the callback list for the entry to be removed
678da14cebeSEric Cheng 	 */
679da14cebeSEric Cheng 	for (pp = mcb_head; (p = *pp) != NULL; pp = &p->mcb_nextp) {
680da14cebeSEric Cheng 		if (p == mcb_elem)
681da14cebeSEric Cheng 			break;
682da14cebeSEric Cheng 	}
683da14cebeSEric Cheng 	VERIFY(p != NULL);
684da14cebeSEric Cheng 
685da14cebeSEric Cheng 	/*
686da14cebeSEric Cheng 	 * If there are walkers just mark it as deleted and the last walker
687da14cebeSEric Cheng 	 * will remove from the list and free it.
688da14cebeSEric Cheng 	 */
689da14cebeSEric Cheng 	if (mcbi->mcbi_walker_cnt != 0) {
690da14cebeSEric Cheng 		p->mcb_flags |= MCB_CONDEMNED;
691da14cebeSEric Cheng 		mcbi->mcbi_del_cnt++;
692da14cebeSEric Cheng 		return (B_FALSE);
693da14cebeSEric Cheng 	}
694da14cebeSEric Cheng 
695da14cebeSEric Cheng 	ASSERT(mcbi->mcbi_del_cnt == 0);
696da14cebeSEric Cheng 	*pp = p->mcb_nextp;
697da14cebeSEric Cheng 	p->mcb_nextp = NULL;
698da14cebeSEric Cheng 	return (B_TRUE);
699da14cebeSEric Cheng }
700da14cebeSEric Cheng 
701da14cebeSEric Cheng /*
702da14cebeSEric Cheng  * Wait for all pending callback removals to be completed
703da14cebeSEric Cheng  */
704da14cebeSEric Cheng void
mac_callback_remove_wait(mac_cb_info_t * mcbi)705da14cebeSEric Cheng mac_callback_remove_wait(mac_cb_info_t *mcbi)
706da14cebeSEric Cheng {
707da14cebeSEric Cheng 	ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
708da14cebeSEric Cheng 	while (mcbi->mcbi_del_cnt != 0) {
709da14cebeSEric Cheng 		DTRACE_PROBE1(need_wait, mac_cb_info_t *, mcbi);
710da14cebeSEric Cheng 		cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
711da14cebeSEric Cheng 	}
712da14cebeSEric Cheng }
713da14cebeSEric Cheng 
714b237158dSPatrick Mooney void
mac_callback_barrier(mac_cb_info_t * mcbi)715b237158dSPatrick Mooney mac_callback_barrier(mac_cb_info_t *mcbi)
716b237158dSPatrick Mooney {
717b237158dSPatrick Mooney 	ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
718b237158dSPatrick Mooney 	ASSERT3U(mcbi->mcbi_barrier_cnt, <, UINT_MAX);
719b237158dSPatrick Mooney 
720b237158dSPatrick Mooney 	if (mcbi->mcbi_walker_cnt == 0) {
721b237158dSPatrick Mooney 		return;
722b237158dSPatrick Mooney 	}
723b237158dSPatrick Mooney 
724b237158dSPatrick Mooney 	mcbi->mcbi_barrier_cnt++;
725b237158dSPatrick Mooney 	do {
726b237158dSPatrick Mooney 		cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
727b237158dSPatrick Mooney 	} while (mcbi->mcbi_walker_cnt > 0);
728b237158dSPatrick Mooney 	mcbi->mcbi_barrier_cnt--;
729b237158dSPatrick Mooney 	cv_broadcast(&mcbi->mcbi_cv);
730b237158dSPatrick Mooney }
731b237158dSPatrick Mooney 
732b237158dSPatrick Mooney void
mac_callback_walker_enter(mac_cb_info_t * mcbi)733b237158dSPatrick Mooney mac_callback_walker_enter(mac_cb_info_t *mcbi)
734b237158dSPatrick Mooney {
735b237158dSPatrick Mooney 	mutex_enter(mcbi->mcbi_lockp);
736b237158dSPatrick Mooney 	/*
737b237158dSPatrick Mooney 	 * Incoming walkers should give precedence to timely clean-up of
738b237158dSPatrick Mooney 	 * deleted callback entries and requested barriers.
739b237158dSPatrick Mooney 	 */
740b237158dSPatrick Mooney 	while (mcbi->mcbi_del_cnt > 0 || mcbi->mcbi_barrier_cnt > 0) {
741b237158dSPatrick Mooney 		cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp);
742b237158dSPatrick Mooney 	}
743b237158dSPatrick Mooney 	mcbi->mcbi_walker_cnt++;
744b237158dSPatrick Mooney 	mutex_exit(mcbi->mcbi_lockp);
745b237158dSPatrick Mooney }
746b237158dSPatrick Mooney 
747da14cebeSEric Cheng /*
748da14cebeSEric Cheng  * The last mac callback walker does the cleanup. Walk the list and unlik
749da14cebeSEric Cheng  * all the logically deleted entries and construct a temporary list of
750da14cebeSEric Cheng  * removed entries. Return the list of removed entries to the caller.
751da14cebeSEric Cheng  */
752b237158dSPatrick Mooney static mac_cb_t *
mac_callback_walker_cleanup(mac_cb_info_t * mcbi,mac_cb_t ** mcb_head)753da14cebeSEric Cheng mac_callback_walker_cleanup(mac_cb_info_t *mcbi, mac_cb_t **mcb_head)
754da14cebeSEric Cheng {
755da14cebeSEric Cheng 	mac_cb_t	*p;
756da14cebeSEric Cheng 	mac_cb_t	**pp;
757da14cebeSEric Cheng 	mac_cb_t	*rmlist = NULL;		/* List of removed elements */
758da14cebeSEric Cheng 	int	cnt = 0;
759da14cebeSEric Cheng 
760da14cebeSEric Cheng 	ASSERT(MUTEX_HELD(mcbi->mcbi_lockp));
761da14cebeSEric Cheng 	ASSERT(mcbi->mcbi_del_cnt != 0 && mcbi->mcbi_walker_cnt == 0);
762da14cebeSEric Cheng 
763da14cebeSEric Cheng 	pp = mcb_head;
764da14cebeSEric Cheng 	while (*pp != NULL) {
765da14cebeSEric Cheng 		if ((*pp)->mcb_flags & MCB_CONDEMNED) {
766da14cebeSEric Cheng 			p = *pp;
767da14cebeSEric Cheng 			*pp = p->mcb_nextp;
768da14cebeSEric Cheng 			p->mcb_nextp = rmlist;
769da14cebeSEric Cheng 			rmlist = p;
770da14cebeSEric Cheng 			cnt++;
771da14cebeSEric Cheng 			continue;
772da14cebeSEric Cheng 		}
773da14cebeSEric Cheng 		pp = &(*pp)->mcb_nextp;
774da14cebeSEric Cheng 	}
775da14cebeSEric Cheng 
776da14cebeSEric Cheng 	ASSERT(mcbi->mcbi_del_cnt == cnt);
777da14cebeSEric Cheng 	mcbi->mcbi_del_cnt = 0;
778da14cebeSEric Cheng 	return (rmlist);
779da14cebeSEric Cheng }
780da14cebeSEric Cheng 
781b237158dSPatrick Mooney void
mac_callback_walker_exit(mac_cb_info_t * mcbi,mac_cb_t ** headp,boolean_t is_promisc)782b237158dSPatrick Mooney mac_callback_walker_exit(mac_cb_info_t *mcbi, mac_cb_t **headp,
783b237158dSPatrick Mooney     boolean_t is_promisc)
784b237158dSPatrick Mooney {
785b237158dSPatrick Mooney 	boolean_t do_wake = B_FALSE;
786b237158dSPatrick Mooney 
787b237158dSPatrick Mooney 	mutex_enter(mcbi->mcbi_lockp);
788b237158dSPatrick Mooney 
789b237158dSPatrick Mooney 	/* If walkers remain, nothing more can be done for now */
790b237158dSPatrick Mooney 	if (--mcbi->mcbi_walker_cnt != 0) {
791b237158dSPatrick Mooney 		mutex_exit(mcbi->mcbi_lockp);
792b237158dSPatrick Mooney 		return;
793b237158dSPatrick Mooney 	}
794b237158dSPatrick Mooney 
795b237158dSPatrick Mooney 	if (mcbi->mcbi_del_cnt != 0) {
796b237158dSPatrick Mooney 		mac_cb_t *rmlist;
797b237158dSPatrick Mooney 
798b237158dSPatrick Mooney 		rmlist = mac_callback_walker_cleanup(mcbi, headp);
799b237158dSPatrick Mooney 
800b237158dSPatrick Mooney 		if (!is_promisc) {
801b237158dSPatrick Mooney 			/* The "normal" non-promisc callback clean-up */
802b237158dSPatrick Mooney 			mac_callback_free(rmlist);
803b237158dSPatrick Mooney 		} else {
804b237158dSPatrick Mooney 			mac_cb_t *mcb, *mcb_next;
805b237158dSPatrick Mooney 
806b237158dSPatrick Mooney 			/*
807b237158dSPatrick Mooney 			 * The promisc callbacks are in 2 lists, one off the
808b237158dSPatrick Mooney 			 * 'mip' and another off the 'mcip' threaded by
809b237158dSPatrick Mooney 			 * mpi_mi_link and mpi_mci_link respectively.  There
810b237158dSPatrick Mooney 			 * is, however, only a single shared total walker
811b237158dSPatrick Mooney 			 * count, and an entry cannot be physically unlinked if
812b237158dSPatrick Mooney 			 * a walker is active on either list. The last walker
813b237158dSPatrick Mooney 			 * does this cleanup of logically deleted entries.
814b237158dSPatrick Mooney 			 *
815b237158dSPatrick Mooney 			 * With a list of callbacks deleted from above from
816b237158dSPatrick Mooney 			 * mi_promisc_list (headp), remove the corresponding
817b237158dSPatrick Mooney 			 * entry from mci_promisc_list (headp_pair) and free
818b237158dSPatrick Mooney 			 * the structure.
819b237158dSPatrick Mooney 			 */
820b237158dSPatrick Mooney 			for (mcb = rmlist; mcb != NULL; mcb = mcb_next) {
821b237158dSPatrick Mooney 				mac_promisc_impl_t *mpip;
822b237158dSPatrick Mooney 				mac_client_impl_t *mcip;
823b237158dSPatrick Mooney 
824b237158dSPatrick Mooney 				mcb_next = mcb->mcb_nextp;
825b237158dSPatrick Mooney 				mpip = (mac_promisc_impl_t *)mcb->mcb_objp;
826b237158dSPatrick Mooney 				mcip = mpip->mpi_mcip;
827b237158dSPatrick Mooney 
828b237158dSPatrick Mooney 				ASSERT3P(&mcip->mci_mip->mi_promisc_cb_info,
829b237158dSPatrick Mooney 				    ==, mcbi);
830b237158dSPatrick Mooney 				ASSERT3P(&mcip->mci_mip->mi_promisc_list,
831b237158dSPatrick Mooney 				    ==, headp);
832b237158dSPatrick Mooney 
833b237158dSPatrick Mooney 				VERIFY(mac_callback_remove(mcbi,
834b237158dSPatrick Mooney 				    &mcip->mci_promisc_list,
835b237158dSPatrick Mooney 				    &mpip->mpi_mci_link));
836b237158dSPatrick Mooney 				mcb->mcb_flags = 0;
837b237158dSPatrick Mooney 				mcb->mcb_nextp = NULL;
838b237158dSPatrick Mooney 				kmem_cache_free(mac_promisc_impl_cache, mpip);
839b237158dSPatrick Mooney 			}
840b237158dSPatrick Mooney 		}
841b237158dSPatrick Mooney 
842b237158dSPatrick Mooney 		/*
843b237158dSPatrick Mooney 		 * Wake any walker threads that could be waiting in
844b237158dSPatrick Mooney 		 * mac_callback_walker_enter() until deleted items have been
845b237158dSPatrick Mooney 		 * cleaned from the list.
846b237158dSPatrick Mooney 		 */
847b237158dSPatrick Mooney 		do_wake = B_TRUE;
848b237158dSPatrick Mooney 	}
849b237158dSPatrick Mooney 
850b237158dSPatrick Mooney 	if (mcbi->mcbi_barrier_cnt != 0) {
851b237158dSPatrick Mooney 		/*
852b237158dSPatrick Mooney 		 * One or more threads are waiting for all walkers to exit the
853b237158dSPatrick Mooney 		 * callback list.  Notify them, now that the list is clear.
854b237158dSPatrick Mooney 		 */
855b237158dSPatrick Mooney 		do_wake = B_TRUE;
856b237158dSPatrick Mooney 	}
857b237158dSPatrick Mooney 
858b237158dSPatrick Mooney 	if (do_wake) {
859b237158dSPatrick Mooney 		cv_broadcast(&mcbi->mcbi_cv);
860b237158dSPatrick Mooney 	}
861b237158dSPatrick Mooney 	mutex_exit(mcbi->mcbi_lockp);
862b237158dSPatrick Mooney }
863b237158dSPatrick Mooney 
864b237158dSPatrick Mooney static boolean_t
mac_callback_lookup(mac_cb_t ** mcb_headp,mac_cb_t * mcb_elem)865da14cebeSEric Cheng mac_callback_lookup(mac_cb_t **mcb_headp, mac_cb_t *mcb_elem)
866da14cebeSEric Cheng {
867da14cebeSEric Cheng 	mac_cb_t	*mcb;
868da14cebeSEric Cheng 
869da14cebeSEric Cheng 	/* Verify it is not already in the list */
870da14cebeSEric Cheng 	for (mcb = *mcb_headp; mcb != NULL; mcb = mcb->mcb_nextp) {
871da14cebeSEric Cheng 		if (mcb == mcb_elem)
872da14cebeSEric Cheng 			return (B_TRUE);
873da14cebeSEric Cheng 	}
874da14cebeSEric Cheng 
875da14cebeSEric Cheng 	return (B_FALSE);
876da14cebeSEric Cheng }
877da14cebeSEric Cheng 
878b237158dSPatrick Mooney static boolean_t
mac_callback_find(mac_cb_info_t * mcbi,mac_cb_t ** mcb_headp,mac_cb_t * mcb_elem)879da14cebeSEric Cheng mac_callback_find(mac_cb_info_t *mcbi, mac_cb_t **mcb_headp, mac_cb_t *mcb_elem)
880da14cebeSEric Cheng {
881da14cebeSEric Cheng 	boolean_t	found;
882da14cebeSEric Cheng 
883da14cebeSEric Cheng 	mutex_enter(mcbi->mcbi_lockp);
884da14cebeSEric Cheng 	found = mac_callback_lookup(mcb_headp, mcb_elem);
885da14cebeSEric Cheng 	mutex_exit(mcbi->mcbi_lockp);
886da14cebeSEric Cheng 
887da14cebeSEric Cheng 	return (found);
888da14cebeSEric Cheng }
889da14cebeSEric Cheng 
890da14cebeSEric Cheng /* Free the list of removed callbacks */
891da14cebeSEric Cheng void
mac_callback_free(mac_cb_t * rmlist)892da14cebeSEric Cheng mac_callback_free(mac_cb_t *rmlist)
893da14cebeSEric Cheng {
894da14cebeSEric Cheng 	mac_cb_t	*mcb;
895da14cebeSEric Cheng 	mac_cb_t	*mcb_next;
896da14cebeSEric Cheng 
897da14cebeSEric Cheng 	for (mcb = rmlist; mcb != NULL; mcb = mcb_next) {
898da14cebeSEric Cheng 		mcb_next = mcb->mcb_nextp;
899da14cebeSEric Cheng 		kmem_free(mcb->mcb_objp, mcb->mcb_objsize);
900da14cebeSEric Cheng 	}
901da14cebeSEric Cheng }
902da14cebeSEric Cheng 
903da14cebeSEric Cheng void
i_mac_notify(mac_impl_t * mip,mac_notify_type_t type)904da14cebeSEric Cheng i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
905da14cebeSEric Cheng {
906da14cebeSEric Cheng 	mac_cb_info_t	*mcbi;
907da14cebeSEric Cheng 
908da14cebeSEric Cheng 	/*
909da14cebeSEric Cheng 	 * Signal the notify thread even after mi_ref has become zero and
910da14cebeSEric Cheng 	 * mi_disabled is set. The synchronization with the notify thread
911da14cebeSEric Cheng 	 * happens in mac_unregister and that implies the driver must make
912da14cebeSEric Cheng 	 * sure it is single-threaded (with respect to mac calls) and that
913da14cebeSEric Cheng 	 * all pending mac calls have returned before it calls mac_unregister
914da14cebeSEric Cheng 	 */
915da14cebeSEric Cheng 	rw_enter(&i_mac_impl_lock, RW_READER);
916da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_DISABLED)
917da14cebeSEric Cheng 		goto exit;
918da14cebeSEric Cheng 
919da14cebeSEric Cheng 	/*
920da14cebeSEric Cheng 	 * Guard against incorrect notifications.  (Running a newer
921da14cebeSEric Cheng 	 * mac client against an older implementation?)
922da14cebeSEric Cheng 	 */
923da14cebeSEric Cheng 	if (type >= MAC_NNOTE)
924da14cebeSEric Cheng 		goto exit;
925da14cebeSEric Cheng 
926da14cebeSEric Cheng 	mcbi = &mip->mi_notify_cb_info;
927da14cebeSEric Cheng 	mutex_enter(mcbi->mcbi_lockp);
928da14cebeSEric Cheng 	mip->mi_notify_bits |= (1 << type);
929da14cebeSEric Cheng 	cv_broadcast(&mcbi->mcbi_cv);
930da14cebeSEric Cheng 	mutex_exit(mcbi->mcbi_lockp);
931da14cebeSEric Cheng 
932da14cebeSEric Cheng exit:
933da14cebeSEric Cheng 	rw_exit(&i_mac_impl_lock);
934da14cebeSEric Cheng }
935da14cebeSEric Cheng 
936da14cebeSEric Cheng /*
937da14cebeSEric Cheng  * Mac serialization primitives. Please see the block comment at the
938da14cebeSEric Cheng  * top of the file.
939da14cebeSEric Cheng  */
940da14cebeSEric Cheng void
i_mac_perim_enter(mac_impl_t * mip)941da14cebeSEric Cheng i_mac_perim_enter(mac_impl_t *mip)
942da14cebeSEric Cheng {
943da14cebeSEric Cheng 	mac_client_impl_t	*mcip;
944da14cebeSEric Cheng 
945da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_IS_VNIC) {
946da14cebeSEric Cheng 		/*
947da14cebeSEric Cheng 		 * This is a VNIC. Return the lower mac since that is what
948da14cebeSEric Cheng 		 * we want to serialize on.
949da14cebeSEric Cheng 		 */
950da14cebeSEric Cheng 		mcip = mac_vnic_lower(mip);
951da14cebeSEric Cheng 		mip = mcip->mci_mip;
952da14cebeSEric Cheng 	}
953da14cebeSEric Cheng 
954da14cebeSEric Cheng 	mutex_enter(&mip->mi_perim_lock);
955da14cebeSEric Cheng 	if (mip->mi_perim_owner == curthread) {
956da14cebeSEric Cheng 		mip->mi_perim_ocnt++;
957da14cebeSEric Cheng 		mutex_exit(&mip->mi_perim_lock);
958da14cebeSEric Cheng 		return;
959da14cebeSEric Cheng 	}
960da14cebeSEric Cheng 
961da14cebeSEric Cheng 	while (mip->mi_perim_owner != NULL)
962da14cebeSEric Cheng 		cv_wait(&mip->mi_perim_cv, &mip->mi_perim_lock);
963da14cebeSEric Cheng 
964da14cebeSEric Cheng 	mip->mi_perim_owner = curthread;
965da14cebeSEric Cheng 	ASSERT(mip->mi_perim_ocnt == 0);
966da14cebeSEric Cheng 	mip->mi_perim_ocnt++;
967da14cebeSEric Cheng #ifdef DEBUG
968da14cebeSEric Cheng 	mip->mi_perim_stack_depth = getpcstack(mip->mi_perim_stack,
969da14cebeSEric Cheng 	    MAC_PERIM_STACK_DEPTH);
970da14cebeSEric Cheng #endif
971da14cebeSEric Cheng 	mutex_exit(&mip->mi_perim_lock);
972da14cebeSEric Cheng }
973da14cebeSEric Cheng 
974da14cebeSEric Cheng int
i_mac_perim_enter_nowait(mac_impl_t * mip)975da14cebeSEric Cheng i_mac_perim_enter_nowait(mac_impl_t *mip)
976da14cebeSEric Cheng {
977da14cebeSEric Cheng 	/*
978da14cebeSEric Cheng 	 * The vnic is a special case, since the serialization is done based
979da14cebeSEric Cheng 	 * on the lower mac. If the lower mac is busy, it does not imply the
980da14cebeSEric Cheng 	 * vnic can't be unregistered. But in the case of other drivers,
981da14cebeSEric Cheng 	 * a busy perimeter or open mac handles implies that the mac is busy
982da14cebeSEric Cheng 	 * and can't be unregistered.
983da14cebeSEric Cheng 	 */
984da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_IS_VNIC) {
985da14cebeSEric Cheng 		i_mac_perim_enter(mip);
986da14cebeSEric Cheng 		return (0);
987da14cebeSEric Cheng 	}
988da14cebeSEric Cheng 
989da14cebeSEric Cheng 	mutex_enter(&mip->mi_perim_lock);
990da14cebeSEric Cheng 	if (mip->mi_perim_owner != NULL) {
991da14cebeSEric Cheng 		mutex_exit(&mip->mi_perim_lock);
992da14cebeSEric Cheng 		return (EBUSY);
993da14cebeSEric Cheng 	}
994da14cebeSEric Cheng 	ASSERT(mip->mi_perim_ocnt == 0);
995da14cebeSEric Cheng 	mip->mi_perim_owner = curthread;
996da14cebeSEric Cheng 	mip->mi_perim_ocnt++;
997da14cebeSEric Cheng 	mutex_exit(&mip->mi_perim_lock);
998da14cebeSEric Cheng 
999da14cebeSEric Cheng 	return (0);
1000da14cebeSEric Cheng }
1001da14cebeSEric Cheng 
1002da14cebeSEric Cheng void
i_mac_perim_exit(mac_impl_t * mip)1003da14cebeSEric Cheng i_mac_perim_exit(mac_impl_t *mip)
1004da14cebeSEric Cheng {
1005da14cebeSEric Cheng 	mac_client_impl_t *mcip;
1006da14cebeSEric Cheng 
1007da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_IS_VNIC) {
1008da14cebeSEric Cheng 		/*
1009da14cebeSEric Cheng 		 * This is a VNIC. Return the lower mac since that is what
1010da14cebeSEric Cheng 		 * we want to serialize on.
1011da14cebeSEric Cheng 		 */
1012da14cebeSEric Cheng 		mcip = mac_vnic_lower(mip);
1013da14cebeSEric Cheng 		mip = mcip->mci_mip;
1014da14cebeSEric Cheng 	}
1015da14cebeSEric Cheng 
1016da14cebeSEric Cheng 	ASSERT(mip->mi_perim_owner == curthread && mip->mi_perim_ocnt != 0);
1017da14cebeSEric Cheng 
1018da14cebeSEric Cheng 	mutex_enter(&mip->mi_perim_lock);
1019da14cebeSEric Cheng 	if (--mip->mi_perim_ocnt == 0) {
1020da14cebeSEric Cheng 		mip->mi_perim_owner = NULL;
1021da14cebeSEric Cheng 		cv_signal(&mip->mi_perim_cv);
1022da14cebeSEric Cheng 	}
1023da14cebeSEric Cheng 	mutex_exit(&mip->mi_perim_lock);
1024da14cebeSEric Cheng }
1025da14cebeSEric Cheng 
1026da14cebeSEric Cheng /*
1027da14cebeSEric Cheng  * Returns whether the current thread holds the mac perimeter. Used in making
1028da14cebeSEric Cheng  * assertions.
1029da14cebeSEric Cheng  */
1030da14cebeSEric Cheng boolean_t
mac_perim_held(mac_handle_t mh)1031da14cebeSEric Cheng mac_perim_held(mac_handle_t mh)
1032da14cebeSEric Cheng {
1033da14cebeSEric Cheng 	mac_impl_t	*mip = (mac_impl_t *)mh;
1034da14cebeSEric Cheng 	mac_client_impl_t *mcip;
1035da14cebeSEric Cheng 
1036da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_IS_VNIC) {
1037da14cebeSEric Cheng 		/*
1038da14cebeSEric Cheng 		 * This is a VNIC. Return the lower mac since that is what
1039da14cebeSEric Cheng 		 * we want to serialize on.
1040da14cebeSEric Cheng 		 */
1041da14cebeSEric Cheng 		mcip = mac_vnic_lower(mip);
1042da14cebeSEric Cheng 		mip = mcip->mci_mip;
1043da14cebeSEric Cheng 	}
1044da14cebeSEric Cheng 	return (mip->mi_perim_owner == curthread);
1045da14cebeSEric Cheng }
1046da14cebeSEric Cheng 
1047da14cebeSEric Cheng /*
1048da14cebeSEric Cheng  * mac client interfaces to enter the mac perimeter of a mac end point, given
1049da14cebeSEric Cheng  * its mac handle, or macname or linkid.
1050da14cebeSEric Cheng  */
1051da14cebeSEric Cheng void
mac_perim_enter_by_mh(mac_handle_t mh,mac_perim_handle_t * mphp)1052da14cebeSEric Cheng mac_perim_enter_by_mh(mac_handle_t mh, mac_perim_handle_t *mphp)
1053da14cebeSEric Cheng {
1054da14cebeSEric Cheng 	mac_impl_t	*mip = (mac_impl_t *)mh;
1055da14cebeSEric Cheng 
1056da14cebeSEric Cheng 	i_mac_perim_enter(mip);
1057da14cebeSEric Cheng 	/*
1058da14cebeSEric Cheng 	 * The mac_perim_handle_t returned encodes the 'mip' and whether a
1059da14cebeSEric Cheng 	 * mac_open has been done internally while entering the perimeter.
1060da14cebeSEric Cheng 	 * This information is used in mac_perim_exit
1061da14cebeSEric Cheng 	 */
1062da14cebeSEric Cheng 	MAC_ENCODE_MPH(*mphp, mip, 0);
1063da14cebeSEric Cheng }
1064da14cebeSEric Cheng 
1065da14cebeSEric Cheng int
mac_perim_enter_by_macname(const char * name,mac_perim_handle_t * mphp)1066da14cebeSEric Cheng mac_perim_enter_by_macname(const char *name, mac_perim_handle_t *mphp)
1067da14cebeSEric Cheng {
1068da14cebeSEric Cheng 	int	err;
1069da14cebeSEric Cheng 	mac_handle_t	mh;
1070da14cebeSEric Cheng 
1071da14cebeSEric Cheng 	if ((err = mac_open(name, &mh)) != 0)
1072da14cebeSEric Cheng 		return (err);
1073da14cebeSEric Cheng 
1074da14cebeSEric Cheng 	mac_perim_enter_by_mh(mh, mphp);
1075da14cebeSEric Cheng 	MAC_ENCODE_MPH(*mphp, mh, 1);
1076da14cebeSEric Cheng 	return (0);
1077da14cebeSEric Cheng }
1078da14cebeSEric Cheng 
1079da14cebeSEric Cheng int
mac_perim_enter_by_linkid(datalink_id_t linkid,mac_perim_handle_t * mphp)1080da14cebeSEric Cheng mac_perim_enter_by_linkid(datalink_id_t linkid, mac_perim_handle_t *mphp)
1081da14cebeSEric Cheng {
1082da14cebeSEric Cheng 	int	err;
1083da14cebeSEric Cheng 	mac_handle_t	mh;
1084da14cebeSEric Cheng 
1085da14cebeSEric Cheng 	if ((err = mac_open_by_linkid(linkid, &mh)) != 0)
1086da14cebeSEric Cheng 		return (err);
1087da14cebeSEric Cheng 
1088da14cebeSEric Cheng 	mac_perim_enter_by_mh(mh, mphp);
1089da14cebeSEric Cheng 	MAC_ENCODE_MPH(*mphp, mh, 1);
1090da14cebeSEric Cheng 	return (0);
1091da14cebeSEric Cheng }
1092da14cebeSEric Cheng 
1093da14cebeSEric Cheng void
mac_perim_exit(mac_perim_handle_t mph)1094da14cebeSEric Cheng mac_perim_exit(mac_perim_handle_t mph)
1095da14cebeSEric Cheng {
1096da14cebeSEric Cheng 	mac_impl_t	*mip;
1097da14cebeSEric Cheng 	boolean_t	need_close;
1098da14cebeSEric Cheng 
1099da14cebeSEric Cheng 	MAC_DECODE_MPH(mph, mip, need_close);
1100da14cebeSEric Cheng 	i_mac_perim_exit(mip);
1101da14cebeSEric Cheng 	if (need_close)
1102da14cebeSEric Cheng 		mac_close((mac_handle_t)mip);
1103da14cebeSEric Cheng }
1104da14cebeSEric Cheng 
1105da14cebeSEric Cheng int
mac_hold(const char * macname,mac_impl_t ** pmip)1106d62bc4baSyz147064 mac_hold(const char *macname, mac_impl_t **pmip)
11077c478bd9Sstevel@tonic-gate {
11087c478bd9Sstevel@tonic-gate 	mac_impl_t	*mip;
11097c478bd9Sstevel@tonic-gate 	int		err;
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	/*
11127c478bd9Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
11137c478bd9Sstevel@tonic-gate 	 * buffer.
11147c478bd9Sstevel@tonic-gate 	 */
1115ba2e4443Sseb 	if (strlen(macname) >= MAXNAMELEN)
11167c478bd9Sstevel@tonic-gate 		return (EINVAL);
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	/*
11197c478bd9Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
11207c478bd9Sstevel@tonic-gate 	 */
1121210db224Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1122ba2e4443Sseb 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
1123210db224Sericheng 	    (mod_hash_val_t *)&mip);
1124d62bc4baSyz147064 
1125210db224Sericheng 	if (err != 0) {
1126d62bc4baSyz147064 		rw_exit(&i_mac_impl_lock);
1127d62bc4baSyz147064 		return (ENOENT);
1128210db224Sericheng 	}
11297c478bd9Sstevel@tonic-gate 
1130da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_DISABLED) {
1131210db224Sericheng 		rw_exit(&i_mac_impl_lock);
1132d62bc4baSyz147064 		return (ENOENT);
1133d62bc4baSyz147064 	}
1134d62bc4baSyz147064 
1135da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_EXCLUSIVE_HELD) {
1136d62bc4baSyz147064 		rw_exit(&i_mac_impl_lock);
1137d62bc4baSyz147064 		return (EBUSY);
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 	mip->mi_ref++;
1141210db224Sericheng 	rw_exit(&i_mac_impl_lock);
11427c478bd9Sstevel@tonic-gate 
1143d62bc4baSyz147064 	*pmip = mip;
1144d62bc4baSyz147064 	return (0);
1145d62bc4baSyz147064 }
1146d62bc4baSyz147064 
1147da14cebeSEric Cheng void
mac_rele(mac_impl_t * mip)1148d62bc4baSyz147064 mac_rele(mac_impl_t *mip)
1149d62bc4baSyz147064 {
1150d62bc4baSyz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1151d62bc4baSyz147064 	ASSERT(mip->mi_ref != 0);
1152da14cebeSEric Cheng 	if (--mip->mi_ref == 0) {
1153da14cebeSEric Cheng 		ASSERT(mip->mi_nactiveclients == 0 &&
1154da14cebeSEric Cheng 		    !(mip->mi_state_flags & MIS_EXCLUSIVE));
1155da14cebeSEric Cheng 	}
1156d62bc4baSyz147064 	rw_exit(&i_mac_impl_lock);
1157d62bc4baSyz147064 }
1158d62bc4baSyz147064 
1159da14cebeSEric Cheng /*
11603bdd2dd4SMichael Lim  * Private GLDv3 function to start a MAC instance.
1161da14cebeSEric Cheng  */
1162d62bc4baSyz147064 int
mac_start(mac_handle_t mh)11633bdd2dd4SMichael Lim mac_start(mac_handle_t mh)
1164d62bc4baSyz147064 {
11653bdd2dd4SMichael Lim 	mac_impl_t	*mip = (mac_impl_t *)mh;
1166da14cebeSEric Cheng 	int		err = 0;
11670dc2366fSVenugopal Iyer 	mac_group_t	*defgrp;
1168d62bc4baSyz147064 
1169da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1170ba2e4443Sseb 	ASSERT(mip->mi_start != NULL);
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	/*
11737c478bd9Sstevel@tonic-gate 	 * Check whether the device is already started.
11747c478bd9Sstevel@tonic-gate 	 */
1175da14cebeSEric Cheng 	if (mip->mi_active++ == 0) {
1176da14cebeSEric Cheng 		mac_ring_t *ring = NULL;
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 		/*
11797c478bd9Sstevel@tonic-gate 		 * Start the device.
11807c478bd9Sstevel@tonic-gate 		 */
1181da14cebeSEric Cheng 		err = mip->mi_start(mip->mi_driver);
1182da14cebeSEric Cheng 		if (err != 0) {
1183da14cebeSEric Cheng 			mip->mi_active--;
11847c478bd9Sstevel@tonic-gate 			return (err);
11857c478bd9Sstevel@tonic-gate 		}
11867c478bd9Sstevel@tonic-gate 
1187da14cebeSEric Cheng 		/*
1188da14cebeSEric Cheng 		 * Start the default tx ring.
1189da14cebeSEric Cheng 		 */
1190da14cebeSEric Cheng 		if (mip->mi_default_tx_ring != NULL) {
1191da14cebeSEric Cheng 
1192da14cebeSEric Cheng 			ring = (mac_ring_t *)mip->mi_default_tx_ring;
11930dc2366fSVenugopal Iyer 			if (ring->mr_state != MR_INUSE) {
1194da14cebeSEric Cheng 				err = mac_start_ring(ring);
1195da14cebeSEric Cheng 				if (err != 0) {
1196da14cebeSEric Cheng 					mip->mi_active--;
1197da14cebeSEric Cheng 					return (err);
1198da14cebeSEric Cheng 				}
11990dc2366fSVenugopal Iyer 			}
1200da14cebeSEric Cheng 		}
1201da14cebeSEric Cheng 
12020dc2366fSVenugopal Iyer 		if ((defgrp = MAC_DEFAULT_RX_GROUP(mip)) != NULL) {
1203da14cebeSEric Cheng 			/*
120484de666eSRyan Zezeski 			 * Start the default group which is responsible
120584de666eSRyan Zezeski 			 * for receiving broadcast and multicast
120684de666eSRyan Zezeski 			 * traffic for both primary and non-primary
120784de666eSRyan Zezeski 			 * MAC clients.
1208da14cebeSEric Cheng 			 */
12090dc2366fSVenugopal Iyer 			ASSERT(defgrp->mrg_state == MAC_GROUP_STATE_REGISTERED);
12100dc2366fSVenugopal Iyer 			err = mac_start_group_and_rings(defgrp);
1211da14cebeSEric Cheng 			if (err != 0) {
1212da14cebeSEric Cheng 				mip->mi_active--;
12130dc2366fSVenugopal Iyer 				if ((ring != NULL) &&
12140dc2366fSVenugopal Iyer 				    (ring->mr_state == MR_INUSE))
1215da14cebeSEric Cheng 					mac_stop_ring(ring);
1216da14cebeSEric Cheng 				return (err);
1217da14cebeSEric Cheng 			}
12180dc2366fSVenugopal Iyer 			mac_set_group_state(defgrp, MAC_GROUP_STATE_SHARED);
1219da14cebeSEric Cheng 		}
1220da14cebeSEric Cheng 	}
1221da14cebeSEric Cheng 
1222da14cebeSEric Cheng 	return (err);
1223da14cebeSEric Cheng }
1224da14cebeSEric Cheng 
1225da14cebeSEric Cheng /*
12263bdd2dd4SMichael Lim  * Private GLDv3 function to stop a MAC instance.
1227da14cebeSEric Cheng  */
12287c478bd9Sstevel@tonic-gate void
mac_stop(mac_handle_t mh)12293bdd2dd4SMichael Lim mac_stop(mac_handle_t mh)
12307c478bd9Sstevel@tonic-gate {
12313bdd2dd4SMichael Lim 	mac_impl_t	*mip = (mac_impl_t *)mh;
12320dc2366fSVenugopal Iyer 	mac_group_t	*grp;
12333bdd2dd4SMichael Lim 
1234ba2e4443Sseb 	ASSERT(mip->mi_stop != NULL);
1235da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	/*
12387c478bd9Sstevel@tonic-gate 	 * Check whether the device is still needed.
12397c478bd9Sstevel@tonic-gate 	 */
12407c478bd9Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
1241da14cebeSEric Cheng 	if (--mip->mi_active == 0) {
12420dc2366fSVenugopal Iyer 		if ((grp = MAC_DEFAULT_RX_GROUP(mip)) != NULL) {
12437c478bd9Sstevel@tonic-gate 			/*
1244da14cebeSEric Cheng 			 * There should be no more active clients since the
1245da14cebeSEric Cheng 			 * MAC is being stopped. Stop the default RX group
1246da14cebeSEric Cheng 			 * and transition it back to registered state.
12470dc2366fSVenugopal Iyer 			 *
1248da14cebeSEric Cheng 			 * When clients are torn down, the groups
1249da14cebeSEric Cheng 			 * are release via mac_release_rx_group which
1250da14cebeSEric Cheng 			 * knows the the default group is always in
1251da14cebeSEric Cheng 			 * started mode since broadcast uses it. So
1252da14cebeSEric Cheng 			 * we can assert that their are no clients
1253da14cebeSEric Cheng 			 * (since mac_bcast_add doesn't register itself
1254da14cebeSEric Cheng 			 * as a client) and group is in SHARED state.
1255da14cebeSEric Cheng 			 */
1256da14cebeSEric Cheng 			ASSERT(grp->mrg_state == MAC_GROUP_STATE_SHARED);
12570dc2366fSVenugopal Iyer 			ASSERT(MAC_GROUP_NO_CLIENT(grp) &&
1258da14cebeSEric Cheng 			    mip->mi_nactiveclients == 0);
1259da14cebeSEric Cheng 			mac_stop_group_and_rings(grp);
12600dc2366fSVenugopal Iyer 			mac_set_group_state(grp, MAC_GROUP_STATE_REGISTERED);
1261da14cebeSEric Cheng 		}
1262da14cebeSEric Cheng 
1263da14cebeSEric Cheng 		if (mip->mi_default_tx_ring != NULL) {
1264da14cebeSEric Cheng 			mac_ring_t *ring;
1265da14cebeSEric Cheng 
1266da14cebeSEric Cheng 			ring = (mac_ring_t *)mip->mi_default_tx_ring;
12670dc2366fSVenugopal Iyer 			if (ring->mr_state == MR_INUSE) {
1268da14cebeSEric Cheng 				mac_stop_ring(ring);
12690dc2366fSVenugopal Iyer 				ring->mr_flag = 0;
12700dc2366fSVenugopal Iyer 			}
12717c478bd9Sstevel@tonic-gate 		}
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 		/*
12747c478bd9Sstevel@tonic-gate 		 * Stop the device.
12757c478bd9Sstevel@tonic-gate 		 */
1276ba2e4443Sseb 		mip->mi_stop(mip->mi_driver);
1277ed8845d8Skrgopi 	}
1278ed8845d8Skrgopi }
1279ed8845d8Skrgopi 
12807c478bd9Sstevel@tonic-gate int
i_mac_promisc_set(mac_impl_t * mip,boolean_t on)1281d91a22bfSGirish Moodalbail i_mac_promisc_set(mac_impl_t *mip, boolean_t on)
12827c478bd9Sstevel@tonic-gate {
12837c478bd9Sstevel@tonic-gate 	int		err = 0;
12847c478bd9Sstevel@tonic-gate 
1285da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
1286ba2e4443Sseb 	ASSERT(mip->mi_setpromisc != NULL);
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	if (on) {
12897c478bd9Sstevel@tonic-gate 		/*
12907c478bd9Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
12917c478bd9Sstevel@tonic-gate 		 */
12927c478bd9Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
1293ba2e4443Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
1294ba2e4443Sseb 			if (err != 0) {
12957c478bd9Sstevel@tonic-gate 				mip->mi_devpromisc--;
1296da14cebeSEric Cheng 				return (err);
12977c478bd9Sstevel@tonic-gate 			}
12987c478bd9Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
12997c478bd9Sstevel@tonic-gate 		}
13007c478bd9Sstevel@tonic-gate 	} else {
1301da14cebeSEric Cheng 		if (mip->mi_devpromisc == 0)
1302da14cebeSEric Cheng 			return (EPROTO);
1303da14cebeSEric Cheng 
13047c478bd9Sstevel@tonic-gate 		/*
13057c478bd9Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
13067c478bd9Sstevel@tonic-gate 		 * enabling.
13077c478bd9Sstevel@tonic-gate 		 */
13087c478bd9Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
1309ba2e4443Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
1310ba2e4443Sseb 			if (err != 0) {
13117c478bd9Sstevel@tonic-gate 				mip->mi_devpromisc++;
1312da14cebeSEric Cheng 				return (err);
13137c478bd9Sstevel@tonic-gate 			}
13147c478bd9Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
13157c478bd9Sstevel@tonic-gate 		}
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 
1318da14cebeSEric Cheng 	return (0);
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
1321da14cebeSEric Cheng /*
1322da14cebeSEric Cheng  * The promiscuity state can change any time. If the caller needs to take
1323da14cebeSEric Cheng  * actions that are atomic with the promiscuity state, then the caller needs
1324da14cebeSEric Cheng  * to bracket the entire sequence with mac_perim_enter/exit
1325da14cebeSEric Cheng  */
13267c478bd9Sstevel@tonic-gate boolean_t
mac_promisc_get(mac_handle_t mh)1327d91a22bfSGirish Moodalbail mac_promisc_get(mac_handle_t mh)
13287c478bd9Sstevel@tonic-gate {
13297c478bd9Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	/*
13327c478bd9Sstevel@tonic-gate 	 * Return the current promiscuity.
13337c478bd9Sstevel@tonic-gate 	 */
13347c478bd9Sstevel@tonic-gate 	return (mip->mi_devpromisc != 0);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate 
1337da14cebeSEric Cheng /*
1338da14cebeSEric Cheng  * Invoked at MAC instance attach time to initialize the list
1339da14cebeSEric Cheng  * of factory MAC addresses supported by a MAC instance. This function
1340da14cebeSEric Cheng  * builds a local cache in the mac_impl_t for the MAC addresses
1341da14cebeSEric Cheng  * supported by the underlying hardware. The MAC clients themselves
1342da14cebeSEric Cheng  * use the mac_addr_factory*() functions to query and reserve
1343da14cebeSEric Cheng  * factory MAC addresses.
1344da14cebeSEric Cheng  */
13457c478bd9Sstevel@tonic-gate void
mac_addr_factory_init(mac_impl_t * mip)1346da14cebeSEric Cheng mac_addr_factory_init(mac_impl_t *mip)
1347e7801d59Ssowmini {
1348da14cebeSEric Cheng 	mac_capab_multifactaddr_t capab;
1349da14cebeSEric Cheng 	uint8_t *addr;
1350da14cebeSEric Cheng 	int i;
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	/*
1353da14cebeSEric Cheng 	 * First round to see how many factory MAC addresses are available.
13547c478bd9Sstevel@tonic-gate 	 */
1355da14cebeSEric Cheng 	bzero(&capab, sizeof (capab));
1356da14cebeSEric Cheng 	if (!i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_MULTIFACTADDR,
1357da14cebeSEric Cheng 	    &capab) || (capab.mcm_naddr == 0)) {
1358e7801d59Ssowmini 		/*
1359da14cebeSEric Cheng 		 * The MAC instance doesn't support multiple factory
1360da14cebeSEric Cheng 		 * MAC addresses, we're done here.
1361e7801d59Ssowmini 		 */
13624045d941Ssowmini 		return;
1363e7801d59Ssowmini 	}
13644045d941Ssowmini 
13657c478bd9Sstevel@tonic-gate 	/*
1366da14cebeSEric Cheng 	 * Allocate the space and get all the factory addresses.
13677c478bd9Sstevel@tonic-gate 	 */
1368da14cebeSEric Cheng 	addr = kmem_alloc(capab.mcm_naddr * MAXMACADDRLEN, KM_SLEEP);
1369da14cebeSEric Cheng 	capab.mcm_getaddr(mip->mi_driver, capab.mcm_naddr, addr);
1370da14cebeSEric Cheng 
1371da14cebeSEric Cheng 	mip->mi_factory_addr_num = capab.mcm_naddr;
1372da14cebeSEric Cheng 	mip->mi_factory_addr = kmem_zalloc(mip->mi_factory_addr_num *
1373da14cebeSEric Cheng 	    sizeof (mac_factory_addr_t), KM_SLEEP);
1374da14cebeSEric Cheng 
1375da14cebeSEric Cheng 	for (i = 0; i < capab.mcm_naddr; i++) {
1376da14cebeSEric Cheng 		bcopy(addr + i * MAXMACADDRLEN,
1377da14cebeSEric Cheng 		    mip->mi_factory_addr[i].mfa_addr,
1378da14cebeSEric Cheng 		    mip->mi_type->mt_addr_length);
1379da14cebeSEric Cheng 		mip->mi_factory_addr[i].mfa_in_use = B_FALSE;
1380da14cebeSEric Cheng 	}
1381da14cebeSEric Cheng 
1382da14cebeSEric Cheng 	kmem_free(addr, capab.mcm_naddr * MAXMACADDRLEN);
1383da14cebeSEric Cheng }
1384da14cebeSEric Cheng 
1385da14cebeSEric Cheng void
mac_addr_factory_fini(mac_impl_t * mip)1386da14cebeSEric Cheng mac_addr_factory_fini(mac_impl_t *mip)
1387da14cebeSEric Cheng {
1388da14cebeSEric Cheng 	if (mip->mi_factory_addr == NULL) {
1389da14cebeSEric Cheng 		ASSERT(mip->mi_factory_addr_num == 0);
1390da14cebeSEric Cheng 		return;
1391da14cebeSEric Cheng 	}
1392da14cebeSEric Cheng 
1393da14cebeSEric Cheng 	kmem_free(mip->mi_factory_addr, mip->mi_factory_addr_num *
1394da14cebeSEric Cheng 	    sizeof (mac_factory_addr_t));
1395da14cebeSEric Cheng 
1396da14cebeSEric Cheng 	mip->mi_factory_addr = NULL;
1397da14cebeSEric Cheng 	mip->mi_factory_addr_num = 0;
1398da14cebeSEric Cheng }
1399da14cebeSEric Cheng 
1400da14cebeSEric Cheng /*
1401da14cebeSEric Cheng  * Reserve a factory MAC address. If *slot is set to -1, the function
1402da14cebeSEric Cheng  * attempts to reserve any of the available factory MAC addresses and
1403da14cebeSEric Cheng  * returns the reserved slot id. If no slots are available, the function
1404da14cebeSEric Cheng  * returns ENOSPC. If *slot is not set to -1, the function reserves
1405da14cebeSEric Cheng  * the specified slot if it is available, or returns EBUSY is the slot
1406da14cebeSEric Cheng  * is already used. Returns ENOTSUP if the underlying MAC does not
1407da14cebeSEric Cheng  * support multiple factory addresses. If the slot number is not -1 but
1408da14cebeSEric Cheng  * is invalid, returns EINVAL.
1409da14cebeSEric Cheng  */
1410da14cebeSEric Cheng int
mac_addr_factory_reserve(mac_client_handle_t mch,int * slot)1411da14cebeSEric Cheng mac_addr_factory_reserve(mac_client_handle_t mch, int *slot)
1412da14cebeSEric Cheng {
1413da14cebeSEric Cheng 	mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1414da14cebeSEric Cheng 	mac_impl_t *mip = mcip->mci_mip;
1415da14cebeSEric Cheng 	int i, ret = 0;
1416da14cebeSEric Cheng 
1417da14cebeSEric Cheng 	i_mac_perim_enter(mip);
1418da14cebeSEric Cheng 	/*
1419da14cebeSEric Cheng 	 * Protect against concurrent readers that may need a self-consistent
1420da14cebeSEric Cheng 	 * view of the factory addresses
1421da14cebeSEric Cheng 	 */
1422da14cebeSEric Cheng 	rw_enter(&mip->mi_rw_lock, RW_WRITER);
1423da14cebeSEric Cheng 
1424da14cebeSEric Cheng 	if (mip->mi_factory_addr_num == 0) {
1425da14cebeSEric Cheng 		ret = ENOTSUP;
1426da14cebeSEric Cheng 		goto bail;
1427da14cebeSEric Cheng 	}
1428da14cebeSEric Cheng 
1429da14cebeSEric Cheng 	if (*slot != -1) {
1430da14cebeSEric Cheng 		/* check the specified slot */
1431da14cebeSEric Cheng 		if (*slot < 1 || *slot > mip->mi_factory_addr_num) {
1432da14cebeSEric Cheng 			ret = EINVAL;
1433da14cebeSEric Cheng 			goto bail;
1434da14cebeSEric Cheng 		}
1435da14cebeSEric Cheng 		if (mip->mi_factory_addr[*slot-1].mfa_in_use) {
1436da14cebeSEric Cheng 			ret = EBUSY;
1437da14cebeSEric Cheng 			goto bail;
1438da14cebeSEric Cheng 		}
1439da14cebeSEric Cheng 	} else {
1440da14cebeSEric Cheng 		/* pick the next available slot */
1441da14cebeSEric Cheng 		for (i = 0; i < mip->mi_factory_addr_num; i++) {
1442da14cebeSEric Cheng 			if (!mip->mi_factory_addr[i].mfa_in_use)
1443da14cebeSEric Cheng 				break;
1444da14cebeSEric Cheng 		}
1445da14cebeSEric Cheng 
1446da14cebeSEric Cheng 		if (i == mip->mi_factory_addr_num) {
1447da14cebeSEric Cheng 			ret = ENOSPC;
1448da14cebeSEric Cheng 			goto bail;
1449da14cebeSEric Cheng 		}
1450da14cebeSEric Cheng 		*slot = i+1;
1451da14cebeSEric Cheng 	}
1452da14cebeSEric Cheng 
1453da14cebeSEric Cheng 	mip->mi_factory_addr[*slot-1].mfa_in_use = B_TRUE;
1454da14cebeSEric Cheng 	mip->mi_factory_addr[*slot-1].mfa_client = mcip;
1455da14cebeSEric Cheng 
1456da14cebeSEric Cheng bail:
1457da14cebeSEric Cheng 	rw_exit(&mip->mi_rw_lock);
1458da14cebeSEric Cheng 	i_mac_perim_exit(mip);
1459da14cebeSEric Cheng 	return (ret);
1460da14cebeSEric Cheng }
1461da14cebeSEric Cheng 
1462da14cebeSEric Cheng /*
1463da14cebeSEric Cheng  * Release the specified factory MAC address slot.
1464da14cebeSEric Cheng  */
1465da14cebeSEric Cheng void
mac_addr_factory_release(mac_client_handle_t mch,uint_t slot)1466da14cebeSEric Cheng mac_addr_factory_release(mac_client_handle_t mch, uint_t slot)
1467da14cebeSEric Cheng {
1468da14cebeSEric Cheng 	mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
1469da14cebeSEric Cheng 	mac_impl_t *mip = mcip->mci_mip;
1470da14cebeSEric Cheng 
1471da14cebeSEric Cheng 	i_mac_perim_enter(mip);
1472da14cebeSEric Cheng 	/*
1473da14cebeSEric Cheng 	 * Protect against concurrent readers that may need a self-consistent
1474da14cebeSEric Cheng 	 * view of the factory addresses
1475da14cebeSEric Cheng 	 */
1476da14cebeSEric Cheng 	rw_enter(&mip->mi_rw_lock, RW_WRITER);
1477da14cebeSEric Cheng 
1478da14cebeSEric Cheng 	ASSERT(slot > 0 && slot <= mip->mi_factory_addr_num);
1479da14cebeSEric Cheng 	ASSERT(mip->mi_factory_addr[slot-1].mfa_in_use);
1480da14cebeSEric Cheng 
1481da14cebeSEric Cheng 	mip->mi_factory_addr[slot-1].mfa_in_use = B_FALSE;
1482da14cebeSEric Cheng 
1483da14cebeSEric Cheng 	rw_exit(&mip->mi_rw_lock);
1484da14cebeSEric Cheng 	i_mac_perim_exit(mip);
1485da14cebeSEric Cheng }
1486da14cebeSEric Cheng 
1487da14cebeSEric Cheng /*
1488da14cebeSEric Cheng  * Stores in mac_addr the value of the specified MAC address. Returns
1489da14cebeSEric Cheng  * 0 on success, or EINVAL if the slot number is not valid for the MAC.
1490da14cebeSEric Cheng  * The caller must provide a string of at least MAXNAMELEN bytes.
1491da14cebeSEric Cheng  */
1492da14cebeSEric Cheng void
mac_addr_factory_value(mac_handle_t mh,int slot,uchar_t * mac_addr,uint_t * addr_len,char * client_name,boolean_t * in_use_arg)1493da14cebeSEric Cheng mac_addr_factory_value(mac_handle_t mh, int slot, uchar_t *mac_addr,
1494da14cebeSEric Cheng     uint_t *addr_len, char *client_name, boolean_t *in_use_arg)
1495da14cebeSEric Cheng {
1496da14cebeSEric Cheng 	mac_impl_t *mip = (mac_impl_t *)mh;
1497da14cebeSEric Cheng 	boolean_t in_use;
1498da14cebeSEric Cheng 
1499da14cebeSEric Cheng 	ASSERT(slot > 0 && slot <= mip->mi_factory_addr_num);
1500da14cebeSEric Cheng 
1501da14cebeSEric Cheng 	/*
1502da14cebeSEric Cheng 	 * Readers need to hold mi_rw_lock. Writers need to hold mac perimeter
1503da14cebeSEric Cheng 	 * and mi_rw_lock
1504da14cebeSEric Cheng 	 */
1505da14cebeSEric Cheng 	rw_enter(&mip->mi_rw_lock, RW_READER);
1506da14cebeSEric Cheng 	bcopy(mip->mi_factory_addr[slot-1].mfa_addr, mac_addr, MAXMACADDRLEN);
1507da14cebeSEric Cheng 	*addr_len = mip->mi_type->mt_addr_length;
1508da14cebeSEric Cheng 	in_use = mip->mi_factory_addr[slot-1].mfa_in_use;
1509da14cebeSEric Cheng 	if (in_use && client_name != NULL) {
1510da14cebeSEric Cheng 		bcopy(mip->mi_factory_addr[slot-1].mfa_client->mci_name,
1511da14cebeSEric Cheng 		    client_name, MAXNAMELEN);
1512da14cebeSEric Cheng 	}
1513da14cebeSEric Cheng 	if (in_use_arg != NULL)
1514da14cebeSEric Cheng 		*in_use_arg = in_use;
1515da14cebeSEric Cheng 	rw_exit(&mip->mi_rw_lock);
1516da14cebeSEric Cheng }
1517da14cebeSEric Cheng 
1518da14cebeSEric Cheng /*
1519da14cebeSEric Cheng  * Returns the number of factory MAC addresses (in addition to the
1520da14cebeSEric Cheng  * primary MAC address), 0 if the underlying MAC doesn't support
1521da14cebeSEric Cheng  * that feature.
1522da14cebeSEric Cheng  */
1523da14cebeSEric Cheng uint_t
mac_addr_factory_num(mac_handle_t mh)1524da14cebeSEric Cheng mac_addr_factory_num(mac_handle_t mh)
1525da14cebeSEric Cheng {
1526da14cebeSEric Cheng 	mac_impl_t *mip = (mac_impl_t *)mh;
1527da14cebeSEric Cheng 
1528da14cebeSEric Cheng 	return (mip->mi_factory_addr_num);
1529da14cebeSEric Cheng }
1530da14cebeSEric Cheng 
1531da14cebeSEric Cheng 
1532da14cebeSEric Cheng void
mac_rx_group_unmark(mac_group_t * grp,uint_t flag)1533da14cebeSEric Cheng mac_rx_group_unmark(mac_group_t *grp, uint_t flag)
1534da14cebeSEric Cheng {
1535da14cebeSEric Cheng 	mac_ring_t	*ring;
1536da14cebeSEric Cheng 
1537da14cebeSEric Cheng 	for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next)
1538da14cebeSEric Cheng 		ring->mr_flag &= ~flag;
1539da14cebeSEric Cheng }
1540da14cebeSEric Cheng 
1541da14cebeSEric Cheng /*
1542da14cebeSEric Cheng  * The following mac_hwrings_xxx() functions are private mac client functions
1543da14cebeSEric Cheng  * used by the aggr driver to access and control the underlying HW Rx group
1544da14cebeSEric Cheng  * and rings. In this case, the aggr driver has exclusive control of the
1545da14cebeSEric Cheng  * underlying HW Rx group/rings, it calls the following functions to
154645948e49SRyan Zezeski  * start/stop the HW Rx rings, disable/enable polling, add/remove MAC
1547da14cebeSEric Cheng  * addresses, or set up the Rx callback.
1548da14cebeSEric Cheng  */
1549da14cebeSEric Cheng /* ARGSUSED */
1550da14cebeSEric Cheng static void
mac_hwrings_rx_process(void * arg,mac_resource_handle_t srs,mblk_t * mp_chain,boolean_t loopback)1551da14cebeSEric Cheng mac_hwrings_rx_process(void *arg, mac_resource_handle_t srs,
1552da14cebeSEric Cheng     mblk_t *mp_chain, boolean_t loopback)
1553da14cebeSEric Cheng {
1554da14cebeSEric Cheng 	mac_soft_ring_set_t	*mac_srs = (mac_soft_ring_set_t *)srs;
1555da14cebeSEric Cheng 	mac_srs_rx_t		*srs_rx = &mac_srs->srs_rx;
1556da14cebeSEric Cheng 	mac_direct_rx_t		proc;
1557da14cebeSEric Cheng 	void			*arg1;
1558da14cebeSEric Cheng 	mac_resource_handle_t	arg2;
1559da14cebeSEric Cheng 
1560da14cebeSEric Cheng 	proc = srs_rx->sr_func;
1561da14cebeSEric Cheng 	arg1 = srs_rx->sr_arg1;
1562da14cebeSEric Cheng 	arg2 = mac_srs->srs_mrh;
1563da14cebeSEric Cheng 
1564da14cebeSEric Cheng 	proc(arg1, arg2, mp_chain, NULL);
1565da14cebeSEric Cheng }
1566da14cebeSEric Cheng 
1567da14cebeSEric Cheng /*
1568da14cebeSEric Cheng  * This function is called to get the list of HW rings that are reserved by
1569da14cebeSEric Cheng  * an exclusive mac client.
1570da14cebeSEric Cheng  *
1571da14cebeSEric Cheng  * Return value: the number of HW rings.
1572da14cebeSEric Cheng  */
1573da14cebeSEric Cheng int
mac_hwrings_get(mac_client_handle_t mch,mac_group_handle_t * hwgh,mac_ring_handle_t * hwrh,mac_ring_type_t rtype)1574da14cebeSEric Cheng mac_hwrings_get(mac_client_handle_t mch, mac_group_handle_t *hwgh,
157563f531d1SSriharsha Basavapatna     mac_ring_handle_t *hwrh, mac_ring_type_t rtype)
1576da14cebeSEric Cheng {
1577da14cebeSEric Cheng 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
157863f531d1SSriharsha Basavapatna 	flow_entry_t		*flent = mcip->mci_flent;
157963f531d1SSriharsha Basavapatna 	mac_group_t		*grp;
158063f531d1SSriharsha Basavapatna 	mac_ring_t		*ring;
15810dc2366fSVenugopal Iyer 	int			cnt = 0;
158263f531d1SSriharsha Basavapatna 
15830dc2366fSVenugopal Iyer 	if (rtype == MAC_RING_TYPE_RX) {
158463f531d1SSriharsha Basavapatna 		grp = flent->fe_rx_ring_group;
15850dc2366fSVenugopal Iyer 	} else if (rtype == MAC_RING_TYPE_TX) {
15860dc2366fSVenugopal Iyer 		grp = flent->fe_tx_ring_group;
15870dc2366fSVenugopal Iyer 	} else {
15880dc2366fSVenugopal Iyer 		ASSERT(B_FALSE);
15890dc2366fSVenugopal Iyer 		return (-1);
15900dc2366fSVenugopal Iyer 	}
159145948e49SRyan Zezeski 
1592da14cebeSEric Cheng 	/*
159345948e49SRyan Zezeski 	 * The MAC client did not reserve an Rx group, return directly.
1594da14cebeSEric Cheng 	 * This is probably because the underlying MAC does not support
159563f531d1SSriharsha Basavapatna 	 * any groups.
1596da14cebeSEric Cheng 	 */
15970dc2366fSVenugopal Iyer 	if (hwgh != NULL)
1598da14cebeSEric Cheng 		*hwgh = NULL;
1599da14cebeSEric Cheng 	if (grp == NULL)
1600da14cebeSEric Cheng 		return (0);
1601da14cebeSEric Cheng 	/*
160245948e49SRyan Zezeski 	 * This group must be reserved by this MAC client.
1603da14cebeSEric Cheng 	 */
1604da14cebeSEric Cheng 	ASSERT((grp->mrg_state == MAC_GROUP_STATE_RESERVED) &&
16050dc2366fSVenugopal Iyer 	    (mcip == MAC_GROUP_ONLY_CLIENT(grp)));
16060dc2366fSVenugopal Iyer 
16070dc2366fSVenugopal Iyer 	for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) {
1608da14cebeSEric Cheng 		ASSERT(cnt < MAX_RINGS_PER_GROUP);
160963f531d1SSriharsha Basavapatna 		hwrh[cnt] = (mac_ring_handle_t)ring;
1610da14cebeSEric Cheng 	}
16110dc2366fSVenugopal Iyer 	if (hwgh != NULL)
1612da14cebeSEric Cheng 		*hwgh = (mac_group_handle_t)grp;
161363f531d1SSriharsha Basavapatna 
161463f531d1SSriharsha Basavapatna 	return (cnt);
161563f531d1SSriharsha Basavapatna }
1616da14cebeSEric Cheng 
1617da14cebeSEric Cheng /*
161845948e49SRyan Zezeski  * Get the HW ring handles of the given group index. If the MAC
161945948e49SRyan Zezeski  * doesn't have a group at this index, or any groups at all, then 0 is
162045948e49SRyan Zezeski  * returned and hwgh is set to NULL. This is a private client API. The
162145948e49SRyan Zezeski  * MAC perimeter must be held when calling this function.
162245948e49SRyan Zezeski  *
162345948e49SRyan Zezeski  * mh: A handle to the MAC that owns the group.
162445948e49SRyan Zezeski  *
162545948e49SRyan Zezeski  * idx: The index of the HW group to be read.
162645948e49SRyan Zezeski  *
162745948e49SRyan Zezeski  * hwgh: If non-NULL, contains a handle to the HW group on return.
162845948e49SRyan Zezeski  *
162945948e49SRyan Zezeski  * hwrh: An array of ring handles pointing to the HW rings in the
163045948e49SRyan Zezeski  * group. The array must be large enough to hold a handle to each ring
163145948e49SRyan Zezeski  * in the group. To be safe, this array should be of size MAX_RINGS_PER_GROUP.
163245948e49SRyan Zezeski  *
163345948e49SRyan Zezeski  * rtype: Used to determine if we are fetching Rx or Tx rings.
163445948e49SRyan Zezeski  *
163545948e49SRyan Zezeski  * Returns the number of rings in the group.
163645948e49SRyan Zezeski  */
163745948e49SRyan Zezeski uint_t
mac_hwrings_idx_get(mac_handle_t mh,uint_t idx,mac_group_handle_t * hwgh,mac_ring_handle_t * hwrh,mac_ring_type_t rtype)163845948e49SRyan Zezeski mac_hwrings_idx_get(mac_handle_t mh, uint_t idx, mac_group_handle_t *hwgh,
163945948e49SRyan Zezeski     mac_ring_handle_t *hwrh, mac_ring_type_t rtype)
164045948e49SRyan Zezeski {
164145948e49SRyan Zezeski 	mac_impl_t		*mip = (mac_impl_t *)mh;
164245948e49SRyan Zezeski 	mac_group_t		*grp;
164345948e49SRyan Zezeski 	mac_ring_t		*ring;
164445948e49SRyan Zezeski 	uint_t			cnt = 0;
164545948e49SRyan Zezeski 
164645948e49SRyan Zezeski 	/*
164745948e49SRyan Zezeski 	 * The MAC perimeter must be held when accessing the
164845948e49SRyan Zezeski 	 * mi_{rx,tx}_groups fields.
164945948e49SRyan Zezeski 	 */
165045948e49SRyan Zezeski 	ASSERT(MAC_PERIM_HELD(mh));
165145948e49SRyan Zezeski 	ASSERT(rtype == MAC_RING_TYPE_RX || rtype == MAC_RING_TYPE_TX);
165245948e49SRyan Zezeski 
165345948e49SRyan Zezeski 	if (rtype == MAC_RING_TYPE_RX) {
165445948e49SRyan Zezeski 		grp = mip->mi_rx_groups;
165545948e49SRyan Zezeski 	} else {
165645948e49SRyan Zezeski 		ASSERT(rtype == MAC_RING_TYPE_TX);
165745948e49SRyan Zezeski 		grp = mip->mi_tx_groups;
165845948e49SRyan Zezeski 	}
165945948e49SRyan Zezeski 
166045948e49SRyan Zezeski 	while (grp != NULL && grp->mrg_index != idx)
166145948e49SRyan Zezeski 		grp = grp->mrg_next;
166245948e49SRyan Zezeski 
166345948e49SRyan Zezeski 	/*
166445948e49SRyan Zezeski 	 * If the MAC doesn't have a group at this index or doesn't
166545948e49SRyan Zezeski 	 * impelement RINGS capab, then set hwgh to NULL and return 0.
166645948e49SRyan Zezeski 	 */
166745948e49SRyan Zezeski 	if (hwgh != NULL)
166845948e49SRyan Zezeski 		*hwgh = NULL;
166945948e49SRyan Zezeski 
167045948e49SRyan Zezeski 	if (grp == NULL)
167145948e49SRyan Zezeski 		return (0);
167245948e49SRyan Zezeski 
167345948e49SRyan Zezeski 	ASSERT3U(idx, ==, grp->mrg_index);
167445948e49SRyan Zezeski 
167545948e49SRyan Zezeski 	for (ring = grp->mrg_rings; ring != NULL; ring = ring->mr_next, cnt++) {
167645948e49SRyan Zezeski 		ASSERT3U(cnt, <, MAX_RINGS_PER_GROUP);
167745948e49SRyan Zezeski 		hwrh[cnt] = (mac_ring_handle_t)ring;
167845948e49SRyan Zezeski 	}
167945948e49SRyan Zezeski 
168045948e49SRyan Zezeski 	/* A group should always have at least one ring. */
168145948e49SRyan Zezeski 	ASSERT3U(cnt, >, 0);
168245948e49SRyan Zezeski 
168345948e49SRyan Zezeski 	if (hwgh != NULL)
168445948e49SRyan Zezeski 		*hwgh = (mac_group_handle_t)grp;
168545948e49SRyan Zezeski 
168645948e49SRyan Zezeski 	return (cnt);
168745948e49SRyan Zezeski }
168845948e49SRyan Zezeski 
168945948e49SRyan Zezeski /*
16900dc2366fSVenugopal Iyer  * This function is called to get info about Tx/Rx rings.
16910dc2366fSVenugopal Iyer  *
16920dc2366fSVenugopal Iyer  * Return value: returns uint_t which will have various bits set
16930dc2366fSVenugopal Iyer  * that indicates different properties of the ring.
16940dc2366fSVenugopal Iyer  */
16950dc2366fSVenugopal Iyer uint_t
mac_hwring_getinfo(mac_ring_handle_t rh)16960dc2366fSVenugopal Iyer mac_hwring_getinfo(mac_ring_handle_t rh)
16970dc2366fSVenugopal Iyer {
16980dc2366fSVenugopal Iyer 	mac_ring_t *ring = (mac_ring_t *)rh;
16990dc2366fSVenugopal Iyer 	mac_ring_info_t *info = &ring->mr_info;
17000dc2366fSVenugopal Iyer 
17010dc2366fSVenugopal Iyer 	return (info->mri_flags);
17020dc2366fSVenugopal Iyer }
17030dc2366fSVenugopal Iyer 
17040dc2366fSVenugopal Iyer /*
170545948e49SRyan Zezeski  * Set the passthru callback on the hardware ring.
170645948e49SRyan Zezeski  */
170745948e49SRyan Zezeski void
mac_hwring_set_passthru(mac_ring_handle_t hwrh,mac_rx_t fn,void * arg1,mac_resource_handle_t arg2)170845948e49SRyan Zezeski mac_hwring_set_passthru(mac_ring_handle_t hwrh, mac_rx_t fn, void *arg1,
170945948e49SRyan Zezeski     mac_resource_handle_t arg2)
171045948e49SRyan Zezeski {
171145948e49SRyan Zezeski 	mac_ring_t *hwring = (mac_ring_t *)hwrh;
171245948e49SRyan Zezeski 
171345948e49SRyan Zezeski 	ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX);
171445948e49SRyan Zezeski 
171545948e49SRyan Zezeski 	hwring->mr_classify_type = MAC_PASSTHRU_CLASSIFIER;
171645948e49SRyan Zezeski 
171745948e49SRyan Zezeski 	hwring->mr_pt_fn = fn;
171845948e49SRyan Zezeski 	hwring->mr_pt_arg1 = arg1;
171945948e49SRyan Zezeski 	hwring->mr_pt_arg2 = arg2;
172045948e49SRyan Zezeski }
172145948e49SRyan Zezeski 
172245948e49SRyan Zezeski /*
172345948e49SRyan Zezeski  * Clear the passthru callback on the hardware ring.
172445948e49SRyan Zezeski  */
172545948e49SRyan Zezeski void
mac_hwring_clear_passthru(mac_ring_handle_t hwrh)172645948e49SRyan Zezeski mac_hwring_clear_passthru(mac_ring_handle_t hwrh)
172745948e49SRyan Zezeski {
172845948e49SRyan Zezeski 	mac_ring_t *hwring = (mac_ring_t *)hwrh;
172945948e49SRyan Zezeski 
173045948e49SRyan Zezeski 	ASSERT3S(hwring->mr_type, ==, MAC_RING_TYPE_RX);
173145948e49SRyan Zezeski 
173245948e49SRyan Zezeski 	hwring->mr_classify_type = MAC_NO_CLASSIFIER;
173345948e49SRyan Zezeski 
173445948e49SRyan Zezeski 	hwring->mr_pt_fn = NULL;
173545948e49SRyan Zezeski 	hwring->mr_pt_arg1 = NULL;
173645948e49SRyan Zezeski 	hwring->mr_pt_arg2 = NULL;
173745948e49SRyan Zezeski }
173845948e49SRyan Zezeski 
173945948e49SRyan Zezeski void
mac_client_set_flow_cb(mac_client_handle_t mch,mac_rx_t func,void * arg1)174045948e49SRyan Zezeski mac_client_set_flow_cb(mac_client_handle_t mch, mac_rx_t func, void *arg1)
174145948e49SRyan Zezeski {
174245948e49SRyan Zezeski 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
174345948e49SRyan Zezeski 	flow_entry_t		*flent = mcip->mci_flent;
174445948e49SRyan Zezeski 
174545948e49SRyan Zezeski 	mutex_enter(&flent->fe_lock);
174645948e49SRyan Zezeski 	flent->fe_cb_fn = (flow_fn_t)func;
174745948e49SRyan Zezeski 	flent->fe_cb_arg1 = arg1;
174845948e49SRyan Zezeski 	flent->fe_cb_arg2 = NULL;
174945948e49SRyan Zezeski 	flent->fe_flags &= ~FE_MC_NO_DATAPATH;
175045948e49SRyan Zezeski 	mutex_exit(&flent->fe_lock);
175145948e49SRyan Zezeski }
175245948e49SRyan Zezeski 
175345948e49SRyan Zezeski void
mac_client_clear_flow_cb(mac_client_handle_t mch)175445948e49SRyan Zezeski mac_client_clear_flow_cb(mac_client_handle_t mch)
175545948e49SRyan Zezeski {
175645948e49SRyan Zezeski 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
175745948e49SRyan Zezeski 	flow_entry_t		*flent = mcip->mci_flent;
175845948e49SRyan Zezeski 
175945948e49SRyan Zezeski 	mutex_enter(&flent->fe_lock);
1760c61a1653SRyan Zezeski 	flent->fe_cb_fn = (flow_fn_t)mac_rx_def;
176145948e49SRyan Zezeski 	flent->fe_cb_arg1 = NULL;
176245948e49SRyan Zezeski 	flent->fe_cb_arg2 = NULL;
176345948e49SRyan Zezeski 	flent->fe_flags |= FE_MC_NO_DATAPATH;
176445948e49SRyan Zezeski 	mutex_exit(&flent->fe_lock);
176545948e49SRyan Zezeski }
176645948e49SRyan Zezeski 
176745948e49SRyan Zezeski /*
17680dc2366fSVenugopal Iyer  * Export ddi interrupt handles from the HW ring to the pseudo ring and
17690dc2366fSVenugopal Iyer  * setup the RX callback of the mac client which exclusively controls
17700dc2366fSVenugopal Iyer  * HW ring.
1771da14cebeSEric Cheng  */
1772da14cebeSEric Cheng void
mac_hwring_setup(mac_ring_handle_t hwrh,mac_resource_handle_t prh,mac_ring_handle_t pseudo_rh)17730dc2366fSVenugopal Iyer mac_hwring_setup(mac_ring_handle_t hwrh, mac_resource_handle_t prh,
17740dc2366fSVenugopal Iyer     mac_ring_handle_t pseudo_rh)
1775da14cebeSEric Cheng {
1776da14cebeSEric Cheng 	mac_ring_t		*hw_ring = (mac_ring_t *)hwrh;
17770dc2366fSVenugopal Iyer 	mac_ring_t		*pseudo_ring;
1778da14cebeSEric Cheng 	mac_soft_ring_set_t	*mac_srs = hw_ring->mr_srs;
1779da14cebeSEric Cheng 
17800dc2366fSVenugopal Iyer 	if (pseudo_rh != NULL) {
17810dc2366fSVenugopal Iyer 		pseudo_ring = (mac_ring_t *)pseudo_rh;
17820dc2366fSVenugopal Iyer 		/* Export the ddi handles to pseudo ring */
17830dc2366fSVenugopal Iyer 		pseudo_ring->mr_info.mri_intr.mi_ddi_handle =
17840dc2366fSVenugopal Iyer 		    hw_ring->mr_info.mri_intr.mi_ddi_handle;
17850dc2366fSVenugopal Iyer 		pseudo_ring->mr_info.mri_intr.mi_ddi_shared =
17860dc2366fSVenugopal Iyer 		    hw_ring->mr_info.mri_intr.mi_ddi_shared;
17870dc2366fSVenugopal Iyer 		/*
17880dc2366fSVenugopal Iyer 		 * Save a pointer to pseudo ring in the hw ring. If
17890dc2366fSVenugopal Iyer 		 * interrupt handle changes, the hw ring will be
17900dc2366fSVenugopal Iyer 		 * notified of the change (see mac_ring_intr_set())
17910dc2366fSVenugopal Iyer 		 * and the appropriate change has to be made to
17920dc2366fSVenugopal Iyer 		 * the pseudo ring that has exported the ddi handle.
17930dc2366fSVenugopal Iyer 		 */
17940dc2366fSVenugopal Iyer 		hw_ring->mr_prh = pseudo_rh;
17950dc2366fSVenugopal Iyer 	}
17960dc2366fSVenugopal Iyer 
17970dc2366fSVenugopal Iyer 	if (hw_ring->mr_type == MAC_RING_TYPE_RX) {
17980dc2366fSVenugopal Iyer 		ASSERT(!(mac_srs->srs_type & SRST_TX));
1799da14cebeSEric Cheng 		mac_srs->srs_mrh = prh;
1800da14cebeSEric Cheng 		mac_srs->srs_rx.sr_lower_proc = mac_hwrings_rx_process;
1801da14cebeSEric Cheng 	}
18020dc2366fSVenugopal Iyer }
1803da14cebeSEric Cheng 
1804da14cebeSEric Cheng void
mac_hwring_teardown(mac_ring_handle_t hwrh)1805da14cebeSEric Cheng mac_hwring_teardown(mac_ring_handle_t hwrh)
1806da14cebeSEric Cheng {
1807da14cebeSEric Cheng 	mac_ring_t		*hw_ring = (mac_ring_t *)hwrh;
18080dc2366fSVenugopal Iyer 	mac_soft_ring_set_t	*mac_srs;
1809da14cebeSEric Cheng 
18100dc2366fSVenugopal Iyer 	if (hw_ring == NULL)
18110dc2366fSVenugopal Iyer 		return;
18120dc2366fSVenugopal Iyer 	hw_ring->mr_prh = NULL;
18130dc2366fSVenugopal Iyer 	if (hw_ring->mr_type == MAC_RING_TYPE_RX) {
18140dc2366fSVenugopal Iyer 		mac_srs = hw_ring->mr_srs;
18150dc2366fSVenugopal Iyer 		ASSERT(!(mac_srs->srs_type & SRST_TX));
1816da14cebeSEric Cheng 		mac_srs->srs_rx.sr_lower_proc = mac_rx_srs_process;
1817da14cebeSEric Cheng 		mac_srs->srs_mrh = NULL;
1818da14cebeSEric Cheng 	}
18190dc2366fSVenugopal Iyer }
1820da14cebeSEric Cheng 
1821da14cebeSEric Cheng int
mac_hwring_disable_intr(mac_ring_handle_t rh)1822da14cebeSEric Cheng mac_hwring_disable_intr(mac_ring_handle_t rh)
1823da14cebeSEric Cheng {
1824da14cebeSEric Cheng 	mac_ring_t *rr_ring = (mac_ring_t *)rh;
1825da14cebeSEric Cheng 	mac_intr_t *intr = &rr_ring->mr_info.mri_intr;
1826da14cebeSEric Cheng 
1827da14cebeSEric Cheng 	return (intr->mi_disable(intr->mi_handle));
1828da14cebeSEric Cheng }
1829da14cebeSEric Cheng 
1830da14cebeSEric Cheng int
mac_hwring_enable_intr(mac_ring_handle_t rh)1831da14cebeSEric Cheng mac_hwring_enable_intr(mac_ring_handle_t rh)
1832da14cebeSEric Cheng {
1833da14cebeSEric Cheng 	mac_ring_t *rr_ring = (mac_ring_t *)rh;
1834da14cebeSEric Cheng 	mac_intr_t *intr = &rr_ring->mr_info.mri_intr;
1835da14cebeSEric Cheng 
1836da14cebeSEric Cheng 	return (intr->mi_enable(intr->mi_handle));
1837da14cebeSEric Cheng }
1838da14cebeSEric Cheng 
183945948e49SRyan Zezeski /*
184045948e49SRyan Zezeski  * Start the HW ring pointed to by rh.
184145948e49SRyan Zezeski  *
184245948e49SRyan Zezeski  * This is used by special MAC clients that are MAC themselves and
184345948e49SRyan Zezeski  * need to exert control over the underlying HW rings of the NIC.
184445948e49SRyan Zezeski  */
1845da14cebeSEric Cheng int
mac_hwring_start(mac_ring_handle_t rh)1846da14cebeSEric Cheng mac_hwring_start(mac_ring_handle_t rh)
1847da14cebeSEric Cheng {
1848da14cebeSEric Cheng 	mac_ring_t *rr_ring = (mac_ring_t *)rh;
184945948e49SRyan Zezeski 	int rv = 0;
185045948e49SRyan Zezeski 
185145948e49SRyan Zezeski 	if (rr_ring->mr_state != MR_INUSE)
185245948e49SRyan Zezeski 		rv = mac_start_ring(rr_ring);
185345948e49SRyan Zezeski 
185445948e49SRyan Zezeski 	return (rv);
185545948e49SRyan Zezeski }
185645948e49SRyan Zezeski 
185745948e49SRyan Zezeski /*
185845948e49SRyan Zezeski  * Stop the HW ring pointed to by rh. Also see mac_hwring_start().
185945948e49SRyan Zezeski  */
186045948e49SRyan Zezeski void
mac_hwring_stop(mac_ring_handle_t rh)186145948e49SRyan Zezeski mac_hwring_stop(mac_ring_handle_t rh)
186245948e49SRyan Zezeski {
186345948e49SRyan Zezeski 	mac_ring_t *rr_ring = (mac_ring_t *)rh;
186445948e49SRyan Zezeski 
186545948e49SRyan Zezeski 	if (rr_ring->mr_state != MR_FREE)
186645948e49SRyan Zezeski 		mac_stop_ring(rr_ring);
186745948e49SRyan Zezeski }
186845948e49SRyan Zezeski 
186945948e49SRyan Zezeski /*
187045948e49SRyan Zezeski  * Remove the quiesced flag from the HW ring pointed to by rh.
187145948e49SRyan Zezeski  *
187245948e49SRyan Zezeski  * This is used by special MAC clients that are MAC themselves and
187345948e49SRyan Zezeski  * need to exert control over the underlying HW rings of the NIC.
187445948e49SRyan Zezeski  */
187545948e49SRyan Zezeski int
mac_hwring_activate(mac_ring_handle_t rh)187645948e49SRyan Zezeski mac_hwring_activate(mac_ring_handle_t rh)
187745948e49SRyan Zezeski {
187845948e49SRyan Zezeski 	mac_ring_t *rr_ring = (mac_ring_t *)rh;
1879da14cebeSEric Cheng 
1880da14cebeSEric Cheng 	MAC_RING_UNMARK(rr_ring, MR_QUIESCE);
1881da14cebeSEric Cheng 	return (0);
1882da14cebeSEric Cheng }
1883da14cebeSEric Cheng 
188445948e49SRyan Zezeski /*
188545948e49SRyan Zezeski  * Quiesce the HW ring pointed to by rh. Also see mac_hwring_activate().
188645948e49SRyan Zezeski  */
1887da14cebeSEric Cheng void
mac_hwring_quiesce(mac_ring_handle_t rh)188845948e49SRyan Zezeski mac_hwring_quiesce(mac_ring_handle_t rh)
1889da14cebeSEric Cheng {
1890da14cebeSEric Cheng 	mac_ring_t *rr_ring = (mac_ring_t *)rh;
1891da14cebeSEric Cheng 
1892da14cebeSEric Cheng 	mac_rx_ring_quiesce(rr_ring, MR_QUIESCE);
1893da14cebeSEric Cheng }
1894da14cebeSEric Cheng 
1895da14cebeSEric Cheng mblk_t *
mac_hwring_poll(mac_ring_handle_t rh,int bytes_to_pickup)1896da14cebeSEric Cheng mac_hwring_poll(mac_ring_handle_t rh, int bytes_to_pickup)
1897da14cebeSEric Cheng {
1898da14cebeSEric Cheng 	mac_ring_t *rr_ring = (mac_ring_t *)rh;
1899da14cebeSEric Cheng 	mac_ring_info_t *info = &rr_ring->mr_info;
1900da14cebeSEric Cheng 
1901da14cebeSEric Cheng 	return (info->mri_poll(info->mri_driver, bytes_to_pickup));
1902da14cebeSEric Cheng }
1903da14cebeSEric Cheng 
190463f531d1SSriharsha Basavapatna /*
19050dc2366fSVenugopal Iyer  * Send packets through a selected tx ring.
190663f531d1SSriharsha Basavapatna  */
190763f531d1SSriharsha Basavapatna mblk_t *
mac_hwring_tx(mac_ring_handle_t rh,mblk_t * mp)190863f531d1SSriharsha Basavapatna mac_hwring_tx(mac_ring_handle_t rh, mblk_t *mp)
190963f531d1SSriharsha Basavapatna {
191063f531d1SSriharsha Basavapatna 	mac_ring_t *ring = (mac_ring_t *)rh;
191163f531d1SSriharsha Basavapatna 	mac_ring_info_t *info = &ring->mr_info;
191263f531d1SSriharsha Basavapatna 
19134eaa4710SRishi Srivatsavai 	ASSERT(ring->mr_type == MAC_RING_TYPE_TX &&
19144eaa4710SRishi Srivatsavai 	    ring->mr_state >= MR_INUSE);
191563f531d1SSriharsha Basavapatna 	return (info->mri_tx(info->mri_driver, mp));
191663f531d1SSriharsha Basavapatna }
191763f531d1SSriharsha Basavapatna 
19180dc2366fSVenugopal Iyer /*
19190dc2366fSVenugopal Iyer  * Query stats for a particular rx/tx ring
19200dc2366fSVenugopal Iyer  */
19210dc2366fSVenugopal Iyer int
mac_hwring_getstat(mac_ring_handle_t rh,uint_t stat,uint64_t * val)19220dc2366fSVenugopal Iyer mac_hwring_getstat(mac_ring_handle_t rh, uint_t stat, uint64_t *val)
19230dc2366fSVenugopal Iyer {
19240dc2366fSVenugopal Iyer 	mac_ring_t	*ring = (mac_ring_t *)rh;
19250dc2366fSVenugopal Iyer 	mac_ring_info_t *info = &ring->mr_info;
19260dc2366fSVenugopal Iyer 
19270dc2366fSVenugopal Iyer 	return (info->mri_stat(info->mri_driver, stat, val));
19280dc2366fSVenugopal Iyer }
19290dc2366fSVenugopal Iyer 
19300dc2366fSVenugopal Iyer /*
19310dc2366fSVenugopal Iyer  * Private function that is only used by aggr to send packets through
19320dc2366fSVenugopal Iyer  * a port/Tx ring. Since aggr exposes a pseudo Tx ring even for ports
19330dc2366fSVenugopal Iyer  * that does not expose Tx rings, aggr_ring_tx() entry point needs
19340dc2366fSVenugopal Iyer  * access to mac_impl_t to send packets through m_tx() entry point.
19350dc2366fSVenugopal Iyer  * It accomplishes this by calling mac_hwring_send_priv() function.
19360dc2366fSVenugopal Iyer  */
19370dc2366fSVenugopal Iyer mblk_t *
mac_hwring_send_priv(mac_client_handle_t mch,mac_ring_handle_t rh,mblk_t * mp)19380dc2366fSVenugopal Iyer mac_hwring_send_priv(mac_client_handle_t mch, mac_ring_handle_t rh, mblk_t *mp)
19390dc2366fSVenugopal Iyer {
19400dc2366fSVenugopal Iyer 	mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
19410dc2366fSVenugopal Iyer 	mac_impl_t *mip = mcip->mci_mip;
19420dc2366fSVenugopal Iyer 
1943c61a1653SRyan Zezeski 	return (mac_provider_tx(mip, rh, mp, mcip));
19440dc2366fSVenugopal Iyer }
19450dc2366fSVenugopal Iyer 
194609b7f21aSRobert Mustacchi /*
194709b7f21aSRobert Mustacchi  * Private function that is only used by aggr to update the default transmission
194809b7f21aSRobert Mustacchi  * ring. Because aggr exposes a pseudo Tx ring even for ports that may
194909b7f21aSRobert Mustacchi  * temporarily be down, it may need to update the default ring that is used by
195009b7f21aSRobert Mustacchi  * MAC such that it refers to a link that can actively be used to send traffic.
195109b7f21aSRobert Mustacchi  * Note that this is different from the case where the port has been removed
195209b7f21aSRobert Mustacchi  * from the group. In those cases, all of the rings will be torn down because
195309b7f21aSRobert Mustacchi  * the ring will no longer exist. It's important to give aggr a case where the
195409b7f21aSRobert Mustacchi  * rings can still exist such that it may be able to continue to send LACP PDUs
195509b7f21aSRobert Mustacchi  * to potentially restore the link.
195609b7f21aSRobert Mustacchi  */
195709b7f21aSRobert Mustacchi void
mac_hwring_set_default(mac_handle_t mh,mac_ring_handle_t rh)195809b7f21aSRobert Mustacchi mac_hwring_set_default(mac_handle_t mh, mac_ring_handle_t rh)
195909b7f21aSRobert Mustacchi {
196009b7f21aSRobert Mustacchi 	mac_impl_t *mip = (mac_impl_t *)mh;
196109b7f21aSRobert Mustacchi 	mac_ring_t *ring = (mac_ring_t *)rh;
196209b7f21aSRobert Mustacchi 
196309b7f21aSRobert Mustacchi 	ASSERT(MAC_PERIM_HELD(mh));
196409b7f21aSRobert Mustacchi 	VERIFY(mip->mi_state_flags & MIS_IS_AGGR);
196509b7f21aSRobert Mustacchi 
196699ad48a4SRyan Zezeski 	/*
196799ad48a4SRyan Zezeski 	 * We used to condition this assignment on the ring's
196899ad48a4SRyan Zezeski 	 * 'mr_state' being one of 'MR_INUSE'. However, there are
196999ad48a4SRyan Zezeski 	 * cases where this is called before the ring has any active
197099ad48a4SRyan Zezeski 	 * clients, and therefore is not marked as in use. Since the
197199ad48a4SRyan Zezeski 	 * sole purpose of this function is for aggr to make sure
197299ad48a4SRyan Zezeski 	 * 'mi_default_tx_ring' matches 'lg_tx_ports[0]', its
197399ad48a4SRyan Zezeski 	 * imperative that we update its value regardless of ring
197499ad48a4SRyan Zezeski 	 * state. Otherwise, we can end up in a state where
197599ad48a4SRyan Zezeski 	 * 'mi_default_tx_ring' points to a pseudo ring of a downed
197699ad48a4SRyan Zezeski 	 * port, even when 'lg_tx_ports[0]' points to a port that is
197799ad48a4SRyan Zezeski 	 * up.
197899ad48a4SRyan Zezeski 	 */
197909b7f21aSRobert Mustacchi 	mip->mi_default_tx_ring = rh;
198009b7f21aSRobert Mustacchi }
198109b7f21aSRobert Mustacchi 
1982da14cebeSEric Cheng int
mac_hwgroup_addmac(mac_group_handle_t gh,const uint8_t * addr)1983da14cebeSEric Cheng mac_hwgroup_addmac(mac_group_handle_t gh, const uint8_t *addr)
1984da14cebeSEric Cheng {
1985da14cebeSEric Cheng 	mac_group_t *group = (mac_group_t *)gh;
1986da14cebeSEric Cheng 
1987da14cebeSEric Cheng 	return (mac_group_addmac(group, addr));
1988da14cebeSEric Cheng }
1989da14cebeSEric Cheng 
1990da14cebeSEric Cheng int
mac_hwgroup_remmac(mac_group_handle_t gh,const uint8_t * addr)1991da14cebeSEric Cheng mac_hwgroup_remmac(mac_group_handle_t gh, const uint8_t *addr)
1992da14cebeSEric Cheng {
1993da14cebeSEric Cheng 	mac_group_t *group = (mac_group_t *)gh;
1994da14cebeSEric Cheng 
1995da14cebeSEric Cheng 	return (mac_group_remmac(group, addr));
1996da14cebeSEric Cheng }
1997da14cebeSEric Cheng 
1998da14cebeSEric Cheng /*
199984de666eSRyan Zezeski  * Program the group's HW VLAN filter if it has such support.
200084de666eSRyan Zezeski  * Otherwise, the group will implicitly accept tagged traffic and
200184de666eSRyan Zezeski  * there is nothing to do.
200284de666eSRyan Zezeski  */
200384de666eSRyan Zezeski int
mac_hwgroup_addvlan(mac_group_handle_t gh,uint16_t vid)200484de666eSRyan Zezeski mac_hwgroup_addvlan(mac_group_handle_t gh, uint16_t vid)
200584de666eSRyan Zezeski {
200684de666eSRyan Zezeski 	mac_group_t *group = (mac_group_t *)gh;
200784de666eSRyan Zezeski 
200884de666eSRyan Zezeski 	if (!MAC_GROUP_HW_VLAN(group))
200984de666eSRyan Zezeski 		return (0);
201084de666eSRyan Zezeski 
201184de666eSRyan Zezeski 	return (mac_group_addvlan(group, vid));
201284de666eSRyan Zezeski }
201384de666eSRyan Zezeski 
201484de666eSRyan Zezeski int
mac_hwgroup_remvlan(mac_group_handle_t gh,uint16_t vid)201584de666eSRyan Zezeski mac_hwgroup_remvlan(mac_group_handle_t gh, uint16_t vid)
201684de666eSRyan Zezeski {
201784de666eSRyan Zezeski 	mac_group_t *group = (mac_group_t *)gh;
201884de666eSRyan Zezeski 
201984de666eSRyan Zezeski 	if (!MAC_GROUP_HW_VLAN(group))
202084de666eSRyan Zezeski 		return (0);
202184de666eSRyan Zezeski 
202284de666eSRyan Zezeski 	return (mac_group_remvlan(group, vid));
202384de666eSRyan Zezeski }
202484de666eSRyan Zezeski 
202584de666eSRyan Zezeski /*
202684de666eSRyan Zezeski  * Determine if a MAC has HW VLAN support. This is a private API
202784de666eSRyan Zezeski  * consumed by aggr. In the future it might be nice to have a bitfield
202884de666eSRyan Zezeski  * in mac_capab_rings_t to track which forms of HW filtering are
202984de666eSRyan Zezeski  * supported by the MAC.
203084de666eSRyan Zezeski  */
203184de666eSRyan Zezeski boolean_t
mac_has_hw_vlan(mac_handle_t mh)203284de666eSRyan Zezeski mac_has_hw_vlan(mac_handle_t mh)
203384de666eSRyan Zezeski {
203484de666eSRyan Zezeski 	mac_impl_t *mip = (mac_impl_t *)mh;
203584de666eSRyan Zezeski 
203684de666eSRyan Zezeski 	return (MAC_GROUP_HW_VLAN(mip->mi_rx_groups));
203784de666eSRyan Zezeski }
203884de666eSRyan Zezeski 
203984de666eSRyan Zezeski /*
204045948e49SRyan Zezeski  * Get the number of Rx HW groups on this MAC.
204145948e49SRyan Zezeski  */
204245948e49SRyan Zezeski uint_t
mac_get_num_rx_groups(mac_handle_t mh)204345948e49SRyan Zezeski mac_get_num_rx_groups(mac_handle_t mh)
204445948e49SRyan Zezeski {
204545948e49SRyan Zezeski 	mac_impl_t *mip = (mac_impl_t *)mh;
204645948e49SRyan Zezeski 
204745948e49SRyan Zezeski 	ASSERT(MAC_PERIM_HELD(mh));
204845948e49SRyan Zezeski 	return (mip->mi_rx_group_count);
204945948e49SRyan Zezeski }
205045948e49SRyan Zezeski 
205145948e49SRyan Zezeski int
mac_set_promisc(mac_handle_t mh,boolean_t value)205245948e49SRyan Zezeski mac_set_promisc(mac_handle_t mh, boolean_t value)
205345948e49SRyan Zezeski {
205445948e49SRyan Zezeski 	mac_impl_t *mip = (mac_impl_t *)mh;
205545948e49SRyan Zezeski 
205645948e49SRyan Zezeski 	ASSERT(MAC_PERIM_HELD(mh));
205745948e49SRyan Zezeski 	return (i_mac_promisc_set(mip, value));
205845948e49SRyan Zezeski }
205945948e49SRyan Zezeski 
206045948e49SRyan Zezeski /*
2061da14cebeSEric Cheng  * Set the RX group to be shared/reserved. Note that the group must be
2062da14cebeSEric Cheng  * started/stopped outside of this function.
2063da14cebeSEric Cheng  */
2064da14cebeSEric Cheng void
mac_set_group_state(mac_group_t * grp,mac_group_state_t state)20650dc2366fSVenugopal Iyer mac_set_group_state(mac_group_t *grp, mac_group_state_t state)
2066da14cebeSEric Cheng {
2067da14cebeSEric Cheng 	/*
2068da14cebeSEric Cheng 	 * If there is no change in the group state, just return.
2069da14cebeSEric Cheng 	 */
2070da14cebeSEric Cheng 	if (grp->mrg_state == state)
2071da14cebeSEric Cheng 		return;
2072da14cebeSEric Cheng 
2073da14cebeSEric Cheng 	switch (state) {
2074da14cebeSEric Cheng 	case MAC_GROUP_STATE_RESERVED:
2075da14cebeSEric Cheng 		/*
2076da14cebeSEric Cheng 		 * Successfully reserved the group.
2077da14cebeSEric Cheng 		 *
2078da14cebeSEric Cheng 		 * Given that there is an exclusive client controlling this
2079da14cebeSEric Cheng 		 * group, we enable the group level polling when available,
2080da14cebeSEric Cheng 		 * so that SRSs get to turn on/off individual rings they's
2081da14cebeSEric Cheng 		 * assigned to.
2082da14cebeSEric Cheng 		 */
2083da14cebeSEric Cheng 		ASSERT(MAC_PERIM_HELD(grp->mrg_mh));
2084da14cebeSEric Cheng 
20850dc2366fSVenugopal Iyer 		if (grp->mrg_type == MAC_RING_TYPE_RX &&
20860dc2366fSVenugopal Iyer 		    GROUP_INTR_DISABLE_FUNC(grp) != NULL) {
2087da14cebeSEric Cheng 			GROUP_INTR_DISABLE_FUNC(grp)(GROUP_INTR_HANDLE(grp));
20880dc2366fSVenugopal Iyer 		}
2089da14cebeSEric Cheng 		break;
2090da14cebeSEric Cheng 
2091da14cebeSEric Cheng 	case MAC_GROUP_STATE_SHARED:
2092da14cebeSEric Cheng 		/*
2093da14cebeSEric Cheng 		 * Set all rings of this group to software classified.
2094da14cebeSEric Cheng 		 * If the group has an overriding interrupt, then re-enable it.
2095da14cebeSEric Cheng 		 */
2096da14cebeSEric Cheng 		ASSERT(MAC_PERIM_HELD(grp->mrg_mh));
2097da14cebeSEric Cheng 
20980dc2366fSVenugopal Iyer 		if (grp->mrg_type == MAC_RING_TYPE_RX &&
20990dc2366fSVenugopal Iyer 		    GROUP_INTR_ENABLE_FUNC(grp) != NULL) {
2100da14cebeSEric Cheng 			GROUP_INTR_ENABLE_FUNC(grp)(GROUP_INTR_HANDLE(grp));
21010dc2366fSVenugopal Iyer 		}
2102da14cebeSEric Cheng 		/* The ring is not available for reservations any more */
2103da14cebeSEric Cheng 		break;
2104da14cebeSEric Cheng 
2105da14cebeSEric Cheng 	case MAC_GROUP_STATE_REGISTERED:
2106da14cebeSEric Cheng 		/* Also callable from mac_register, perim is not held */
2107da14cebeSEric Cheng 		break;
2108da14cebeSEric Cheng 
2109da14cebeSEric Cheng 	default:
2110da14cebeSEric Cheng 		ASSERT(B_FALSE);
2111da14cebeSEric Cheng 		break;
2112da14cebeSEric Cheng 	}
2113da14cebeSEric Cheng 
2114da14cebeSEric Cheng 	grp->mrg_state = state;
2115da14cebeSEric Cheng }
2116da14cebeSEric Cheng 
2117da14cebeSEric Cheng /*
2118da14cebeSEric Cheng  * Quiesce future hardware classified packets for the specified Rx ring
2119da14cebeSEric Cheng  */
2120da14cebeSEric Cheng static void
mac_rx_ring_quiesce(mac_ring_t * rx_ring,uint_t ring_flag)2121da14cebeSEric Cheng mac_rx_ring_quiesce(mac_ring_t *rx_ring, uint_t ring_flag)
2122da14cebeSEric Cheng {
2123da14cebeSEric Cheng 	ASSERT(rx_ring->mr_classify_type == MAC_HW_CLASSIFIER);
2124da14cebeSEric Cheng 	ASSERT(ring_flag == MR_CONDEMNED || ring_flag  == MR_QUIESCE);
2125da14cebeSEric Cheng 
2126da14cebeSEric Cheng 	mutex_enter(&rx_ring->mr_lock);
2127da14cebeSEric Cheng 	rx_ring->mr_flag |= ring_flag;
2128da14cebeSEric Cheng 	while (rx_ring->mr_refcnt != 0)
2129da14cebeSEric Cheng 		cv_wait(&rx_ring->mr_cv, &rx_ring->mr_lock);
2130da14cebeSEric Cheng 	mutex_exit(&rx_ring->mr_lock);
2131da14cebeSEric Cheng }
2132da14cebeSEric Cheng 
2133da14cebeSEric Cheng /*
2134da14cebeSEric Cheng  * Please see mac_tx for details about the per cpu locking scheme
2135da14cebeSEric Cheng  */
2136da14cebeSEric Cheng static void
mac_tx_lock_all(mac_client_impl_t * mcip)2137da14cebeSEric Cheng mac_tx_lock_all(mac_client_impl_t *mcip)
2138da14cebeSEric Cheng {
2139da14cebeSEric Cheng 	int	i;
2140da14cebeSEric Cheng 
2141da14cebeSEric Cheng 	for (i = 0; i <= mac_tx_percpu_cnt; i++)
2142da14cebeSEric Cheng 		mutex_enter(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
2143da14cebeSEric Cheng }
2144da14cebeSEric Cheng 
2145da14cebeSEric Cheng static void
mac_tx_unlock_all(mac_client_impl_t * mcip)2146da14cebeSEric Cheng mac_tx_unlock_all(mac_client_impl_t *mcip)
2147da14cebeSEric Cheng {
2148da14cebeSEric Cheng 	int	i;
2149da14cebeSEric Cheng 
2150da14cebeSEric Cheng 	for (i = mac_tx_percpu_cnt; i >= 0; i--)
2151da14cebeSEric Cheng 		mutex_exit(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
2152da14cebeSEric Cheng }
2153da14cebeSEric Cheng 
2154da14cebeSEric Cheng static void
mac_tx_unlock_allbutzero(mac_client_impl_t * mcip)2155da14cebeSEric Cheng mac_tx_unlock_allbutzero(mac_client_impl_t *mcip)
2156da14cebeSEric Cheng {
2157da14cebeSEric Cheng 	int	i;
2158da14cebeSEric Cheng 
2159da14cebeSEric Cheng 	for (i = mac_tx_percpu_cnt; i > 0; i--)
2160da14cebeSEric Cheng 		mutex_exit(&mcip->mci_tx_pcpu[i].pcpu_tx_lock);
2161da14cebeSEric Cheng }
2162da14cebeSEric Cheng 
2163da14cebeSEric Cheng static int
mac_tx_sum_refcnt(mac_client_impl_t * mcip)2164da14cebeSEric Cheng mac_tx_sum_refcnt(mac_client_impl_t *mcip)
2165da14cebeSEric Cheng {
2166da14cebeSEric Cheng 	int	i;
2167da14cebeSEric Cheng 	int	refcnt = 0;
2168da14cebeSEric Cheng 
2169da14cebeSEric Cheng 	for (i = 0; i <= mac_tx_percpu_cnt; i++)
2170da14cebeSEric Cheng 		refcnt += mcip->mci_tx_pcpu[i].pcpu_tx_refcnt;
2171da14cebeSEric Cheng 
2172da14cebeSEric Cheng 	return (refcnt);
2173da14cebeSEric Cheng }
2174da14cebeSEric Cheng 
2175da14cebeSEric Cheng /*
2176da14cebeSEric Cheng  * Stop future Tx packets coming down from the client in preparation for
2177da14cebeSEric Cheng  * quiescing the Tx side. This is needed for dynamic reclaim and reassignment
2178da14cebeSEric Cheng  * of rings between clients
2179da14cebeSEric Cheng  */
2180da14cebeSEric Cheng void
mac_tx_client_block(mac_client_impl_t * mcip)2181da14cebeSEric Cheng mac_tx_client_block(mac_client_impl_t *mcip)
2182da14cebeSEric Cheng {
2183da14cebeSEric Cheng 	mac_tx_lock_all(mcip);
2184da14cebeSEric Cheng 	mcip->mci_tx_flag |= MCI_TX_QUIESCE;
2185da14cebeSEric Cheng 	while (mac_tx_sum_refcnt(mcip) != 0) {
2186da14cebeSEric Cheng 		mac_tx_unlock_allbutzero(mcip);
2187da14cebeSEric Cheng 		cv_wait(&mcip->mci_tx_cv, &mcip->mci_tx_pcpu[0].pcpu_tx_lock);
2188da14cebeSEric Cheng 		mutex_exit(&mcip->mci_tx_pcpu[0].pcpu_tx_lock);
2189da14cebeSEric Cheng 		mac_tx_lock_all(mcip);
2190da14cebeSEric Cheng 	}
2191da14cebeSEric Cheng 	mac_tx_unlock_all(mcip);
2192da14cebeSEric Cheng }
2193da14cebeSEric Cheng 
2194da14cebeSEric Cheng void
mac_tx_client_unblock(mac_client_impl_t * mcip)2195da14cebeSEric Cheng mac_tx_client_unblock(mac_client_impl_t *mcip)
2196da14cebeSEric Cheng {
2197da14cebeSEric Cheng 	mac_tx_lock_all(mcip);
2198da14cebeSEric Cheng 	mcip->mci_tx_flag &= ~MCI_TX_QUIESCE;
2199da14cebeSEric Cheng 	mac_tx_unlock_all(mcip);
2200ae6aa22aSVenugopal Iyer 	/*
2201ae6aa22aSVenugopal Iyer 	 * We may fail to disable flow control for the last MAC_NOTE_TX
2202ae6aa22aSVenugopal Iyer 	 * notification because the MAC client is quiesced. Send the
2203ae6aa22aSVenugopal Iyer 	 * notification again.
2204ae6aa22aSVenugopal Iyer 	 */
2205ae6aa22aSVenugopal Iyer 	i_mac_notify(mcip->mci_mip, MAC_NOTE_TX);
2206da14cebeSEric Cheng }
2207da14cebeSEric Cheng 
2208da14cebeSEric Cheng /*
2209da14cebeSEric Cheng  * Wait for an SRS to quiesce. The SRS worker will signal us when the
2210da14cebeSEric Cheng  * quiesce is done.
2211da14cebeSEric Cheng  */
2212da14cebeSEric Cheng static void
mac_srs_quiesce_wait(mac_soft_ring_set_t * srs,uint_t srs_flag)2213da14cebeSEric Cheng mac_srs_quiesce_wait(mac_soft_ring_set_t *srs, uint_t srs_flag)
2214da14cebeSEric Cheng {
2215da14cebeSEric Cheng 	mutex_enter(&srs->srs_lock);
2216da14cebeSEric Cheng 	while (!(srs->srs_state & srs_flag))
2217da14cebeSEric Cheng 		cv_wait(&srs->srs_quiesce_done_cv, &srs->srs_lock);
2218da14cebeSEric Cheng 	mutex_exit(&srs->srs_lock);
2219da14cebeSEric Cheng }
2220da14cebeSEric Cheng 
2221da14cebeSEric Cheng /*
2222da14cebeSEric Cheng  * Quiescing an Rx SRS is achieved by the following sequence. The protocol
2223da14cebeSEric Cheng  * works bottom up by cutting off packet flow from the bottommost point in the
2224da14cebeSEric Cheng  * mac, then the SRS, and then the soft rings. There are 2 use cases of this
2225da14cebeSEric Cheng  * mechanism. One is a temporary quiesce of the SRS, such as say while changing
2226da14cebeSEric Cheng  * the Rx callbacks. Another use case is Rx SRS teardown. In the former case
2227da14cebeSEric Cheng  * the QUIESCE prefix/suffix is used and in the latter the CONDEMNED is used
2228da14cebeSEric Cheng  * for the SRS and MR flags. In the former case the threads pause waiting for
2229da14cebeSEric Cheng  * a restart, while in the latter case the threads exit. The Tx SRS teardown
2230da14cebeSEric Cheng  * is also mostly similar to the above.
2231da14cebeSEric Cheng  *
2232da14cebeSEric Cheng  * 1. Stop future hardware classified packets at the lowest level in the mac.
2233da14cebeSEric Cheng  *    Remove any hardware classification rule (CONDEMNED case) and mark the
2234da14cebeSEric Cheng  *    rings as CONDEMNED or QUIESCE as appropriate. This prevents the mr_refcnt
2235da14cebeSEric Cheng  *    from increasing. Upcalls from the driver that come through hardware
2236da14cebeSEric Cheng  *    classification will be dropped in mac_rx from now on. Then we wait for
2237da14cebeSEric Cheng  *    the mr_refcnt to drop to zero. When the mr_refcnt reaches zero we are
2238da14cebeSEric Cheng  *    sure there aren't any upcall threads from the driver through hardware
2239da14cebeSEric Cheng  *    classification. In the case of SRS teardown we also remove the
2240da14cebeSEric Cheng  *    classification rule in the driver.
2241da14cebeSEric Cheng  *
2242da14cebeSEric Cheng  * 2. Stop future software classified packets by marking the flow entry with
2243da14cebeSEric Cheng  *    FE_QUIESCE or FE_CONDEMNED as appropriate which prevents the refcnt from
2244da14cebeSEric Cheng  *    increasing. We also remove the flow entry from the table in the latter
2245da14cebeSEric Cheng  *    case. Then wait for the fe_refcnt to reach an appropriate quiescent value
2246da14cebeSEric Cheng  *    that indicates there aren't any active threads using that flow entry.
2247da14cebeSEric Cheng  *
2248da14cebeSEric Cheng  * 3. Quiesce the SRS and softrings by signaling the SRS. The SRS poll thread,
2249da14cebeSEric Cheng  *    SRS worker thread, and the soft ring threads are quiesced in sequence
2250da14cebeSEric Cheng  *    with the SRS worker thread serving as a master controller. This
2251da14cebeSEric Cheng  *    mechansim is explained in mac_srs_worker_quiesce().
2252da14cebeSEric Cheng  *
2253da14cebeSEric Cheng  * The restart mechanism to reactivate the SRS and softrings is explained
2254da14cebeSEric Cheng  * in mac_srs_worker_restart(). Here we just signal the SRS worker to start the
2255da14cebeSEric Cheng  * restart sequence.
2256da14cebeSEric Cheng  */
2257da14cebeSEric Cheng void
mac_rx_srs_quiesce(mac_soft_ring_set_t * srs,uint_t srs_quiesce_flag)2258da14cebeSEric Cheng mac_rx_srs_quiesce(mac_soft_ring_set_t *srs, uint_t srs_quiesce_flag)
2259da14cebeSEric Cheng {
2260da14cebeSEric Cheng 	flow_entry_t	*flent = srs->srs_flent;
2261da14cebeSEric Cheng 	uint_t	mr_flag, srs_done_flag;
2262da14cebeSEric Cheng 
2263da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)FLENT_TO_MIP(flent)));
2264da14cebeSEric Cheng 	ASSERT(!(srs->srs_type & SRST_TX));
2265da14cebeSEric Cheng 
2266da14cebeSEric Cheng 	if (srs_quiesce_flag == SRS_CONDEMNED) {
2267da14cebeSEric Cheng 		mr_flag = MR_CONDEMNED;
2268da14cebeSEric Cheng 		srs_done_flag = SRS_CONDEMNED_DONE;
2269da14cebeSEric Cheng 		if (srs->srs_type & SRST_CLIENT_POLL_ENABLED)
2270da14cebeSEric Cheng 			mac_srs_client_poll_disable(srs->srs_mcip, srs);
2271da14cebeSEric Cheng 	} else {
2272da14cebeSEric Cheng 		ASSERT(srs_quiesce_flag == SRS_QUIESCE);
2273da14cebeSEric Cheng 		mr_flag = MR_QUIESCE;
2274da14cebeSEric Cheng 		srs_done_flag = SRS_QUIESCE_DONE;
2275da14cebeSEric Cheng 		if (srs->srs_type & SRST_CLIENT_POLL_ENABLED)
2276da14cebeSEric Cheng 			mac_srs_client_poll_quiesce(srs->srs_mcip, srs);
2277da14cebeSEric Cheng 	}
2278da14cebeSEric Cheng 
2279da14cebeSEric Cheng 	if (srs->srs_ring != NULL) {
2280da14cebeSEric Cheng 		mac_rx_ring_quiesce(srs->srs_ring, mr_flag);
2281da14cebeSEric Cheng 	} else {
2282da14cebeSEric Cheng 		/*
2283da14cebeSEric Cheng 		 * SRS is driven by software classification. In case
2284da14cebeSEric Cheng 		 * of CONDEMNED, the top level teardown functions will
2285da14cebeSEric Cheng 		 * deal with flow removal.
2286da14cebeSEric Cheng 		 */
2287da14cebeSEric Cheng 		if (srs_quiesce_flag != SRS_CONDEMNED) {
2288da14cebeSEric Cheng 			FLOW_MARK(flent, FE_QUIESCE);
2289da14cebeSEric Cheng 			mac_flow_wait(flent, FLOW_DRIVER_UPCALL);
2290da14cebeSEric Cheng 		}
2291da14cebeSEric Cheng 	}
2292da14cebeSEric Cheng 
2293da14cebeSEric Cheng 	/*
2294da14cebeSEric Cheng 	 * Signal the SRS to quiesce itself, and then cv_wait for the
2295da14cebeSEric Cheng 	 * SRS quiesce to complete. The SRS worker thread will wake us
2296da14cebeSEric Cheng 	 * up when the quiesce is complete
2297da14cebeSEric Cheng 	 */
2298da14cebeSEric Cheng 	mac_srs_signal(srs, srs_quiesce_flag);
2299da14cebeSEric Cheng 	mac_srs_quiesce_wait(srs, srs_done_flag);
2300da14cebeSEric Cheng }
2301da14cebeSEric Cheng 
2302da14cebeSEric Cheng /*
2303da14cebeSEric Cheng  * Remove an SRS.
2304da14cebeSEric Cheng  */
2305da14cebeSEric Cheng void
mac_rx_srs_remove(mac_soft_ring_set_t * srs)2306da14cebeSEric Cheng mac_rx_srs_remove(mac_soft_ring_set_t *srs)
2307da14cebeSEric Cheng {
2308da14cebeSEric Cheng 	flow_entry_t *flent = srs->srs_flent;
2309da14cebeSEric Cheng 	int i;
2310da14cebeSEric Cheng 
2311da14cebeSEric Cheng 	mac_rx_srs_quiesce(srs, SRS_CONDEMNED);
2312da14cebeSEric Cheng 	/*
2313da14cebeSEric Cheng 	 * Locate and remove our entry in the fe_rx_srs[] array, and
2314da14cebeSEric Cheng 	 * adjust the fe_rx_srs array entries and array count by
2315da14cebeSEric Cheng 	 * moving the last entry into the vacated spot.
2316da14cebeSEric Cheng 	 */
2317da14cebeSEric Cheng 	mutex_enter(&flent->fe_lock);
2318da14cebeSEric Cheng 	for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
2319da14cebeSEric Cheng 		if (flent->fe_rx_srs[i] == srs)
2320da14cebeSEric Cheng 			break;
2321da14cebeSEric Cheng 	}
2322da14cebeSEric Cheng 
2323da14cebeSEric Cheng 	ASSERT(i != 0 && i < flent->fe_rx_srs_cnt);
2324da14cebeSEric Cheng 	if (i != flent->fe_rx_srs_cnt - 1) {
2325da14cebeSEric Cheng 		flent->fe_rx_srs[i] =
2326da14cebeSEric Cheng 		    flent->fe_rx_srs[flent->fe_rx_srs_cnt - 1];
2327da14cebeSEric Cheng 		i = flent->fe_rx_srs_cnt - 1;
2328da14cebeSEric Cheng 	}
2329da14cebeSEric Cheng 
2330da14cebeSEric Cheng 	flent->fe_rx_srs[i] = NULL;
2331da14cebeSEric Cheng 	flent->fe_rx_srs_cnt--;
2332da14cebeSEric Cheng 	mutex_exit(&flent->fe_lock);
2333da14cebeSEric Cheng 
2334da14cebeSEric Cheng 	mac_srs_free(srs);
2335da14cebeSEric Cheng }
2336da14cebeSEric Cheng 
2337da14cebeSEric Cheng static void
mac_srs_clear_flag(mac_soft_ring_set_t * srs,uint_t flag)2338da14cebeSEric Cheng mac_srs_clear_flag(mac_soft_ring_set_t *srs, uint_t flag)
2339da14cebeSEric Cheng {
2340da14cebeSEric Cheng 	mutex_enter(&srs->srs_lock);
2341da14cebeSEric Cheng 	srs->srs_state &= ~flag;
2342da14cebeSEric Cheng 	mutex_exit(&srs->srs_lock);
2343da14cebeSEric Cheng }
2344da14cebeSEric Cheng 
2345da14cebeSEric Cheng void
mac_rx_srs_restart(mac_soft_ring_set_t * srs)2346da14cebeSEric Cheng mac_rx_srs_restart(mac_soft_ring_set_t *srs)
2347da14cebeSEric Cheng {
2348da14cebeSEric Cheng 	flow_entry_t	*flent = srs->srs_flent;
2349da14cebeSEric Cheng 	mac_ring_t	*mr;
2350da14cebeSEric Cheng 
2351da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)FLENT_TO_MIP(flent)));
2352da14cebeSEric Cheng 	ASSERT((srs->srs_type & SRST_TX) == 0);
2353da14cebeSEric Cheng 
2354da14cebeSEric Cheng 	/*
2355da14cebeSEric Cheng 	 * This handles a change in the number of SRSs between the quiesce and
2356da14cebeSEric Cheng 	 * and restart operation of a flow.
2357da14cebeSEric Cheng 	 */
2358da14cebeSEric Cheng 	if (!SRS_QUIESCED(srs))
2359da14cebeSEric Cheng 		return;
2360da14cebeSEric Cheng 
2361da14cebeSEric Cheng 	/*
2362da14cebeSEric Cheng 	 * Signal the SRS to restart itself. Wait for the restart to complete
2363da14cebeSEric Cheng 	 * Note that we only restart the SRS if it is not marked as
2364da14cebeSEric Cheng 	 * permanently quiesced.
2365da14cebeSEric Cheng 	 */
2366da14cebeSEric Cheng 	if (!SRS_QUIESCED_PERMANENT(srs)) {
2367da14cebeSEric Cheng 		mac_srs_signal(srs, SRS_RESTART);
2368da14cebeSEric Cheng 		mac_srs_quiesce_wait(srs, SRS_RESTART_DONE);
2369da14cebeSEric Cheng 		mac_srs_clear_flag(srs, SRS_RESTART_DONE);
2370da14cebeSEric Cheng 
2371da14cebeSEric Cheng 		mac_srs_client_poll_restart(srs->srs_mcip, srs);
2372da14cebeSEric Cheng 	}
2373da14cebeSEric Cheng 
2374da14cebeSEric Cheng 	/* Finally clear the flags to let the packets in */
2375da14cebeSEric Cheng 	mr = srs->srs_ring;
2376da14cebeSEric Cheng 	if (mr != NULL) {
2377da14cebeSEric Cheng 		MAC_RING_UNMARK(mr, MR_QUIESCE);
2378da14cebeSEric Cheng 		/* In case the ring was stopped, safely restart it */
23790dc2366fSVenugopal Iyer 		if (mr->mr_state != MR_INUSE)
2380da14cebeSEric Cheng 			(void) mac_start_ring(mr);
2381da14cebeSEric Cheng 	} else {
2382da14cebeSEric Cheng 		FLOW_UNMARK(flent, FE_QUIESCE);
2383da14cebeSEric Cheng 	}
2384da14cebeSEric Cheng }
2385da14cebeSEric Cheng 
2386da14cebeSEric Cheng /*
2387da14cebeSEric Cheng  * Temporary quiesce of a flow and associated Rx SRS.
2388da14cebeSEric Cheng  * Please see block comment above mac_rx_classify_flow_rem.
2389da14cebeSEric Cheng  */
2390da14cebeSEric Cheng /* ARGSUSED */
2391da14cebeSEric Cheng int
mac_rx_classify_flow_quiesce(flow_entry_t * flent,void * arg)2392da14cebeSEric Cheng mac_rx_classify_flow_quiesce(flow_entry_t *flent, void *arg)
2393da14cebeSEric Cheng {
2394da14cebeSEric Cheng 	int		i;
2395da14cebeSEric Cheng 
2396da14cebeSEric Cheng 	for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
2397da14cebeSEric Cheng 		mac_rx_srs_quiesce((mac_soft_ring_set_t *)flent->fe_rx_srs[i],
2398da14cebeSEric Cheng 		    SRS_QUIESCE);
2399da14cebeSEric Cheng 	}
2400da14cebeSEric Cheng 	return (0);
2401da14cebeSEric Cheng }
2402da14cebeSEric Cheng 
2403da14cebeSEric Cheng /*
2404da14cebeSEric Cheng  * Restart a flow and associated Rx SRS that has been quiesced temporarily
2405da14cebeSEric Cheng  * Please see block comment above mac_rx_classify_flow_rem
2406da14cebeSEric Cheng  */
2407da14cebeSEric Cheng /* ARGSUSED */
2408da14cebeSEric Cheng int
mac_rx_classify_flow_restart(flow_entry_t * flent,void * arg)2409da14cebeSEric Cheng mac_rx_classify_flow_restart(flow_entry_t *flent, void *arg)
2410da14cebeSEric Cheng {
2411da14cebeSEric Cheng 	int		i;
2412da14cebeSEric Cheng 
2413da14cebeSEric Cheng 	for (i = 0; i < flent->fe_rx_srs_cnt; i++)
2414da14cebeSEric Cheng 		mac_rx_srs_restart((mac_soft_ring_set_t *)flent->fe_rx_srs[i]);
2415da14cebeSEric Cheng 
2416da14cebeSEric Cheng 	return (0);
2417da14cebeSEric Cheng }
2418da14cebeSEric Cheng 
2419da14cebeSEric Cheng void
mac_srs_perm_quiesce(mac_client_handle_t mch,boolean_t on)2420da14cebeSEric Cheng mac_srs_perm_quiesce(mac_client_handle_t mch, boolean_t on)
2421da14cebeSEric Cheng {
2422da14cebeSEric Cheng 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
2423da14cebeSEric Cheng 	flow_entry_t		*flent = mcip->mci_flent;
2424da14cebeSEric Cheng 	mac_impl_t		*mip = mcip->mci_mip;
2425da14cebeSEric Cheng 	mac_soft_ring_set_t	*mac_srs;
2426da14cebeSEric Cheng 	int			i;
2427da14cebeSEric Cheng 
2428da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2429da14cebeSEric Cheng 
2430da14cebeSEric Cheng 	if (flent == NULL)
2431da14cebeSEric Cheng 		return;
2432da14cebeSEric Cheng 
2433da14cebeSEric Cheng 	for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
2434da14cebeSEric Cheng 		mac_srs = flent->fe_rx_srs[i];
2435da14cebeSEric Cheng 		mutex_enter(&mac_srs->srs_lock);
2436da14cebeSEric Cheng 		if (on)
2437da14cebeSEric Cheng 			mac_srs->srs_state |= SRS_QUIESCE_PERM;
2438ba2e4443Sseb 		else
2439da14cebeSEric Cheng 			mac_srs->srs_state &= ~SRS_QUIESCE_PERM;
2440da14cebeSEric Cheng 		mutex_exit(&mac_srs->srs_lock);
24417c478bd9Sstevel@tonic-gate 	}
24427c478bd9Sstevel@tonic-gate }
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate void
mac_rx_client_quiesce(mac_client_handle_t mch)2445da14cebeSEric Cheng mac_rx_client_quiesce(mac_client_handle_t mch)
24467c478bd9Sstevel@tonic-gate {
2447da14cebeSEric Cheng 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
2448da14cebeSEric Cheng 	mac_impl_t		*mip = mcip->mci_mip;
24497c478bd9Sstevel@tonic-gate 
2450da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2451da14cebeSEric Cheng 
2452da14cebeSEric Cheng 	if (MCIP_DATAPATH_SETUP(mcip)) {
2453da14cebeSEric Cheng 		(void) mac_rx_classify_flow_quiesce(mcip->mci_flent,
2454da14cebeSEric Cheng 		    NULL);
2455da14cebeSEric Cheng 		(void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2456da14cebeSEric Cheng 		    mac_rx_classify_flow_quiesce, NULL);
24577c478bd9Sstevel@tonic-gate 	}
24587c478bd9Sstevel@tonic-gate }
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate void
mac_rx_client_restart(mac_client_handle_t mch)2461da14cebeSEric Cheng mac_rx_client_restart(mac_client_handle_t mch)
24627c478bd9Sstevel@tonic-gate {
2463da14cebeSEric Cheng 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
2464da14cebeSEric Cheng 	mac_impl_t		*mip = mcip->mci_mip;
24657c478bd9Sstevel@tonic-gate 
2466da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
2467da14cebeSEric Cheng 
2468da14cebeSEric Cheng 	if (MCIP_DATAPATH_SETUP(mcip)) {
2469da14cebeSEric Cheng 		(void) mac_rx_classify_flow_restart(mcip->mci_flent, NULL);
2470da14cebeSEric Cheng 		(void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2471da14cebeSEric Cheng 		    mac_rx_classify_flow_restart, NULL);
2472da14cebeSEric Cheng 	}
24737c478bd9Sstevel@tonic-gate }
24747c478bd9Sstevel@tonic-gate 
24751f8aaf0dSethindra /*
2476da14cebeSEric Cheng  * This function only quiesces the Tx SRS and softring worker threads. Callers
2477da14cebeSEric Cheng  * need to make sure that there aren't any mac client threads doing current or
2478da14cebeSEric Cheng  * future transmits in the mac before calling this function.
24797c478bd9Sstevel@tonic-gate  */
24807c478bd9Sstevel@tonic-gate void
mac_tx_srs_quiesce(mac_soft_ring_set_t * srs,uint_t srs_quiesce_flag)2481da14cebeSEric Cheng mac_tx_srs_quiesce(mac_soft_ring_set_t *srs, uint_t srs_quiesce_flag)
24827c478bd9Sstevel@tonic-gate {
2483da14cebeSEric Cheng 	mac_client_impl_t	*mcip = srs->srs_mcip;
2484da14cebeSEric Cheng 
2485da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
2486da14cebeSEric Cheng 
2487da14cebeSEric Cheng 	ASSERT(srs->srs_type & SRST_TX);
2488da14cebeSEric Cheng 	ASSERT(srs_quiesce_flag == SRS_CONDEMNED ||
2489da14cebeSEric Cheng 	    srs_quiesce_flag == SRS_QUIESCE);
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	/*
2492da14cebeSEric Cheng 	 * Signal the SRS to quiesce itself, and then cv_wait for the
2493da14cebeSEric Cheng 	 * SRS quiesce to complete. The SRS worker thread will wake us
2494da14cebeSEric Cheng 	 * up when the quiesce is complete
24957c478bd9Sstevel@tonic-gate 	 */
2496da14cebeSEric Cheng 	mac_srs_signal(srs, srs_quiesce_flag);
2497da14cebeSEric Cheng 	mac_srs_quiesce_wait(srs, srs_quiesce_flag == SRS_QUIESCE ?
2498da14cebeSEric Cheng 	    SRS_QUIESCE_DONE : SRS_CONDEMNED_DONE);
24997c478bd9Sstevel@tonic-gate }
25007c478bd9Sstevel@tonic-gate 
2501da14cebeSEric Cheng void
mac_tx_srs_restart(mac_soft_ring_set_t * srs)2502da14cebeSEric Cheng mac_tx_srs_restart(mac_soft_ring_set_t *srs)
2503da14cebeSEric Cheng {
25041f8aaf0dSethindra 	/*
2505da14cebeSEric Cheng 	 * Resizing the fanout could result in creation of new SRSs.
2506da14cebeSEric Cheng 	 * They may not necessarily be in the quiesced state in which
2507da14cebeSEric Cheng 	 * case it need be restarted
25081f8aaf0dSethindra 	 */
2509da14cebeSEric Cheng 	if (!SRS_QUIESCED(srs))
25101f8aaf0dSethindra 		return;
25111f8aaf0dSethindra 
2512da14cebeSEric Cheng 	mac_srs_signal(srs, SRS_RESTART);
2513da14cebeSEric Cheng 	mac_srs_quiesce_wait(srs, SRS_RESTART_DONE);
2514da14cebeSEric Cheng 	mac_srs_clear_flag(srs, SRS_RESTART_DONE);
25151f8aaf0dSethindra }
25161f8aaf0dSethindra 
25171f8aaf0dSethindra /*
2518da14cebeSEric Cheng  * Temporary quiesce of a flow and associated Rx SRS.
2519da14cebeSEric Cheng  * Please see block comment above mac_rx_srs_quiesce
25201f8aaf0dSethindra  */
2521da14cebeSEric Cheng /* ARGSUSED */
2522da14cebeSEric Cheng int
mac_tx_flow_quiesce(flow_entry_t * flent,void * arg)2523da14cebeSEric Cheng mac_tx_flow_quiesce(flow_entry_t *flent, void *arg)
25241f8aaf0dSethindra {
2525da14cebeSEric Cheng 	/*
2526da14cebeSEric Cheng 	 * The fe_tx_srs is null for a subflow on an interface that is
2527da14cebeSEric Cheng 	 * not plumbed
2528da14cebeSEric Cheng 	 */
2529da14cebeSEric Cheng 	if (flent->fe_tx_srs != NULL)
2530da14cebeSEric Cheng 		mac_tx_srs_quiesce(flent->fe_tx_srs, SRS_QUIESCE);
2531da14cebeSEric Cheng 	return (0);
25327c478bd9Sstevel@tonic-gate }
25337c478bd9Sstevel@tonic-gate 
2534da14cebeSEric Cheng /* ARGSUSED */
2535da14cebeSEric Cheng int
mac_tx_flow_restart(flow_entry_t * flent,void * arg)2536da14cebeSEric Cheng mac_tx_flow_restart(flow_entry_t *flent, void *arg)
25377c478bd9Sstevel@tonic-gate {
25387c478bd9Sstevel@tonic-gate 	/*
2539da14cebeSEric Cheng 	 * The fe_tx_srs is null for a subflow on an interface that is
2540da14cebeSEric Cheng 	 * not plumbed
25417c478bd9Sstevel@tonic-gate 	 */
2542da14cebeSEric Cheng 	if (flent->fe_tx_srs != NULL)
2543da14cebeSEric Cheng 		mac_tx_srs_restart(flent->fe_tx_srs);
2544da14cebeSEric Cheng 	return (0);
25457c478bd9Sstevel@tonic-gate }
25467c478bd9Sstevel@tonic-gate 
25470dc2366fSVenugopal Iyer static void
i_mac_tx_client_quiesce(mac_client_handle_t mch,uint_t srs_quiesce_flag)25480dc2366fSVenugopal Iyer i_mac_tx_client_quiesce(mac_client_handle_t mch, uint_t srs_quiesce_flag)
25497c478bd9Sstevel@tonic-gate {
25500dc2366fSVenugopal Iyer 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
25510dc2366fSVenugopal Iyer 
2552da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
25537c478bd9Sstevel@tonic-gate 
2554da14cebeSEric Cheng 	mac_tx_client_block(mcip);
2555da14cebeSEric Cheng 	if (MCIP_TX_SRS(mcip) != NULL) {
2556da14cebeSEric Cheng 		mac_tx_srs_quiesce(MCIP_TX_SRS(mcip), srs_quiesce_flag);
2557da14cebeSEric Cheng 		(void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2558da14cebeSEric Cheng 		    mac_tx_flow_quiesce, NULL);
25597c478bd9Sstevel@tonic-gate 	}
2560ba2e4443Sseb }
2561ba2e4443Sseb 
2562ba2e4443Sseb void
mac_tx_client_quiesce(mac_client_handle_t mch)25630dc2366fSVenugopal Iyer mac_tx_client_quiesce(mac_client_handle_t mch)
2564ba2e4443Sseb {
25650dc2366fSVenugopal Iyer 	i_mac_tx_client_quiesce(mch, SRS_QUIESCE);
25660dc2366fSVenugopal Iyer }
25670dc2366fSVenugopal Iyer 
25680dc2366fSVenugopal Iyer void
mac_tx_client_condemn(mac_client_handle_t mch)25690dc2366fSVenugopal Iyer mac_tx_client_condemn(mac_client_handle_t mch)
25700dc2366fSVenugopal Iyer {
25710dc2366fSVenugopal Iyer 	i_mac_tx_client_quiesce(mch, SRS_CONDEMNED);
25720dc2366fSVenugopal Iyer }
25730dc2366fSVenugopal Iyer 
25740dc2366fSVenugopal Iyer void
mac_tx_client_restart(mac_client_handle_t mch)25750dc2366fSVenugopal Iyer mac_tx_client_restart(mac_client_handle_t mch)
25760dc2366fSVenugopal Iyer {
25770dc2366fSVenugopal Iyer 	mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
25780dc2366fSVenugopal Iyer 
2579da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
2580da14cebeSEric Cheng 
2581da14cebeSEric Cheng 	mac_tx_client_unblock(mcip);
2582da14cebeSEric Cheng 	if (MCIP_TX_SRS(mcip) != NULL) {
2583da14cebeSEric Cheng 		mac_tx_srs_restart(MCIP_TX_SRS(mcip));
2584da14cebeSEric Cheng 		(void) mac_flow_walk_nolock(mcip->mci_subflow_tab,
2585da14cebeSEric Cheng 		    mac_tx_flow_restart, NULL);
2586da14cebeSEric Cheng 	}
2587da14cebeSEric Cheng }
2588da14cebeSEric Cheng 
2589da14cebeSEric Cheng void
mac_tx_client_flush(mac_client_impl_t * mcip)2590da14cebeSEric Cheng mac_tx_client_flush(mac_client_impl_t *mcip)
2591da14cebeSEric Cheng {
2592da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
2593da14cebeSEric Cheng 
25940dc2366fSVenugopal Iyer 	mac_tx_client_quiesce((mac_client_handle_t)mcip);
25950dc2366fSVenugopal Iyer 	mac_tx_client_restart((mac_client_handle_t)mcip);
2596da14cebeSEric Cheng }
2597da14cebeSEric Cheng 
2598da14cebeSEric Cheng void
mac_client_quiesce(mac_client_impl_t * mcip)2599da14cebeSEric Cheng mac_client_quiesce(mac_client_impl_t *mcip)
2600da14cebeSEric Cheng {
2601da14cebeSEric Cheng 	mac_rx_client_quiesce((mac_client_handle_t)mcip);
26020dc2366fSVenugopal Iyer 	mac_tx_client_quiesce((mac_client_handle_t)mcip);
2603da14cebeSEric Cheng }
2604da14cebeSEric Cheng 
2605da14cebeSEric Cheng void
mac_client_restart(mac_client_impl_t * mcip)2606da14cebeSEric Cheng mac_client_restart(mac_client_impl_t *mcip)
2607da14cebeSEric Cheng {
2608da14cebeSEric Cheng 	mac_rx_client_restart((mac_client_handle_t)mcip);
26090dc2366fSVenugopal Iyer 	mac_tx_client_restart((mac_client_handle_t)mcip);
2610210db224Sericheng }
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate /*
2613d62bc4baSyz147064  * Allocate a minor number.
2614d62bc4baSyz147064  */
2615d62bc4baSyz147064 minor_t
mac_minor_hold(boolean_t sleep)2616d62bc4baSyz147064 mac_minor_hold(boolean_t sleep)
2617d62bc4baSyz147064 {
2618249622b3SJohn Levon 	id_t id;
2619d62bc4baSyz147064 
2620d62bc4baSyz147064 	/*
2621d62bc4baSyz147064 	 * Grab a value from the arena.
2622d62bc4baSyz147064 	 */
26231a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&minor_count);
2624d62bc4baSyz147064 
2625d62bc4baSyz147064 	if (sleep)
2626249622b3SJohn Levon 		return ((uint_t)id_alloc(minor_ids));
2627d62bc4baSyz147064 
2628249622b3SJohn Levon 	if ((id = id_alloc_nosleep(minor_ids)) == -1) {
26291a5e258fSJosef 'Jeff' Sipek 		atomic_dec_32(&minor_count);
2630d62bc4baSyz147064 		return (0);
2631d62bc4baSyz147064 	}
2632d62bc4baSyz147064 
2633249622b3SJohn Levon 	return ((uint_t)id);
2634d62bc4baSyz147064 }
2635d62bc4baSyz147064 
2636d62bc4baSyz147064 /*
2637d62bc4baSyz147064  * Release a previously allocated minor number.
2638d62bc4baSyz147064  */
2639d62bc4baSyz147064 void
mac_minor_rele(minor_t minor)2640d62bc4baSyz147064 mac_minor_rele(minor_t minor)
2641d62bc4baSyz147064 {
2642d62bc4baSyz147064 	/*
2643d62bc4baSyz147064 	 * Return the value to the arena.
2644d62bc4baSyz147064 	 */
2645d62bc4baSyz147064 	id_free(minor_ids, minor);
26461a5e258fSJosef 'Jeff' Sipek 	atomic_dec_32(&minor_count);
2647d62bc4baSyz147064 }
2648d62bc4baSyz147064 
2649d62bc4baSyz147064 uint32_t
mac_no_notification(mac_handle_t mh)2650d62bc4baSyz147064 mac_no_notification(mac_handle_t mh)
2651d62bc4baSyz147064 {
2652d62bc4baSyz147064 	mac_impl_t *mip = (mac_impl_t *)mh;
26535d460eafSCathy Zhou 
26545d460eafSCathy Zhou 	return (((mip->mi_state_flags & MIS_LEGACY) != 0) ?
26555d460eafSCathy Zhou 	    mip->mi_capab_legacy.ml_unsup_note : 0);
2656d62bc4baSyz147064 }
2657d62bc4baSyz147064 
2658d62bc4baSyz147064 /*
2659da14cebeSEric Cheng  * Prevent any new opens of this mac in preparation for unregister
26607c478bd9Sstevel@tonic-gate  */
2661ba2e4443Sseb int
i_mac_disable(mac_impl_t * mip)2662da14cebeSEric Cheng i_mac_disable(mac_impl_t *mip)
2663ba2e4443Sseb {
2664da14cebeSEric Cheng 	mac_client_impl_t	*mcip;
26657c478bd9Sstevel@tonic-gate 
2666fbe1721bSyz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
2667da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_DISABLED) {
2668da14cebeSEric Cheng 		/* Already disabled, return success */
2669fbe1721bSyz147064 		rw_exit(&i_mac_impl_lock);
2670da14cebeSEric Cheng 		return (0);
2671fbe1721bSyz147064 	}
2672da14cebeSEric Cheng 	/*
2673da14cebeSEric Cheng 	 * See if there are any other references to this mac_t (e.g., VLAN's).
2674da14cebeSEric Cheng 	 * If so return failure. If all the other checks below pass, then
2675da14cebeSEric Cheng 	 * set mi_disabled atomically under the i_mac_impl_lock to prevent
2676da14cebeSEric Cheng 	 * any new VLAN's from being created or new mac client opens of this
2677da14cebeSEric Cheng 	 * mac end point.
2678da14cebeSEric Cheng 	 */
2679da14cebeSEric Cheng 	if (mip->mi_ref > 0) {
2680da14cebeSEric Cheng 		rw_exit(&i_mac_impl_lock);
2681da14cebeSEric Cheng 		return (EBUSY);
2682da14cebeSEric Cheng 	}
2683e7801d59Ssowmini 
2684490ed22dSyz147064 	/*
2685da14cebeSEric Cheng 	 * mac clients must delete all multicast groups they join before
2686da14cebeSEric Cheng 	 * closing. bcast groups are reference counted, the last client
2687da14cebeSEric Cheng 	 * to delete the group will wait till the group is physically
2688da14cebeSEric Cheng 	 * deleted. Since all clients have closed this mac end point
2689da14cebeSEric Cheng 	 * mi_bcast_ngrps must be zero at this point
2690490ed22dSyz147064 	 */
2691da14cebeSEric Cheng 	ASSERT(mip->mi_bcast_ngrps == 0);
2692490ed22dSyz147064 
2693da14cebeSEric Cheng 	/*
2694da14cebeSEric Cheng 	 * Don't let go of this if it has some flows.
2695da14cebeSEric Cheng 	 * All other code guarantees no flows are added to a disabled
2696da14cebeSEric Cheng 	 * mac, therefore it is sufficient to check for the flow table
2697da14cebeSEric Cheng 	 * only here.
2698da14cebeSEric Cheng 	 */
2699da14cebeSEric Cheng 	mcip = mac_primary_client_handle(mip);
2700da14cebeSEric Cheng 	if ((mcip != NULL) && mac_link_has_flows((mac_client_handle_t)mcip)) {
2701ba2e4443Sseb 		rw_exit(&i_mac_impl_lock);
2702da14cebeSEric Cheng 		return (ENOTEMPTY);
2703da14cebeSEric Cheng 	}
2704fbe1721bSyz147064 
2705da14cebeSEric Cheng 	mip->mi_state_flags |= MIS_DISABLED;
2706da14cebeSEric Cheng 	rw_exit(&i_mac_impl_lock);
27077c478bd9Sstevel@tonic-gate 	return (0);
27080487e2c9Sgd78059 }
27090487e2c9Sgd78059 
2710da14cebeSEric Cheng int
mac_disable_nowait(mac_handle_t mh)2711da14cebeSEric Cheng mac_disable_nowait(mac_handle_t mh)
2712da14cebeSEric Cheng {
2713da14cebeSEric Cheng 	mac_impl_t	*mip = (mac_impl_t *)mh;
2714da14cebeSEric Cheng 	int err;
2715ba2e4443Sseb 
2716da14cebeSEric Cheng 	if ((err = i_mac_perim_enter_nowait(mip)) != 0)
2717da14cebeSEric Cheng 		return (err);
2718da14cebeSEric Cheng 	err = i_mac_disable(mip);
2719da14cebeSEric Cheng 	i_mac_perim_exit(mip);
2720210db224Sericheng 	return (err);
27217c478bd9Sstevel@tonic-gate }
27227c478bd9Sstevel@tonic-gate 
27237c478bd9Sstevel@tonic-gate int
mac_disable(mac_handle_t mh)2724843e1988Sjohnlev mac_disable(mac_handle_t mh)
27257c478bd9Sstevel@tonic-gate {
2726ba2e4443Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
2727843e1988Sjohnlev 	int err;
2728da14cebeSEric Cheng 
2729da14cebeSEric Cheng 	i_mac_perim_enter(mip);
2730da14cebeSEric Cheng 	err = i_mac_disable(mip);
2731da14cebeSEric Cheng 	i_mac_perim_exit(mip);
2732843e1988Sjohnlev 
2733843e1988Sjohnlev 	/*
2734da14cebeSEric Cheng 	 * Clean up notification thread and wait for it to exit.
2735843e1988Sjohnlev 	 */
2736da14cebeSEric Cheng 	if (err == 0)
2737da14cebeSEric Cheng 		i_mac_notify_exit(mip);
2738da14cebeSEric Cheng 
2739843e1988Sjohnlev 	return (err);
2740843e1988Sjohnlev }
2741843e1988Sjohnlev 
27427c478bd9Sstevel@tonic-gate /*
2743da14cebeSEric Cheng  * Called when the MAC instance has a non empty flow table, to de-multiplex
2744da14cebeSEric Cheng  * incoming packets to the right flow.
27450487e2c9Sgd78059  */
2746da14cebeSEric Cheng /* ARGSUSED */
2747*67cac09cSKyle Simpson static flow_entry_t *
mac_rx_classify(mac_impl_t * mip,mac_resource_handle_t mrh,mblk_t * mp)2748da14cebeSEric Cheng mac_rx_classify(mac_impl_t *mip, mac_resource_handle_t mrh, mblk_t *mp)
2749da14cebeSEric Cheng {
2750da14cebeSEric Cheng 	flow_entry_t	*flent = NULL;
2751da14cebeSEric Cheng 	uint_t		flags = FLOW_INBOUND;
2752da14cebeSEric Cheng 	int		err;
2753ba2e4443Sseb 
2754da14cebeSEric Cheng 	err = mac_flow_lookup(mip->mi_flow_tab, mp, flags, &flent);
2755*67cac09cSKyle Simpson 	if (err == 0) {
2756da14cebeSEric Cheng 		mac_client_impl_t	*mcip;
27571f8aaf0dSethindra 
27581f8aaf0dSethindra 		/*
2759da14cebeSEric Cheng 		 * This flent might just be an additional one on the MAC client,
2760da14cebeSEric Cheng 		 * i.e. for classification purposes (different fdesc), however
2761da14cebeSEric Cheng 		 * the resources, SRS et. al., are in the mci_flent, so if
2762da14cebeSEric Cheng 		 * this isn't the mci_flent, we need to get it.
27631f8aaf0dSethindra 		 */
2764da14cebeSEric Cheng 		if ((mcip = flent->fe_mcip) != NULL &&
2765da14cebeSEric Cheng 		    mcip->mci_flent != flent) {
2766da14cebeSEric Cheng 			FLOW_REFRELE(flent);
2767da14cebeSEric Cheng 			flent = mcip->mci_flent;
2768da14cebeSEric Cheng 			FLOW_TRY_REFHOLD(flent, err);
2769da14cebeSEric Cheng 			if (err != 0)
2770843e1988Sjohnlev 				return (NULL);
2771843e1988Sjohnlev 		}
2772*67cac09cSKyle Simpson 	}
2773*67cac09cSKyle Simpson 
2774*67cac09cSKyle Simpson 	/* flent will be NULL if mac_flow_lookup fails to find a match. */
2775*67cac09cSKyle Simpson 	return (flent);
2776*67cac09cSKyle Simpson }
2777843e1988Sjohnlev 
27787c478bd9Sstevel@tonic-gate mblk_t *
mac_rx_flow(mac_handle_t mh,mac_resource_handle_t mrh,mblk_t * mp_chain)2779da14cebeSEric Cheng mac_rx_flow(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
27807c478bd9Sstevel@tonic-gate {
2781da14cebeSEric Cheng 	mac_impl_t	*mip = (mac_impl_t *)mh;
2782*67cac09cSKyle Simpson 	mblk_t		*mp_next, *tail, **unclass_nextp;
2783*67cac09cSKyle Simpson 	mblk_t		*unclass_list = NULL;
2784*67cac09cSKyle Simpson 	flow_entry_t	*prev_flent = NULL;
27857c478bd9Sstevel@tonic-gate 
2786843e1988Sjohnlev 	/*
2787da14cebeSEric Cheng 	 * We walk the chain and attempt to classify each packet.
2788da14cebeSEric Cheng 	 * The packets that couldn't be classified will be returned
2789da14cebeSEric Cheng 	 * back to the caller.
2790*67cac09cSKyle Simpson 	 *
2791*67cac09cSKyle Simpson 	 * We want to batch together runs of matched packets bound
2792*67cac09cSKyle Simpson 	 * for the same flent into the same callback. Unmatched
2793*67cac09cSKyle Simpson 	 * packets should not break an ongoing chain.
2794843e1988Sjohnlev 	 */
2795*67cac09cSKyle Simpson 	mp_next = tail = mp_chain;
2796*67cac09cSKyle Simpson 	unclass_nextp = &unclass_list;
2797*67cac09cSKyle Simpson 	while (mp_next != NULL) {
2798*67cac09cSKyle Simpson 		flow_entry_t	*flent;
2799*67cac09cSKyle Simpson 		mblk_t		*mp = mp_next;
2800*67cac09cSKyle Simpson 		mp_next = mp_next->b_next;
2801*67cac09cSKyle Simpson 		mp->b_next = NULL;
28027c478bd9Sstevel@tonic-gate 
2803*67cac09cSKyle Simpson 		flent = mac_rx_classify(mip, mrh, mp);
2804*67cac09cSKyle Simpson 		if (flent == NULL) {
2805*67cac09cSKyle Simpson 			/*
2806*67cac09cSKyle Simpson 			 * Add the current mblk_t to the end of the
2807*67cac09cSKyle Simpson 			 * unclassified packet chain at 'unclass_list'.
2808*67cac09cSKyle Simpson 			 * Move the current head forward if we have not
2809*67cac09cSKyle Simpson 			 * yet made any match.
2810*67cac09cSKyle Simpson 			 */
2811*67cac09cSKyle Simpson 			if (prev_flent == NULL) {
2812*67cac09cSKyle Simpson 				mp_chain = mp_next;
2813*67cac09cSKyle Simpson 				tail = mp_next;
2814da14cebeSEric Cheng 			}
2815*67cac09cSKyle Simpson 			*unclass_nextp = mp;
2816*67cac09cSKyle Simpson 			unclass_nextp = &mp->b_next;
2817*67cac09cSKyle Simpson 			continue;
2818da14cebeSEric Cheng 		}
2819*67cac09cSKyle Simpson 
2820*67cac09cSKyle Simpson 		if (prev_flent == NULL || flent == prev_flent) {
2821*67cac09cSKyle Simpson 			/* Either the first valid match, or in the same chain */
2822*67cac09cSKyle Simpson 			if (prev_flent != NULL)
2823*67cac09cSKyle Simpson 				FLOW_REFRELE(prev_flent);
2824*67cac09cSKyle Simpson 			if (mp != tail)
2825*67cac09cSKyle Simpson 				tail->b_next = mp;
2826*67cac09cSKyle Simpson 		} else {
2827*67cac09cSKyle Simpson 			ASSERT3P(prev_flent, !=, NULL);
2828*67cac09cSKyle Simpson 			(prev_flent->fe_cb_fn)(prev_flent->fe_cb_arg1,
2829*67cac09cSKyle Simpson 			    prev_flent->fe_cb_arg2, mp_chain, B_FALSE);
2830*67cac09cSKyle Simpson 			FLOW_REFRELE(prev_flent);
2831*67cac09cSKyle Simpson 			mp_chain = mp;
2832*67cac09cSKyle Simpson 		}
2833*67cac09cSKyle Simpson 
2834*67cac09cSKyle Simpson 		prev_flent = flent;
2835*67cac09cSKyle Simpson 		tail = mp;
2836*67cac09cSKyle Simpson 	}
2837*67cac09cSKyle Simpson 	/* Last chain */
2838*67cac09cSKyle Simpson 	if (mp_chain != NULL) {
2839*67cac09cSKyle Simpson 		ASSERT3P(prev_flent, !=, NULL);
2840*67cac09cSKyle Simpson 		(prev_flent->fe_cb_fn)(prev_flent->fe_cb_arg1,
2841*67cac09cSKyle Simpson 		    prev_flent->fe_cb_arg2, mp_chain, B_FALSE);
2842*67cac09cSKyle Simpson 		FLOW_REFRELE(prev_flent);
2843*67cac09cSKyle Simpson 	}
2844*67cac09cSKyle Simpson 	return (unclass_list);
28457c478bd9Sstevel@tonic-gate }
28467c478bd9Sstevel@tonic-gate 
2847da14cebeSEric Cheng static int
mac_tx_flow_srs_wakeup(flow_entry_t * flent,void * arg)2848da14cebeSEric Cheng mac_tx_flow_srs_wakeup(flow_entry_t *flent, void *arg)
2849843e1988Sjohnlev {
2850da14cebeSEric Cheng 	mac_ring_handle_t ring = arg;
2851843e1988Sjohnlev 
2852da14cebeSEric Cheng 	if (flent->fe_tx_srs)
2853da14cebeSEric Cheng 		mac_tx_srs_wakeup(flent->fe_tx_srs, ring);
2854ba2e4443Sseb 	return (0);
2855ba2e4443Sseb }
2856ba2e4443Sseb 
28577c478bd9Sstevel@tonic-gate void
i_mac_tx_srs_notify(mac_impl_t * mip,mac_ring_handle_t ring)2858da14cebeSEric Cheng i_mac_tx_srs_notify(mac_impl_t *mip, mac_ring_handle_t ring)
2859da14cebeSEric Cheng {
2860da14cebeSEric Cheng 	mac_client_impl_t	*cclient;
2861da14cebeSEric Cheng 	mac_soft_ring_set_t	*mac_srs;
2862da14cebeSEric Cheng 
2863da14cebeSEric Cheng 	/*
2864da14cebeSEric Cheng 	 * After grabbing the mi_rw_lock, the list of clients can't change.
2865da14cebeSEric Cheng 	 * If there are any clients mi_disabled must be B_FALSE and can't
2866da14cebeSEric Cheng 	 * get set since there are clients. If there aren't any clients we
2867da14cebeSEric Cheng 	 * don't do anything. In any case the mip has to be valid. The driver
2868da14cebeSEric Cheng 	 * must make sure that it goes single threaded (with respect to mac
2869da14cebeSEric Cheng 	 * calls) and wait for all pending mac calls to finish before calling
2870da14cebeSEric Cheng 	 * mac_unregister.
2871da14cebeSEric Cheng 	 */
2872da14cebeSEric Cheng 	rw_enter(&i_mac_impl_lock, RW_READER);
2873da14cebeSEric Cheng 	if (mip->mi_state_flags & MIS_DISABLED) {
2874da14cebeSEric Cheng 		rw_exit(&i_mac_impl_lock);
2875da14cebeSEric Cheng 		return;
2876da14cebeSEric Cheng 	}
2877da14cebeSEric Cheng 
2878da14cebeSEric Cheng 	/*
2879da14cebeSEric Cheng 	 * Get MAC tx srs from walking mac_client_handle list.
2880da14cebeSEric Cheng 	 */
2881da14cebeSEric Cheng 	rw_enter(&mip->mi_rw_lock, RW_READER);
2882da14cebeSEric Cheng 	for (cclient = mip->mi_clients_list; cclient != NULL;
2883da14cebeSEric Cheng 	    cclient = cclient->mci_client_next) {
28840dc2366fSVenugopal Iyer 		if ((mac_srs = MCIP_TX_SRS(cclient)) != NULL) {
2885da14cebeSEric Cheng 			mac_tx_srs_wakeup(mac_srs, ring);
28860dc2366fSVenugopal Iyer 		} else {
28870dc2366fSVenugopal Iyer 			/*
28880dc2366fSVenugopal Iyer 			 * Aggr opens underlying ports in exclusive mode
28890dc2366fSVenugopal Iyer 			 * and registers flow control callbacks using
28900dc2366fSVenugopal Iyer 			 * mac_tx_client_notify(). When opened in
28910dc2366fSVenugopal Iyer 			 * exclusive mode, Tx SRS won't be created
28920dc2366fSVenugopal Iyer 			 * during mac_unicast_add().
28930dc2366fSVenugopal Iyer 			 */
28940dc2366fSVenugopal Iyer 			if (cclient->mci_state_flags & MCIS_EXCLUSIVE) {
28950dc2366fSVenugopal Iyer 				mac_tx_invoke_callbacks(cclient,
28960dc2366fSVenugopal Iyer 				    (mac_tx_cookie_t)ring);
28970dc2366fSVenugopal Iyer 			}
28980dc2366fSVenugopal Iyer 		}
2899ae6aa22aSVenugopal Iyer 		(void) mac_flow_walk(cclient->mci_subflow_tab,
2900da14cebeSEric Cheng 		    mac_tx_flow_srs_wakeup, ring);
2901da14cebeSEric Cheng 	}
2902da14cebeSEric Cheng 	rw_exit(&mip->mi_rw_lock);
2903da14cebeSEric Cheng 	rw_exit(&i_mac_impl_lock);
2904da14cebeSEric Cheng }
2905da14cebeSEric Cheng 
2906da14cebeSEric Cheng /* ARGSUSED */
2907da14cebeSEric Cheng void
mac_multicast_refresh(mac_handle_t mh,mac_multicst_t refresh,void * arg,boolean_t add)2908da14cebeSEric Cheng mac_multicast_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
29097c478bd9Sstevel@tonic-gate     boolean_t add)
29107c478bd9Sstevel@tonic-gate {
2911ba2e4443Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
29127c478bd9Sstevel@tonic-gate 
2913da14cebeSEric Cheng 	i_mac_perim_enter((mac_impl_t *)mh);
29147c478bd9Sstevel@tonic-gate 	/*
29157c478bd9Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
29167c478bd9Sstevel@tonic-gate 	 * driver's m_multicst entry point.
29177c478bd9Sstevel@tonic-gate 	 */
29187c478bd9Sstevel@tonic-gate 	if (refresh == NULL) {
2919ba2e4443Sseb 		refresh = mip->mi_multicst;
2920ba2e4443Sseb 		arg = mip->mi_driver;
29217c478bd9Sstevel@tonic-gate 	}
29227c478bd9Sstevel@tonic-gate 
2923da14cebeSEric Cheng 	mac_bcast_refresh(mip, refresh, arg, add);
2924da14cebeSEric Cheng 	i_mac_perim_exit((mac_impl_t *)mh);
29257c478bd9Sstevel@tonic-gate }
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate void
mac_promisc_refresh(mac_handle_t mh,mac_setpromisc_t refresh,void * arg)2928ba2e4443Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
29297c478bd9Sstevel@tonic-gate {
2930ba2e4443Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
29317c478bd9Sstevel@tonic-gate 
29327c478bd9Sstevel@tonic-gate 	/*
29337c478bd9Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
29347c478bd9Sstevel@tonic-gate 	 * driver's m_promisc entry point.
29357c478bd9Sstevel@tonic-gate 	 */
29367c478bd9Sstevel@tonic-gate 	if (refresh == NULL) {
2937ba2e4443Sseb 		refresh = mip->mi_setpromisc;
2938ba2e4443Sseb 		arg = mip->mi_driver;
29397c478bd9Sstevel@tonic-gate 	}
29407c478bd9Sstevel@tonic-gate 	ASSERT(refresh != NULL);
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 	/*
29437c478bd9Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
29447c478bd9Sstevel@tonic-gate 	 */
29457c478bd9Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
29467c478bd9Sstevel@tonic-gate }
29477c478bd9Sstevel@tonic-gate 
2948d62bc4baSyz147064 /*
2949d62bc4baSyz147064  * The mac client requests that the mac not to change its margin size to
2950d62bc4baSyz147064  * be less than the specified value.  If "current" is B_TRUE, then the client
2951d62bc4baSyz147064  * requests the mac not to change its margin size to be smaller than the
2952d62bc4baSyz147064  * current size. Further, return the current margin size value in this case.
2953d62bc4baSyz147064  *
2954d62bc4baSyz147064  * We keep every requested size in an ordered list from largest to smallest.
2955d62bc4baSyz147064  */
2956d62bc4baSyz147064 int
mac_margin_add(mac_handle_t mh,uint32_t * marginp,boolean_t current)2957d62bc4baSyz147064 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current)
2958d62bc4baSyz147064 {
2959d62bc4baSyz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
2960d62bc4baSyz147064 	mac_margin_req_t	**pp, *p;
2961d62bc4baSyz147064 	int			err = 0;
2962d62bc4baSyz147064 
2963da14cebeSEric Cheng 	rw_enter(&(mip->mi_rw_lock), RW_WRITER);
2964d62bc4baSyz147064 	if (current)
2965d62bc4baSyz147064 		*marginp = mip->mi_margin;
2966d62bc4baSyz147064 
2967d62bc4baSyz147064 	/*
2968d62bc4baSyz147064 	 * If the current margin value cannot satisfy the margin requested,
2969d62bc4baSyz147064 	 * return ENOTSUP directly.
2970d62bc4baSyz147064 	 */
2971d62bc4baSyz147064 	if (*marginp > mip->mi_margin) {
2972d62bc4baSyz147064 		err = ENOTSUP;
2973d62bc4baSyz147064 		goto done;
2974d62bc4baSyz147064 	}
2975d62bc4baSyz147064 
2976d62bc4baSyz147064 	/*
2977d62bc4baSyz147064 	 * Check whether the given margin is already in the list. If so,
2978d62bc4baSyz147064 	 * bump the reference count.
2979d62bc4baSyz147064 	 */
2980da14cebeSEric Cheng 	for (pp = &mip->mi_mmrp; (p = *pp) != NULL; pp = &p->mmr_nextp) {
2981d62bc4baSyz147064 		if (p->mmr_margin == *marginp) {
2982d62bc4baSyz147064 			/*
2983d62bc4baSyz147064 			 * The margin requested is already in the list,
2984d62bc4baSyz147064 			 * so just bump the reference count.
2985d62bc4baSyz147064 			 */
2986d62bc4baSyz147064 			p->mmr_ref++;
2987d62bc4baSyz147064 			goto done;
2988d62bc4baSyz147064 		}
2989d62bc4baSyz147064 		if (p->mmr_margin < *marginp)
2990d62bc4baSyz147064 			break;
2991d62bc4baSyz147064 	}
2992d62bc4baSyz147064 
2993d62bc4baSyz147064 
2994da14cebeSEric Cheng 	p = kmem_zalloc(sizeof (mac_margin_req_t), KM_SLEEP);
2995d62bc4baSyz147064 	p->mmr_margin = *marginp;
2996d62bc4baSyz147064 	p->mmr_ref++;
2997d62bc4baSyz147064 	p->mmr_nextp = *pp;
2998d62bc4baSyz147064 	*pp = p;
2999d62bc4baSyz147064 
3000d62bc4baSyz147064 done:
3001da14cebeSEric Cheng 	rw_exit(&(mip->mi_rw_lock));
3002d62bc4baSyz147064 	return (err);
3003d62bc4baSyz147064 }
3004d62bc4baSyz147064 
3005d62bc4baSyz147064 /*
3006d62bc4baSyz147064  * The mac client requests to cancel its previous mac_margin_add() request.
3007d62bc4baSyz147064  * We remove the requested margin size from the list.
3008d62bc4baSyz147064  */
3009d62bc4baSyz147064 int
mac_margin_remove(mac_handle_t mh,uint32_t margin)3010d62bc4baSyz147064 mac_margin_remove(mac_handle_t mh, uint32_t margin)
3011d62bc4baSyz147064 {
3012d62bc4baSyz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
3013d62bc4baSyz147064 	mac_margin_req_t	**pp, *p;
3014d62bc4baSyz147064 	int			err = 0;
3015d62bc4baSyz147064 
3016da14cebeSEric Cheng 	rw_enter(&(mip->mi_rw_lock), RW_WRITER);
3017d62bc4baSyz147064 	/*
3018d62bc4baSyz147064 	 * Find the entry in the list for the given margin.
3019d62bc4baSyz147064 	 */
3020d62bc4baSyz147064 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
3021d62bc4baSyz147064 		if (p->mmr_margin == margin) {
3022d62bc4baSyz147064 			if (--p->mmr_ref == 0)
3023d62bc4baSyz147064 				break;
3024d62bc4baSyz147064 
3025d62bc4baSyz147064 			/*
3026d62bc4baSyz147064 			 * There is still a reference to this address so
3027d62bc4baSyz147064 			 * there's nothing more to do.
3028d62bc4baSyz147064 			 */
3029d62bc4baSyz147064 			goto done;
3030d62bc4baSyz147064 		}
3031d62bc4baSyz147064 	}
3032d62bc4baSyz147064 
3033d62bc4baSyz147064 	/*
3034d62bc4baSyz147064 	 * We did not find an entry for the given margin.
3035d62bc4baSyz147064 	 */
3036d62bc4baSyz147064 	if (p == NULL) {
3037d62bc4baSyz147064 		err = ENOENT;
3038d62bc4baSyz147064 		goto done;
3039d62bc4baSyz147064 	}
3040d62bc4baSyz147064 
3041d62bc4baSyz147064 	ASSERT(p->mmr_ref == 0);
3042d62bc4baSyz147064 
3043d62bc4baSyz147064 	/*
3044d62bc4baSyz147064 	 * Remove it from the list.
3045d62bc4baSyz147064 	 */
3046d62bc4baSyz147064 	*pp = p->mmr_nextp;
3047d62bc4baSyz147064 	kmem_free(p, sizeof (mac_margin_req_t));
3048d62bc4baSyz147064 done:
3049da14cebeSEric Cheng 	rw_exit(&(mip->mi_rw_lock));
3050d62bc4baSyz147064 	return (err);
3051d62bc4baSyz147064 }
3052d62bc4baSyz147064 
3053d62bc4baSyz147064 boolean_t
mac_margin_update(mac_handle_t mh,uint32_t margin)3054d62bc4baSyz147064 mac_margin_update(mac_handle_t mh, uint32_t margin)
3055d62bc4baSyz147064 {
3056d62bc4baSyz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
3057d62bc4baSyz147064 	uint32_t	margin_needed = 0;
3058d62bc4baSyz147064 
3059da14cebeSEric Cheng 	rw_enter(&(mip->mi_rw_lock), RW_WRITER);
3060d62bc4baSyz147064 
3061d62bc4baSyz147064 	if (mip->mi_mmrp != NULL)
3062d62bc4baSyz147064 		margin_needed = mip->mi_mmrp->mmr_margin;
3063d62bc4baSyz147064 
3064d62bc4baSyz147064 	if (margin_needed <= margin)
3065d62bc4baSyz147064 		mip->mi_margin = margin;
3066d62bc4baSyz147064 
3067da14cebeSEric Cheng 	rw_exit(&(mip->mi_rw_lock));
3068d62bc4baSyz147064 
3069d62bc4baSyz147064 	if (margin_needed <= margin)
3070d62bc4baSyz147064 		i_mac_notify(mip, MAC_NOTE_MARGIN);
3071d62bc4baSyz147064 
3072d62bc4baSyz147064 	return (margin_needed <= margin);
3073d62bc4baSyz147064 }
3074d62bc4baSyz147064 
3075ba2e4443Sseb /*
3076a776d98eSRobert Mustacchi  * MAC clients use this interface to request that a MAC device not change its
3077a776d98eSRobert Mustacchi  * MTU below the specified amount. At this time, that amount must be within the
3078a776d98eSRobert Mustacchi  * range of the device's current minimum and the device's current maximum. eg. a
3079a776d98eSRobert Mustacchi  * client cannot request a 3000 byte MTU when the device's MTU is currently
3080a776d98eSRobert Mustacchi  * 2000.
3081a776d98eSRobert Mustacchi  *
3082a776d98eSRobert Mustacchi  * If "current" is set to B_TRUE, then the request is to simply to reserve the
3083a776d98eSRobert Mustacchi  * current underlying mac's maximum for this mac client and return it in mtup.
3084a776d98eSRobert Mustacchi  */
3085a776d98eSRobert Mustacchi int
mac_mtu_add(mac_handle_t mh,uint32_t * mtup,boolean_t current)3086a776d98eSRobert Mustacchi mac_mtu_add(mac_handle_t mh, uint32_t *mtup, boolean_t current)
3087a776d98eSRobert Mustacchi {
3088a776d98eSRobert Mustacchi 	mac_impl_t		*mip = (mac_impl_t *)mh;
3089a776d98eSRobert Mustacchi 	mac_mtu_req_t		*prev, *cur;
3090a776d98eSRobert Mustacchi 	mac_propval_range_t	mpr;
3091a776d98eSRobert Mustacchi 	int			err;
3092a776d98eSRobert Mustacchi 
3093a776d98eSRobert Mustacchi 	i_mac_perim_enter(mip);
3094a776d98eSRobert Mustacchi 	rw_enter(&mip->mi_rw_lock, RW_WRITER);
3095a776d98eSRobert Mustacchi 
3096a776d98eSRobert Mustacchi 	if (current == B_TRUE)
3097a776d98eSRobert Mustacchi 		*mtup = mip->mi_sdu_max;
3098a776d98eSRobert Mustacchi 	mpr.mpr_count = 1;
3099a776d98eSRobert Mustacchi 	err = mac_prop_info(mh, MAC_PROP_MTU, "mtu", NULL, 0, &mpr, NULL);
3100a776d98eSRobert Mustacchi 	if (err != 0) {
3101a776d98eSRobert Mustacchi 		rw_exit(&mip->mi_rw_lock);
3102a776d98eSRobert Mustacchi 		i_mac_perim_exit(mip);
3103a776d98eSRobert Mustacchi 		return (err);
3104a776d98eSRobert Mustacchi 	}
3105a776d98eSRobert Mustacchi 
3106a776d98eSRobert Mustacchi 	if (*mtup > mip->mi_sdu_max ||
3107a776d98eSRobert Mustacchi 	    *mtup < mpr.mpr_range_uint32[0].mpur_min) {
3108a776d98eSRobert Mustacchi 		rw_exit(&mip->mi_rw_lock);
3109a776d98eSRobert Mustacchi 		i_mac_perim_exit(mip);
3110a776d98eSRobert Mustacchi 		return (ENOTSUP);
3111a776d98eSRobert Mustacchi 	}
3112a776d98eSRobert Mustacchi 
3113a776d98eSRobert Mustacchi 	prev = NULL;
3114a776d98eSRobert Mustacchi 	for (cur = mip->mi_mtrp; cur != NULL; cur = cur->mtr_nextp) {
3115a776d98eSRobert Mustacchi 		if (*mtup == cur->mtr_mtu) {
3116a776d98eSRobert Mustacchi 			cur->mtr_ref++;
3117a776d98eSRobert Mustacchi 			rw_exit(&mip->mi_rw_lock);
3118a776d98eSRobert Mustacchi 			i_mac_perim_exit(mip);
3119a776d98eSRobert Mustacchi 			return (0);
3120a776d98eSRobert Mustacchi 		}
3121a776d98eSRobert Mustacchi 
3122a776d98eSRobert Mustacchi 		if (*mtup > cur->mtr_mtu)
3123a776d98eSRobert Mustacchi 			break;
3124a776d98eSRobert Mustacchi 
3125a776d98eSRobert Mustacchi 		prev = cur;
3126a776d98eSRobert Mustacchi 	}
3127a776d98eSRobert Mustacchi 
3128a776d98eSRobert Mustacchi 	cur = kmem_alloc(sizeof (mac_mtu_req_t), KM_SLEEP);
3129a776d98eSRobert Mustacchi 	cur->mtr_mtu = *mtup;
3130a776d98eSRobert Mustacchi 	cur->mtr_ref = 1;
3131a776d98eSRobert Mustacchi 	if (prev != NULL) {
3132a776d98eSRobert Mustacchi 		cur->mtr_nextp = prev->mtr_nextp;
3133a776d98eSRobert Mustacchi 		prev->mtr_nextp = cur;
3134a776d98eSRobert Mustacchi 	} else {
3135a776d98eSRobert Mustacchi 		cur->mtr_nextp = mip->mi_mtrp;
3136a776d98eSRobert Mustacchi 		mip->mi_mtrp = cur;
3137a776d98eSRobert Mustacchi 	}
3138a776d98eSRobert Mustacchi 
3139a776d98eSRobert Mustacchi 	rw_exit(&mip->mi_rw_lock);
3140a776d98eSRobert Mustacchi 	i_mac_perim_exit(mip);
3141a776d98eSRobert Mustacchi 	return (0);
3142a776d98eSRobert Mustacchi }
3143a776d98eSRobert Mustacchi 
3144a776d98eSRobert Mustacchi int
mac_mtu_remove(mac_handle_t mh,uint32_t mtu)3145a776d98eSRobert Mustacchi mac_mtu_remove(mac_handle_t mh, uint32_t mtu)
3146a776d98eSRobert Mustacchi {
3147a776d98eSRobert Mustacchi 	mac_impl_t *mip = (mac_impl_t *)mh;
3148a776d98eSRobert Mustacchi 	mac_mtu_req_t *cur, *prev;
3149a776d98eSRobert Mustacchi 
3150a776d98eSRobert Mustacchi 	i_mac_perim_enter(mip);
3151a776d98eSRobert Mustacchi 	rw_enter(&mip->mi_rw_lock, RW_WRITER);
3152a776d98eSRobert Mustacchi 
3153a776d98eSRobert Mustacchi 	prev = NULL;
3154a776d98eSRobert Mustacchi 	for (cur = mip->mi_mtrp; cur != NULL; cur = cur->mtr_nextp) {
3155a776d98eSRobert Mustacchi 		if (cur->mtr_mtu == mtu) {
3156a776d98eSRobert Mustacchi 			ASSERT(cur->mtr_ref > 0);
3157a776d98eSRobert Mustacchi 			cur->mtr_ref--;
3158a776d98eSRobert Mustacchi 			if (cur->mtr_ref == 0) {
3159a776d98eSRobert Mustacchi 				if (prev == NULL) {
3160a776d98eSRobert Mustacchi 					mip->mi_mtrp = cur->mtr_nextp;
3161a776d98eSRobert Mustacchi 				} else {
3162a776d98eSRobert Mustacchi 					prev->mtr_nextp = cur->mtr_nextp;
3163a776d98eSRobert Mustacchi 				}
3164a776d98eSRobert Mustacchi 				kmem_free(cur, sizeof (mac_mtu_req_t));
3165a776d98eSRobert Mustacchi 			}
3166a776d98eSRobert Mustacchi 			rw_exit(&mip->mi_rw_lock);
3167a776d98eSRobert Mustacchi 			i_mac_perim_exit(mip);
3168a776d98eSRobert Mustacchi 			return (0);
3169a776d98eSRobert Mustacchi 		}
3170a776d98eSRobert Mustacchi 
3171a776d98eSRobert Mustacchi 		prev = cur;
3172a776d98eSRobert Mustacchi 	}
3173a776d98eSRobert Mustacchi 
3174a776d98eSRobert Mustacchi 	rw_exit(&mip->mi_rw_lock);
3175a776d98eSRobert Mustacchi 	i_mac_perim_exit(mip);
3176a776d98eSRobert Mustacchi 	return (ENOENT);
3177a776d98eSRobert Mustacchi }
3178a776d98eSRobert Mustacchi 
3179a776d98eSRobert Mustacchi /*
3180ba2e4443Sseb  * MAC Type Plugin functions.
3181ba2e4443Sseb  */
3182ba2e4443Sseb 
3183da14cebeSEric Cheng mactype_t *
mactype_getplugin(const char * pname)3184da14cebeSEric Cheng mactype_getplugin(const char *pname)
3185da14cebeSEric Cheng {
3186da14cebeSEric Cheng 	mactype_t	*mtype = NULL;
3187da14cebeSEric Cheng 	boolean_t	tried_modload = B_FALSE;
3188da14cebeSEric Cheng 
3189da14cebeSEric Cheng 	mutex_enter(&i_mactype_lock);
3190da14cebeSEric Cheng 
3191da14cebeSEric Cheng find_registered_mactype:
3192da14cebeSEric Cheng 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
3193da14cebeSEric Cheng 	    (mod_hash_val_t *)&mtype) != 0) {
3194da14cebeSEric Cheng 		if (!tried_modload) {
3195da14cebeSEric Cheng 			/*
3196da14cebeSEric Cheng 			 * If the plugin has not yet been loaded, then
3197da14cebeSEric Cheng 			 * attempt to load it now.  If modload() succeeds,
3198da14cebeSEric Cheng 			 * the plugin should have registered using
3199da14cebeSEric Cheng 			 * mactype_register(), in which case we can go back
3200da14cebeSEric Cheng 			 * and attempt to find it again.
3201da14cebeSEric Cheng 			 */
3202da14cebeSEric Cheng 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
3203da14cebeSEric Cheng 				tried_modload = B_TRUE;
3204da14cebeSEric Cheng 				goto find_registered_mactype;
3205da14cebeSEric Cheng 			}
3206da14cebeSEric Cheng 		}
3207da14cebeSEric Cheng 	} else {
3208da14cebeSEric Cheng 		/*
3209da14cebeSEric Cheng 		 * Note that there's no danger that the plugin we've loaded
3210da14cebeSEric Cheng 		 * could be unloaded between the modload() step and the
3211da14cebeSEric Cheng 		 * reference count bump here, as we're holding
3212da14cebeSEric Cheng 		 * i_mactype_lock, which mactype_unregister() also holds.
3213da14cebeSEric Cheng 		 */
3214da14cebeSEric Cheng 		atomic_inc_32(&mtype->mt_ref);
3215da14cebeSEric Cheng 	}
3216da14cebeSEric Cheng 
3217da14cebeSEric Cheng 	mutex_exit(&i_mactype_lock);
3218da14cebeSEric Cheng 	return (mtype);
3219da14cebeSEric Cheng }
3220da14cebeSEric Cheng 
3221ba2e4443Sseb mactype_register_t *
mactype_alloc(uint_t mactype_version)3222ba2e4443Sseb mactype_alloc(uint_t mactype_version)
3223ba2e4443Sseb {
3224ba2e4443Sseb 	mactype_register_t *mtrp;
3225ba2e4443Sseb 
3226ba2e4443Sseb 	/*
3227ba2e4443Sseb 	 * Make sure there isn't a version mismatch between the plugin and
3228ba2e4443Sseb 	 * the framework.  In the future, if multiple versions are
3229ba2e4443Sseb 	 * supported, this check could become more sophisticated.
3230ba2e4443Sseb 	 */
3231ba2e4443Sseb 	if (mactype_version != MACTYPE_VERSION)
3232ba2e4443Sseb 		return (NULL);
3233ba2e4443Sseb 
3234ba2e4443Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
3235ba2e4443Sseb 	mtrp->mtr_version = mactype_version;
3236ba2e4443Sseb 	return (mtrp);
3237ba2e4443Sseb }
3238ba2e4443Sseb 
3239ba2e4443Sseb void
mactype_free(mactype_register_t * mtrp)3240ba2e4443Sseb mactype_free(mactype_register_t *mtrp)
3241ba2e4443Sseb {
3242ba2e4443Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
3243ba2e4443Sseb }
3244ba2e4443Sseb 
3245ba2e4443Sseb int
mactype_register(mactype_register_t * mtrp)3246ba2e4443Sseb mactype_register(mactype_register_t *mtrp)
3247ba2e4443Sseb {
3248ba2e4443Sseb 	mactype_t	*mtp;
3249ba2e4443Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
3250ba2e4443Sseb 
3251ba2e4443Sseb 	/* Do some sanity checking before we register this MAC type. */
3252c08e5e1aSdr146992 	if (mtrp->mtr_ident == NULL || ops == NULL)
3253ba2e4443Sseb 		return (EINVAL);
3254ba2e4443Sseb 
3255ba2e4443Sseb 	/*
3256ba2e4443Sseb 	 * Verify that all mandatory callbacks are set in the ops
3257ba2e4443Sseb 	 * vector.
3258ba2e4443Sseb 	 */
3259ba2e4443Sseb 	if (ops->mtops_unicst_verify == NULL ||
3260ba2e4443Sseb 	    ops->mtops_multicst_verify == NULL ||
3261ba2e4443Sseb 	    ops->mtops_sap_verify == NULL ||
3262ba2e4443Sseb 	    ops->mtops_header == NULL ||
3263ba2e4443Sseb 	    ops->mtops_header_info == NULL) {
3264ba2e4443Sseb 		return (EINVAL);
3265ba2e4443Sseb 	}
3266ba2e4443Sseb 
3267ba2e4443Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
3268ba2e4443Sseb 	mtp->mt_ident = mtrp->mtr_ident;
3269ba2e4443Sseb 	mtp->mt_ops = *ops;
3270ba2e4443Sseb 	mtp->mt_type = mtrp->mtr_mactype;
32710ba2cbe9Sxc151355 	mtp->mt_nativetype = mtrp->mtr_nativetype;
3272ba2e4443Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
3273ba2e4443Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
3274ba2e4443Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
3275ba2e4443Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
3276ba2e4443Sseb 		    mtrp->mtr_addrlen);
3277ba2e4443Sseb 	}
3278ba2e4443Sseb 
3279ba2e4443Sseb 	mtp->mt_stats = mtrp->mtr_stats;
3280ba2e4443Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
3281ba2e4443Sseb 
32824045d941Ssowmini 	mtp->mt_mapping = mtrp->mtr_mapping;
32834045d941Ssowmini 	mtp->mt_mappingcount = mtrp->mtr_mappingcount;
32844045d941Ssowmini 
3285ba2e4443Sseb 	if (mod_hash_insert(i_mactype_hash,
3286ba2e4443Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
3287ba2e4443Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
3288ba2e4443Sseb 		kmem_free(mtp, sizeof (*mtp));
3289ba2e4443Sseb 		return (EEXIST);
3290ba2e4443Sseb 	}
3291ba2e4443Sseb 	return (0);
3292ba2e4443Sseb }
3293ba2e4443Sseb 
3294ba2e4443Sseb int
mactype_unregister(const char * ident)3295ba2e4443Sseb mactype_unregister(const char *ident)
3296ba2e4443Sseb {
3297ba2e4443Sseb 	mactype_t	*mtp;
3298ba2e4443Sseb 	mod_hash_val_t	val;
3299ba2e4443Sseb 	int		err;
3300ba2e4443Sseb 
3301ba2e4443Sseb 	/*
3302ba2e4443Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
3303bd7f69f6Sseb 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
3304bd7f69f6Sseb 	 * plugin from unregistering while a MAC driver is attempting to
3305bd7f69f6Sseb 	 * hold a reference to it in i_mactype_getplugin().
3306ba2e4443Sseb 	 */
3307bd7f69f6Sseb 	mutex_enter(&i_mactype_lock);
3308ba2e4443Sseb 
3309ba2e4443Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
3310ba2e4443Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
3311ba2e4443Sseb 		/* A plugin is trying to unregister, but it never registered. */
3312bd7f69f6Sseb 		err = ENXIO;
3313bd7f69f6Sseb 		goto done;
3314ba2e4443Sseb 	}
3315ba2e4443Sseb 
3316bd7f69f6Sseb 	if (mtp->mt_ref != 0) {
3317bd7f69f6Sseb 		err = EBUSY;
3318bd7f69f6Sseb 		goto done;
3319ba2e4443Sseb 	}
3320ba2e4443Sseb 
3321ba2e4443Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
3322ba2e4443Sseb 	ASSERT(err == 0);
3323ba2e4443Sseb 	if (err != 0) {
3324ba2e4443Sseb 		/* This should never happen, thus the ASSERT() above. */
3325bd7f69f6Sseb 		err = EINVAL;
3326bd7f69f6Sseb 		goto done;
3327ba2e4443Sseb 	}
3328ba2e4443Sseb 	ASSERT(mtp == (mactype_t *)val);
3329ba2e4443Sseb 
33302b24ab6bSSebastien Roy 	if (mtp->mt_brdcst_addr != NULL)
3331ba2e4443Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
3332ba2e4443Sseb 	kmem_free(mtp, sizeof (mactype_t));
3333bd7f69f6Sseb done:
3334bd7f69f6Sseb 	mutex_exit(&i_mactype_lock);
3335bd7f69f6Sseb 	return (err);
3336ba2e4443Sseb }
3337e7801d59Ssowmini 
3338da14cebeSEric Cheng /*
33390dc2366fSVenugopal Iyer  * Checks the size of the value size specified for a property as
33400dc2366fSVenugopal Iyer  * part of a property operation. Returns B_TRUE if the size is
33410dc2366fSVenugopal Iyer  * correct, B_FALSE otherwise.
33420dc2366fSVenugopal Iyer  */
33430dc2366fSVenugopal Iyer boolean_t
mac_prop_check_size(mac_prop_id_t id,uint_t valsize,boolean_t is_range)33440dc2366fSVenugopal Iyer mac_prop_check_size(mac_prop_id_t id, uint_t valsize, boolean_t is_range)
33450dc2366fSVenugopal Iyer {
33460dc2366fSVenugopal Iyer 	uint_t minsize = 0;
33470dc2366fSVenugopal Iyer 
33480dc2366fSVenugopal Iyer 	if (is_range)
33490dc2366fSVenugopal Iyer 		return (valsize >= sizeof (mac_propval_range_t));
33500dc2366fSVenugopal Iyer 
33510dc2366fSVenugopal Iyer 	switch (id) {
33520dc2366fSVenugopal Iyer 	case MAC_PROP_ZONE:
33530dc2366fSVenugopal Iyer 		minsize = sizeof (dld_ioc_zid_t);
33540dc2366fSVenugopal Iyer 		break;
33550dc2366fSVenugopal Iyer 	case MAC_PROP_AUTOPUSH:
33560dc2366fSVenugopal Iyer 		if (valsize != 0)
33570dc2366fSVenugopal Iyer 			minsize = sizeof (struct dlautopush);
33580dc2366fSVenugopal Iyer 		break;
33590dc2366fSVenugopal Iyer 	case MAC_PROP_TAGMODE:
33600dc2366fSVenugopal Iyer 		minsize = sizeof (link_tagmode_t);
33610dc2366fSVenugopal Iyer 		break;
33620dc2366fSVenugopal Iyer 	case MAC_PROP_RESOURCE:
33630dc2366fSVenugopal Iyer 	case MAC_PROP_RESOURCE_EFF:
33640dc2366fSVenugopal Iyer 		minsize = sizeof (mac_resource_props_t);
33650dc2366fSVenugopal Iyer 		break;
33660dc2366fSVenugopal Iyer 	case MAC_PROP_DUPLEX:
33670dc2366fSVenugopal Iyer 		minsize = sizeof (link_duplex_t);
33680dc2366fSVenugopal Iyer 		break;
33690dc2366fSVenugopal Iyer 	case MAC_PROP_SPEED:
33700dc2366fSVenugopal Iyer 		minsize = sizeof (uint64_t);
33710dc2366fSVenugopal Iyer 		break;
33720dc2366fSVenugopal Iyer 	case MAC_PROP_STATUS:
33730dc2366fSVenugopal Iyer 		minsize = sizeof (link_state_t);
33740dc2366fSVenugopal Iyer 		break;
33750dc2366fSVenugopal Iyer 	case MAC_PROP_AUTONEG:
33760dc2366fSVenugopal Iyer 	case MAC_PROP_EN_AUTONEG:
33770dc2366fSVenugopal Iyer 		minsize = sizeof (uint8_t);
33780dc2366fSVenugopal Iyer 		break;
33790dc2366fSVenugopal Iyer 	case MAC_PROP_MTU:
33800dc2366fSVenugopal Iyer 	case MAC_PROP_LLIMIT:
33810dc2366fSVenugopal Iyer 	case MAC_PROP_LDECAY:
33820dc2366fSVenugopal Iyer 		minsize = sizeof (uint32_t);
33830dc2366fSVenugopal Iyer 		break;
33840dc2366fSVenugopal Iyer 	case MAC_PROP_FLOWCTRL:
33850dc2366fSVenugopal Iyer 		minsize = sizeof (link_flowctrl_t);
33860dc2366fSVenugopal Iyer 		break;
3387d77e6e0fSPaul Winder 	case MAC_PROP_ADV_FEC_CAP:
3388d77e6e0fSPaul Winder 	case MAC_PROP_EN_FEC_CAP:
3389d77e6e0fSPaul Winder 		minsize = sizeof (link_fec_t);
3390d77e6e0fSPaul Winder 		break;
33912aaafd60SRobert Mustacchi 	case MAC_PROP_ADV_400GFDX_CAP:
33922aaafd60SRobert Mustacchi 	case MAC_PROP_EN_400GFDX_CAP:
33932aaafd60SRobert Mustacchi 	case MAC_PROP_ADV_200GFDX_CAP:
33942aaafd60SRobert Mustacchi 	case MAC_PROP_EN_200GFDX_CAP:
33953bc4925dSGarrett D'Amore 	case MAC_PROP_ADV_100GFDX_CAP:
33963bc4925dSGarrett D'Amore 	case MAC_PROP_EN_100GFDX_CAP:
33973d75a287SRobert Mustacchi 	case MAC_PROP_ADV_50GFDX_CAP:
33983d75a287SRobert Mustacchi 	case MAC_PROP_EN_50GFDX_CAP:
33993bc4925dSGarrett D'Amore 	case MAC_PROP_ADV_40GFDX_CAP:
34003bc4925dSGarrett D'Amore 	case MAC_PROP_EN_40GFDX_CAP:
34013d75a287SRobert Mustacchi 	case MAC_PROP_ADV_25GFDX_CAP:
34023d75a287SRobert Mustacchi 	case MAC_PROP_EN_25GFDX_CAP:
34030dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_10GFDX_CAP:
34040dc2366fSVenugopal Iyer 	case MAC_PROP_EN_10GFDX_CAP:
34052aaafd60SRobert Mustacchi 	case MAC_PROP_ADV_5000FDX_CAP:
34062aaafd60SRobert Mustacchi 	case MAC_PROP_EN_5000FDX_CAP:
34072aaafd60SRobert Mustacchi 	case MAC_PROP_ADV_2500FDX_CAP:
34082aaafd60SRobert Mustacchi 	case MAC_PROP_EN_2500FDX_CAP:
34090dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_1000HDX_CAP:
34100dc2366fSVenugopal Iyer 	case MAC_PROP_EN_1000HDX_CAP:
34110dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100FDX_CAP:
34120dc2366fSVenugopal Iyer 	case MAC_PROP_EN_100FDX_CAP:
34132aaafd60SRobert Mustacchi 	case MAC_PROP_ADV_100T4_CAP:
34142aaafd60SRobert Mustacchi 	case MAC_PROP_EN_100T4_CAP:
34150dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_100HDX_CAP:
34160dc2366fSVenugopal Iyer 	case MAC_PROP_EN_100HDX_CAP:
34170dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_10FDX_CAP:
34180dc2366fSVenugopal Iyer 	case MAC_PROP_EN_10FDX_CAP:
34190dc2366fSVenugopal Iyer 	case MAC_PROP_ADV_10HDX_CAP:
34200dc2366fSVenugopal Iyer 	case MAC_PROP_EN_10HDX_CAP:
34210dc2366fSVenugopal Iyer 		minsize = sizeof (uint8_t);
34220dc2366fSVenugopal Iyer 		break;
34230dc2366fSVenugopal Iyer 	case MAC_PROP_PVID:
34240dc2366fSVenugopal Iyer 		minsize = sizeof (uint16_t);
34250dc2366fSVenugopal Iyer 		break;
34260dc2366fSVenugopal Iyer 	case MAC_PROP_IPTUN_HOPLIMIT:
34270dc2366fSVenugopal Iyer 		minsize = sizeof (uint32_t);
34280dc2366fSVenugopal Iyer 		break;
34290dc2366fSVenugopal Iyer 	case MAC_PROP_IPTUN_ENCAPLIMIT:
34300dc2366fSVenugopal Iyer 		minsize = sizeof (uint32_t);
34310dc2366fSVenugopal Iyer 		break;
34320dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_TX_RINGS_AVAIL:
34330dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_RX_RINGS_AVAIL:
34340dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_RXHWCLNT_AVAIL:
34350dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_TXHWCLNT_AVAIL:
34360dc2366fSVenugopal Iyer 		minsize = sizeof (uint_t);
34370dc2366fSVenugopal Iyer 		break;
34380dc2366fSVenugopal Iyer 	case MAC_PROP_WL_ESSID:
34390dc2366fSVenugopal Iyer 		minsize = sizeof (wl_linkstatus_t);
34400dc2366fSVenugopal Iyer 		break;
34410dc2366fSVenugopal Iyer 	case MAC_PROP_WL_BSSID:
34420dc2366fSVenugopal Iyer 		minsize = sizeof (wl_bssid_t);
34430dc2366fSVenugopal Iyer 		break;
34440dc2366fSVenugopal Iyer 	case MAC_PROP_WL_BSSTYPE:
34450dc2366fSVenugopal Iyer 		minsize = sizeof (wl_bss_type_t);
34460dc2366fSVenugopal Iyer 		break;
34470dc2366fSVenugopal Iyer 	case MAC_PROP_WL_LINKSTATUS:
34480dc2366fSVenugopal Iyer 		minsize = sizeof (wl_linkstatus_t);
34490dc2366fSVenugopal Iyer 		break;
34500dc2366fSVenugopal Iyer 	case MAC_PROP_WL_DESIRED_RATES:
34510dc2366fSVenugopal Iyer 		minsize = sizeof (wl_rates_t);
34520dc2366fSVenugopal Iyer 		break;
34530dc2366fSVenugopal Iyer 	case MAC_PROP_WL_SUPPORTED_RATES:
34540dc2366fSVenugopal Iyer 		minsize = sizeof (wl_rates_t);
34550dc2366fSVenugopal Iyer 		break;
34560dc2366fSVenugopal Iyer 	case MAC_PROP_WL_AUTH_MODE:
34570dc2366fSVenugopal Iyer 		minsize = sizeof (wl_authmode_t);
34580dc2366fSVenugopal Iyer 		break;
34590dc2366fSVenugopal Iyer 	case MAC_PROP_WL_ENCRYPTION:
34600dc2366fSVenugopal Iyer 		minsize = sizeof (wl_encryption_t);
34610dc2366fSVenugopal Iyer 		break;
34620dc2366fSVenugopal Iyer 	case MAC_PROP_WL_RSSI:
34630dc2366fSVenugopal Iyer 		minsize = sizeof (wl_rssi_t);
34640dc2366fSVenugopal Iyer 		break;
34650dc2366fSVenugopal Iyer 	case MAC_PROP_WL_PHY_CONFIG:
34660dc2366fSVenugopal Iyer 		minsize = sizeof (wl_phy_conf_t);
34670dc2366fSVenugopal Iyer 		break;
34680dc2366fSVenugopal Iyer 	case MAC_PROP_WL_CAPABILITY:
34690dc2366fSVenugopal Iyer 		minsize = sizeof (wl_capability_t);
34700dc2366fSVenugopal Iyer 		break;
34710dc2366fSVenugopal Iyer 	case MAC_PROP_WL_WPA:
34720dc2366fSVenugopal Iyer 		minsize = sizeof (wl_wpa_t);
34730dc2366fSVenugopal Iyer 		break;
34740dc2366fSVenugopal Iyer 	case MAC_PROP_WL_SCANRESULTS:
34750dc2366fSVenugopal Iyer 		minsize = sizeof (wl_wpa_ess_t);
34760dc2366fSVenugopal Iyer 		break;
34770dc2366fSVenugopal Iyer 	case MAC_PROP_WL_POWER_MODE:
34780dc2366fSVenugopal Iyer 		minsize = sizeof (wl_ps_mode_t);
34790dc2366fSVenugopal Iyer 		break;
34800dc2366fSVenugopal Iyer 	case MAC_PROP_WL_RADIO:
34810dc2366fSVenugopal Iyer 		minsize = sizeof (wl_radio_t);
34820dc2366fSVenugopal Iyer 		break;
34830dc2366fSVenugopal Iyer 	case MAC_PROP_WL_ESS_LIST:
34840dc2366fSVenugopal Iyer 		minsize = sizeof (wl_ess_list_t);
34850dc2366fSVenugopal Iyer 		break;
34860dc2366fSVenugopal Iyer 	case MAC_PROP_WL_KEY_TAB:
34870dc2366fSVenugopal Iyer 		minsize = sizeof (wl_wep_key_tab_t);
34880dc2366fSVenugopal Iyer 		break;
34890dc2366fSVenugopal Iyer 	case MAC_PROP_WL_CREATE_IBSS:
34900dc2366fSVenugopal Iyer 		minsize = sizeof (wl_create_ibss_t);
34910dc2366fSVenugopal Iyer 		break;
34920dc2366fSVenugopal Iyer 	case MAC_PROP_WL_SETOPTIE:
34930dc2366fSVenugopal Iyer 		minsize = sizeof (wl_wpa_ie_t);
34940dc2366fSVenugopal Iyer 		break;
34950dc2366fSVenugopal Iyer 	case MAC_PROP_WL_DELKEY:
34960dc2366fSVenugopal Iyer 		minsize = sizeof (wl_del_key_t);
34970dc2366fSVenugopal Iyer 		break;
34980dc2366fSVenugopal Iyer 	case MAC_PROP_WL_KEY:
34990dc2366fSVenugopal Iyer 		minsize = sizeof (wl_key_t);
35000dc2366fSVenugopal Iyer 		break;
35010dc2366fSVenugopal Iyer 	case MAC_PROP_WL_MLME:
35020dc2366fSVenugopal Iyer 		minsize = sizeof (wl_mlme_t);
35030dc2366fSVenugopal Iyer 		break;
350410a40492SRobert Mustacchi 	case MAC_PROP_VN_PROMISC_FILTERED:
350510a40492SRobert Mustacchi 		minsize = sizeof (boolean_t);
350610a40492SRobert Mustacchi 		break;
3507dd72704bSRobert Mustacchi 	case MAC_PROP_MEDIA:
3508dd72704bSRobert Mustacchi 		/*
3509dd72704bSRobert Mustacchi 		 * Our assumption is that each class of device uses an enum and
3510dd72704bSRobert Mustacchi 		 * that all enums will be the same size so it is OK to use a
3511dd72704bSRobert Mustacchi 		 * single one.
3512dd72704bSRobert Mustacchi 		 */
3513dd72704bSRobert Mustacchi 		minsize = sizeof (mac_ether_media_t);
3514dd72704bSRobert Mustacchi 		break;
35150dc2366fSVenugopal Iyer 	}
35160dc2366fSVenugopal Iyer 
35170dc2366fSVenugopal Iyer 	return (valsize >= minsize);
35180dc2366fSVenugopal Iyer }
35190dc2366fSVenugopal Iyer 
35200dc2366fSVenugopal Iyer /*
35210dc2366fSVenugopal Iyer  * mac_set_prop() sets MAC or hardware driver properties:
35220dc2366fSVenugopal Iyer  *
35230dc2366fSVenugopal Iyer  * - MAC-managed properties such as resource properties include maxbw,
35240dc2366fSVenugopal Iyer  *   priority, and cpu binding list, as well as the default port VID
35250dc2366fSVenugopal Iyer  *   used by bridging. These properties are consumed by the MAC layer
35260dc2366fSVenugopal Iyer  *   itself and not passed down to the driver. For resource control
35270dc2366fSVenugopal Iyer  *   properties, this function invokes mac_set_resources() which will
35280dc2366fSVenugopal Iyer  *   cache the property value in mac_impl_t and may call
35290dc2366fSVenugopal Iyer  *   mac_client_set_resource() to update property value of the primary
35304eaa4710SRishi Srivatsavai  *   mac client, if it exists.
35310dc2366fSVenugopal Iyer  *
35320dc2366fSVenugopal Iyer  * - Properties which act on the hardware and must be passed to the
35330dc2366fSVenugopal Iyer  *   driver, such as MTU, through the driver's mc_setprop() entry point.
3534da14cebeSEric Cheng  */
3535e7801d59Ssowmini int
mac_set_prop(mac_handle_t mh,mac_prop_id_t id,char * name,void * val,uint_t valsize)35360dc2366fSVenugopal Iyer mac_set_prop(mac_handle_t mh, mac_prop_id_t id, char *name, void *val,
35370dc2366fSVenugopal Iyer     uint_t valsize)
3538e7801d59Ssowmini {
3539e7801d59Ssowmini 	int err = ENOTSUP;
3540e7801d59Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
3541e7801d59Ssowmini 
3542da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(mh));
3543da14cebeSEric Cheng 
35440dc2366fSVenugopal Iyer 	switch (id) {
35450dc2366fSVenugopal Iyer 	case MAC_PROP_RESOURCE: {
35460dc2366fSVenugopal Iyer 		mac_resource_props_t *mrp;
3547da14cebeSEric Cheng 
35480dc2366fSVenugopal Iyer 		/* call mac_set_resources() for MAC properties */
35490dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (mac_resource_props_t));
35500dc2366fSVenugopal Iyer 		mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
35510dc2366fSVenugopal Iyer 		bcopy(val, mrp, sizeof (*mrp));
35520dc2366fSVenugopal Iyer 		err = mac_set_resources(mh, mrp);
35530dc2366fSVenugopal Iyer 		kmem_free(mrp, sizeof (*mrp));
35544eaa4710SRishi Srivatsavai 		break;
3555da14cebeSEric Cheng 	}
35564eaa4710SRishi Srivatsavai 
35574eaa4710SRishi Srivatsavai 	case MAC_PROP_PVID:
35580dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (uint16_t));
35590dc2366fSVenugopal Iyer 		if (mip->mi_state_flags & MIS_IS_VNIC)
35604eaa4710SRishi Srivatsavai 			return (EINVAL);
35614eaa4710SRishi Srivatsavai 		err = mac_set_pvid(mh, *(uint16_t *)val);
35624eaa4710SRishi Srivatsavai 		break;
35634eaa4710SRishi Srivatsavai 
3564986cab2cSGirish Moodalbail 	case MAC_PROP_MTU: {
3565986cab2cSGirish Moodalbail 		uint32_t mtu;
3566986cab2cSGirish Moodalbail 
35670dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (uint32_t));
3568986cab2cSGirish Moodalbail 		bcopy(val, &mtu, sizeof (mtu));
3569986cab2cSGirish Moodalbail 		err = mac_set_mtu(mh, mtu, NULL);
3570986cab2cSGirish Moodalbail 		break;
3571986cab2cSGirish Moodalbail 	}
35724eaa4710SRishi Srivatsavai 
35734eaa4710SRishi Srivatsavai 	case MAC_PROP_LLIMIT:
35744eaa4710SRishi Srivatsavai 	case MAC_PROP_LDECAY: {
35754eaa4710SRishi Srivatsavai 		uint32_t learnval;
35764eaa4710SRishi Srivatsavai 
35774eaa4710SRishi Srivatsavai 		if (valsize < sizeof (learnval) ||
35784eaa4710SRishi Srivatsavai 		    (mip->mi_state_flags & MIS_IS_VNIC))
35794eaa4710SRishi Srivatsavai 			return (EINVAL);
35804eaa4710SRishi Srivatsavai 		bcopy(val, &learnval, sizeof (learnval));
35810dc2366fSVenugopal Iyer 		if (learnval == 0 && id == MAC_PROP_LDECAY)
35824eaa4710SRishi Srivatsavai 			return (EINVAL);
35830dc2366fSVenugopal Iyer 		if (id == MAC_PROP_LLIMIT)
35844eaa4710SRishi Srivatsavai 			mip->mi_llimit = learnval;
35854eaa4710SRishi Srivatsavai 		else
35864eaa4710SRishi Srivatsavai 			mip->mi_ldecay = learnval;
35874eaa4710SRishi Srivatsavai 		err = 0;
35884eaa4710SRishi Srivatsavai 		break;
35894eaa4710SRishi Srivatsavai 	}
35904eaa4710SRishi Srivatsavai 
3591d77e6e0fSPaul Winder 	case MAC_PROP_ADV_FEC_CAP:
3592d77e6e0fSPaul Winder 	case MAC_PROP_EN_FEC_CAP: {
3593d77e6e0fSPaul Winder 		link_fec_t fec;
3594d77e6e0fSPaul Winder 
3595d77e6e0fSPaul Winder 		ASSERT(valsize >= sizeof (link_fec_t));
3596d77e6e0fSPaul Winder 
3597d77e6e0fSPaul Winder 		/*
3598d77e6e0fSPaul Winder 		 * fec cannot be zero, and auto must be set exclusively.
3599d77e6e0fSPaul Winder 		 */
3600d77e6e0fSPaul Winder 		bcopy(val, &fec, sizeof (link_fec_t));
3601d77e6e0fSPaul Winder 		if (fec == 0)
3602d77e6e0fSPaul Winder 			return (EINVAL);
3603d77e6e0fSPaul Winder 		if ((fec & LINK_FEC_AUTO) != 0 && (fec & ~LINK_FEC_AUTO) != 0)
3604d77e6e0fSPaul Winder 			return (EINVAL);
3605d77e6e0fSPaul Winder 
3606d77e6e0fSPaul Winder 		if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
3607d77e6e0fSPaul Winder 			err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
3608d77e6e0fSPaul Winder 			    name, id, valsize, val);
3609d77e6e0fSPaul Winder 		}
3610d77e6e0fSPaul Winder 		break;
3611d77e6e0fSPaul Winder 	}
3612d77e6e0fSPaul Winder 
3613986cab2cSGirish Moodalbail 	default:
3614986cab2cSGirish Moodalbail 		/* For other driver properties, call driver's callback */
3615e7801d59Ssowmini 		if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
3616e7801d59Ssowmini 			err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
36170dc2366fSVenugopal Iyer 			    name, id, valsize, val);
3618e7801d59Ssowmini 		}
3619986cab2cSGirish Moodalbail 	}
3620e7801d59Ssowmini 	return (err);
3621e7801d59Ssowmini }
3622e7801d59Ssowmini 
3623da14cebeSEric Cheng /*
36240dc2366fSVenugopal Iyer  * mac_get_prop() gets MAC or device driver properties.
3625da14cebeSEric Cheng  *
3626da14cebeSEric Cheng  * If the property is a driver property, mac_get_prop() calls driver's callback
36270dc2366fSVenugopal Iyer  * entry point to get it.
36280dc2366fSVenugopal Iyer  * If the property is a MAC property, mac_get_prop() invokes mac_get_resources()
3629da14cebeSEric Cheng  * which returns the cached value in mac_impl_t.
3630da14cebeSEric Cheng  */
3631e7801d59Ssowmini int
mac_get_prop(mac_handle_t mh,mac_prop_id_t id,char * name,void * val,uint_t valsize)36320dc2366fSVenugopal Iyer mac_get_prop(mac_handle_t mh, mac_prop_id_t id, char *name, void *val,
36330dc2366fSVenugopal Iyer     uint_t valsize)
3634e7801d59Ssowmini {
3635e7801d59Ssowmini 	int err = ENOTSUP;
3636e7801d59Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
36370dc2366fSVenugopal Iyer 	uint_t	rings;
36380dc2366fSVenugopal Iyer 	uint_t	vlinks;
3639f0f2c3a5SGirish Moodalbail 
36400dc2366fSVenugopal Iyer 	bzero(val, valsize);
3641e7801d59Ssowmini 
36420dc2366fSVenugopal Iyer 	switch (id) {
36430dc2366fSVenugopal Iyer 	case MAC_PROP_RESOURCE: {
36440dc2366fSVenugopal Iyer 		mac_resource_props_t *mrp;
3645da14cebeSEric Cheng 
36464eaa4710SRishi Srivatsavai 		/* If mac property, read from cache */
36470dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (mac_resource_props_t));
36480dc2366fSVenugopal Iyer 		mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
36490dc2366fSVenugopal Iyer 		mac_get_resources(mh, mrp);
36500dc2366fSVenugopal Iyer 		bcopy(mrp, val, sizeof (*mrp));
36510dc2366fSVenugopal Iyer 		kmem_free(mrp, sizeof (*mrp));
36520dc2366fSVenugopal Iyer 		return (0);
36530dc2366fSVenugopal Iyer 	}
36540dc2366fSVenugopal Iyer 	case MAC_PROP_RESOURCE_EFF: {
36550dc2366fSVenugopal Iyer 		mac_resource_props_t *mrp;
36560dc2366fSVenugopal Iyer 
36570dc2366fSVenugopal Iyer 		/* If mac effective property, read from client */
36580dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (mac_resource_props_t));
36590dc2366fSVenugopal Iyer 		mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
36600dc2366fSVenugopal Iyer 		mac_get_effective_resources(mh, mrp);
36610dc2366fSVenugopal Iyer 		bcopy(mrp, val, sizeof (*mrp));
36620dc2366fSVenugopal Iyer 		kmem_free(mrp, sizeof (*mrp));
3663da14cebeSEric Cheng 		return (0);
3664da14cebeSEric Cheng 	}
3665da14cebeSEric Cheng 
36664eaa4710SRishi Srivatsavai 	case MAC_PROP_PVID:
36670dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (uint16_t));
36680dc2366fSVenugopal Iyer 		if (mip->mi_state_flags & MIS_IS_VNIC)
36694eaa4710SRishi Srivatsavai 			return (EINVAL);
36704eaa4710SRishi Srivatsavai 		*(uint16_t *)val = mac_get_pvid(mh);
36714eaa4710SRishi Srivatsavai 		return (0);
36724eaa4710SRishi Srivatsavai 
36734eaa4710SRishi Srivatsavai 	case MAC_PROP_LLIMIT:
36744eaa4710SRishi Srivatsavai 	case MAC_PROP_LDECAY:
36750dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (uint32_t));
36760dc2366fSVenugopal Iyer 		if (mip->mi_state_flags & MIS_IS_VNIC)
36774eaa4710SRishi Srivatsavai 			return (EINVAL);
36780dc2366fSVenugopal Iyer 		if (id == MAC_PROP_LLIMIT)
36794eaa4710SRishi Srivatsavai 			bcopy(&mip->mi_llimit, val, sizeof (mip->mi_llimit));
36804eaa4710SRishi Srivatsavai 		else
36814eaa4710SRishi Srivatsavai 			bcopy(&mip->mi_ldecay, val, sizeof (mip->mi_ldecay));
36824eaa4710SRishi Srivatsavai 		return (0);
36834eaa4710SRishi Srivatsavai 
3684f0f2c3a5SGirish Moodalbail 	case MAC_PROP_MTU: {
3685f0f2c3a5SGirish Moodalbail 		uint32_t sdu;
3686f0f2c3a5SGirish Moodalbail 
36870dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (uint32_t));
36881eee170aSErik Nordmark 		mac_sdu_get2(mh, NULL, &sdu, NULL);
36894045d941Ssowmini 		bcopy(&sdu, val, sizeof (sdu));
3690986cab2cSGirish Moodalbail 
36914045d941Ssowmini 		return (0);
36924045d941Ssowmini 	}
36930dc2366fSVenugopal Iyer 	case MAC_PROP_STATUS: {
36940dc2366fSVenugopal Iyer 		link_state_t link_state;
36950dc2366fSVenugopal Iyer 
36964045d941Ssowmini 		if (valsize < sizeof (link_state))
36974045d941Ssowmini 			return (EINVAL);
36984045d941Ssowmini 		link_state = mac_link_get(mh);
36994045d941Ssowmini 		bcopy(&link_state, val, sizeof (link_state));
37000dc2366fSVenugopal Iyer 
37014045d941Ssowmini 		return (0);
37020dc2366fSVenugopal Iyer 	}
37030dc2366fSVenugopal Iyer 
37040dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_RX_RINGS_AVAIL:
37050dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_TX_RINGS_AVAIL:
37060dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (uint_t));
37070dc2366fSVenugopal Iyer 		rings = id == MAC_PROP_MAX_RX_RINGS_AVAIL ?
37080dc2366fSVenugopal Iyer 		    mac_rxavail_get(mh) : mac_txavail_get(mh);
37090dc2366fSVenugopal Iyer 		bcopy(&rings, val, sizeof (uint_t));
37100dc2366fSVenugopal Iyer 		return (0);
37110dc2366fSVenugopal Iyer 
37120dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_RXHWCLNT_AVAIL:
37130dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_TXHWCLNT_AVAIL:
37140dc2366fSVenugopal Iyer 		ASSERT(valsize >= sizeof (uint_t));
37150dc2366fSVenugopal Iyer 		vlinks = id == MAC_PROP_MAX_RXHWCLNT_AVAIL ?
37160dc2366fSVenugopal Iyer 		    mac_rxhwlnksavail_get(mh) : mac_txhwlnksavail_get(mh);
37170dc2366fSVenugopal Iyer 		bcopy(&vlinks, val, sizeof (uint_t));
37180dc2366fSVenugopal Iyer 		return (0);
37190dc2366fSVenugopal Iyer 
37200dc2366fSVenugopal Iyer 	case MAC_PROP_RXRINGSRANGE:
37210dc2366fSVenugopal Iyer 	case MAC_PROP_TXRINGSRANGE:
37220dc2366fSVenugopal Iyer 		/*
37230dc2366fSVenugopal Iyer 		 * The value for these properties are returned through
37240dc2366fSVenugopal Iyer 		 * the MAC_PROP_RESOURCE property.
37250dc2366fSVenugopal Iyer 		 */
37260dc2366fSVenugopal Iyer 		return (0);
37270dc2366fSVenugopal Iyer 
37284045d941Ssowmini 	default:
37294045d941Ssowmini 		break;
3730da14cebeSEric Cheng 
37314045d941Ssowmini 	}
37320dc2366fSVenugopal Iyer 
3733da14cebeSEric Cheng 	/* If driver property, request from driver */
37340dc2366fSVenugopal Iyer 	if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) {
37350dc2366fSVenugopal Iyer 		err = mip->mi_callbacks->mc_getprop(mip->mi_driver, name, id,
37360dc2366fSVenugopal Iyer 		    valsize, val);
3737e7801d59Ssowmini 	}
37380dc2366fSVenugopal Iyer 
3739e7801d59Ssowmini 	return (err);
3740e7801d59Ssowmini }
3741e7801d59Ssowmini 
37420dc2366fSVenugopal Iyer /*
37430dc2366fSVenugopal Iyer  * Helper function to initialize the range structure for use in
37440dc2366fSVenugopal Iyer  * mac_get_prop. If the type can be other than uint32, we can
37450dc2366fSVenugopal Iyer  * pass that as an arg.
37460dc2366fSVenugopal Iyer  */
37470dc2366fSVenugopal Iyer static void
_mac_set_range(mac_propval_range_t * range,uint32_t min,uint32_t max)37480dc2366fSVenugopal Iyer _mac_set_range(mac_propval_range_t *range, uint32_t min, uint32_t max)
37490dc2366fSVenugopal Iyer {
37500dc2366fSVenugopal Iyer 	range->mpr_count = 1;
37510dc2366fSVenugopal Iyer 	range->mpr_type = MAC_PROPVAL_UINT32;
37520dc2366fSVenugopal Iyer 	range->mpr_range_uint32[0].mpur_min = min;
37530dc2366fSVenugopal Iyer 	range->mpr_range_uint32[0].mpur_max = max;
37540dc2366fSVenugopal Iyer }
37550dc2366fSVenugopal Iyer 
37560dc2366fSVenugopal Iyer /*
37570dc2366fSVenugopal Iyer  * Returns information about the specified property, such as default
37580dc2366fSVenugopal Iyer  * values or permissions.
37590dc2366fSVenugopal Iyer  */
37600dc2366fSVenugopal Iyer int
mac_prop_info(mac_handle_t mh,mac_prop_id_t id,char * name,void * default_val,uint_t default_size,mac_propval_range_t * range,uint_t * perm)37610dc2366fSVenugopal Iyer mac_prop_info(mac_handle_t mh, mac_prop_id_t id, char *name,
37620dc2366fSVenugopal Iyer     void *default_val, uint_t default_size, mac_propval_range_t *range,
37630dc2366fSVenugopal Iyer     uint_t *perm)
37640dc2366fSVenugopal Iyer {
37650dc2366fSVenugopal Iyer 	mac_prop_info_state_t state;
37660dc2366fSVenugopal Iyer 	mac_impl_t *mip = (mac_impl_t *)mh;
37670dc2366fSVenugopal Iyer 	uint_t	max;
37680dc2366fSVenugopal Iyer 
37690dc2366fSVenugopal Iyer 	/*
37700dc2366fSVenugopal Iyer 	 * A property is read/write by default unless the driver says
37710dc2366fSVenugopal Iyer 	 * otherwise.
37720dc2366fSVenugopal Iyer 	 */
37730dc2366fSVenugopal Iyer 	if (perm != NULL)
37740dc2366fSVenugopal Iyer 		*perm = MAC_PROP_PERM_RW;
37750dc2366fSVenugopal Iyer 
37760dc2366fSVenugopal Iyer 	if (default_val != NULL)
37770dc2366fSVenugopal Iyer 		bzero(default_val, default_size);
37780dc2366fSVenugopal Iyer 
37790dc2366fSVenugopal Iyer 	/*
37800dc2366fSVenugopal Iyer 	 * First, handle framework properties for which we don't need to
37810dc2366fSVenugopal Iyer 	 * involve the driver.
37820dc2366fSVenugopal Iyer 	 */
37830dc2366fSVenugopal Iyer 	switch (id) {
37840dc2366fSVenugopal Iyer 	case MAC_PROP_RESOURCE:
37850dc2366fSVenugopal Iyer 	case MAC_PROP_PVID:
37860dc2366fSVenugopal Iyer 	case MAC_PROP_LLIMIT:
37870dc2366fSVenugopal Iyer 	case MAC_PROP_LDECAY:
37880dc2366fSVenugopal Iyer 		return (0);
37890dc2366fSVenugopal Iyer 
37900dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_RX_RINGS_AVAIL:
37910dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_TX_RINGS_AVAIL:
37920dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_RXHWCLNT_AVAIL:
37930dc2366fSVenugopal Iyer 	case MAC_PROP_MAX_TXHWCLNT_AVAIL:
37940dc2366fSVenugopal Iyer 		if (perm != NULL)
37950dc2366fSVenugopal Iyer 			*perm = MAC_PROP_PERM_READ;
37960dc2366fSVenugopal Iyer 		return (0);
37970dc2366fSVenugopal Iyer 
37980dc2366fSVenugopal Iyer 	case MAC_PROP_RXRINGSRANGE:
37990dc2366fSVenugopal Iyer 	case MAC_PROP_TXRINGSRANGE:
38000dc2366fSVenugopal Iyer 		/*
38010dc2366fSVenugopal Iyer 		 * Currently, we support range for RX and TX rings properties.
38020dc2366fSVenugopal Iyer 		 * When we extend this support to maxbw, cpus and priority,
38030dc2366fSVenugopal Iyer 		 * we should move this to mac_get_resources.
38040dc2366fSVenugopal Iyer 		 * There is no default value for RX or TX rings.
38050dc2366fSVenugopal Iyer 		 */
38060dc2366fSVenugopal Iyer 		if ((mip->mi_state_flags & MIS_IS_VNIC) &&
38070dc2366fSVenugopal Iyer 		    mac_is_vnic_primary(mh)) {
38080dc2366fSVenugopal Iyer 			/*
38090dc2366fSVenugopal Iyer 			 * We don't support setting rings for a VLAN
38100dc2366fSVenugopal Iyer 			 * data link because it shares its ring with the
38110dc2366fSVenugopal Iyer 			 * primary MAC client.
38120dc2366fSVenugopal Iyer 			 */
38130dc2366fSVenugopal Iyer 			if (perm != NULL)
38140dc2366fSVenugopal Iyer 				*perm = MAC_PROP_PERM_READ;
38150dc2366fSVenugopal Iyer 			if (range != NULL)
38160dc2366fSVenugopal Iyer 				range->mpr_count = 0;
38170dc2366fSVenugopal Iyer 		} else if (range != NULL) {
38180dc2366fSVenugopal Iyer 			if (mip->mi_state_flags & MIS_IS_VNIC)
38190dc2366fSVenugopal Iyer 				mh = mac_get_lower_mac_handle(mh);
38200dc2366fSVenugopal Iyer 			mip = (mac_impl_t *)mh;
38210dc2366fSVenugopal Iyer 			if ((id == MAC_PROP_RXRINGSRANGE &&
38220dc2366fSVenugopal Iyer 			    mip->mi_rx_group_type == MAC_GROUP_TYPE_STATIC) ||
38230dc2366fSVenugopal Iyer 			    (id == MAC_PROP_TXRINGSRANGE &&
38240dc2366fSVenugopal Iyer 			    mip->mi_tx_group_type == MAC_GROUP_TYPE_STATIC)) {
38250dc2366fSVenugopal Iyer 				if (id == MAC_PROP_RXRINGSRANGE) {
38260dc2366fSVenugopal Iyer 					if ((mac_rxhwlnksavail_get(mh) +
38270dc2366fSVenugopal Iyer 					    mac_rxhwlnksrsvd_get(mh)) <= 1) {
38280dc2366fSVenugopal Iyer 						/*
38290dc2366fSVenugopal Iyer 						 * doesn't support groups or
38300dc2366fSVenugopal Iyer 						 * rings
38310dc2366fSVenugopal Iyer 						 */
38320dc2366fSVenugopal Iyer 						range->mpr_count = 0;
38330dc2366fSVenugopal Iyer 					} else {
38340dc2366fSVenugopal Iyer 						/*
38350dc2366fSVenugopal Iyer 						 * supports specifying groups,
38360dc2366fSVenugopal Iyer 						 * but not rings
38370dc2366fSVenugopal Iyer 						 */
38380dc2366fSVenugopal Iyer 						_mac_set_range(range, 0, 0);
38390dc2366fSVenugopal Iyer 					}
38400dc2366fSVenugopal Iyer 				} else {
38410dc2366fSVenugopal Iyer 					if ((mac_txhwlnksavail_get(mh) +
38420dc2366fSVenugopal Iyer 					    mac_txhwlnksrsvd_get(mh)) <= 1) {
38430dc2366fSVenugopal Iyer 						/*
38440dc2366fSVenugopal Iyer 						 * doesn't support groups or
38450dc2366fSVenugopal Iyer 						 * rings
38460dc2366fSVenugopal Iyer 						 */
38470dc2366fSVenugopal Iyer 						range->mpr_count = 0;
38480dc2366fSVenugopal Iyer 					} else {
38490dc2366fSVenugopal Iyer 						/*
38500dc2366fSVenugopal Iyer 						 * supports specifying groups,
38510dc2366fSVenugopal Iyer 						 * but not rings
38520dc2366fSVenugopal Iyer 						 */
38530dc2366fSVenugopal Iyer 						_mac_set_range(range, 0, 0);
38540dc2366fSVenugopal Iyer 					}
38550dc2366fSVenugopal Iyer 				}
38560dc2366fSVenugopal Iyer 			} else {
38570dc2366fSVenugopal Iyer 				max = id == MAC_PROP_RXRINGSRANGE ?
38580dc2366fSVenugopal Iyer 				    mac_rxavail_get(mh) + mac_rxrsvd_get(mh) :
38590dc2366fSVenugopal Iyer 				    mac_txavail_get(mh) + mac_txrsvd_get(mh);
38600dc2366fSVenugopal Iyer 				if (max <= 1) {
38610dc2366fSVenugopal Iyer 					/*
38620dc2366fSVenugopal Iyer 					 * doesn't support groups or
38630dc2366fSVenugopal Iyer 					 * rings
38640dc2366fSVenugopal Iyer 					 */
38650dc2366fSVenugopal Iyer 					range->mpr_count = 0;
38660dc2366fSVenugopal Iyer 				} else  {
38670dc2366fSVenugopal Iyer 					/*
38680dc2366fSVenugopal Iyer 					 * -1 because we have to leave out the
38690dc2366fSVenugopal Iyer 					 * default ring.
38700dc2366fSVenugopal Iyer 					 */
38710dc2366fSVenugopal Iyer 					_mac_set_range(range, 1, max - 1);
38720dc2366fSVenugopal Iyer 				}
38730dc2366fSVenugopal Iyer 			}
38740dc2366fSVenugopal Iyer 		}
38750dc2366fSVenugopal Iyer 		return (0);
38760dc2366fSVenugopal Iyer 
38770dc2366fSVenugopal Iyer 	case MAC_PROP_STATUS:
3878dd72704bSRobert Mustacchi 	case MAC_PROP_MEDIA:
38790dc2366fSVenugopal Iyer 		if (perm != NULL)
38800dc2366fSVenugopal Iyer 			*perm = MAC_PROP_PERM_READ;
38810dc2366fSVenugopal Iyer 		return (0);
38820dc2366fSVenugopal Iyer 	}
38830dc2366fSVenugopal Iyer 
38840dc2366fSVenugopal Iyer 	/*
38850dc2366fSVenugopal Iyer 	 * Get the property info from the driver if it implements the
38860dc2366fSVenugopal Iyer 	 * property info entry point.
38870dc2366fSVenugopal Iyer 	 */
38880dc2366fSVenugopal Iyer 	bzero(&state, sizeof (state));
38890dc2366fSVenugopal Iyer 
38900dc2366fSVenugopal Iyer 	if (mip->mi_callbacks->mc_callbacks & MC_PROPINFO) {
38910dc2366fSVenugopal Iyer 		state.pr_default = default_val;
38920dc2366fSVenugopal Iyer 		state.pr_default_size = default_size;
38930591ddd0SPrakash Jalan 
38940591ddd0SPrakash Jalan 		/*
38950591ddd0SPrakash Jalan 		 * The caller specifies the maximum number of ranges
38960591ddd0SPrakash Jalan 		 * it can accomodate using mpr_count. We don't touch
38970591ddd0SPrakash Jalan 		 * this value until the driver returns from its
38980591ddd0SPrakash Jalan 		 * mc_propinfo() callback, and ensure we don't exceed
38990591ddd0SPrakash Jalan 		 * this number of range as the driver defines
39000591ddd0SPrakash Jalan 		 * supported range from its mc_propinfo().
39010591ddd0SPrakash Jalan 		 *
39020591ddd0SPrakash Jalan 		 * pr_range_cur_count keeps track of how many ranges
39030591ddd0SPrakash Jalan 		 * were defined by the driver from its mc_propinfo()
39040591ddd0SPrakash Jalan 		 * entry point.
39050591ddd0SPrakash Jalan 		 *
39060591ddd0SPrakash Jalan 		 * On exit, the user-specified range mpr_count returns
39070591ddd0SPrakash Jalan 		 * the number of ranges specified by the driver on
39080591ddd0SPrakash Jalan 		 * success, or the number of ranges it wanted to
39090591ddd0SPrakash Jalan 		 * define if that number of ranges could not be
39100591ddd0SPrakash Jalan 		 * accomodated by the specified range structure.  In
39110591ddd0SPrakash Jalan 		 * the latter case, the caller will be able to
39120591ddd0SPrakash Jalan 		 * allocate a larger range structure, and query the
39130591ddd0SPrakash Jalan 		 * property again.
39140591ddd0SPrakash Jalan 		 */
39150591ddd0SPrakash Jalan 		state.pr_range_cur_count = 0;
39160dc2366fSVenugopal Iyer 		state.pr_range = range;
39170dc2366fSVenugopal Iyer 
39180dc2366fSVenugopal Iyer 		mip->mi_callbacks->mc_propinfo(mip->mi_driver, name, id,
39190dc2366fSVenugopal Iyer 		    (mac_prop_info_handle_t)&state);
39200dc2366fSVenugopal Iyer 
39210591ddd0SPrakash Jalan 		if (state.pr_flags & MAC_PROP_INFO_RANGE)
39220591ddd0SPrakash Jalan 			range->mpr_count = state.pr_range_cur_count;
39230591ddd0SPrakash Jalan 
39240dc2366fSVenugopal Iyer 		/*
39250dc2366fSVenugopal Iyer 		 * The operation could fail if the buffer supplied by
39260dc2366fSVenugopal Iyer 		 * the user was too small for the range or default
39270dc2366fSVenugopal Iyer 		 * value of the property.
39280dc2366fSVenugopal Iyer 		 */
39290591ddd0SPrakash Jalan 		if (state.pr_errno != 0)
39300591ddd0SPrakash Jalan 			return (state.pr_errno);
39310dc2366fSVenugopal Iyer 
39320dc2366fSVenugopal Iyer 		if (perm != NULL && state.pr_flags & MAC_PROP_INFO_PERM)
39330dc2366fSVenugopal Iyer 			*perm = state.pr_perm;
39340dc2366fSVenugopal Iyer 	}
39350dc2366fSVenugopal Iyer 
39360dc2366fSVenugopal Iyer 	/*
39370dc2366fSVenugopal Iyer 	 * The MAC layer may want to provide default values or allowed
39380dc2366fSVenugopal Iyer 	 * ranges for properties if the driver does not provide a
39390dc2366fSVenugopal Iyer 	 * property info entry point, or that entry point exists, but
39400dc2366fSVenugopal Iyer 	 * it did not provide a default value or allowed ranges for
39410dc2366fSVenugopal Iyer 	 * that property.
39420dc2366fSVenugopal Iyer 	 */
39430dc2366fSVenugopal Iyer 	switch (id) {
39440dc2366fSVenugopal Iyer 	case MAC_PROP_MTU: {
39450dc2366fSVenugopal Iyer 		uint32_t sdu;
39460dc2366fSVenugopal Iyer 
39471eee170aSErik Nordmark 		mac_sdu_get2(mh, NULL, &sdu, NULL);
39480dc2366fSVenugopal Iyer 
39490dc2366fSVenugopal Iyer 		if (range != NULL && !(state.pr_flags &
39500dc2366fSVenugopal Iyer 		    MAC_PROP_INFO_RANGE)) {
39510dc2366fSVenugopal Iyer 			/* MTU range */
39520dc2366fSVenugopal Iyer 			_mac_set_range(range, sdu, sdu);
39530dc2366fSVenugopal Iyer 		}
39540dc2366fSVenugopal Iyer 
39550dc2366fSVenugopal Iyer 		if (default_val != NULL && !(state.pr_flags &
39560dc2366fSVenugopal Iyer 		    MAC_PROP_INFO_DEFAULT)) {
39570dc2366fSVenugopal Iyer 			if (mip->mi_info.mi_media == DL_ETHER)
39580dc2366fSVenugopal Iyer 				sdu = ETHERMTU;
39590dc2366fSVenugopal Iyer 			/* default MTU value */
39600dc2366fSVenugopal Iyer 			bcopy(&sdu, default_val, sizeof (sdu));
39610dc2366fSVenugopal Iyer 		}
39620dc2366fSVenugopal Iyer 	}
39630dc2366fSVenugopal Iyer 	}
39640dc2366fSVenugopal Iyer 
39650dc2366fSVenugopal Iyer 	return (0);
39660dc2366fSVenugopal Iyer }
39670dc2366fSVenugopal Iyer 
39685d460eafSCathy Zhou int
mac_fastpath_disable(mac_handle_t mh)39695d460eafSCathy Zhou mac_fastpath_disable(mac_handle_t mh)
39705d460eafSCathy Zhou {
39715d460eafSCathy Zhou 	mac_impl_t	*mip = (mac_impl_t *)mh;
39725d460eafSCathy Zhou 
39735d460eafSCathy Zhou 	if ((mip->mi_state_flags & MIS_LEGACY) == 0)
39745d460eafSCathy Zhou 		return (0);
39755d460eafSCathy Zhou 
39765d460eafSCathy Zhou 	return (mip->mi_capab_legacy.ml_fastpath_disable(mip->mi_driver));
39775d460eafSCathy Zhou }
39785d460eafSCathy Zhou 
39795d460eafSCathy Zhou void
mac_fastpath_enable(mac_handle_t mh)39805d460eafSCathy Zhou mac_fastpath_enable(mac_handle_t mh)
39815d460eafSCathy Zhou {
39825d460eafSCathy Zhou 	mac_impl_t	*mip = (mac_impl_t *)mh;
39835d460eafSCathy Zhou 
39845d460eafSCathy Zhou 	if ((mip->mi_state_flags & MIS_LEGACY) == 0)
39855d460eafSCathy Zhou 		return;
39865d460eafSCathy Zhou 
39875d460eafSCathy Zhou 	mip->mi_capab_legacy.ml_fastpath_enable(mip->mi_driver);
39885d460eafSCathy Zhou }
39895d460eafSCathy Zhou 
3990da14cebeSEric Cheng void
mac_register_priv_prop(mac_impl_t * mip,char ** priv_props)39910dc2366fSVenugopal Iyer mac_register_priv_prop(mac_impl_t *mip, char **priv_props)
39924045d941Ssowmini {
39930dc2366fSVenugopal Iyer 	uint_t nprops, i;
39944045d941Ssowmini 
39950dc2366fSVenugopal Iyer 	if (priv_props == NULL)
39964045d941Ssowmini 		return;
39974045d941Ssowmini 
39980dc2366fSVenugopal Iyer 	nprops = 0;
39990dc2366fSVenugopal Iyer 	while (priv_props[nprops] != NULL)
40000dc2366fSVenugopal Iyer 		nprops++;
40010dc2366fSVenugopal Iyer 	if (nprops == 0)
40020dc2366fSVenugopal Iyer 		return;
40030dc2366fSVenugopal Iyer 
40040dc2366fSVenugopal Iyer 
40050dc2366fSVenugopal Iyer 	mip->mi_priv_prop = kmem_zalloc(nprops * sizeof (char *), KM_SLEEP);
40060dc2366fSVenugopal Iyer 
40070dc2366fSVenugopal Iyer 	for (i = 0; i < nprops; i++) {
40080dc2366fSVenugopal Iyer 		mip->mi_priv_prop[i] = kmem_zalloc(MAXLINKPROPNAME, KM_SLEEP);
40090dc2366fSVenugopal Iyer 		(void) strlcpy(mip->mi_priv_prop[i], priv_props[i],
40100dc2366fSVenugopal Iyer 		    MAXLINKPROPNAME);
40110dc2366fSVenugopal Iyer 	}
40120dc2366fSVenugopal Iyer 
40130dc2366fSVenugopal Iyer 	mip->mi_priv_prop_count = nprops;
40144045d941Ssowmini }
40154c3c4458SSowmini Varadhan 
4016da14cebeSEric Cheng void
mac_unregister_priv_prop(mac_impl_t * mip)40174c3c4458SSowmini Varadhan mac_unregister_priv_prop(mac_impl_t *mip)
40184c3c4458SSowmini Varadhan {
40190dc2366fSVenugopal Iyer 	uint_t i;
40204c3c4458SSowmini Varadhan 
40210dc2366fSVenugopal Iyer 	if (mip->mi_priv_prop_count == 0) {
40220dc2366fSVenugopal Iyer 		ASSERT(mip->mi_priv_prop == NULL);
40230dc2366fSVenugopal Iyer 		return;
40244c3c4458SSowmini Varadhan 	}
40250dc2366fSVenugopal Iyer 
40260dc2366fSVenugopal Iyer 	for (i = 0; i < mip->mi_priv_prop_count; i++)
40270dc2366fSVenugopal Iyer 		kmem_free(mip->mi_priv_prop[i], MAXLINKPROPNAME);
40280dc2366fSVenugopal Iyer 	kmem_free(mip->mi_priv_prop, mip->mi_priv_prop_count *
40290dc2366fSVenugopal Iyer 	    sizeof (char *));
40300dc2366fSVenugopal Iyer 
40310dc2366fSVenugopal Iyer 	mip->mi_priv_prop = NULL;
40324c3c4458SSowmini Varadhan 	mip->mi_priv_prop_count = 0;
40334c3c4458SSowmini Varadhan }
4034da14cebeSEric Cheng 
4035da14cebeSEric Cheng /*
4036da14cebeSEric Cheng  * mac_ring_t 'mr' macros. Some rogue drivers may access ring structure
4037da14cebeSEric Cheng  * (by invoking mac_rx()) even after processing mac_stop_ring(). In such
4038da14cebeSEric Cheng  * cases if MAC free's the ring structure after mac_stop_ring(), any
4039da14cebeSEric Cheng  * illegal access to the ring structure coming from the driver will panic
4040da14cebeSEric Cheng  * the system. In order to protect the system from such inadverent access,
4041da14cebeSEric Cheng  * we maintain a cache of rings in the mac_impl_t after they get free'd up.
4042da14cebeSEric Cheng  * When packets are received on free'd up rings, MAC (through the generation
4043da14cebeSEric Cheng  * count mechanism) will drop such packets.
4044da14cebeSEric Cheng  */
4045da14cebeSEric Cheng static mac_ring_t *
mac_ring_alloc(mac_impl_t * mip)40460dc2366fSVenugopal Iyer mac_ring_alloc(mac_impl_t *mip)
4047da14cebeSEric Cheng {
4048da14cebeSEric Cheng 	mac_ring_t *ring;
4049da14cebeSEric Cheng 
4050da14cebeSEric Cheng 	mutex_enter(&mip->mi_ring_lock);
4051da14cebeSEric Cheng 	if (mip->mi_ring_freelist != NULL) {
4052da14cebeSEric Cheng 		ring = mip->mi_ring_freelist;
4053da14cebeSEric Cheng 		mip->mi_ring_freelist = ring->mr_next;
4054da14cebeSEric Cheng 		bzero(ring, sizeof (mac_ring_t));
4055da14cebeSEric Cheng 		mutex_exit(&mip->mi_ring_lock);
4056da14cebeSEric Cheng 	} else {
40570dc2366fSVenugopal Iyer 		mutex_exit(&mip->mi_ring_lock);
40580dc2366fSVenugopal Iyer 		ring = kmem_cache_alloc(mac_ring_cache, KM_SLEEP);
4059da14cebeSEric Cheng 	}
4060da14cebeSEric Cheng 	ASSERT((ring != NULL) && (ring->mr_state == MR_FREE));
4061da14cebeSEric Cheng 	return (ring);
4062da14cebeSEric Cheng }
4063da14cebeSEric Cheng 
4064da14cebeSEric Cheng static void
mac_ring_free(mac_impl_t * mip,mac_ring_t * ring)4065da14cebeSEric Cheng mac_ring_free(mac_impl_t *mip, mac_ring_t *ring)
4066da14cebeSEric Cheng {
40670dc2366fSVenugopal Iyer 	ASSERT(ring->mr_state == MR_FREE);
40680dc2366fSVenugopal Iyer 
4069da14cebeSEric Cheng 	mutex_enter(&mip->mi_ring_lock);
4070da14cebeSEric Cheng 	ring->mr_state = MR_FREE;
4071da14cebeSEric Cheng 	ring->mr_flag = 0;
4072da14cebeSEric Cheng 	ring->mr_next = mip->mi_ring_freelist;
40730dc2366fSVenugopal Iyer 	ring->mr_mip = NULL;
4074da14cebeSEric Cheng 	mip->mi_ring_freelist = ring;
40750dc2366fSVenugopal Iyer 	mac_ring_stat_delete(ring);
4076da14cebeSEric Cheng 	mutex_exit(&mip->mi_ring_lock);
4077da14cebeSEric Cheng }
4078da14cebeSEric Cheng 
4079da14cebeSEric Cheng static void
mac_ring_freeall(mac_impl_t * mip)4080da14cebeSEric Cheng mac_ring_freeall(mac_impl_t *mip)
4081da14cebeSEric Cheng {
4082da14cebeSEric Cheng 	mac_ring_t *ring_next;
4083da14cebeSEric Cheng 	mutex_enter(&mip->mi_ring_lock);
4084da14cebeSEric Cheng 	mac_ring_t *ring = mip->mi_ring_freelist;
4085da14cebeSEric Cheng 	while (ring != NULL) {
4086da14cebeSEric Cheng 		ring_next = ring->mr_next;
4087da14cebeSEric Cheng 		kmem_cache_free(mac_ring_cache, ring);
4088da14cebeSEric Cheng 		ring = ring_next;
4089da14cebeSEric Cheng 	}
4090da14cebeSEric Cheng 	mip->mi_ring_freelist = NULL;
4091da14cebeSEric Cheng 	mutex_exit(&mip->mi_ring_lock);
4092da14cebeSEric Cheng }
4093da14cebeSEric Cheng 
4094da14cebeSEric Cheng int
mac_start_ring(mac_ring_t * ring)4095da14cebeSEric Cheng mac_start_ring(mac_ring_t *ring)
4096da14cebeSEric Cheng {
4097da14cebeSEric Cheng 	int rv = 0;
4098da14cebeSEric Cheng 
40990dc2366fSVenugopal Iyer 	ASSERT(ring->mr_state == MR_FREE);
4100da14cebeSEric Cheng 
41010dc2366fSVenugopal Iyer 	if (ring->mr_start != NULL) {
41020dc2366fSVenugopal Iyer 		rv = ring->mr_start(ring->mr_driver, ring->mr_gen_num);
41030dc2366fSVenugopal Iyer 		if (rv != 0)
41040dc2366fSVenugopal Iyer 			return (rv);
41050dc2366fSVenugopal Iyer 	}
41060dc2366fSVenugopal Iyer 
41070dc2366fSVenugopal Iyer 	ring->mr_state = MR_INUSE;
4108da14cebeSEric Cheng 	return (rv);
4109da14cebeSEric Cheng }
4110da14cebeSEric Cheng 
4111da14cebeSEric Cheng void
mac_stop_ring(mac_ring_t * ring)4112da14cebeSEric Cheng mac_stop_ring(mac_ring_t *ring)
4113da14cebeSEric Cheng {
41140dc2366fSVenugopal Iyer 	ASSERT(ring->mr_state == MR_INUSE);
41150dc2366fSVenugopal Iyer 
4116da14cebeSEric Cheng 	if (ring->mr_stop != NULL)
4117da14cebeSEric Cheng 		ring->mr_stop(ring->mr_driver);
4118da14cebeSEric Cheng 
41190dc2366fSVenugopal Iyer 	ring->mr_state = MR_FREE;
41200dc2366fSVenugopal Iyer 
4121da14cebeSEric Cheng 	/*
4122da14cebeSEric Cheng 	 * Increment the ring generation number for this ring.
4123da14cebeSEric Cheng 	 */
4124da14cebeSEric Cheng 	ring->mr_gen_num++;
4125da14cebeSEric Cheng }
4126da14cebeSEric Cheng 
4127da14cebeSEric Cheng int
mac_start_group(mac_group_t * group)4128da14cebeSEric Cheng mac_start_group(mac_group_t *group)
4129da14cebeSEric Cheng {
4130da14cebeSEric Cheng 	int rv = 0;
4131da14cebeSEric Cheng 
4132da14cebeSEric Cheng 	if (group->mrg_start != NULL)
4133da14cebeSEric Cheng 		rv = group->mrg_start(group->mrg_driver);
4134da14cebeSEric Cheng 
4135da14cebeSEric Cheng 	return (rv);
4136da14cebeSEric Cheng }
4137da14cebeSEric Cheng 
4138da14cebeSEric Cheng void
mac_stop_group(mac_group_t * group)4139da14cebeSEric Cheng mac_stop_group(mac_group_t *group)
4140da14cebeSEric Cheng {
4141da14cebeSEric Cheng 	if (group->mrg_stop != NULL)
4142da14cebeSEric Cheng 		group->mrg_stop(group->mrg_driver);
4143da14cebeSEric Cheng }
4144da14cebeSEric Cheng 
4145da14cebeSEric Cheng /*
4146da14cebeSEric Cheng  * Called from mac_start() on the default Rx group. Broadcast and multicast
4147da14cebeSEric Cheng  * packets are received only on the default group. Hence the default group
4148da14cebeSEric Cheng  * needs to be up even if the primary client is not up, for the other groups
4149da14cebeSEric Cheng  * to be functional. We do this by calling this function at mac_start time
4150da14cebeSEric Cheng  * itself. However the broadcast packets that are received can't make their
4151da14cebeSEric Cheng  * way beyond mac_rx until a mac client creates a broadcast flow.
4152da14cebeSEric Cheng  */
4153da14cebeSEric Cheng static int
mac_start_group_and_rings(mac_group_t * group)4154da14cebeSEric Cheng mac_start_group_and_rings(mac_group_t *group)
4155da14cebeSEric Cheng {
4156da14cebeSEric Cheng 	mac_ring_t	*ring;
4157da14cebeSEric Cheng 	int		rv = 0;
4158da14cebeSEric Cheng 
4159da14cebeSEric Cheng 	ASSERT(group->mrg_state == MAC_GROUP_STATE_REGISTERED);
4160da14cebeSEric Cheng 	if ((rv = mac_start_group(group)) != 0)
4161da14cebeSEric Cheng 		return (rv);
4162da14cebeSEric Cheng 
4163da14cebeSEric Cheng 	for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
4164da14cebeSEric Cheng 		ASSERT(ring->mr_state == MR_FREE);
416545948e49SRyan Zezeski 
4166da14cebeSEric Cheng 		if ((rv = mac_start_ring(ring)) != 0)
4167da14cebeSEric Cheng 			goto error;
416845948e49SRyan Zezeski 
416945948e49SRyan Zezeski 		/*
417045948e49SRyan Zezeski 		 * When aggr_set_port_sdu() is called, it will remove
417145948e49SRyan Zezeski 		 * the port client's unicast address. This will cause
417245948e49SRyan Zezeski 		 * MAC to stop the default group's rings on the port
417345948e49SRyan Zezeski 		 * MAC. After it modifies the SDU, it will then re-add
417445948e49SRyan Zezeski 		 * the unicast address. At which time, this function is
417545948e49SRyan Zezeski 		 * called to start the default group's rings. Normally
417645948e49SRyan Zezeski 		 * this function would set the classify type to
417745948e49SRyan Zezeski 		 * MAC_SW_CLASSIFIER; but that will break aggr which
417845948e49SRyan Zezeski 		 * relies on the passthru classify mode being set for
417945948e49SRyan Zezeski 		 * correct delivery (see mac_rx_common()). To avoid
418045948e49SRyan Zezeski 		 * that, we check for a passthru callback and set the
418145948e49SRyan Zezeski 		 * classify type to MAC_PASSTHRU_CLASSIFIER; as it was
418245948e49SRyan Zezeski 		 * before the rings were stopped.
418345948e49SRyan Zezeski 		 */
418445948e49SRyan Zezeski 		ring->mr_classify_type = (ring->mr_pt_fn != NULL) ?
418545948e49SRyan Zezeski 		    MAC_PASSTHRU_CLASSIFIER : MAC_SW_CLASSIFIER;
4186da14cebeSEric Cheng 	}
4187da14cebeSEric Cheng 	return (0);
4188da14cebeSEric Cheng 
4189da14cebeSEric Cheng error:
4190da14cebeSEric Cheng 	mac_stop_group_and_rings(group);
4191da14cebeSEric Cheng 	return (rv);
4192da14cebeSEric Cheng }
4193da14cebeSEric Cheng 
4194da14cebeSEric Cheng /* Called from mac_stop on the default Rx group */
4195da14cebeSEric Cheng static void
mac_stop_group_and_rings(mac_group_t * group)4196da14cebeSEric Cheng mac_stop_group_and_rings(mac_group_t *group)
4197da14cebeSEric Cheng {
4198da14cebeSEric Cheng 	mac_ring_t	*ring;
4199da14cebeSEric Cheng 
4200da14cebeSEric Cheng 	for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
4201da14cebeSEric Cheng 		if (ring->mr_state != MR_FREE) {
4202da14cebeSEric Cheng 			mac_stop_ring(ring);
4203da14cebeSEric Cheng 			ring->mr_flag = 0;
4204da14cebeSEric Cheng 			ring->mr_classify_type = MAC_NO_CLASSIFIER;
4205da14cebeSEric Cheng 		}
4206da14cebeSEric Cheng 	}
4207da14cebeSEric Cheng 	mac_stop_group(group);
4208da14cebeSEric Cheng }
4209da14cebeSEric Cheng 
4210da14cebeSEric Cheng 
4211da14cebeSEric Cheng static mac_ring_t *
mac_init_ring(mac_impl_t * mip,mac_group_t * group,int index,mac_capab_rings_t * cap_rings)4212da14cebeSEric Cheng mac_init_ring(mac_impl_t *mip, mac_group_t *group, int index,
4213da14cebeSEric Cheng     mac_capab_rings_t *cap_rings)
4214da14cebeSEric Cheng {
42150dc2366fSVenugopal Iyer 	mac_ring_t *ring, *rnext;
4216da14cebeSEric Cheng 	mac_ring_info_t ring_info;
42170dc2366fSVenugopal Iyer 	ddi_intr_handle_t ddi_handle;
4218da14cebeSEric Cheng 
42190dc2366fSVenugopal Iyer 	ring = mac_ring_alloc(mip);
4220da14cebeSEric Cheng 
4221da14cebeSEric Cheng 	/* Prepare basic information of ring */
42220dc2366fSVenugopal Iyer 
42230dc2366fSVenugopal Iyer 	/*
42240dc2366fSVenugopal Iyer 	 * Ring index is numbered to be unique across a particular device.
42250dc2366fSVenugopal Iyer 	 * Ring index computation makes following assumptions:
42260dc2366fSVenugopal Iyer 	 *	- For drivers with static grouping (e.g. ixgbe, bge),
42270dc2366fSVenugopal Iyer 	 *	ring index exchanged with the driver (e.g. during mr_rget)
42280dc2366fSVenugopal Iyer 	 *	is unique only across the group the ring belongs to.
42290dc2366fSVenugopal Iyer 	 *	- Drivers with dynamic grouping (e.g. nxge), start
42300dc2366fSVenugopal Iyer 	 *	with single group (mrg_index = 0).
42310dc2366fSVenugopal Iyer 	 */
42320dc2366fSVenugopal Iyer 	ring->mr_index = group->mrg_index * group->mrg_info.mgi_count + index;
4233da14cebeSEric Cheng 	ring->mr_type = group->mrg_type;
4234da14cebeSEric Cheng 	ring->mr_gh = (mac_group_handle_t)group;
4235da14cebeSEric Cheng 
4236da14cebeSEric Cheng 	/* Insert the new ring to the list. */
4237da14cebeSEric Cheng 	ring->mr_next = group->mrg_rings;
4238da14cebeSEric Cheng 	group->mrg_rings = ring;
4239da14cebeSEric Cheng 
4240da14cebeSEric Cheng 	/* Zero to reuse the info data structure */
4241da14cebeSEric Cheng 	bzero(&ring_info, sizeof (ring_info));
4242da14cebeSEric Cheng 
4243da14cebeSEric Cheng 	/* Query ring information from driver */
4244da14cebeSEric Cheng 	cap_rings->mr_rget(mip->mi_driver, group->mrg_type, group->mrg_index,
4245da14cebeSEric Cheng 	    index, &ring_info, (mac_ring_handle_t)ring);
4246da14cebeSEric Cheng 
4247da14cebeSEric Cheng 	ring->mr_info = ring_info;
4248da14cebeSEric Cheng 
42490dc2366fSVenugopal Iyer 	/*
42500dc2366fSVenugopal Iyer 	 * The interrupt handle could be shared among multiple rings.
42510dc2366fSVenugopal Iyer 	 * Thus if there is a bunch of rings that are sharing an
42520dc2366fSVenugopal Iyer 	 * interrupt, then only one ring among the bunch will be made
42530dc2366fSVenugopal Iyer 	 * available for interrupt re-targeting; the rest will have
42540dc2366fSVenugopal Iyer 	 * ddi_shared flag set to TRUE and would not be available for
42550dc2366fSVenugopal Iyer 	 * be interrupt re-targeting.
42560dc2366fSVenugopal Iyer 	 */
42570dc2366fSVenugopal Iyer 	if ((ddi_handle = ring_info.mri_intr.mi_ddi_handle) != NULL) {
42580dc2366fSVenugopal Iyer 		rnext = ring->mr_next;
42590dc2366fSVenugopal Iyer 		while (rnext != NULL) {
42600dc2366fSVenugopal Iyer 			if (rnext->mr_info.mri_intr.mi_ddi_handle ==
42610dc2366fSVenugopal Iyer 			    ddi_handle) {
42620dc2366fSVenugopal Iyer 				/*
42630dc2366fSVenugopal Iyer 				 * If default ring (mr_index == 0) is part
42640dc2366fSVenugopal Iyer 				 * of a group of rings sharing an
42650dc2366fSVenugopal Iyer 				 * interrupt, then set ddi_shared flag for
42660dc2366fSVenugopal Iyer 				 * the default ring and give another ring
42670dc2366fSVenugopal Iyer 				 * the chance to be re-targeted.
42680dc2366fSVenugopal Iyer 				 */
42690dc2366fSVenugopal Iyer 				if (rnext->mr_index == 0 &&
42700dc2366fSVenugopal Iyer 				    !rnext->mr_info.mri_intr.mi_ddi_shared) {
42710dc2366fSVenugopal Iyer 					rnext->mr_info.mri_intr.mi_ddi_shared =
42720dc2366fSVenugopal Iyer 					    B_TRUE;
42730dc2366fSVenugopal Iyer 				} else {
42740dc2366fSVenugopal Iyer 					ring->mr_info.mri_intr.mi_ddi_shared =
42750dc2366fSVenugopal Iyer 					    B_TRUE;
42760dc2366fSVenugopal Iyer 				}
42770dc2366fSVenugopal Iyer 				break;
42780dc2366fSVenugopal Iyer 			}
42790dc2366fSVenugopal Iyer 			rnext = rnext->mr_next;
42800dc2366fSVenugopal Iyer 		}
42810dc2366fSVenugopal Iyer 		/*
42820dc2366fSVenugopal Iyer 		 * If rnext is NULL, then no matching ddi_handle was found.
42830dc2366fSVenugopal Iyer 		 * Rx rings get registered first. So if this is a Tx ring,
42840dc2366fSVenugopal Iyer 		 * then go through all the Rx rings and see if there is a
42850dc2366fSVenugopal Iyer 		 * matching ddi handle.
42860dc2366fSVenugopal Iyer 		 */
42870dc2366fSVenugopal Iyer 		if (rnext == NULL && ring->mr_type == MAC_RING_TYPE_TX) {
42880dc2366fSVenugopal Iyer 			mac_compare_ddi_handle(mip->mi_rx_groups,
42890dc2366fSVenugopal Iyer 			    mip->mi_rx_group_count, ring);
42900dc2366fSVenugopal Iyer 		}
42910dc2366fSVenugopal Iyer 	}
42920dc2366fSVenugopal Iyer 
4293da14cebeSEric Cheng 	/* Update ring's status */
4294da14cebeSEric Cheng 	ring->mr_state = MR_FREE;
4295da14cebeSEric Cheng 	ring->mr_flag = 0;
4296da14cebeSEric Cheng 
4297da14cebeSEric Cheng 	/* Update the ring count of the group */
4298da14cebeSEric Cheng 	group->mrg_cur_count++;
42990dc2366fSVenugopal Iyer 
43000dc2366fSVenugopal Iyer 	/* Create per ring kstats */
43010dc2366fSVenugopal Iyer 	if (ring->mr_stat != NULL) {
43020dc2366fSVenugopal Iyer 		ring->mr_mip = mip;
43030dc2366fSVenugopal Iyer 		mac_ring_stat_create(ring);
43040dc2366fSVenugopal Iyer 	}
43050dc2366fSVenugopal Iyer 
4306da14cebeSEric Cheng 	return (ring);
4307da14cebeSEric Cheng }
4308da14cebeSEric Cheng 
4309da14cebeSEric Cheng /*
4310da14cebeSEric Cheng  * Rings are chained together for easy regrouping.
4311da14cebeSEric Cheng  */
4312da14cebeSEric Cheng static void
mac_init_group(mac_impl_t * mip,mac_group_t * group,int size,mac_capab_rings_t * cap_rings)4313da14cebeSEric Cheng mac_init_group(mac_impl_t *mip, mac_group_t *group, int size,
4314da14cebeSEric Cheng     mac_capab_rings_t *cap_rings)
4315da14cebeSEric Cheng {
4316da14cebeSEric Cheng 	int index;
4317da14cebeSEric Cheng 
4318da14cebeSEric Cheng 	/*
4319da14cebeSEric Cheng 	 * Initialize all ring members of this group. Size of zero will not
4320da14cebeSEric Cheng 	 * enter the loop, so it's safe for initializing an empty group.
4321da14cebeSEric Cheng 	 */
4322da14cebeSEric Cheng 	for (index = size - 1; index >= 0; index--)
4323da14cebeSEric Cheng 		(void) mac_init_ring(mip, group, index, cap_rings);
4324da14cebeSEric Cheng }
4325da14cebeSEric Cheng 
4326da14cebeSEric Cheng int
mac_init_rings(mac_impl_t * mip,mac_ring_type_t rtype)4327da14cebeSEric Cheng mac_init_rings(mac_impl_t *mip, mac_ring_type_t rtype)
4328da14cebeSEric Cheng {
4329da14cebeSEric Cheng 	mac_capab_rings_t	*cap_rings;
43300dc2366fSVenugopal Iyer 	mac_group_t		*group;
43310dc2366fSVenugopal Iyer 	mac_group_t		*groups;
4332da14cebeSEric Cheng 	mac_group_info_t	group_info;
4333da14cebeSEric Cheng 	uint_t			group_free = 0;
4334da14cebeSEric Cheng 	uint_t			ring_left;
4335da14cebeSEric Cheng 	mac_ring_t		*ring;
43360dc2366fSVenugopal Iyer 	int			g;
43370dc2366fSVenugopal Iyer 	int			err = 0;
43380dc2366fSVenugopal Iyer 	uint_t			grpcnt;
43390dc2366fSVenugopal Iyer 	boolean_t		pseudo_txgrp = B_FALSE;
4340da14cebeSEric Cheng 
4341da14cebeSEric Cheng 	switch (rtype) {
4342da14cebeSEric Cheng 	case MAC_RING_TYPE_RX:
4343da14cebeSEric Cheng 		ASSERT(mip->mi_rx_groups == NULL);
4344da14cebeSEric Cheng 
4345da14cebeSEric Cheng 		cap_rings = &mip->mi_rx_rings_cap;
4346da14cebeSEric Cheng 		cap_rings->mr_type = MAC_RING_TYPE_RX;
4347da14cebeSEric Cheng 		break;
4348da14cebeSEric Cheng 	case MAC_RING_TYPE_TX:
4349da14cebeSEric Cheng 		ASSERT(mip->mi_tx_groups == NULL);
4350da14cebeSEric Cheng 
4351da14cebeSEric Cheng 		cap_rings = &mip->mi_tx_rings_cap;
4352da14cebeSEric Cheng 		cap_rings->mr_type = MAC_RING_TYPE_TX;
4353da14cebeSEric Cheng 		break;
4354da14cebeSEric Cheng 	default:
4355da14cebeSEric Cheng 		ASSERT(B_FALSE);
4356da14cebeSEric Cheng 	}
4357da14cebeSEric Cheng 
43580dc2366fSVenugopal Iyer 	if (!i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_RINGS, cap_rings))
4359da14cebeSEric Cheng 		return (0);
43600dc2366fSVenugopal Iyer 	grpcnt = cap_rings->mr_gnum;
43610dc2366fSVenugopal Iyer 
43620dc2366fSVenugopal Iyer 	/*
43630dc2366fSVenugopal Iyer 	 * If we have multiple TX rings, but only one TX group, we can
43640dc2366fSVenugopal Iyer 	 * create pseudo TX groups (one per TX ring) in the MAC layer,
43650dc2366fSVenugopal Iyer 	 * except for an aggr. For an aggr currently we maintain only
43660dc2366fSVenugopal Iyer 	 * one group with all the rings (for all its ports), going
43670dc2366fSVenugopal Iyer 	 * forwards we might change this.
43680dc2366fSVenugopal Iyer 	 */
43690dc2366fSVenugopal Iyer 	if (rtype == MAC_RING_TYPE_TX &&
43700dc2366fSVenugopal Iyer 	    cap_rings->mr_gnum == 0 && cap_rings->mr_rnum >  0 &&
43710dc2366fSVenugopal Iyer 	    (mip->mi_state_flags & MIS_IS_AGGR) == 0) {
43720dc2366fSVenugopal Iyer 		/*
43730dc2366fSVenugopal Iyer 		 * The -1 here is because we create a default TX group
43740dc2366fSVenugopal Iyer 		 * with all the rings in it.
43750dc2366fSVenugopal Iyer 		 */
43760dc2366fSVenugopal Iyer 		grpcnt = cap_rings->mr_rnum - 1;
43770dc2366fSVenugopal Iyer 		pseudo_txgrp = B_TRUE;
43780dc2366fSVenugopal Iyer 	}
4379da14cebeSEric Cheng 
4380da14cebeSEric Cheng 	/*
4381da14cebeSEric Cheng 	 * Allocate a contiguous buffer for all groups.
4382da14cebeSEric Cheng 	 */
43830dc2366fSVenugopal Iyer 	groups = kmem_zalloc(sizeof (mac_group_t) * (grpcnt+ 1), KM_SLEEP);
4384da14cebeSEric Cheng 
4385da14cebeSEric Cheng 	ring_left = cap_rings->mr_rnum;
4386da14cebeSEric Cheng 
4387da14cebeSEric Cheng 	/*
4388da14cebeSEric Cheng 	 * Get all ring groups if any, and get their ring members
4389da14cebeSEric Cheng 	 * if any.
4390da14cebeSEric Cheng 	 */
43910dc2366fSVenugopal Iyer 	for (g = 0; g < grpcnt; g++) {
4392da14cebeSEric Cheng 		group = groups + g;
4393da14cebeSEric Cheng 
4394da14cebeSEric Cheng 		/* Prepare basic information of the group */
4395da14cebeSEric Cheng 		group->mrg_index = g;
4396da14cebeSEric Cheng 		group->mrg_type = rtype;
4397da14cebeSEric Cheng 		group->mrg_state = MAC_GROUP_STATE_UNINIT;
4398da14cebeSEric Cheng 		group->mrg_mh = (mac_handle_t)mip;
4399da14cebeSEric Cheng 		group->mrg_next = group + 1;
4400da14cebeSEric Cheng 
4401da14cebeSEric Cheng 		/* Zero to reuse the info data structure */
4402da14cebeSEric Cheng 		bzero(&group_info, sizeof (group_info));
4403da14cebeSEric Cheng 
44040dc2366fSVenugopal Iyer 		if (pseudo_txgrp) {
44050dc2366fSVenugopal Iyer 			/*
44060dc2366fSVenugopal Iyer 			 * This is a pseudo group that we created, apart
44070dc2366fSVenugopal Iyer 			 * from setting the state there is nothing to be
44080dc2366fSVenugopal Iyer 			 * done.
44090dc2366fSVenugopal Iyer 			 */
44100dc2366fSVenugopal Iyer 			group->mrg_state = MAC_GROUP_STATE_REGISTERED;
44110dc2366fSVenugopal Iyer 			group_free++;
44120dc2366fSVenugopal Iyer 			continue;
44130dc2366fSVenugopal Iyer 		}
4414da14cebeSEric Cheng 		/* Query group information from driver */
4415da14cebeSEric Cheng 		cap_rings->mr_gget(mip->mi_driver, rtype, g, &group_info,
4416da14cebeSEric Cheng 		    (mac_group_handle_t)group);
4417da14cebeSEric Cheng 
4418da14cebeSEric Cheng 		switch (cap_rings->mr_group_type) {
4419da14cebeSEric Cheng 		case MAC_GROUP_TYPE_DYNAMIC:
4420da14cebeSEric Cheng 			if (cap_rings->mr_gaddring == NULL ||
4421da14cebeSEric Cheng 			    cap_rings->mr_gremring == NULL) {
4422da14cebeSEric Cheng 				DTRACE_PROBE3(
4423da14cebeSEric Cheng 				    mac__init__rings_no_addremring,
4424da14cebeSEric Cheng 				    char *, mip->mi_name,
4425da14cebeSEric Cheng 				    mac_group_add_ring_t,
4426da14cebeSEric Cheng 				    cap_rings->mr_gaddring,
4427da14cebeSEric Cheng 				    mac_group_add_ring_t,
4428da14cebeSEric Cheng 				    cap_rings->mr_gremring);
4429da14cebeSEric Cheng 				err = EINVAL;
4430da14cebeSEric Cheng 				goto bail;
4431da14cebeSEric Cheng 			}
4432da14cebeSEric Cheng 
4433da14cebeSEric Cheng 			switch (rtype) {
4434da14cebeSEric Cheng 			case MAC_RING_TYPE_RX:
4435da14cebeSEric Cheng 				/*
4436da14cebeSEric Cheng 				 * The first RX group must have non-zero
4437da14cebeSEric Cheng 				 * rings, and the following groups must
4438da14cebeSEric Cheng 				 * have zero rings.
4439da14cebeSEric Cheng 				 */
4440da14cebeSEric Cheng 				if (g == 0 && group_info.mgi_count == 0) {
4441da14cebeSEric Cheng 					DTRACE_PROBE1(
4442da14cebeSEric Cheng 					    mac__init__rings__rx__def__zero,
4443da14cebeSEric Cheng 					    char *, mip->mi_name);
4444da14cebeSEric Cheng 					err = EINVAL;
4445da14cebeSEric Cheng 					goto bail;
4446da14cebeSEric Cheng 				}
4447da14cebeSEric Cheng 				if (g > 0 && group_info.mgi_count != 0) {
4448da14cebeSEric Cheng 					DTRACE_PROBE3(
4449da14cebeSEric Cheng 					    mac__init__rings__rx__nonzero,
4450da14cebeSEric Cheng 					    char *, mip->mi_name,
4451da14cebeSEric Cheng 					    int, g, int, group_info.mgi_count);
4452da14cebeSEric Cheng 					err = EINVAL;
4453da14cebeSEric Cheng 					goto bail;
4454da14cebeSEric Cheng 				}
4455da14cebeSEric Cheng 				break;
4456da14cebeSEric Cheng 			case MAC_RING_TYPE_TX:
4457da14cebeSEric Cheng 				/*
4458da14cebeSEric Cheng 				 * All TX ring groups must have zero rings.
4459da14cebeSEric Cheng 				 */
4460da14cebeSEric Cheng 				if (group_info.mgi_count != 0) {
4461da14cebeSEric Cheng 					DTRACE_PROBE3(
4462da14cebeSEric Cheng 					    mac__init__rings__tx__nonzero,
4463da14cebeSEric Cheng 					    char *, mip->mi_name,
4464da14cebeSEric Cheng 					    int, g, int, group_info.mgi_count);
4465da14cebeSEric Cheng 					err = EINVAL;
4466da14cebeSEric Cheng 					goto bail;
4467da14cebeSEric Cheng 				}
4468da14cebeSEric Cheng 				break;
4469da14cebeSEric Cheng 			}
4470da14cebeSEric Cheng 			break;
4471da14cebeSEric Cheng 		case MAC_GROUP_TYPE_STATIC:
4472da14cebeSEric Cheng 			/*
4473da14cebeSEric Cheng 			 * Note that an empty group is allowed, e.g., an aggr
4474da14cebeSEric Cheng 			 * would start with an empty group.
4475da14cebeSEric Cheng 			 */
4476da14cebeSEric Cheng 			break;
4477da14cebeSEric Cheng 		default:
4478da14cebeSEric Cheng 			/* unknown group type */
4479da14cebeSEric Cheng 			DTRACE_PROBE2(mac__init__rings__unknown__type,
4480da14cebeSEric Cheng 			    char *, mip->mi_name,
4481da14cebeSEric Cheng 			    int, cap_rings->mr_group_type);
4482da14cebeSEric Cheng 			err = EINVAL;
4483da14cebeSEric Cheng 			goto bail;
4484da14cebeSEric Cheng 		}
4485da14cebeSEric Cheng 
4486da14cebeSEric Cheng 
4487da14cebeSEric Cheng 		/*
448884de666eSRyan Zezeski 		 * The driver must register some form of hardware MAC
448984de666eSRyan Zezeski 		 * filter in order for Rx groups to support multiple
449084de666eSRyan Zezeski 		 * MAC addresses.
4491da14cebeSEric Cheng 		 */
4492d05c2e38SDan McDonald 		if (rtype == MAC_RING_TYPE_RX &&
449384de666eSRyan Zezeski 		    (group_info.mgi_addmac == NULL ||
449484de666eSRyan Zezeski 		    group_info.mgi_remmac == NULL)) {
449584de666eSRyan Zezeski 			DTRACE_PROBE1(mac__init__rings__no__mac__filter,
449684de666eSRyan Zezeski 			    char *, mip->mi_name);
4497d05c2e38SDan McDonald 			err = EINVAL;
4498da14cebeSEric Cheng 			goto bail;
4499da14cebeSEric Cheng 		}
4500da14cebeSEric Cheng 
4501da14cebeSEric Cheng 		/* Cache driver-supplied information */
4502da14cebeSEric Cheng 		group->mrg_info = group_info;
4503da14cebeSEric Cheng 
4504da14cebeSEric Cheng 		/* Update the group's status and group count. */
45050dc2366fSVenugopal Iyer 		mac_set_group_state(group, MAC_GROUP_STATE_REGISTERED);
4506da14cebeSEric Cheng 		group_free++;
4507da14cebeSEric Cheng 
4508da14cebeSEric Cheng 		group->mrg_rings = NULL;
4509da14cebeSEric Cheng 		group->mrg_cur_count = 0;
4510da14cebeSEric Cheng 		mac_init_group(mip, group, group_info.mgi_count, cap_rings);
4511da14cebeSEric Cheng 		ring_left -= group_info.mgi_count;
4512da14cebeSEric Cheng 
4513da14cebeSEric Cheng 		/* The current group size should be equal to default value */
4514da14cebeSEric Cheng 		ASSERT(group->mrg_cur_count == group_info.mgi_count);
4515da14cebeSEric Cheng 	}
4516da14cebeSEric Cheng 
4517da14cebeSEric Cheng 	/* Build up a dummy group for free resources as a pool */
45180dc2366fSVenugopal Iyer 	group = groups + grpcnt;
4519da14cebeSEric Cheng 
4520da14cebeSEric Cheng 	/* Prepare basic information of the group */
4521da14cebeSEric Cheng 	group->mrg_index = -1;
4522da14cebeSEric Cheng 	group->mrg_type = rtype;
4523da14cebeSEric Cheng 	group->mrg_state = MAC_GROUP_STATE_UNINIT;
4524da14cebeSEric Cheng 	group->mrg_mh = (mac_handle_t)mip;
4525da14cebeSEric Cheng 	group->mrg_next = NULL;
4526da14cebeSEric Cheng 
4527da14cebeSEric Cheng 	/*
4528da14cebeSEric Cheng 	 * If there are ungrouped rings, allocate a continuous buffer for
4529da14cebeSEric Cheng 	 * remaining resources.
4530da14cebeSEric Cheng 	 */
4531da14cebeSEric Cheng 	if (ring_left != 0) {
4532da14cebeSEric Cheng 		group->mrg_rings = NULL;
4533da14cebeSEric Cheng 		group->mrg_cur_count = 0;
4534da14cebeSEric Cheng 		mac_init_group(mip, group, ring_left, cap_rings);
4535da14cebeSEric Cheng 
4536da14cebeSEric Cheng 		/* The current group size should be equal to ring_left */
4537da14cebeSEric Cheng 		ASSERT(group->mrg_cur_count == ring_left);
4538da14cebeSEric Cheng 
4539da14cebeSEric Cheng 		ring_left = 0;
4540da14cebeSEric Cheng 
4541da14cebeSEric Cheng 		/* Update this group's status */
45420dc2366fSVenugopal Iyer 		mac_set_group_state(group, MAC_GROUP_STATE_REGISTERED);
454384de666eSRyan Zezeski 	} else {
4544da14cebeSEric Cheng 		group->mrg_rings = NULL;
454584de666eSRyan Zezeski 	}
4546da14cebeSEric Cheng 
4547da14cebeSEric Cheng 	ASSERT(ring_left == 0);
4548da14cebeSEric Cheng 
4549da14cebeSEric Cheng bail:
45500dc2366fSVenugopal Iyer 
4551da14cebeSEric Cheng 	/* Cache other important information to finalize the initialization */
4552da14cebeSEric Cheng 	switch (rtype) {
4553da14cebeSEric Cheng 	case MAC_RING_TYPE_RX:
4554da14cebeSEric Cheng 		mip->mi_rx_group_type = cap_rings->mr_group_type;
4555da14cebeSEric Cheng 		mip->mi_rx_group_count = cap_rings->mr_gnum;
4556da14cebeSEric Cheng 		mip->mi_rx_groups = groups;
45570dc2366fSVenugopal Iyer 		mip->mi_rx_donor_grp = groups;
45580dc2366fSVenugopal Iyer 		if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
45590dc2366fSVenugopal Iyer 			/*
45600dc2366fSVenugopal Iyer 			 * The default ring is reserved since it is
45610dc2366fSVenugopal Iyer 			 * used for sending the broadcast etc. packets.
45620dc2366fSVenugopal Iyer 			 */
45630dc2366fSVenugopal Iyer 			mip->mi_rxrings_avail =
45640dc2366fSVenugopal Iyer 			    mip->mi_rx_groups->mrg_cur_count - 1;
45650dc2366fSVenugopal Iyer 			mip->mi_rxrings_rsvd = 1;
45660dc2366fSVenugopal Iyer 		}
45670dc2366fSVenugopal Iyer 		/*
45680dc2366fSVenugopal Iyer 		 * The default group cannot be reserved. It is used by
45690dc2366fSVenugopal Iyer 		 * all the clients that do not have an exclusive group.
45700dc2366fSVenugopal Iyer 		 */
45710dc2366fSVenugopal Iyer 		mip->mi_rxhwclnt_avail = mip->mi_rx_group_count - 1;
45720dc2366fSVenugopal Iyer 		mip->mi_rxhwclnt_used = 1;
4573da14cebeSEric Cheng 		break;
4574da14cebeSEric Cheng 	case MAC_RING_TYPE_TX:
45750dc2366fSVenugopal Iyer 		mip->mi_tx_group_type = pseudo_txgrp ? MAC_GROUP_TYPE_DYNAMIC :
45760dc2366fSVenugopal Iyer 		    cap_rings->mr_group_type;
45770dc2366fSVenugopal Iyer 		mip->mi_tx_group_count = grpcnt;
4578da14cebeSEric Cheng 		mip->mi_tx_group_free = group_free;
4579da14cebeSEric Cheng 		mip->mi_tx_groups = groups;
4580da14cebeSEric Cheng 
45810dc2366fSVenugopal Iyer 		group = groups + grpcnt;
4582da14cebeSEric Cheng 		ring = group->mrg_rings;
45830dc2366fSVenugopal Iyer 		/*
45840dc2366fSVenugopal Iyer 		 * The ring can be NULL in the case of aggr. Aggr will
45850dc2366fSVenugopal Iyer 		 * have an empty Tx group which will get populated
45860dc2366fSVenugopal Iyer 		 * later when pseudo Tx rings are added after
45870dc2366fSVenugopal Iyer 		 * mac_register() is done.
45880dc2366fSVenugopal Iyer 		 */
45890dc2366fSVenugopal Iyer 		if (ring == NULL) {
45900dc2366fSVenugopal Iyer 			ASSERT(mip->mi_state_flags & MIS_IS_AGGR);
45910dc2366fSVenugopal Iyer 			/*
45920dc2366fSVenugopal Iyer 			 * pass the group to aggr so it can add Tx
45930dc2366fSVenugopal Iyer 			 * rings to the group later.
45940dc2366fSVenugopal Iyer 			 */
45950dc2366fSVenugopal Iyer 			cap_rings->mr_gget(mip->mi_driver, rtype, 0, NULL,
45960dc2366fSVenugopal Iyer 			    (mac_group_handle_t)group);
45970dc2366fSVenugopal Iyer 			/*
45980dc2366fSVenugopal Iyer 			 * Even though there are no rings at this time
45990dc2366fSVenugopal Iyer 			 * (rings will come later), set the group
46000dc2366fSVenugopal Iyer 			 * state to registered.
46010dc2366fSVenugopal Iyer 			 */
46020dc2366fSVenugopal Iyer 			group->mrg_state = MAC_GROUP_STATE_REGISTERED;
46030dc2366fSVenugopal Iyer 		} else {
46040dc2366fSVenugopal Iyer 			/*
46050dc2366fSVenugopal Iyer 			 * Ring 0 is used as the default one and it could be
46060dc2366fSVenugopal Iyer 			 * assigned to a client as well.
46070dc2366fSVenugopal Iyer 			 */
4608da14cebeSEric Cheng 			while ((ring->mr_index != 0) && (ring->mr_next != NULL))
4609da14cebeSEric Cheng 				ring = ring->mr_next;
4610da14cebeSEric Cheng 			ASSERT(ring->mr_index == 0);
4611da14cebeSEric Cheng 			mip->mi_default_tx_ring = (mac_ring_handle_t)ring;
46120dc2366fSVenugopal Iyer 		}
4613af5d3c33SToomas Soome 		if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
46140dc2366fSVenugopal Iyer 			mip->mi_txrings_avail = group->mrg_cur_count - 1;
46150dc2366fSVenugopal Iyer 			/*
46160dc2366fSVenugopal Iyer 			 * The default ring cannot be reserved.
46170dc2366fSVenugopal Iyer 			 */
46180dc2366fSVenugopal Iyer 			mip->mi_txrings_rsvd = 1;
4619af5d3c33SToomas Soome 		}
46200dc2366fSVenugopal Iyer 		/*
46210dc2366fSVenugopal Iyer 		 * The default group cannot be reserved. It will be shared
46220dc2366fSVenugopal Iyer 		 * by clients that do not have an exclusive group.
46230dc2366fSVenugopal Iyer 		 */
46240dc2366fSVenugopal Iyer 		mip->mi_txhwclnt_avail = mip->mi_tx_group_count;
46250dc2366fSVenugopal Iyer 		mip->mi_txhwclnt_used = 1;
4626da14cebeSEric Cheng 		break;
4627da14cebeSEric Cheng 	default:
4628da14cebeSEric Cheng 		ASSERT(B_FALSE);
4629da14cebeSEric Cheng 	}
4630da14cebeSEric Cheng 
4631da14cebeSEric Cheng 	if (err != 0)
4632da14cebeSEric Cheng 		mac_free_rings(mip, rtype);
4633da14cebeSEric Cheng 
4634da14cebeSEric Cheng 	return (err);
4635da14cebeSEric Cheng }
4636da14cebeSEric Cheng 
4637da14cebeSEric Cheng /*
46380dc2366fSVenugopal Iyer  * The ddi interrupt handle could be shared amoung rings. If so, compare
46390dc2366fSVenugopal Iyer  * the new ring's ddi handle with the existing ones and set ddi_shared
46400dc2366fSVenugopal Iyer  * flag.
46410dc2366fSVenugopal Iyer  */
46420dc2366fSVenugopal Iyer void
mac_compare_ddi_handle(mac_group_t * groups,uint_t grpcnt,mac_ring_t * cring)46430dc2366fSVenugopal Iyer mac_compare_ddi_handle(mac_group_t *groups, uint_t grpcnt, mac_ring_t *cring)
46440dc2366fSVenugopal Iyer {
46450dc2366fSVenugopal Iyer 	mac_group_t *group;
46460dc2366fSVenugopal Iyer 	mac_ring_t *ring;
46470dc2366fSVenugopal Iyer 	ddi_intr_handle_t ddi_handle;
46480dc2366fSVenugopal Iyer 	int g;
46490dc2366fSVenugopal Iyer 
46500dc2366fSVenugopal Iyer 	ddi_handle = cring->mr_info.mri_intr.mi_ddi_handle;
46510dc2366fSVenugopal Iyer 	for (g = 0; g < grpcnt; g++) {
46520dc2366fSVenugopal Iyer 		group = groups + g;
46530dc2366fSVenugopal Iyer 		for (ring = group->mrg_rings; ring != NULL;
46540dc2366fSVenugopal Iyer 		    ring = ring->mr_next) {
46550dc2366fSVenugopal Iyer 			if (ring == cring)
46560dc2366fSVenugopal Iyer 				continue;
46570dc2366fSVenugopal Iyer 			if (ring->mr_info.mri_intr.mi_ddi_handle ==
46580dc2366fSVenugopal Iyer 			    ddi_handle) {
46590dc2366fSVenugopal Iyer 				if (cring->mr_type == MAC_RING_TYPE_RX &&
46600dc2366fSVenugopal Iyer 				    ring->mr_index == 0 &&
46610dc2366fSVenugopal Iyer 				    !ring->mr_info.mri_intr.mi_ddi_shared) {
46620dc2366fSVenugopal Iyer 					ring->mr_info.mri_intr.mi_ddi_shared =
46630dc2366fSVenugopal Iyer 					    B_TRUE;
46640dc2366fSVenugopal Iyer 				} else {
46650dc2366fSVenugopal Iyer 					cring->mr_info.mri_intr.mi_ddi_shared =
46660dc2366fSVenugopal Iyer 					    B_TRUE;
46670dc2366fSVenugopal Iyer 				}
46680dc2366fSVenugopal Iyer 				return;
46690dc2366fSVenugopal Iyer 			}
46700dc2366fSVenugopal Iyer 		}
46710dc2366fSVenugopal Iyer 	}
46720dc2366fSVenugopal Iyer }
46730dc2366fSVenugopal Iyer 
46740dc2366fSVenugopal Iyer /*
46750dc2366fSVenugopal Iyer  * Called to free all groups of particular type (RX or TX). It's assumed that
46760dc2366fSVenugopal Iyer  * no clients are using these groups.
4677da14cebeSEric Cheng  */
4678da14cebeSEric Cheng void
mac_free_rings(mac_impl_t * mip,mac_ring_type_t rtype)4679da14cebeSEric Cheng mac_free_rings(mac_impl_t *mip, mac_ring_type_t rtype)
4680da14cebeSEric Cheng {
4681da14cebeSEric Cheng 	mac_group_t *group, *groups;
4682da14cebeSEric Cheng 	uint_t group_count;
4683da14cebeSEric Cheng 
4684da14cebeSEric Cheng 	switch (rtype) {
4685da14cebeSEric Cheng 	case MAC_RING_TYPE_RX:
4686da14cebeSEric Cheng 		if (mip->mi_rx_groups == NULL)
4687da14cebeSEric Cheng 			return;
4688da14cebeSEric Cheng 
4689da14cebeSEric Cheng 		groups = mip->mi_rx_groups;
4690da14cebeSEric Cheng 		group_count = mip->mi_rx_group_count;
4691da14cebeSEric Cheng 
4692da14cebeSEric Cheng 		mip->mi_rx_groups = NULL;
46930dc2366fSVenugopal Iyer 		mip->mi_rx_donor_grp = NULL;
4694da14cebeSEric Cheng 		mip->mi_rx_group_count = 0;
4695da14cebeSEric Cheng 		break;
4696da14cebeSEric Cheng 	case MAC_RING_TYPE_TX:
4697da14cebeSEric Cheng 		ASSERT(mip->mi_tx_group_count == mip->mi_tx_group_free);
4698da14cebeSEric Cheng 
4699da14cebeSEric Cheng 		if (mip->mi_tx_groups == NULL)
4700da14cebeSEric Cheng 			return;
4701da14cebeSEric Cheng 
4702da14cebeSEric Cheng 		groups = mip->mi_tx_groups;
4703da14cebeSEric Cheng 		group_count = mip->mi_tx_group_count;
4704da14cebeSEric Cheng 
4705da14cebeSEric Cheng 		mip->mi_tx_groups = NULL;
4706da14cebeSEric Cheng 		mip->mi_tx_group_count = 0;
4707da14cebeSEric Cheng 		mip->mi_tx_group_free = 0;
4708da14cebeSEric Cheng 		mip->mi_default_tx_ring = NULL;
4709da14cebeSEric Cheng 		break;
4710da14cebeSEric Cheng 	default:
4711da14cebeSEric Cheng 		ASSERT(B_FALSE);
4712da14cebeSEric Cheng 	}
4713da14cebeSEric Cheng 
4714da14cebeSEric Cheng 	for (group = groups; group != NULL; group = group->mrg_next) {
4715da14cebeSEric Cheng 		mac_ring_t *ring;
4716da14cebeSEric Cheng 
4717da14cebeSEric Cheng 		if (group->mrg_cur_count == 0)
4718da14cebeSEric Cheng 			continue;
4719da14cebeSEric Cheng 
4720da14cebeSEric Cheng 		ASSERT(group->mrg_rings != NULL);
4721da14cebeSEric Cheng 
4722da14cebeSEric Cheng 		while ((ring = group->mrg_rings) != NULL) {
4723da14cebeSEric Cheng 			group->mrg_rings = ring->mr_next;
4724da14cebeSEric Cheng 			mac_ring_free(mip, ring);
4725da14cebeSEric Cheng 		}
4726da14cebeSEric Cheng 	}
4727da14cebeSEric Cheng 
4728da14cebeSEric Cheng 	/* Free all the cached rings */
4729da14cebeSEric Cheng 	mac_ring_freeall(mip);
4730da14cebeSEric Cheng 	/* Free the block of group data strutures */
4731da14cebeSEric Cheng 	kmem_free(groups, sizeof (mac_group_t) * (group_count + 1));
4732da14cebeSEric Cheng }
4733da14cebeSEric Cheng 
4734da14cebeSEric Cheng /*
473584de666eSRyan Zezeski  * Associate the VLAN filter to the receive group.
473684de666eSRyan Zezeski  */
473784de666eSRyan Zezeski int
mac_group_addvlan(mac_group_t * group,uint16_t vlan)473884de666eSRyan Zezeski mac_group_addvlan(mac_group_t *group, uint16_t vlan)
473984de666eSRyan Zezeski {
474084de666eSRyan Zezeski 	VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
474184de666eSRyan Zezeski 	VERIFY3P(group->mrg_info.mgi_addvlan, !=, NULL);
474284de666eSRyan Zezeski 
474384de666eSRyan Zezeski 	if (vlan > VLAN_ID_MAX)
474484de666eSRyan Zezeski 		return (EINVAL);
474584de666eSRyan Zezeski 
474684de666eSRyan Zezeski 	vlan = MAC_VLAN_UNTAGGED_VID(vlan);
474784de666eSRyan Zezeski 	return (group->mrg_info.mgi_addvlan(group->mrg_info.mgi_driver, vlan));
474884de666eSRyan Zezeski }
474984de666eSRyan Zezeski 
475084de666eSRyan Zezeski /*
475184de666eSRyan Zezeski  * Dissociate the VLAN from the receive group.
475284de666eSRyan Zezeski  */
475384de666eSRyan Zezeski int
mac_group_remvlan(mac_group_t * group,uint16_t vlan)475484de666eSRyan Zezeski mac_group_remvlan(mac_group_t *group, uint16_t vlan)
475584de666eSRyan Zezeski {
475684de666eSRyan Zezeski 	VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
475784de666eSRyan Zezeski 	VERIFY3P(group->mrg_info.mgi_remvlan, !=, NULL);
475884de666eSRyan Zezeski 
475984de666eSRyan Zezeski 	if (vlan > VLAN_ID_MAX)
476084de666eSRyan Zezeski 		return (EINVAL);
476184de666eSRyan Zezeski 
476284de666eSRyan Zezeski 	vlan = MAC_VLAN_UNTAGGED_VID(vlan);
476384de666eSRyan Zezeski 	return (group->mrg_info.mgi_remvlan(group->mrg_info.mgi_driver, vlan));
476484de666eSRyan Zezeski }
476584de666eSRyan Zezeski 
476684de666eSRyan Zezeski /*
4767da14cebeSEric Cheng  * Associate a MAC address with a receive group.
4768da14cebeSEric Cheng  *
4769da14cebeSEric Cheng  * The return value of this function should always be checked properly, because
4770da14cebeSEric Cheng  * any type of failure could cause unexpected results. A group can be added
4771da14cebeSEric Cheng  * or removed with a MAC address only after it has been reserved. Ideally,
4772da14cebeSEric Cheng  * a successful reservation always leads to calling mac_group_addmac() to
4773da14cebeSEric Cheng  * steer desired traffic. Failure of adding an unicast MAC address doesn't
4774da14cebeSEric Cheng  * always imply that the group is functioning abnormally.
4775da14cebeSEric Cheng  *
4776da14cebeSEric Cheng  * Currently this function is called everywhere, and it reflects assumptions
4777da14cebeSEric Cheng  * about MAC addresses in the implementation. CR 6735196.
4778da14cebeSEric Cheng  */
4779da14cebeSEric Cheng int
mac_group_addmac(mac_group_t * group,const uint8_t * addr)4780da14cebeSEric Cheng mac_group_addmac(mac_group_t *group, const uint8_t *addr)
4781da14cebeSEric Cheng {
478284de666eSRyan Zezeski 	VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
478384de666eSRyan Zezeski 	VERIFY3P(group->mrg_info.mgi_addmac, !=, NULL);
4784da14cebeSEric Cheng 
4785da14cebeSEric Cheng 	return (group->mrg_info.mgi_addmac(group->mrg_info.mgi_driver, addr));
4786da14cebeSEric Cheng }
4787da14cebeSEric Cheng 
4788da14cebeSEric Cheng /*
4789da14cebeSEric Cheng  * Remove the association between MAC address and receive group.
4790da14cebeSEric Cheng  */
4791da14cebeSEric Cheng int
mac_group_remmac(mac_group_t * group,const uint8_t * addr)4792da14cebeSEric Cheng mac_group_remmac(mac_group_t *group, const uint8_t *addr)
4793da14cebeSEric Cheng {
479484de666eSRyan Zezeski 	VERIFY3S(group->mrg_type, ==, MAC_RING_TYPE_RX);
479584de666eSRyan Zezeski 	VERIFY3P(group->mrg_info.mgi_remmac, !=, NULL);
4796da14cebeSEric Cheng 
4797da14cebeSEric Cheng 	return (group->mrg_info.mgi_remmac(group->mrg_info.mgi_driver, addr));
4798da14cebeSEric Cheng }
4799da14cebeSEric Cheng 
4800da14cebeSEric Cheng /*
4801c61a1653SRyan Zezeski  * This is the entry point for packets transmitted through the bridge
4802c61a1653SRyan Zezeski  * code. If no bridge is in place, mac_ring_tx() transmits via the tx
4803c61a1653SRyan Zezeski  * ring. The 'rh' pointer may be NULL to select the default ring.
48044eaa4710SRishi Srivatsavai  */
48054eaa4710SRishi Srivatsavai mblk_t *
mac_bridge_tx(mac_impl_t * mip,mac_ring_handle_t rh,mblk_t * mp)48064eaa4710SRishi Srivatsavai mac_bridge_tx(mac_impl_t *mip, mac_ring_handle_t rh, mblk_t *mp)
48074eaa4710SRishi Srivatsavai {
48084eaa4710SRishi Srivatsavai 	mac_handle_t mh;
48094eaa4710SRishi Srivatsavai 
48104eaa4710SRishi Srivatsavai 	/*
48114eaa4710SRishi Srivatsavai 	 * Once we take a reference on the bridge link, the bridge
48124eaa4710SRishi Srivatsavai 	 * module itself can't unload, so the callback pointers are
48134eaa4710SRishi Srivatsavai 	 * stable.
48144eaa4710SRishi Srivatsavai 	 */
48154eaa4710SRishi Srivatsavai 	mutex_enter(&mip->mi_bridge_lock);
48164eaa4710SRishi Srivatsavai 	if ((mh = mip->mi_bridge_link) != NULL)
48174eaa4710SRishi Srivatsavai 		mac_bridge_ref_cb(mh, B_TRUE);
48184eaa4710SRishi Srivatsavai 	mutex_exit(&mip->mi_bridge_lock);
48194eaa4710SRishi Srivatsavai 	if (mh == NULL) {
4820c61a1653SRyan Zezeski 		mp = mac_ring_tx((mac_handle_t)mip, rh, mp);
48214eaa4710SRishi Srivatsavai 	} else {
4822c61a1653SRyan Zezeski 		/*
4823c61a1653SRyan Zezeski 		 * The bridge may place this mblk on a provider's Tx
4824c61a1653SRyan Zezeski 		 * path, a mac's Rx path, or both. Since we don't have
4825c61a1653SRyan Zezeski 		 * enough information at this point, we can't be sure
4826c61a1653SRyan Zezeski 		 * that the destination(s) are capable of handling the
4827c61a1653SRyan Zezeski 		 * hardware offloads requested by the mblk. We emulate
4828c61a1653SRyan Zezeski 		 * them here as it is the safest choice. In the
4829c61a1653SRyan Zezeski 		 * future, if bridge performance becomes a priority,
4830c61a1653SRyan Zezeski 		 * we can elide the emulation here and leave the
4831c61a1653SRyan Zezeski 		 * choice up to bridge.
4832c61a1653SRyan Zezeski 		 *
4833c61a1653SRyan Zezeski 		 * We don't clear the DB_CKSUMFLAGS here because
4834c61a1653SRyan Zezeski 		 * HCK_IPV4_HDRCKSUM (Tx) and HCK_IPV4_HDRCKSUM_OK
4835c61a1653SRyan Zezeski 		 * (Rx) still have the same value. If the bridge
4836c61a1653SRyan Zezeski 		 * receives a packet from a HCKSUM_IPHDRCKSUM NIC then
4837c61a1653SRyan Zezeski 		 * the mac(s) it is forwarded on may calculate the
4838c61a1653SRyan Zezeski 		 * checksum again, but incorrectly (because the
4839c61a1653SRyan Zezeski 		 * checksum field is not zero). Until the
4840c61a1653SRyan Zezeski 		 * HCK_IPV4_HDRCKSUM/HCK_IPV4_HDRCKSUM_OK issue is
4841c61a1653SRyan Zezeski 		 * resovled, we leave the flag clearing in bridge
4842c61a1653SRyan Zezeski 		 * itself.
4843c61a1653SRyan Zezeski 		 */
4844c61a1653SRyan Zezeski 		if ((DB_CKSUMFLAGS(mp) & (HCK_TX_FLAGS | HW_LSO_FLAGS)) != 0) {
4845c61a1653SRyan Zezeski 			mac_hw_emul(&mp, NULL, NULL, MAC_ALL_EMULS);
4846c61a1653SRyan Zezeski 		}
4847c61a1653SRyan Zezeski 
48484eaa4710SRishi Srivatsavai 		mp = mac_bridge_tx_cb(mh, rh, mp);
48494eaa4710SRishi Srivatsavai 		mac_bridge_ref_cb(mh, B_FALSE);
48504eaa4710SRishi Srivatsavai 	}
48514eaa4710SRishi Srivatsavai 
48524eaa4710SRishi Srivatsavai 	return (mp);
48534eaa4710SRishi Srivatsavai }
48544eaa4710SRishi Srivatsavai 
48554eaa4710SRishi Srivatsavai /*
4856da14cebeSEric Cheng  * Find a ring from its index.
4857da14cebeSEric Cheng  */
48580dc2366fSVenugopal Iyer mac_ring_handle_t
mac_find_ring(mac_group_handle_t gh,int index)48590dc2366fSVenugopal Iyer mac_find_ring(mac_group_handle_t gh, int index)
4860da14cebeSEric Cheng {
48610dc2366fSVenugopal Iyer 	mac_group_t *group = (mac_group_t *)gh;
4862da14cebeSEric Cheng 	mac_ring_t *ring = group->mrg_rings;
4863da14cebeSEric Cheng 
4864da14cebeSEric Cheng 	for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next)
4865da14cebeSEric Cheng 		if (ring->mr_index == index)
4866da14cebeSEric Cheng 			break;
4867da14cebeSEric Cheng 
48680dc2366fSVenugopal Iyer 	return ((mac_ring_handle_t)ring);
4869da14cebeSEric Cheng }
4870da14cebeSEric Cheng /*
4871da14cebeSEric Cheng  * Add a ring to an existing group.
4872da14cebeSEric Cheng  *
4873da14cebeSEric Cheng  * The ring must be either passed directly (for example if the ring
4874da14cebeSEric Cheng  * movement is initiated by the framework), or specified through a driver
4875da14cebeSEric Cheng  * index (for example when the ring is added by the driver.
4876da14cebeSEric Cheng  *
4877da14cebeSEric Cheng  * The caller needs to call mac_perim_enter() before calling this function.
4878da14cebeSEric Cheng  */
4879da14cebeSEric Cheng int
i_mac_group_add_ring(mac_group_t * group,mac_ring_t * ring,int index)4880da14cebeSEric Cheng i_mac_group_add_ring(mac_group_t *group, mac_ring_t *ring, int index)
4881da14cebeSEric Cheng {
4882da14cebeSEric Cheng 	mac_impl_t *mip = (mac_impl_t *)group->mrg_mh;
4883da14cebeSEric Cheng 	mac_capab_rings_t *cap_rings;
4884da14cebeSEric Cheng 	boolean_t driver_call = (ring == NULL);
4885da14cebeSEric Cheng 	mac_group_type_t group_type;
4886da14cebeSEric Cheng 	int ret = 0;
48870dc2366fSVenugopal Iyer 	flow_entry_t *flent;
4888da14cebeSEric Cheng 
4889da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
4890da14cebeSEric Cheng 
4891da14cebeSEric Cheng 	switch (group->mrg_type) {
4892da14cebeSEric Cheng 	case MAC_RING_TYPE_RX:
4893da14cebeSEric Cheng 		cap_rings = &mip->mi_rx_rings_cap;
4894da14cebeSEric Cheng 		group_type = mip->mi_rx_group_type;
4895da14cebeSEric Cheng 		break;
4896da14cebeSEric Cheng 	case MAC_RING_TYPE_TX:
4897da14cebeSEric Cheng 		cap_rings = &mip->mi_tx_rings_cap;
4898da14cebeSEric Cheng 		group_type = mip->mi_tx_group_type;
4899da14cebeSEric Cheng 		break;
4900da14cebeSEric Cheng 	default:
4901da14cebeSEric Cheng 		ASSERT(B_FALSE);
4902da14cebeSEric Cheng 	}
4903da14cebeSEric Cheng 
4904da14cebeSEric Cheng 	/*
4905da14cebeSEric Cheng 	 * There should be no ring with the same ring index in the target
4906da14cebeSEric Cheng 	 * group.
4907da14cebeSEric Cheng 	 */
49080dc2366fSVenugopal Iyer 	ASSERT(mac_find_ring((mac_group_handle_t)group,
49090dc2366fSVenugopal Iyer 	    driver_call ? index : ring->mr_index) == NULL);
4910da14cebeSEric Cheng 
4911da14cebeSEric Cheng 	if (driver_call) {
4912da14cebeSEric Cheng 		/*
4913da14cebeSEric Cheng 		 * The function is called as a result of a request from
4914da14cebeSEric Cheng 		 * a driver to add a ring to an existing group, for example
4915da14cebeSEric Cheng 		 * from the aggregation driver. Allocate a new mac_ring_t
4916da14cebeSEric Cheng 		 * for that ring.
4917da14cebeSEric Cheng 		 */
4918da14cebeSEric Cheng 		ring = mac_init_ring(mip, group, index, cap_rings);
4919da14cebeSEric Cheng 		ASSERT(group->mrg_state > MAC_GROUP_STATE_UNINIT);
4920da14cebeSEric Cheng 	} else {
4921da14cebeSEric Cheng 		/*
4922da14cebeSEric Cheng 		 * The function is called as a result of a MAC layer request
4923da14cebeSEric Cheng 		 * to add a ring to an existing group. In this case the
4924da14cebeSEric Cheng 		 * ring is being moved between groups, which requires
4925da14cebeSEric Cheng 		 * the underlying driver to support dynamic grouping,
4926da14cebeSEric Cheng 		 * and the mac_ring_t already exists.
4927da14cebeSEric Cheng 		 */
4928da14cebeSEric Cheng 		ASSERT(group_type == MAC_GROUP_TYPE_DYNAMIC);
49290dc2366fSVenugopal Iyer 		ASSERT(group->mrg_driver == NULL ||
49300dc2366fSVenugopal Iyer 		    cap_rings->mr_gaddring != NULL);
4931da14cebeSEric Cheng 		ASSERT(ring->mr_gh == NULL);
4932da14cebeSEric Cheng 	}
4933da14cebeSEric Cheng 
4934da14cebeSEric Cheng 	/*
4935da14cebeSEric Cheng 	 * At this point the ring should not be in use, and it should be
4936da14cebeSEric Cheng 	 * of the right for the target group.
4937da14cebeSEric Cheng 	 */
4938da14cebeSEric Cheng 	ASSERT(ring->mr_state < MR_INUSE);
4939da14cebeSEric Cheng 	ASSERT(ring->mr_srs == NULL);
4940da14cebeSEric Cheng 	ASSERT(ring->mr_type == group->mrg_type);
4941da14cebeSEric Cheng 
4942da14cebeSEric Cheng 	if (!driver_call) {
4943da14cebeSEric Cheng 		/*
4944da14cebeSEric Cheng 		 * Add the driver level hardware ring if the process was not
4945da14cebeSEric Cheng 		 * initiated by the driver, and the target group is not the
4946da14cebeSEric Cheng 		 * group.
4947da14cebeSEric Cheng 		 */
4948da14cebeSEric Cheng 		if (group->mrg_driver != NULL) {
4949da14cebeSEric Cheng 			cap_rings->mr_gaddring(group->mrg_driver,
4950da14cebeSEric Cheng 			    ring->mr_driver, ring->mr_type);
4951da14cebeSEric Cheng 		}
4952da14cebeSEric Cheng 
4953da14cebeSEric Cheng 		/*
4954da14cebeSEric Cheng 		 * Insert the ring ahead existing rings.
4955da14cebeSEric Cheng 		 */
4956da14cebeSEric Cheng 		ring->mr_next = group->mrg_rings;
4957da14cebeSEric Cheng 		group->mrg_rings = ring;
4958da14cebeSEric Cheng 		ring->mr_gh = (mac_group_handle_t)group;
4959da14cebeSEric Cheng 		group->mrg_cur_count++;
4960da14cebeSEric Cheng 	}
4961da14cebeSEric Cheng 
4962da14cebeSEric Cheng 	/*
4963da14cebeSEric Cheng 	 * If the group has not been actively used, we're done.
4964da14cebeSEric Cheng 	 */
4965da14cebeSEric Cheng 	if (group->mrg_index != -1 &&
4966da14cebeSEric Cheng 	    group->mrg_state < MAC_GROUP_STATE_RESERVED)
4967da14cebeSEric Cheng 		return (0);
4968da14cebeSEric Cheng 
4969da14cebeSEric Cheng 	/*
4970da14cebeSEric Cheng 	 * Start the ring if needed. Failure causes to undo the grouping action.
4971da14cebeSEric Cheng 	 */
49720dc2366fSVenugopal Iyer 	if (ring->mr_state != MR_INUSE) {
4973da14cebeSEric Cheng 		if ((ret = mac_start_ring(ring)) != 0) {
4974da14cebeSEric Cheng 			if (!driver_call) {
4975da14cebeSEric Cheng 				cap_rings->mr_gremring(group->mrg_driver,
4976da14cebeSEric Cheng 				    ring->mr_driver, ring->mr_type);
4977da14cebeSEric Cheng 			}
4978da14cebeSEric Cheng 			group->mrg_cur_count--;
4979da14cebeSEric Cheng 			group->mrg_rings = ring->mr_next;
4980da14cebeSEric Cheng 
4981da14cebeSEric Cheng 			ring->mr_gh = NULL;
4982da14cebeSEric Cheng 
4983da14cebeSEric Cheng 			if (driver_call)
4984da14cebeSEric Cheng 				mac_ring_free(mip, ring);
4985da14cebeSEric Cheng 
4986da14cebeSEric Cheng 			return (ret);
4987da14cebeSEric Cheng 		}
49880dc2366fSVenugopal Iyer 	}
4989da14cebeSEric Cheng 
4990da14cebeSEric Cheng 	/*
49910dc2366fSVenugopal Iyer 	 * Set up SRS/SR according to the ring type.
4992da14cebeSEric Cheng 	 */
49930dc2366fSVenugopal Iyer 	switch (ring->mr_type) {
49940dc2366fSVenugopal Iyer 	case MAC_RING_TYPE_RX:
49950dc2366fSVenugopal Iyer 		/*
499684de666eSRyan Zezeski 		 * Setup an SRS on top of the new ring if the group is
499784de666eSRyan Zezeski 		 * reserved for someone's exclusive use.
49980dc2366fSVenugopal Iyer 		 */
49990dc2366fSVenugopal Iyer 		if (group->mrg_state == MAC_GROUP_STATE_RESERVED) {
500084de666eSRyan Zezeski 			mac_client_impl_t *mcip =  MAC_GROUP_ONLY_CLIENT(group);
50010dc2366fSVenugopal Iyer 
500284de666eSRyan Zezeski 			VERIFY3P(mcip, !=, NULL);
50030dc2366fSVenugopal Iyer 			flent = mcip->mci_flent;
500484de666eSRyan Zezeski 			VERIFY3S(flent->fe_rx_srs_cnt, >, 0);
50050dc2366fSVenugopal Iyer 			mac_rx_srs_group_setup(mcip, flent, SRST_LINK);
500684de666eSRyan Zezeski 			mac_fanout_setup(mcip, flent, MCIP_RESOURCE_PROPS(mcip),
500784de666eSRyan Zezeski 			    mac_rx_deliver, mcip, NULL, NULL);
50080dc2366fSVenugopal Iyer 		} else {
50090dc2366fSVenugopal Iyer 			ring->mr_classify_type = MAC_SW_CLASSIFIER;
50100dc2366fSVenugopal Iyer 		}
50110dc2366fSVenugopal Iyer 		break;
50120dc2366fSVenugopal Iyer 	case MAC_RING_TYPE_TX:
50130dc2366fSVenugopal Iyer 	{
50140dc2366fSVenugopal Iyer 		mac_grp_client_t	*mgcp = group->mrg_clients;
50150dc2366fSVenugopal Iyer 		mac_client_impl_t	*mcip;
50160dc2366fSVenugopal Iyer 		mac_soft_ring_set_t	*mac_srs;
50170dc2366fSVenugopal Iyer 		mac_srs_tx_t		*tx;
50180dc2366fSVenugopal Iyer 
50190dc2366fSVenugopal Iyer 		if (MAC_GROUP_NO_CLIENT(group)) {
50200dc2366fSVenugopal Iyer 			if (ring->mr_state == MR_INUSE)
50210dc2366fSVenugopal Iyer 				mac_stop_ring(ring);
50220dc2366fSVenugopal Iyer 			ring->mr_flag = 0;
50230dc2366fSVenugopal Iyer 			break;
50240dc2366fSVenugopal Iyer 		}
50250dc2366fSVenugopal Iyer 		/*
50260dc2366fSVenugopal Iyer 		 * If the rings are being moved to a group that has
50270dc2366fSVenugopal Iyer 		 * clients using it, then add the new rings to the
50280dc2366fSVenugopal Iyer 		 * clients SRS.
50290dc2366fSVenugopal Iyer 		 */
50300dc2366fSVenugopal Iyer 		while (mgcp != NULL) {
50310dc2366fSVenugopal Iyer 			boolean_t	is_aggr;
50320dc2366fSVenugopal Iyer 
50330dc2366fSVenugopal Iyer 			mcip = mgcp->mgc_client;
50340dc2366fSVenugopal Iyer 			flent = mcip->mci_flent;
503584de666eSRyan Zezeski 			is_aggr = (mcip->mci_state_flags & MCIS_IS_AGGR_CLIENT);
50360dc2366fSVenugopal Iyer 			mac_srs = MCIP_TX_SRS(mcip);
50370dc2366fSVenugopal Iyer 			tx = &mac_srs->srs_tx;
50380dc2366fSVenugopal Iyer 			mac_tx_client_quiesce((mac_client_handle_t)mcip);
50390dc2366fSVenugopal Iyer 			/*
50400dc2366fSVenugopal Iyer 			 * If we are  growing from 1 to multiple rings.
50410dc2366fSVenugopal Iyer 			 */
50420dc2366fSVenugopal Iyer 			if (tx->st_mode == SRS_TX_BW ||
50430dc2366fSVenugopal Iyer 			    tx->st_mode == SRS_TX_SERIALIZE ||
50440dc2366fSVenugopal Iyer 			    tx->st_mode == SRS_TX_DEFAULT) {
50450dc2366fSVenugopal Iyer 				mac_ring_t	*tx_ring = tx->st_arg2;
50460dc2366fSVenugopal Iyer 
50470dc2366fSVenugopal Iyer 				tx->st_arg2 = NULL;
50480dc2366fSVenugopal Iyer 				mac_tx_srs_stat_recreate(mac_srs, B_TRUE);
50490dc2366fSVenugopal Iyer 				mac_tx_srs_add_ring(mac_srs, tx_ring);
50500dc2366fSVenugopal Iyer 				if (mac_srs->srs_type & SRST_BW_CONTROL) {
50510dc2366fSVenugopal Iyer 					tx->st_mode = is_aggr ? SRS_TX_BW_AGGR :
50520dc2366fSVenugopal Iyer 					    SRS_TX_BW_FANOUT;
50530dc2366fSVenugopal Iyer 				} else {
50540dc2366fSVenugopal Iyer 					tx->st_mode = is_aggr ? SRS_TX_AGGR :
50550dc2366fSVenugopal Iyer 					    SRS_TX_FANOUT;
50560dc2366fSVenugopal Iyer 				}
50570dc2366fSVenugopal Iyer 				tx->st_func = mac_tx_get_func(tx->st_mode);
50580dc2366fSVenugopal Iyer 			}
50590dc2366fSVenugopal Iyer 			mac_tx_srs_add_ring(mac_srs, ring);
50600dc2366fSVenugopal Iyer 			mac_fanout_setup(mcip, flent, MCIP_RESOURCE_PROPS(mcip),
50610dc2366fSVenugopal Iyer 			    mac_rx_deliver, mcip, NULL, NULL);
50620dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)mcip);
50630dc2366fSVenugopal Iyer 			mgcp = mgcp->mgc_next;
50640dc2366fSVenugopal Iyer 		}
50650dc2366fSVenugopal Iyer 		break;
50660dc2366fSVenugopal Iyer 	}
50670dc2366fSVenugopal Iyer 	default:
50680dc2366fSVenugopal Iyer 		ASSERT(B_FALSE);
50690dc2366fSVenugopal Iyer 	}
50700dc2366fSVenugopal Iyer 	/*
50710dc2366fSVenugopal Iyer 	 * For aggr, the default ring will be NULL to begin with. If it
50720dc2366fSVenugopal Iyer 	 * is NULL, then pick the first ring that gets added as the
50730dc2366fSVenugopal Iyer 	 * default ring. Any ring in an aggregation can be removed at
50740dc2366fSVenugopal Iyer 	 * any time (by the user action of removing a link) and if the
50750dc2366fSVenugopal Iyer 	 * current default ring gets removed, then a new one gets
50760dc2366fSVenugopal Iyer 	 * picked (see i_mac_group_rem_ring()).
50770dc2366fSVenugopal Iyer 	 */
50780dc2366fSVenugopal Iyer 	if (mip->mi_state_flags & MIS_IS_AGGR &&
50790dc2366fSVenugopal Iyer 	    mip->mi_default_tx_ring == NULL &&
50800dc2366fSVenugopal Iyer 	    ring->mr_type == MAC_RING_TYPE_TX) {
50810dc2366fSVenugopal Iyer 		mip->mi_default_tx_ring = (mac_ring_handle_t)ring;
50820dc2366fSVenugopal Iyer 	}
50830dc2366fSVenugopal Iyer 
5084da14cebeSEric Cheng 	MAC_RING_UNMARK(ring, MR_INCIPIENT);
5085da14cebeSEric Cheng 	return (0);
5086da14cebeSEric Cheng }
5087da14cebeSEric Cheng 
5088da14cebeSEric Cheng /*
5089da14cebeSEric Cheng  * Remove a ring from it's current group. MAC internal function for dynamic
5090da14cebeSEric Cheng  * grouping.
5091da14cebeSEric Cheng  *
5092da14cebeSEric Cheng  * The caller needs to call mac_perim_enter() before calling this function.
5093da14cebeSEric Cheng  */
5094da14cebeSEric Cheng void
i_mac_group_rem_ring(mac_group_t * group,mac_ring_t * ring,boolean_t driver_call)5095da14cebeSEric Cheng i_mac_group_rem_ring(mac_group_t *group, mac_ring_t *ring,
5096da14cebeSEric Cheng     boolean_t driver_call)
5097da14cebeSEric Cheng {
5098da14cebeSEric Cheng 	mac_impl_t *mip = (mac_impl_t *)group->mrg_mh;
5099da14cebeSEric Cheng 	mac_capab_rings_t *cap_rings = NULL;
5100da14cebeSEric Cheng 	mac_group_type_t group_type;
5101da14cebeSEric Cheng 
5102da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5103da14cebeSEric Cheng 
51040dc2366fSVenugopal Iyer 	ASSERT(mac_find_ring((mac_group_handle_t)group,
51050dc2366fSVenugopal Iyer 	    ring->mr_index) == (mac_ring_handle_t)ring);
5106da14cebeSEric Cheng 	ASSERT((mac_group_t *)ring->mr_gh == group);
5107da14cebeSEric Cheng 	ASSERT(ring->mr_type == group->mrg_type);
5108da14cebeSEric Cheng 
51090dc2366fSVenugopal Iyer 	if (ring->mr_state == MR_INUSE)
51100dc2366fSVenugopal Iyer 		mac_stop_ring(ring);
5111da14cebeSEric Cheng 	switch (ring->mr_type) {
5112da14cebeSEric Cheng 	case MAC_RING_TYPE_RX:
5113da14cebeSEric Cheng 		group_type = mip->mi_rx_group_type;
5114da14cebeSEric Cheng 		cap_rings = &mip->mi_rx_rings_cap;
5115da14cebeSEric Cheng 
5116da14cebeSEric Cheng 		/*
5117da14cebeSEric Cheng 		 * Only hardware classified packets hold a reference to the
5118da14cebeSEric Cheng 		 * ring all the way up the Rx path. mac_rx_srs_remove()
5119da14cebeSEric Cheng 		 * will take care of quiescing the Rx path and removing the
5120da14cebeSEric Cheng 		 * SRS. The software classified path neither holds a reference
5121da14cebeSEric Cheng 		 * nor any association with the ring in mac_rx.
5122da14cebeSEric Cheng 		 */
5123da14cebeSEric Cheng 		if (ring->mr_srs != NULL) {
5124da14cebeSEric Cheng 			mac_rx_srs_remove(ring->mr_srs);
5125da14cebeSEric Cheng 			ring->mr_srs = NULL;
5126da14cebeSEric Cheng 		}
5127da14cebeSEric Cheng 
5128da14cebeSEric Cheng 		break;
5129da14cebeSEric Cheng 	case MAC_RING_TYPE_TX:
51300dc2366fSVenugopal Iyer 	{
51310dc2366fSVenugopal Iyer 		mac_grp_client_t	*mgcp;
51320dc2366fSVenugopal Iyer 		mac_client_impl_t	*mcip;
51330dc2366fSVenugopal Iyer 		mac_soft_ring_set_t	*mac_srs;
51340dc2366fSVenugopal Iyer 		mac_srs_tx_t		*tx;
51350dc2366fSVenugopal Iyer 		mac_ring_t		*rem_ring;
51360dc2366fSVenugopal Iyer 		mac_group_t		*defgrp;
51370dc2366fSVenugopal Iyer 		uint_t			ring_info = 0;
51380dc2366fSVenugopal Iyer 
5139da14cebeSEric Cheng 		/*
51400dc2366fSVenugopal Iyer 		 * For TX this function is invoked in three
5141da14cebeSEric Cheng 		 * cases:
5142da14cebeSEric Cheng 		 *
5143da14cebeSEric Cheng 		 * 1) In the case of a failure during the
5144da14cebeSEric Cheng 		 * initial creation of a group when a share is
5145da14cebeSEric Cheng 		 * associated with a MAC client. So the SRS is not
5146da14cebeSEric Cheng 		 * yet setup, and will be setup later after the
5147da14cebeSEric Cheng 		 * group has been reserved and populated.
5148da14cebeSEric Cheng 		 *
5149da14cebeSEric Cheng 		 * 2) From mac_release_tx_group() when freeing
5150da14cebeSEric Cheng 		 * a TX SRS.
5151da14cebeSEric Cheng 		 *
51520dc2366fSVenugopal Iyer 		 * 3) In the case of aggr, when a port gets removed,
51530dc2366fSVenugopal Iyer 		 * the pseudo Tx rings that it exposed gets removed.
51540dc2366fSVenugopal Iyer 		 *
51550dc2366fSVenugopal Iyer 		 * In the first two cases the SRS and its soft
51560dc2366fSVenugopal Iyer 		 * rings are already quiesced.
5157da14cebeSEric Cheng 		 */
51580dc2366fSVenugopal Iyer 		if (driver_call) {
51590dc2366fSVenugopal Iyer 			mac_client_impl_t *mcip;
51600dc2366fSVenugopal Iyer 			mac_soft_ring_set_t *mac_srs;
51610dc2366fSVenugopal Iyer 			mac_soft_ring_t *sringp;
51620dc2366fSVenugopal Iyer 			mac_srs_tx_t *srs_tx;
51630dc2366fSVenugopal Iyer 
51640dc2366fSVenugopal Iyer 			if (mip->mi_state_flags & MIS_IS_AGGR &&
51650dc2366fSVenugopal Iyer 			    mip->mi_default_tx_ring ==
51660dc2366fSVenugopal Iyer 			    (mac_ring_handle_t)ring) {
51670dc2366fSVenugopal Iyer 				/* pick a new default Tx ring */
51680dc2366fSVenugopal Iyer 				mip->mi_default_tx_ring =
51690dc2366fSVenugopal Iyer 				    (group->mrg_rings != ring) ?
51700dc2366fSVenugopal Iyer 				    (mac_ring_handle_t)group->mrg_rings :
51710dc2366fSVenugopal Iyer 				    (mac_ring_handle_t)(ring->mr_next);
51720dc2366fSVenugopal Iyer 			}
51730dc2366fSVenugopal Iyer 			/* Presently only aggr case comes here */
51740dc2366fSVenugopal Iyer 			if (group->mrg_state != MAC_GROUP_STATE_RESERVED)
51750dc2366fSVenugopal Iyer 				break;
51760dc2366fSVenugopal Iyer 
51770dc2366fSVenugopal Iyer 			mcip = MAC_GROUP_ONLY_CLIENT(group);
51780dc2366fSVenugopal Iyer 			ASSERT(mcip != NULL);
517984de666eSRyan Zezeski 			ASSERT(mcip->mci_state_flags & MCIS_IS_AGGR_CLIENT);
51800dc2366fSVenugopal Iyer 			mac_srs = MCIP_TX_SRS(mcip);
51810dc2366fSVenugopal Iyer 			ASSERT(mac_srs->srs_tx.st_mode == SRS_TX_AGGR ||
51820dc2366fSVenugopal Iyer 			    mac_srs->srs_tx.st_mode == SRS_TX_BW_AGGR);
51830dc2366fSVenugopal Iyer 			srs_tx = &mac_srs->srs_tx;
51840dc2366fSVenugopal Iyer 			/*
51850dc2366fSVenugopal Iyer 			 * Wakeup any callers blocked on this
51860dc2366fSVenugopal Iyer 			 * Tx ring due to flow control.
51870dc2366fSVenugopal Iyer 			 */
51880dc2366fSVenugopal Iyer 			sringp = srs_tx->st_soft_rings[ring->mr_index];
51890dc2366fSVenugopal Iyer 			ASSERT(sringp != NULL);
51900dc2366fSVenugopal Iyer 			mac_tx_invoke_callbacks(mcip, (mac_tx_cookie_t)sringp);
51910dc2366fSVenugopal Iyer 			mac_tx_client_quiesce((mac_client_handle_t)mcip);
51920dc2366fSVenugopal Iyer 			mac_tx_srs_del_ring(mac_srs, ring);
51930dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)mcip);
51940dc2366fSVenugopal Iyer 			break;
51950dc2366fSVenugopal Iyer 		}
51960dc2366fSVenugopal Iyer 		ASSERT(ring != (mac_ring_t *)mip->mi_default_tx_ring);
5197da14cebeSEric Cheng 		group_type = mip->mi_tx_group_type;
5198da14cebeSEric Cheng 		cap_rings = &mip->mi_tx_rings_cap;
51990dc2366fSVenugopal Iyer 		/*
52000dc2366fSVenugopal Iyer 		 * See if we need to take it out of the MAC clients using
52010dc2366fSVenugopal Iyer 		 * this group
52020dc2366fSVenugopal Iyer 		 */
52030dc2366fSVenugopal Iyer 		if (MAC_GROUP_NO_CLIENT(group))
5204da14cebeSEric Cheng 			break;
52050dc2366fSVenugopal Iyer 		mgcp = group->mrg_clients;
52060dc2366fSVenugopal Iyer 		defgrp = MAC_DEFAULT_TX_GROUP(mip);
52070dc2366fSVenugopal Iyer 		while (mgcp != NULL) {
52080dc2366fSVenugopal Iyer 			mcip = mgcp->mgc_client;
52090dc2366fSVenugopal Iyer 			mac_srs = MCIP_TX_SRS(mcip);
52100dc2366fSVenugopal Iyer 			tx = &mac_srs->srs_tx;
52110dc2366fSVenugopal Iyer 			mac_tx_client_quiesce((mac_client_handle_t)mcip);
52120dc2366fSVenugopal Iyer 			/*
52130dc2366fSVenugopal Iyer 			 * If we are here when removing rings from the
52140dc2366fSVenugopal Iyer 			 * defgroup, mac_reserve_tx_ring would have
52150dc2366fSVenugopal Iyer 			 * already deleted the ring from the MAC
52160dc2366fSVenugopal Iyer 			 * clients in the group.
52170dc2366fSVenugopal Iyer 			 */
52180dc2366fSVenugopal Iyer 			if (group != defgrp) {
52190dc2366fSVenugopal Iyer 				mac_tx_invoke_callbacks(mcip,
52200dc2366fSVenugopal Iyer 				    (mac_tx_cookie_t)
52210dc2366fSVenugopal Iyer 				    mac_tx_srs_get_soft_ring(mac_srs, ring));
52220dc2366fSVenugopal Iyer 				mac_tx_srs_del_ring(mac_srs, ring);
52230dc2366fSVenugopal Iyer 			}
52240dc2366fSVenugopal Iyer 			/*
52250dc2366fSVenugopal Iyer 			 * Additionally, if  we are left with only
52260dc2366fSVenugopal Iyer 			 * one ring in the group after this, we need
52270dc2366fSVenugopal Iyer 			 * to modify the mode etc. to. (We haven't
52280dc2366fSVenugopal Iyer 			 * yet taken the ring out, so we check with 2).
52290dc2366fSVenugopal Iyer 			 */
52300dc2366fSVenugopal Iyer 			if (group->mrg_cur_count == 2) {
52310dc2366fSVenugopal Iyer 				if (ring->mr_next == NULL)
52320dc2366fSVenugopal Iyer 					rem_ring = group->mrg_rings;
52330dc2366fSVenugopal Iyer 				else
52340dc2366fSVenugopal Iyer 					rem_ring = ring->mr_next;
52350dc2366fSVenugopal Iyer 				mac_tx_invoke_callbacks(mcip,
52360dc2366fSVenugopal Iyer 				    (mac_tx_cookie_t)
52370dc2366fSVenugopal Iyer 				    mac_tx_srs_get_soft_ring(mac_srs,
52380dc2366fSVenugopal Iyer 				    rem_ring));
52390dc2366fSVenugopal Iyer 				mac_tx_srs_del_ring(mac_srs, rem_ring);
52400dc2366fSVenugopal Iyer 				if (rem_ring->mr_state != MR_INUSE) {
52410dc2366fSVenugopal Iyer 					(void) mac_start_ring(rem_ring);
52420dc2366fSVenugopal Iyer 				}
52430dc2366fSVenugopal Iyer 				tx->st_arg2 = (void *)rem_ring;
52440dc2366fSVenugopal Iyer 				mac_tx_srs_stat_recreate(mac_srs, B_FALSE);
52450dc2366fSVenugopal Iyer 				ring_info = mac_hwring_getinfo(
52460dc2366fSVenugopal Iyer 				    (mac_ring_handle_t)rem_ring);
52470dc2366fSVenugopal Iyer 				/*
52480dc2366fSVenugopal Iyer 				 * We are  shrinking from multiple
52490dc2366fSVenugopal Iyer 				 * to 1 ring.
52500dc2366fSVenugopal Iyer 				 */
52510dc2366fSVenugopal Iyer 				if (mac_srs->srs_type & SRST_BW_CONTROL) {
52520dc2366fSVenugopal Iyer 					tx->st_mode = SRS_TX_BW;
52530dc2366fSVenugopal Iyer 				} else if (mac_tx_serialize ||
52540dc2366fSVenugopal Iyer 				    (ring_info & MAC_RING_TX_SERIALIZE)) {
52550dc2366fSVenugopal Iyer 					tx->st_mode = SRS_TX_SERIALIZE;
52560dc2366fSVenugopal Iyer 				} else {
52570dc2366fSVenugopal Iyer 					tx->st_mode = SRS_TX_DEFAULT;
52580dc2366fSVenugopal Iyer 				}
52590dc2366fSVenugopal Iyer 				tx->st_func = mac_tx_get_func(tx->st_mode);
52600dc2366fSVenugopal Iyer 			}
52610dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)mcip);
52620dc2366fSVenugopal Iyer 			mgcp = mgcp->mgc_next;
52630dc2366fSVenugopal Iyer 		}
52640dc2366fSVenugopal Iyer 		break;
52650dc2366fSVenugopal Iyer 	}
5266da14cebeSEric Cheng 	default:
5267da14cebeSEric Cheng 		ASSERT(B_FALSE);
5268da14cebeSEric Cheng 	}
5269da14cebeSEric Cheng 
5270da14cebeSEric Cheng 	/*
5271da14cebeSEric Cheng 	 * Remove the ring from the group.
5272da14cebeSEric Cheng 	 */
5273da14cebeSEric Cheng 	if (ring == group->mrg_rings)
5274da14cebeSEric Cheng 		group->mrg_rings = ring->mr_next;
5275da14cebeSEric Cheng 	else {
5276da14cebeSEric Cheng 		mac_ring_t *pre;
5277da14cebeSEric Cheng 
5278da14cebeSEric Cheng 		pre = group->mrg_rings;
5279da14cebeSEric Cheng 		while (pre->mr_next != ring)
5280da14cebeSEric Cheng 			pre = pre->mr_next;
5281da14cebeSEric Cheng 		pre->mr_next = ring->mr_next;
5282da14cebeSEric Cheng 	}
5283da14cebeSEric Cheng 	group->mrg_cur_count--;
5284da14cebeSEric Cheng 
5285da14cebeSEric Cheng 	if (!driver_call) {
5286da14cebeSEric Cheng 		ASSERT(group_type == MAC_GROUP_TYPE_DYNAMIC);
52870dc2366fSVenugopal Iyer 		ASSERT(group->mrg_driver == NULL ||
52880dc2366fSVenugopal Iyer 		    cap_rings->mr_gremring != NULL);
5289da14cebeSEric Cheng 
5290da14cebeSEric Cheng 		/*
5291da14cebeSEric Cheng 		 * Remove the driver level hardware ring.
5292da14cebeSEric Cheng 		 */
5293da14cebeSEric Cheng 		if (group->mrg_driver != NULL) {
5294da14cebeSEric Cheng 			cap_rings->mr_gremring(group->mrg_driver,
5295da14cebeSEric Cheng 			    ring->mr_driver, ring->mr_type);
5296da14cebeSEric Cheng 		}
5297da14cebeSEric Cheng 	}
5298da14cebeSEric Cheng 
5299da14cebeSEric Cheng 	ring->mr_gh = NULL;
53000dc2366fSVenugopal Iyer 	if (driver_call)
5301da14cebeSEric Cheng 		mac_ring_free(mip, ring);
53020dc2366fSVenugopal Iyer 	else
5303da14cebeSEric Cheng 		ring->mr_flag = 0;
5304da14cebeSEric Cheng }
5305da14cebeSEric Cheng 
5306da14cebeSEric Cheng /*
5307da14cebeSEric Cheng  * Move a ring to the target group. If needed, remove the ring from the group
5308da14cebeSEric Cheng  * that it currently belongs to.
5309da14cebeSEric Cheng  *
5310da14cebeSEric Cheng  * The caller need to enter MAC's perimeter by calling mac_perim_enter().
5311da14cebeSEric Cheng  */
5312da14cebeSEric Cheng static int
mac_group_mov_ring(mac_impl_t * mip,mac_group_t * d_group,mac_ring_t * ring)5313da14cebeSEric Cheng mac_group_mov_ring(mac_impl_t *mip, mac_group_t *d_group, mac_ring_t *ring)
5314da14cebeSEric Cheng {
5315da14cebeSEric Cheng 	mac_group_t *s_group = (mac_group_t *)ring->mr_gh;
5316da14cebeSEric Cheng 	int rv;
5317da14cebeSEric Cheng 
5318da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5319da14cebeSEric Cheng 	ASSERT(d_group != NULL);
5320c85f09ccSJohn Levon 	ASSERT(s_group == NULL || s_group->mrg_mh == d_group->mrg_mh);
5321da14cebeSEric Cheng 
5322da14cebeSEric Cheng 	if (s_group == d_group)
5323da14cebeSEric Cheng 		return (0);
5324da14cebeSEric Cheng 
5325da14cebeSEric Cheng 	/*
5326da14cebeSEric Cheng 	 * Remove it from current group first.
5327da14cebeSEric Cheng 	 */
5328da14cebeSEric Cheng 	if (s_group != NULL)
5329da14cebeSEric Cheng 		i_mac_group_rem_ring(s_group, ring, B_FALSE);
5330da14cebeSEric Cheng 
5331da14cebeSEric Cheng 	/*
5332da14cebeSEric Cheng 	 * Add it to the new group.
5333da14cebeSEric Cheng 	 */
5334da14cebeSEric Cheng 	rv = i_mac_group_add_ring(d_group, ring, 0);
5335da14cebeSEric Cheng 	if (rv != 0) {
5336da14cebeSEric Cheng 		/*
5337da14cebeSEric Cheng 		 * Failed to add ring back to source group. If
5338da14cebeSEric Cheng 		 * that fails, the ring is stuck in limbo, log message.
5339da14cebeSEric Cheng 		 */
5340da14cebeSEric Cheng 		if (i_mac_group_add_ring(s_group, ring, 0)) {
5341da14cebeSEric Cheng 			cmn_err(CE_WARN, "%s: failed to move ring %p\n",
5342da14cebeSEric Cheng 			    mip->mi_name, (void *)ring);
5343da14cebeSEric Cheng 		}
5344da14cebeSEric Cheng 	}
5345da14cebeSEric Cheng 
5346da14cebeSEric Cheng 	return (rv);
5347da14cebeSEric Cheng }
5348da14cebeSEric Cheng 
5349da14cebeSEric Cheng /*
5350da14cebeSEric Cheng  * Find a MAC address according to its value.
5351da14cebeSEric Cheng  */
5352da14cebeSEric Cheng mac_address_t *
mac_find_macaddr(mac_impl_t * mip,uint8_t * mac_addr)5353da14cebeSEric Cheng mac_find_macaddr(mac_impl_t *mip, uint8_t *mac_addr)
5354da14cebeSEric Cheng {
5355da14cebeSEric Cheng 	mac_address_t *map;
5356da14cebeSEric Cheng 
5357da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5358da14cebeSEric Cheng 
5359da14cebeSEric Cheng 	for (map = mip->mi_addresses; map != NULL; map = map->ma_next) {
5360da14cebeSEric Cheng 		if (bcmp(mac_addr, map->ma_addr, map->ma_len) == 0)
5361da14cebeSEric Cheng 			break;
5362da14cebeSEric Cheng 	}
5363da14cebeSEric Cheng 
5364da14cebeSEric Cheng 	return (map);
5365da14cebeSEric Cheng }
5366da14cebeSEric Cheng 
5367da14cebeSEric Cheng /*
5368da14cebeSEric Cheng  * Check whether the MAC address is shared by multiple clients.
5369da14cebeSEric Cheng  */
5370da14cebeSEric Cheng boolean_t
mac_check_macaddr_shared(mac_address_t * map)5371da14cebeSEric Cheng mac_check_macaddr_shared(mac_address_t *map)
5372da14cebeSEric Cheng {
5373da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)map->ma_mip));
5374da14cebeSEric Cheng 
5375da14cebeSEric Cheng 	return (map->ma_nusers > 1);
5376da14cebeSEric Cheng }
5377da14cebeSEric Cheng 
5378da14cebeSEric Cheng /*
5379da14cebeSEric Cheng  * Remove the specified MAC address from the MAC address list and free it.
5380da14cebeSEric Cheng  */
5381da14cebeSEric Cheng static void
mac_free_macaddr(mac_address_t * map)5382da14cebeSEric Cheng mac_free_macaddr(mac_address_t *map)
5383da14cebeSEric Cheng {
5384da14cebeSEric Cheng 	mac_impl_t *mip = map->ma_mip;
5385da14cebeSEric Cheng 
5386da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
538784de666eSRyan Zezeski 	VERIFY3P(mip->mi_addresses, !=, NULL);
5388da14cebeSEric Cheng 
538984de666eSRyan Zezeski 	VERIFY3P(map, ==, mac_find_macaddr(mip, map->ma_addr));
539084de666eSRyan Zezeski 	VERIFY3P(map, !=, NULL);
539184de666eSRyan Zezeski 	VERIFY3S(map->ma_nusers, ==, 0);
539284de666eSRyan Zezeski 	VERIFY3P(map->ma_vlans, ==, NULL);
5393da14cebeSEric Cheng 
5394da14cebeSEric Cheng 	if (map == mip->mi_addresses) {
5395da14cebeSEric Cheng 		mip->mi_addresses = map->ma_next;
5396da14cebeSEric Cheng 	} else {
5397da14cebeSEric Cheng 		mac_address_t *pre;
5398da14cebeSEric Cheng 
5399da14cebeSEric Cheng 		pre = mip->mi_addresses;
5400da14cebeSEric Cheng 		while (pre->ma_next != map)
5401da14cebeSEric Cheng 			pre = pre->ma_next;
5402da14cebeSEric Cheng 		pre->ma_next = map->ma_next;
5403da14cebeSEric Cheng 	}
5404da14cebeSEric Cheng 
5405da14cebeSEric Cheng 	kmem_free(map, sizeof (mac_address_t));
5406da14cebeSEric Cheng }
5407da14cebeSEric Cheng 
540884de666eSRyan Zezeski static mac_vlan_t *
mac_find_vlan(mac_address_t * map,uint16_t vid)540984de666eSRyan Zezeski mac_find_vlan(mac_address_t *map, uint16_t vid)
541084de666eSRyan Zezeski {
541184de666eSRyan Zezeski 	mac_vlan_t *mvp;
541284de666eSRyan Zezeski 
541384de666eSRyan Zezeski 	for (mvp = map->ma_vlans; mvp != NULL; mvp = mvp->mv_next) {
541484de666eSRyan Zezeski 		if (mvp->mv_vid == vid)
541584de666eSRyan Zezeski 			return (mvp);
541684de666eSRyan Zezeski 	}
541784de666eSRyan Zezeski 
541884de666eSRyan Zezeski 	return (NULL);
541984de666eSRyan Zezeski }
542084de666eSRyan Zezeski 
542184de666eSRyan Zezeski static mac_vlan_t *
mac_add_vlan(mac_address_t * map,uint16_t vid)542284de666eSRyan Zezeski mac_add_vlan(mac_address_t *map, uint16_t vid)
542384de666eSRyan Zezeski {
542484de666eSRyan Zezeski 	mac_vlan_t *mvp;
542584de666eSRyan Zezeski 
5426da14cebeSEric Cheng 	/*
542784de666eSRyan Zezeski 	 * We should never add the same {addr, VID} tuple more
542884de666eSRyan Zezeski 	 * than once, but let's be sure.
542984de666eSRyan Zezeski 	 */
543084de666eSRyan Zezeski 	for (mvp = map->ma_vlans; mvp != NULL; mvp = mvp->mv_next)
543184de666eSRyan Zezeski 		VERIFY3U(mvp->mv_vid, !=, vid);
543284de666eSRyan Zezeski 
543384de666eSRyan Zezeski 	/* Add the VLAN to the head of the VLAN list. */
543484de666eSRyan Zezeski 	mvp = kmem_zalloc(sizeof (mac_vlan_t), KM_SLEEP);
543584de666eSRyan Zezeski 	mvp->mv_vid = vid;
543684de666eSRyan Zezeski 	mvp->mv_next = map->ma_vlans;
543784de666eSRyan Zezeski 	map->ma_vlans = mvp;
543884de666eSRyan Zezeski 
543984de666eSRyan Zezeski 	return (mvp);
544084de666eSRyan Zezeski }
544184de666eSRyan Zezeski 
544284de666eSRyan Zezeski static void
mac_rem_vlan(mac_address_t * map,mac_vlan_t * mvp)544384de666eSRyan Zezeski mac_rem_vlan(mac_address_t *map, mac_vlan_t *mvp)
544484de666eSRyan Zezeski {
544584de666eSRyan Zezeski 	mac_vlan_t *pre;
544684de666eSRyan Zezeski 
544784de666eSRyan Zezeski 	if (map->ma_vlans == mvp) {
544884de666eSRyan Zezeski 		map->ma_vlans = mvp->mv_next;
544984de666eSRyan Zezeski 	} else {
545084de666eSRyan Zezeski 		pre = map->ma_vlans;
545184de666eSRyan Zezeski 		while (pre->mv_next != mvp) {
545284de666eSRyan Zezeski 			pre = pre->mv_next;
545384de666eSRyan Zezeski 
545484de666eSRyan Zezeski 			/*
545584de666eSRyan Zezeski 			 * We've reached the end of the list without
545684de666eSRyan Zezeski 			 * finding mvp.
545784de666eSRyan Zezeski 			 */
545884de666eSRyan Zezeski 			VERIFY3P(pre, !=, NULL);
545984de666eSRyan Zezeski 		}
546084de666eSRyan Zezeski 		pre->mv_next = mvp->mv_next;
546184de666eSRyan Zezeski 	}
546284de666eSRyan Zezeski 
546384de666eSRyan Zezeski 	kmem_free(mvp, sizeof (mac_vlan_t));
546484de666eSRyan Zezeski }
546584de666eSRyan Zezeski 
546684de666eSRyan Zezeski /*
546784de666eSRyan Zezeski  * Create a new mac_address_t if this is the first use of the address
546884de666eSRyan Zezeski  * or add a VID to an existing address. In either case, the
546984de666eSRyan Zezeski  * mac_address_t acts as a list of {addr, VID} tuples where each tuple
547084de666eSRyan Zezeski  * shares the same addr. If group is non-NULL then attempt to program
547184de666eSRyan Zezeski  * the MAC's HW filters for this group. Otherwise, if group is NULL,
547284de666eSRyan Zezeski  * then the MAC has no rings and there is nothing to program.
5473da14cebeSEric Cheng  */
5474da14cebeSEric Cheng int
mac_add_macaddr_vlan(mac_impl_t * mip,mac_group_t * group,uint8_t * addr,uint16_t vid,boolean_t use_hw)547584de666eSRyan Zezeski mac_add_macaddr_vlan(mac_impl_t *mip, mac_group_t *group, uint8_t *addr,
547684de666eSRyan Zezeski     uint16_t vid, boolean_t use_hw)
5477da14cebeSEric Cheng {
5478da14cebeSEric Cheng 	mac_address_t	*map;
547984de666eSRyan Zezeski 	mac_vlan_t	*mvp;
5480da14cebeSEric Cheng 	int		err = 0;
5481da14cebeSEric Cheng 	boolean_t	allocated_map = B_FALSE;
548284de666eSRyan Zezeski 	boolean_t	hw_mac = B_FALSE;
548384de666eSRyan Zezeski 	boolean_t	hw_vlan = B_FALSE;
5484da14cebeSEric Cheng 
5485da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5486da14cebeSEric Cheng 
548784de666eSRyan Zezeski 	map = mac_find_macaddr(mip, addr);
5488da14cebeSEric Cheng 
5489da14cebeSEric Cheng 	/*
549084de666eSRyan Zezeski 	 * If this is the first use of this MAC address then allocate
549184de666eSRyan Zezeski 	 * and initialize a new structure.
5492da14cebeSEric Cheng 	 */
5493da14cebeSEric Cheng 	if (map == NULL) {
5494da14cebeSEric Cheng 		map = kmem_zalloc(sizeof (mac_address_t), KM_SLEEP);
5495da14cebeSEric Cheng 		map->ma_len = mip->mi_type->mt_addr_length;
549684de666eSRyan Zezeski 		bcopy(addr, map->ma_addr, map->ma_len);
5497da14cebeSEric Cheng 		map->ma_nusers = 0;
5498da14cebeSEric Cheng 		map->ma_group = group;
5499da14cebeSEric Cheng 		map->ma_mip = mip;
550084de666eSRyan Zezeski 		map->ma_untagged = B_FALSE;
5501da14cebeSEric Cheng 
550284de666eSRyan Zezeski 		/* Add the new MAC address to the head of the address list. */
5503da14cebeSEric Cheng 		map->ma_next = mip->mi_addresses;
5504da14cebeSEric Cheng 		mip->mi_addresses = map;
5505da14cebeSEric Cheng 
5506da14cebeSEric Cheng 		allocated_map = B_TRUE;
5507da14cebeSEric Cheng 	}
5508da14cebeSEric Cheng 
550984de666eSRyan Zezeski 	VERIFY(map->ma_group == NULL || map->ma_group == group);
55100dc2366fSVenugopal Iyer 	if (map->ma_group == NULL)
55110dc2366fSVenugopal Iyer 		map->ma_group = group;
5512da14cebeSEric Cheng 
551384de666eSRyan Zezeski 	if (vid == VLAN_ID_NONE) {
551484de666eSRyan Zezeski 		map->ma_untagged = B_TRUE;
551584de666eSRyan Zezeski 		mvp = NULL;
551684de666eSRyan Zezeski 	} else {
551784de666eSRyan Zezeski 		mvp = mac_add_vlan(map, vid);
551884de666eSRyan Zezeski 	}
551984de666eSRyan Zezeski 
5520da14cebeSEric Cheng 	/*
552184de666eSRyan Zezeski 	 * Set the VLAN HW filter if:
552284de666eSRyan Zezeski 	 *
552384de666eSRyan Zezeski 	 * o the MAC's VLAN HW filtering is enabled, and
552484de666eSRyan Zezeski 	 * o the address does not currently rely on promisc mode.
552584de666eSRyan Zezeski 	 *
552684de666eSRyan Zezeski 	 * This is called even when the client specifies an untagged
552784de666eSRyan Zezeski 	 * address (VLAN_ID_NONE) because some MAC providers require
552884de666eSRyan Zezeski 	 * setting additional bits to accept untagged traffic when
552984de666eSRyan Zezeski 	 * VLAN HW filtering is enabled.
5530da14cebeSEric Cheng 	 */
553184de666eSRyan Zezeski 	if (MAC_GROUP_HW_VLAN(group) &&
553284de666eSRyan Zezeski 	    map->ma_type != MAC_ADDRESS_TYPE_UNICAST_PROMISC) {
553384de666eSRyan Zezeski 		if ((err = mac_group_addvlan(group, vid)) != 0)
553484de666eSRyan Zezeski 			goto bail;
553584de666eSRyan Zezeski 
553684de666eSRyan Zezeski 		hw_vlan = B_TRUE;
553784de666eSRyan Zezeski 	}
553884de666eSRyan Zezeski 
553984de666eSRyan Zezeski 	VERIFY3S(map->ma_nusers, >=, 0);
554084de666eSRyan Zezeski 	map->ma_nusers++;
554184de666eSRyan Zezeski 
554284de666eSRyan Zezeski 	/*
554384de666eSRyan Zezeski 	 * If this MAC address already has a HW filter then simply
554484de666eSRyan Zezeski 	 * increment the counter.
554584de666eSRyan Zezeski 	 */
554684de666eSRyan Zezeski 	if (map->ma_nusers > 1)
5547da14cebeSEric Cheng 		return (0);
5548da14cebeSEric Cheng 
5549da14cebeSEric Cheng 	/*
555084de666eSRyan Zezeski 	 * All logic from here on out is executed during initial
555184de666eSRyan Zezeski 	 * creation only.
555284de666eSRyan Zezeski 	 */
555384de666eSRyan Zezeski 	VERIFY3S(map->ma_nusers, ==, 1);
555484de666eSRyan Zezeski 
555584de666eSRyan Zezeski 	/*
5556da14cebeSEric Cheng 	 * Activate this MAC address by adding it to the reserved group.
5557da14cebeSEric Cheng 	 */
5558da14cebeSEric Cheng 	if (group != NULL) {
555984de666eSRyan Zezeski 		err = mac_group_addmac(group, (const uint8_t *)addr);
556084de666eSRyan Zezeski 
556184de666eSRyan Zezeski 		/*
556284de666eSRyan Zezeski 		 * If the driver is out of filters then we can
556384de666eSRyan Zezeski 		 * continue and use promisc mode. For any other error,
556484de666eSRyan Zezeski 		 * assume the driver is in a state where we can't
556584de666eSRyan Zezeski 		 * program the filters or use promisc mode; so we must
556684de666eSRyan Zezeski 		 * bail.
556784de666eSRyan Zezeski 		 */
556884de666eSRyan Zezeski 		if (err != 0 && err != ENOSPC) {
556984de666eSRyan Zezeski 			map->ma_nusers--;
557084de666eSRyan Zezeski 			goto bail;
557184de666eSRyan Zezeski 		}
557284de666eSRyan Zezeski 
557384de666eSRyan Zezeski 		hw_mac = (err == 0);
557484de666eSRyan Zezeski 	}
557584de666eSRyan Zezeski 
557684de666eSRyan Zezeski 	if (hw_mac) {
5577da14cebeSEric Cheng 		map->ma_type = MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED;
5578da14cebeSEric Cheng 		return (0);
5579da14cebeSEric Cheng 	}
5580da14cebeSEric Cheng 
5581da14cebeSEric Cheng 	/*
558208ac1c49SNicolas Droux 	 * The MAC address addition failed. If the client requires a
558384de666eSRyan Zezeski 	 * hardware classified MAC address, fail the operation. This
558484de666eSRyan Zezeski 	 * feature is only used by sun4v vsw.
5585da14cebeSEric Cheng 	 */
558684de666eSRyan Zezeski 	if (use_hw && !hw_mac) {
558708ac1c49SNicolas Droux 		err = ENOSPC;
558884de666eSRyan Zezeski 		map->ma_nusers--;
558908ac1c49SNicolas Droux 		goto bail;
559008ac1c49SNicolas Droux 	}
559108ac1c49SNicolas Droux 
5592da14cebeSEric Cheng 	/*
559384de666eSRyan Zezeski 	 * If we reach this point then either the MAC doesn't have
559484de666eSRyan Zezeski 	 * RINGS capability or we are out of MAC address HW filters.
559584de666eSRyan Zezeski 	 * In any case we must put the MAC into promiscuous mode.
559684de666eSRyan Zezeski 	 */
559784de666eSRyan Zezeski 	VERIFY(group == NULL || !hw_mac);
559884de666eSRyan Zezeski 
559984de666eSRyan Zezeski 	/*
560084de666eSRyan Zezeski 	 * The one exception is the primary address. A non-RINGS
560184de666eSRyan Zezeski 	 * driver filters the primary address by default; promisc mode
560284de666eSRyan Zezeski 	 * is not needed.
5603da14cebeSEric Cheng 	 */
5604da14cebeSEric Cheng 	if ((group == NULL) &&
5605da14cebeSEric Cheng 	    (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) == 0)) {
5606da14cebeSEric Cheng 		map->ma_type = MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED;
5607da14cebeSEric Cheng 		return (0);
5608da14cebeSEric Cheng 	}
5609da14cebeSEric Cheng 
5610da14cebeSEric Cheng 	/*
561184de666eSRyan Zezeski 	 * Enable promiscuous mode in order to receive traffic to the
561284de666eSRyan Zezeski 	 * new MAC address. All existing HW filters still send their
561384de666eSRyan Zezeski 	 * traffic to their respective group/SRSes. But with promisc
561484de666eSRyan Zezeski 	 * enabled all unknown traffic is delivered to the default
561584de666eSRyan Zezeski 	 * group where it is SW classified via mac_rx_classify().
5616da14cebeSEric Cheng 	 */
5617d91a22bfSGirish Moodalbail 	if ((err = i_mac_promisc_set(mip, B_TRUE)) == 0) {
5618da14cebeSEric Cheng 		map->ma_type = MAC_ADDRESS_TYPE_UNICAST_PROMISC;
5619da14cebeSEric Cheng 		return (0);
5620da14cebeSEric Cheng 	}
5621da14cebeSEric Cheng 
5622da14cebeSEric Cheng 	/*
562384de666eSRyan Zezeski 	 * We failed to set promisc mode and we are about to free 'map'.
5624da14cebeSEric Cheng 	 */
562584de666eSRyan Zezeski 	map->ma_nusers = 0;
562684de666eSRyan Zezeski 
562708ac1c49SNicolas Droux bail:
562884de666eSRyan Zezeski 	if (hw_vlan) {
562984de666eSRyan Zezeski 		int err2 = mac_group_remvlan(group, vid);
563084de666eSRyan Zezeski 
563184de666eSRyan Zezeski 		if (err2 != 0) {
563284de666eSRyan Zezeski 			cmn_err(CE_WARN, "Failed to remove VLAN %u from group"
563384de666eSRyan Zezeski 			    " %d on MAC %s: %d.", vid, group->mrg_index,
563484de666eSRyan Zezeski 			    mip->mi_name, err2);
563584de666eSRyan Zezeski 		}
563684de666eSRyan Zezeski 	}
563784de666eSRyan Zezeski 
563884de666eSRyan Zezeski 	if (mvp != NULL)
563984de666eSRyan Zezeski 		mac_rem_vlan(map, mvp);
564084de666eSRyan Zezeski 
5641da14cebeSEric Cheng 	if (allocated_map)
5642da14cebeSEric Cheng 		mac_free_macaddr(map);
564384de666eSRyan Zezeski 
5644da14cebeSEric Cheng 	return (err);
5645da14cebeSEric Cheng }
5646da14cebeSEric Cheng 
5647da14cebeSEric Cheng int
mac_remove_macaddr_vlan(mac_address_t * map,uint16_t vid)564884de666eSRyan Zezeski mac_remove_macaddr_vlan(mac_address_t *map, uint16_t vid)
5649da14cebeSEric Cheng {
565084de666eSRyan Zezeski 	mac_vlan_t	*mvp;
5651da14cebeSEric Cheng 	mac_impl_t	*mip = map->ma_mip;
565284de666eSRyan Zezeski 	mac_group_t	*group = map->ma_group;
5653da14cebeSEric Cheng 	int		err = 0;
5654da14cebeSEric Cheng 
5655da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
565684de666eSRyan Zezeski 	VERIFY3P(map, ==, mac_find_macaddr(mip, map->ma_addr));
5657da14cebeSEric Cheng 
565884de666eSRyan Zezeski 	if (vid == VLAN_ID_NONE) {
565984de666eSRyan Zezeski 		map->ma_untagged = B_FALSE;
566084de666eSRyan Zezeski 		mvp = NULL;
566184de666eSRyan Zezeski 	} else {
566284de666eSRyan Zezeski 		mvp = mac_find_vlan(map, vid);
566384de666eSRyan Zezeski 		VERIFY3P(mvp, !=, NULL);
566484de666eSRyan Zezeski 	}
566584de666eSRyan Zezeski 
566684de666eSRyan Zezeski 	if (MAC_GROUP_HW_VLAN(group) &&
566784de666eSRyan Zezeski 	    map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED &&
566884de666eSRyan Zezeski 	    ((err = mac_group_remvlan(group, vid)) != 0))
566984de666eSRyan Zezeski 		return (err);
567084de666eSRyan Zezeski 
567184de666eSRyan Zezeski 	if (mvp != NULL)
567284de666eSRyan Zezeski 		mac_rem_vlan(map, mvp);
5673da14cebeSEric Cheng 
5674da14cebeSEric Cheng 	/*
5675da14cebeSEric Cheng 	 * If it's not the last client using this MAC address, only update
5676da14cebeSEric Cheng 	 * the MAC clients count.
5677da14cebeSEric Cheng 	 */
567884de666eSRyan Zezeski 	map->ma_nusers--;
567984de666eSRyan Zezeski 	if (map->ma_nusers > 0)
5680da14cebeSEric Cheng 		return (0);
5681da14cebeSEric Cheng 
568284de666eSRyan Zezeski 	VERIFY3S(map->ma_nusers, ==, 0);
568384de666eSRyan Zezeski 
5684da14cebeSEric Cheng 	/*
568584de666eSRyan Zezeski 	 * The MAC address is no longer used by any MAC client, so
568684de666eSRyan Zezeski 	 * remove it from its associated group. Turn off promiscuous
568784de666eSRyan Zezeski 	 * mode if this is the last address relying on it.
5688da14cebeSEric Cheng 	 */
5689da14cebeSEric Cheng 	switch (map->ma_type) {
5690da14cebeSEric Cheng 	case MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED:
5691da14cebeSEric Cheng 		/*
5692da14cebeSEric Cheng 		 * Don't free the preset primary address for drivers that
5693da14cebeSEric Cheng 		 * don't advertise RINGS capability.
5694da14cebeSEric Cheng 		 */
569584de666eSRyan Zezeski 		if (group == NULL)
5696da14cebeSEric Cheng 			return (0);
5697da14cebeSEric Cheng 
569884de666eSRyan Zezeski 		if ((err = mac_group_remmac(group, map->ma_addr)) != 0) {
569984de666eSRyan Zezeski 			if (vid == VLAN_ID_NONE)
570084de666eSRyan Zezeski 				map->ma_untagged = B_TRUE;
570184de666eSRyan Zezeski 			else
570284de666eSRyan Zezeski 				(void) mac_add_vlan(map, vid);
570384de666eSRyan Zezeski 
570484de666eSRyan Zezeski 			/*
570584de666eSRyan Zezeski 			 * If we fail to remove the MAC address HW
570684de666eSRyan Zezeski 			 * filter but then also fail to re-add the
570784de666eSRyan Zezeski 			 * VLAN HW filter then we are in a busted
570884de666eSRyan Zezeski 			 * state. We do our best by logging a warning
570984de666eSRyan Zezeski 			 * and returning the original 'err' that got
571084de666eSRyan Zezeski 			 * us here. At this point, traffic for this
571184de666eSRyan Zezeski 			 * address + VLAN combination will be dropped
571284de666eSRyan Zezeski 			 * until the user reboots the system. In the
571384de666eSRyan Zezeski 			 * future, it would be nice to have a system
571484de666eSRyan Zezeski 			 * that can compare the state of expected
571584de666eSRyan Zezeski 			 * classification according to mac to the
571684de666eSRyan Zezeski 			 * actual state of the provider, and report
571784de666eSRyan Zezeski 			 * and fix any inconsistencies.
571884de666eSRyan Zezeski 			 */
571984de666eSRyan Zezeski 			if (MAC_GROUP_HW_VLAN(group)) {
572084de666eSRyan Zezeski 				int err2;
572184de666eSRyan Zezeski 
572284de666eSRyan Zezeski 				err2 = mac_group_addvlan(group, vid);
572384de666eSRyan Zezeski 				if (err2 != 0) {
572484de666eSRyan Zezeski 					cmn_err(CE_WARN, "Failed to readd VLAN"
572584de666eSRyan Zezeski 					    " %u to group %d on MAC %s: %d.",
572684de666eSRyan Zezeski 					    vid, group->mrg_index, mip->mi_name,
572784de666eSRyan Zezeski 					    err2);
572884de666eSRyan Zezeski 				}
572984de666eSRyan Zezeski 			}
573084de666eSRyan Zezeski 
573184de666eSRyan Zezeski 			map->ma_nusers = 1;
573284de666eSRyan Zezeski 			return (err);
573384de666eSRyan Zezeski 		}
573484de666eSRyan Zezeski 
57350dc2366fSVenugopal Iyer 		map->ma_group = NULL;
5736da14cebeSEric Cheng 		break;
5737da14cebeSEric Cheng 	case MAC_ADDRESS_TYPE_UNICAST_PROMISC:
5738d91a22bfSGirish Moodalbail 		err = i_mac_promisc_set(mip, B_FALSE);
5739da14cebeSEric Cheng 		break;
5740da14cebeSEric Cheng 	default:
574184de666eSRyan Zezeski 		panic("Unexpected ma_type 0x%x, file: %s, line %d",
574284de666eSRyan Zezeski 		    map->ma_type, __FILE__, __LINE__);
5743da14cebeSEric Cheng 	}
5744da14cebeSEric Cheng 
574584de666eSRyan Zezeski 	if (err != 0) {
574684de666eSRyan Zezeski 		map->ma_nusers = 1;
5747da14cebeSEric Cheng 		return (err);
574884de666eSRyan Zezeski 	}
5749da14cebeSEric Cheng 
5750da14cebeSEric Cheng 	/*
5751da14cebeSEric Cheng 	 * We created MAC address for the primary one at registration, so we
5752da14cebeSEric Cheng 	 * won't free it here. mac_fini_macaddr() will take care of it.
5753da14cebeSEric Cheng 	 */
5754da14cebeSEric Cheng 	if (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) != 0)
5755da14cebeSEric Cheng 		mac_free_macaddr(map);
5756da14cebeSEric Cheng 
5757da14cebeSEric Cheng 	return (0);
5758da14cebeSEric Cheng }
5759da14cebeSEric Cheng 
5760da14cebeSEric Cheng /*
5761da14cebeSEric Cheng  * Update an existing MAC address. The caller need to make sure that the new
5762da14cebeSEric Cheng  * value has not been used.
5763da14cebeSEric Cheng  */
5764da14cebeSEric Cheng int
mac_update_macaddr(mac_address_t * map,uint8_t * mac_addr)5765da14cebeSEric Cheng mac_update_macaddr(mac_address_t *map, uint8_t *mac_addr)
5766da14cebeSEric Cheng {
5767da14cebeSEric Cheng 	mac_impl_t *mip = map->ma_mip;
5768da14cebeSEric Cheng 	int err = 0;
5769da14cebeSEric Cheng 
5770da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5771da14cebeSEric Cheng 	ASSERT(mac_find_macaddr(mip, mac_addr) == NULL);
5772da14cebeSEric Cheng 
5773da14cebeSEric Cheng 	switch (map->ma_type) {
5774da14cebeSEric Cheng 	case MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED:
5775da14cebeSEric Cheng 		/*
5776da14cebeSEric Cheng 		 * Update the primary address for drivers that are not
5777da14cebeSEric Cheng 		 * RINGS capable.
5778da14cebeSEric Cheng 		 */
57790dc2366fSVenugopal Iyer 		if (mip->mi_rx_groups == NULL) {
5780da14cebeSEric Cheng 			err = mip->mi_unicst(mip->mi_driver, (const uint8_t *)
5781da14cebeSEric Cheng 			    mac_addr);
5782da14cebeSEric Cheng 			if (err != 0)
5783da14cebeSEric Cheng 				return (err);
5784da14cebeSEric Cheng 			break;
5785da14cebeSEric Cheng 		}
5786da14cebeSEric Cheng 
5787da14cebeSEric Cheng 		/*
5788da14cebeSEric Cheng 		 * If this MAC address is not currently in use,
5789da14cebeSEric Cheng 		 * simply break out and update the value.
5790da14cebeSEric Cheng 		 */
5791da14cebeSEric Cheng 		if (map->ma_nusers == 0)
5792da14cebeSEric Cheng 			break;
5793da14cebeSEric Cheng 
5794da14cebeSEric Cheng 		/*
5795da14cebeSEric Cheng 		 * Need to replace the MAC address associated with a group.
5796da14cebeSEric Cheng 		 */
5797da14cebeSEric Cheng 		err = mac_group_remmac(map->ma_group, map->ma_addr);
5798da14cebeSEric Cheng 		if (err != 0)
5799da14cebeSEric Cheng 			return (err);
5800da14cebeSEric Cheng 
5801da14cebeSEric Cheng 		err = mac_group_addmac(map->ma_group, mac_addr);
5802da14cebeSEric Cheng 
5803da14cebeSEric Cheng 		/*
5804da14cebeSEric Cheng 		 * Failure hints hardware error. The MAC layer needs to
5805da14cebeSEric Cheng 		 * have error notification facility to handle this.
5806da14cebeSEric Cheng 		 * Now, simply try to restore the value.
5807da14cebeSEric Cheng 		 */
5808da14cebeSEric Cheng 		if (err != 0)
5809da14cebeSEric Cheng 			(void) mac_group_addmac(map->ma_group, map->ma_addr);
5810da14cebeSEric Cheng 
5811da14cebeSEric Cheng 		break;
5812da14cebeSEric Cheng 	case MAC_ADDRESS_TYPE_UNICAST_PROMISC:
5813da14cebeSEric Cheng 		/*
5814da14cebeSEric Cheng 		 * Need to do nothing more if in promiscuous mode.
5815da14cebeSEric Cheng 		 */
5816da14cebeSEric Cheng 		break;
5817da14cebeSEric Cheng 	default:
5818da14cebeSEric Cheng 		ASSERT(B_FALSE);
5819da14cebeSEric Cheng 	}
5820da14cebeSEric Cheng 
5821da14cebeSEric Cheng 	/*
5822da14cebeSEric Cheng 	 * Successfully replaced the MAC address.
5823da14cebeSEric Cheng 	 */
5824da14cebeSEric Cheng 	if (err == 0)
5825da14cebeSEric Cheng 		bcopy(mac_addr, map->ma_addr, map->ma_len);
5826da14cebeSEric Cheng 
5827da14cebeSEric Cheng 	return (err);
5828da14cebeSEric Cheng }
5829da14cebeSEric Cheng 
5830da14cebeSEric Cheng /*
5831da14cebeSEric Cheng  * Freshen the MAC address with new value. Its caller must have updated the
5832da14cebeSEric Cheng  * hardware MAC address before calling this function.
5833da14cebeSEric Cheng  * This funcitons is supposed to be used to handle the MAC address change
5834da14cebeSEric Cheng  * notification from underlying drivers.
5835da14cebeSEric Cheng  */
5836da14cebeSEric Cheng void
mac_freshen_macaddr(mac_address_t * map,uint8_t * mac_addr)5837da14cebeSEric Cheng mac_freshen_macaddr(mac_address_t *map, uint8_t *mac_addr)
5838da14cebeSEric Cheng {
5839da14cebeSEric Cheng 	mac_impl_t *mip = map->ma_mip;
5840da14cebeSEric Cheng 
5841da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
5842da14cebeSEric Cheng 	ASSERT(mac_find_macaddr(mip, mac_addr) == NULL);
5843da14cebeSEric Cheng 
5844da14cebeSEric Cheng 	/*
5845da14cebeSEric Cheng 	 * Freshen the MAC address with new value.
5846da14cebeSEric Cheng 	 */
5847da14cebeSEric Cheng 	bcopy(mac_addr, map->ma_addr, map->ma_len);
5848da14cebeSEric Cheng 	bcopy(mac_addr, mip->mi_addr, map->ma_len);
5849da14cebeSEric Cheng 
5850da14cebeSEric Cheng 	/*
5851da14cebeSEric Cheng 	 * Update all MAC clients that share this MAC address.
5852da14cebeSEric Cheng 	 */
5853da14cebeSEric Cheng 	mac_unicast_update_clients(mip, map);
5854da14cebeSEric Cheng }
5855da14cebeSEric Cheng 
5856da14cebeSEric Cheng /*
5857da14cebeSEric Cheng  * Set up the primary MAC address.
5858da14cebeSEric Cheng  */
5859da14cebeSEric Cheng void
mac_init_macaddr(mac_impl_t * mip)5860da14cebeSEric Cheng mac_init_macaddr(mac_impl_t *mip)
5861da14cebeSEric Cheng {
5862da14cebeSEric Cheng 	mac_address_t *map;
5863da14cebeSEric Cheng 
5864da14cebeSEric Cheng 	/*
5865da14cebeSEric Cheng 	 * The reference count is initialized to zero, until it's really
5866da14cebeSEric Cheng 	 * activated.
5867da14cebeSEric Cheng 	 */
5868da14cebeSEric Cheng 	map = kmem_zalloc(sizeof (mac_address_t), KM_SLEEP);
5869da14cebeSEric Cheng 	map->ma_len = mip->mi_type->mt_addr_length;
5870da14cebeSEric Cheng 	bcopy(mip->mi_addr, map->ma_addr, map->ma_len);
5871da14cebeSEric Cheng 
5872da14cebeSEric Cheng 	/*
5873da14cebeSEric Cheng 	 * If driver advertises RINGS capability, it shouldn't have initialized
5874da14cebeSEric Cheng 	 * its primary MAC address. For other drivers, including VNIC, the
5875da14cebeSEric Cheng 	 * primary address must work after registration.
5876da14cebeSEric Cheng 	 */
5877da14cebeSEric Cheng 	if (mip->mi_rx_groups == NULL)
5878da14cebeSEric Cheng 		map->ma_type = MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED;
5879da14cebeSEric Cheng 
5880da14cebeSEric Cheng 	map->ma_mip = mip;
5881da14cebeSEric Cheng 
5882da14cebeSEric Cheng 	mip->mi_addresses = map;
5883da14cebeSEric Cheng }
5884da14cebeSEric Cheng 
5885da14cebeSEric Cheng /*
5886da14cebeSEric Cheng  * Clean up the primary MAC address. Note, only one primary MAC address
5887da14cebeSEric Cheng  * is allowed. All other MAC addresses must have been freed appropriately.
5888da14cebeSEric Cheng  */
5889da14cebeSEric Cheng void
mac_fini_macaddr(mac_impl_t * mip)5890da14cebeSEric Cheng mac_fini_macaddr(mac_impl_t *mip)
5891da14cebeSEric Cheng {
5892da14cebeSEric Cheng 	mac_address_t *map = mip->mi_addresses;
5893da14cebeSEric Cheng 
5894ae6aa22aSVenugopal Iyer 	if (map == NULL)
5895ae6aa22aSVenugopal Iyer 		return;
5896ae6aa22aSVenugopal Iyer 
5897ae6aa22aSVenugopal Iyer 	/*
5898ae6aa22aSVenugopal Iyer 	 * If mi_addresses is initialized, there should be exactly one
5899ae6aa22aSVenugopal Iyer 	 * entry left on the list with no users.
5900ae6aa22aSVenugopal Iyer 	 */
590184de666eSRyan Zezeski 	VERIFY3S(map->ma_nusers, ==, 0);
590284de666eSRyan Zezeski 	VERIFY3P(map->ma_next, ==, NULL);
590384de666eSRyan Zezeski 	VERIFY3P(map->ma_vlans, ==, NULL);
5904da14cebeSEric Cheng 
5905da14cebeSEric Cheng 	kmem_free(map, sizeof (mac_address_t));
5906da14cebeSEric Cheng 	mip->mi_addresses = NULL;
5907da14cebeSEric Cheng }
5908da14cebeSEric Cheng 
5909da14cebeSEric Cheng /*
5910da14cebeSEric Cheng  * Logging related functions.
59110dc2366fSVenugopal Iyer  *
59120dc2366fSVenugopal Iyer  * Note that Kernel statistics have been extended to maintain fine
59130dc2366fSVenugopal Iyer  * granularity of statistics viz. hardware lane, software lane, fanout
59140dc2366fSVenugopal Iyer  * stats etc. However, extended accounting continues to support only
59150dc2366fSVenugopal Iyer  * aggregate statistics like before.
5916da14cebeSEric Cheng  */
5917da14cebeSEric Cheng 
5918c228408bSMichael Lim /* Write the flow description to a netinfo_t record */
5919c228408bSMichael Lim static netinfo_t *
mac_write_flow_desc(flow_entry_t * flent,mac_client_impl_t * mcip)5920da14cebeSEric Cheng mac_write_flow_desc(flow_entry_t *flent, mac_client_impl_t *mcip)
5921da14cebeSEric Cheng {
5922c228408bSMichael Lim 	netinfo_t		*ninfo;
5923c228408bSMichael Lim 	net_desc_t		*ndesc;
5924da14cebeSEric Cheng 	flow_desc_t		*fdesc;
5925da14cebeSEric Cheng 	mac_resource_props_t	*mrp;
5926da14cebeSEric Cheng 
5927c228408bSMichael Lim 	ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
5928c228408bSMichael Lim 	if (ninfo == NULL)
5929c228408bSMichael Lim 		return (NULL);
5930c228408bSMichael Lim 	ndesc = kmem_zalloc(sizeof (net_desc_t), KM_NOSLEEP);
5931c228408bSMichael Lim 	if (ndesc == NULL) {
5932c228408bSMichael Lim 		kmem_free(ninfo, sizeof (netinfo_t));
5933c228408bSMichael Lim 		return (NULL);
5934c228408bSMichael Lim 	}
5935da14cebeSEric Cheng 
5936da14cebeSEric Cheng 	/*
5937da14cebeSEric Cheng 	 * Grab the fe_lock to see a self-consistent fe_flow_desc.
5938da14cebeSEric Cheng 	 * Updates to the fe_flow_desc are done under the fe_lock
5939da14cebeSEric Cheng 	 */
5940da14cebeSEric Cheng 	mutex_enter(&flent->fe_lock);
5941da14cebeSEric Cheng 	fdesc = &flent->fe_flow_desc;
5942da14cebeSEric Cheng 	mrp = &flent->fe_resource_props;
5943da14cebeSEric Cheng 
5944c228408bSMichael Lim 	ndesc->nd_name = flent->fe_flow_name;
5945c228408bSMichael Lim 	ndesc->nd_devname = mcip->mci_name;
5946c228408bSMichael Lim 	bcopy(fdesc->fd_src_mac, ndesc->nd_ehost, ETHERADDRL);
5947c228408bSMichael Lim 	bcopy(fdesc->fd_dst_mac, ndesc->nd_edest, ETHERADDRL);
5948c228408bSMichael Lim 	ndesc->nd_sap = htonl(fdesc->fd_sap);
5949c228408bSMichael Lim 	ndesc->nd_isv4 = (uint8_t)fdesc->fd_ipversion == IPV4_VERSION;
5950c228408bSMichael Lim 	ndesc->nd_bw_limit = mrp->mrp_maxbw;
5951c228408bSMichael Lim 	if (ndesc->nd_isv4) {
5952c228408bSMichael Lim 		ndesc->nd_saddr[3] = htonl(fdesc->fd_local_addr.s6_addr32[3]);
5953c228408bSMichael Lim 		ndesc->nd_daddr[3] = htonl(fdesc->fd_remote_addr.s6_addr32[3]);
5954da14cebeSEric Cheng 	} else {
5955c228408bSMichael Lim 		bcopy(&fdesc->fd_local_addr, ndesc->nd_saddr, IPV6_ADDR_LEN);
5956c228408bSMichael Lim 		bcopy(&fdesc->fd_remote_addr, ndesc->nd_daddr, IPV6_ADDR_LEN);
5957da14cebeSEric Cheng 	}
5958c228408bSMichael Lim 	ndesc->nd_sport = htons(fdesc->fd_local_port);
5959c228408bSMichael Lim 	ndesc->nd_dport = htons(fdesc->fd_remote_port);
5960c228408bSMichael Lim 	ndesc->nd_protocol = (uint8_t)fdesc->fd_protocol;
5961da14cebeSEric Cheng 	mutex_exit(&flent->fe_lock);
5962da14cebeSEric Cheng 
5963c228408bSMichael Lim 	ninfo->ni_record = ndesc;
5964c228408bSMichael Lim 	ninfo->ni_size = sizeof (net_desc_t);
5965c228408bSMichael Lim 	ninfo->ni_type = EX_NET_FLDESC_REC;
5966c228408bSMichael Lim 
5967c228408bSMichael Lim 	return (ninfo);
5968da14cebeSEric Cheng }
5969da14cebeSEric Cheng 
5970c228408bSMichael Lim /* Write the flow statistics to a netinfo_t record */
5971c228408bSMichael Lim static netinfo_t *
mac_write_flow_stats(flow_entry_t * flent)5972da14cebeSEric Cheng mac_write_flow_stats(flow_entry_t *flent)
5973da14cebeSEric Cheng {
5974c228408bSMichael Lim 	netinfo_t		*ninfo;
5975c228408bSMichael Lim 	net_stat_t		*nstat;
59760dc2366fSVenugopal Iyer 	mac_soft_ring_set_t	*mac_srs;
59770dc2366fSVenugopal Iyer 	mac_rx_stats_t		*mac_rx_stat;
59780dc2366fSVenugopal Iyer 	mac_tx_stats_t		*mac_tx_stat;
59790dc2366fSVenugopal Iyer 	int			i;
5980da14cebeSEric Cheng 
5981c228408bSMichael Lim 	ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
5982c228408bSMichael Lim 	if (ninfo == NULL)
5983c228408bSMichael Lim 		return (NULL);
5984c228408bSMichael Lim 	nstat = kmem_zalloc(sizeof (net_stat_t), KM_NOSLEEP);
5985c228408bSMichael Lim 	if (nstat == NULL) {
5986c228408bSMichael Lim 		kmem_free(ninfo, sizeof (netinfo_t));
5987c228408bSMichael Lim 		return (NULL);
5988c228408bSMichael Lim 	}
5989c228408bSMichael Lim 
5990c228408bSMichael Lim 	nstat->ns_name = flent->fe_flow_name;
59910dc2366fSVenugopal Iyer 	for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
59920dc2366fSVenugopal Iyer 		mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
59930dc2366fSVenugopal Iyer 		mac_rx_stat = &mac_srs->srs_rx.sr_stat;
5994da14cebeSEric Cheng 
5995c228408bSMichael Lim 		nstat->ns_ibytes += mac_rx_stat->mrs_intrbytes +
59960dc2366fSVenugopal Iyer 		    mac_rx_stat->mrs_pollbytes + mac_rx_stat->mrs_lclbytes;
5997c228408bSMichael Lim 		nstat->ns_ipackets += mac_rx_stat->mrs_intrcnt +
59980dc2366fSVenugopal Iyer 		    mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt;
5999c228408bSMichael Lim 		nstat->ns_oerrors += mac_rx_stat->mrs_ierrors;
60000dc2366fSVenugopal Iyer 	}
60010dc2366fSVenugopal Iyer 
60020dc2366fSVenugopal Iyer 	mac_srs = (mac_soft_ring_set_t *)(flent->fe_tx_srs);
60030dc2366fSVenugopal Iyer 	if (mac_srs != NULL) {
60040dc2366fSVenugopal Iyer 		mac_tx_stat = &mac_srs->srs_tx.st_stat;
60050dc2366fSVenugopal Iyer 
6006c228408bSMichael Lim 		nstat->ns_obytes = mac_tx_stat->mts_obytes;
6007c228408bSMichael Lim 		nstat->ns_opackets = mac_tx_stat->mts_opackets;
6008c228408bSMichael Lim 		nstat->ns_oerrors = mac_tx_stat->mts_oerrors;
6009da14cebeSEric Cheng 	}
6010da14cebeSEric Cheng 
6011c228408bSMichael Lim 	ninfo->ni_record = nstat;
6012c228408bSMichael Lim 	ninfo->ni_size = sizeof (net_stat_t);
6013c228408bSMichael Lim 	ninfo->ni_type = EX_NET_FLSTAT_REC;
6014c228408bSMichael Lim 
6015c228408bSMichael Lim 	return (ninfo);
6016c228408bSMichael Lim }
6017c228408bSMichael Lim 
6018c228408bSMichael Lim /* Write the link description to a netinfo_t record */
6019c228408bSMichael Lim static netinfo_t *
mac_write_link_desc(mac_client_impl_t * mcip)6020da14cebeSEric Cheng mac_write_link_desc(mac_client_impl_t *mcip)
6021da14cebeSEric Cheng {
6022c228408bSMichael Lim 	netinfo_t		*ninfo;
6023c228408bSMichael Lim 	net_desc_t		*ndesc;
6024da14cebeSEric Cheng 	flow_entry_t		*flent = mcip->mci_flent;
6025da14cebeSEric Cheng 
6026c228408bSMichael Lim 	ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
6027c228408bSMichael Lim 	if (ninfo == NULL)
6028c228408bSMichael Lim 		return (NULL);
6029c228408bSMichael Lim 	ndesc = kmem_zalloc(sizeof (net_desc_t), KM_NOSLEEP);
6030c228408bSMichael Lim 	if (ndesc == NULL) {
6031c228408bSMichael Lim 		kmem_free(ninfo, sizeof (netinfo_t));
6032c228408bSMichael Lim 		return (NULL);
6033c228408bSMichael Lim 	}
6034da14cebeSEric Cheng 
6035c228408bSMichael Lim 	ndesc->nd_name = mcip->mci_name;
6036c228408bSMichael Lim 	ndesc->nd_devname = mcip->mci_name;
6037c228408bSMichael Lim 	ndesc->nd_isv4 = B_TRUE;
6038da14cebeSEric Cheng 	/*
6039da14cebeSEric Cheng 	 * Grab the fe_lock to see a self-consistent fe_flow_desc.
6040da14cebeSEric Cheng 	 * Updates to the fe_flow_desc are done under the fe_lock
6041da14cebeSEric Cheng 	 * after removing the flent from the flow table.
6042da14cebeSEric Cheng 	 */
6043da14cebeSEric Cheng 	mutex_enter(&flent->fe_lock);
6044c228408bSMichael Lim 	bcopy(flent->fe_flow_desc.fd_src_mac, ndesc->nd_ehost, ETHERADDRL);
6045da14cebeSEric Cheng 	mutex_exit(&flent->fe_lock);
6046da14cebeSEric Cheng 
6047c228408bSMichael Lim 	ninfo->ni_record = ndesc;
6048c228408bSMichael Lim 	ninfo->ni_size = sizeof (net_desc_t);
6049c228408bSMichael Lim 	ninfo->ni_type = EX_NET_LNDESC_REC;
6050c228408bSMichael Lim 
6051c228408bSMichael Lim 	return (ninfo);
6052da14cebeSEric Cheng }
6053da14cebeSEric Cheng 
6054c228408bSMichael Lim /* Write the link statistics to a netinfo_t record */
6055c228408bSMichael Lim static netinfo_t *
mac_write_link_stats(mac_client_impl_t * mcip)6056da14cebeSEric Cheng mac_write_link_stats(mac_client_impl_t *mcip)
6057da14cebeSEric Cheng {
6058c228408bSMichael Lim 	netinfo_t		*ninfo;
6059c228408bSMichael Lim 	net_stat_t		*nstat;
60600dc2366fSVenugopal Iyer 	flow_entry_t		*flent;
60610dc2366fSVenugopal Iyer 	mac_soft_ring_set_t	*mac_srs;
60620dc2366fSVenugopal Iyer 	mac_rx_stats_t		*mac_rx_stat;
60630dc2366fSVenugopal Iyer 	mac_tx_stats_t		*mac_tx_stat;
60640dc2366fSVenugopal Iyer 	int			i;
6065da14cebeSEric Cheng 
6066c228408bSMichael Lim 	ninfo = kmem_zalloc(sizeof (netinfo_t), KM_NOSLEEP);
6067c228408bSMichael Lim 	if (ninfo == NULL)
6068c228408bSMichael Lim 		return (NULL);
6069c228408bSMichael Lim 	nstat = kmem_zalloc(sizeof (net_stat_t), KM_NOSLEEP);
6070c228408bSMichael Lim 	if (nstat == NULL) {
6071c228408bSMichael Lim 		kmem_free(ninfo, sizeof (netinfo_t));
6072c228408bSMichael Lim 		return (NULL);
6073c228408bSMichael Lim 	}
6074c228408bSMichael Lim 
6075c228408bSMichael Lim 	nstat->ns_name = mcip->mci_name;
60760dc2366fSVenugopal Iyer 	flent = mcip->mci_flent;
60770dc2366fSVenugopal Iyer 	if (flent != NULL)  {
60780dc2366fSVenugopal Iyer 		for (i = 0; i < flent->fe_rx_srs_cnt; i++) {
60790dc2366fSVenugopal Iyer 			mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i];
60800dc2366fSVenugopal Iyer 			mac_rx_stat = &mac_srs->srs_rx.sr_stat;
6081da14cebeSEric Cheng 
6082c228408bSMichael Lim 			nstat->ns_ibytes += mac_rx_stat->mrs_intrbytes +
60830dc2366fSVenugopal Iyer 			    mac_rx_stat->mrs_pollbytes +
60840dc2366fSVenugopal Iyer 			    mac_rx_stat->mrs_lclbytes;
6085c228408bSMichael Lim 			nstat->ns_ipackets += mac_rx_stat->mrs_intrcnt +
60860dc2366fSVenugopal Iyer 			    mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt;
6087c228408bSMichael Lim 			nstat->ns_oerrors += mac_rx_stat->mrs_ierrors;
60880dc2366fSVenugopal Iyer 		}
60890dc2366fSVenugopal Iyer 	}
60900dc2366fSVenugopal Iyer 
60910dc2366fSVenugopal Iyer 	mac_srs = (mac_soft_ring_set_t *)(mcip->mci_flent->fe_tx_srs);
60920dc2366fSVenugopal Iyer 	if (mac_srs != NULL) {
60930dc2366fSVenugopal Iyer 		mac_tx_stat = &mac_srs->srs_tx.st_stat;
60940dc2366fSVenugopal Iyer 
6095c228408bSMichael Lim 		nstat->ns_obytes = mac_tx_stat->mts_obytes;
6096c228408bSMichael Lim 		nstat->ns_opackets = mac_tx_stat->mts_opackets;
6097c228408bSMichael Lim 		nstat->ns_oerrors = mac_tx_stat->mts_oerrors;
6098da14cebeSEric Cheng 	}
6099da14cebeSEric Cheng 
6100c228408bSMichael Lim 	ninfo->ni_record = nstat;
6101c228408bSMichael Lim 	ninfo->ni_size = sizeof (net_stat_t);
6102c228408bSMichael Lim 	ninfo->ni_type = EX_NET_LNSTAT_REC;
6103c228408bSMichael Lim 
6104c228408bSMichael Lim 	return (ninfo);
6105c228408bSMichael Lim }
6106c228408bSMichael Lim 
6107c228408bSMichael Lim typedef struct i_mac_log_state_s {
6108c228408bSMichael Lim 	boolean_t	mi_last;
6109c228408bSMichael Lim 	int		mi_fenable;
6110c228408bSMichael Lim 	int		mi_lenable;
6111c228408bSMichael Lim 	list_t		*mi_list;
6112c228408bSMichael Lim } i_mac_log_state_t;
6113c228408bSMichael Lim 
6114da14cebeSEric Cheng /*
6115c228408bSMichael Lim  * For a given flow, if the description has not been logged before, do it now.
6116da14cebeSEric Cheng  * If it is a VNIC, then we have collected information about it from the MAC
6117da14cebeSEric Cheng  * table, so skip it.
6118c228408bSMichael Lim  *
6119c228408bSMichael Lim  * Called through mac_flow_walk_nolock()
6120c228408bSMichael Lim  *
6121c228408bSMichael Lim  * Return 0 if successful.
6122da14cebeSEric Cheng  */
6123da14cebeSEric Cheng static int
mac_log_flowinfo(flow_entry_t * flent,void * arg)6124c228408bSMichael Lim mac_log_flowinfo(flow_entry_t *flent, void *arg)
6125da14cebeSEric Cheng {
6126da14cebeSEric Cheng 	mac_client_impl_t	*mcip = flent->fe_mcip;
6127c228408bSMichael Lim 	i_mac_log_state_t	*lstate = arg;
6128c228408bSMichael Lim 	netinfo_t		*ninfo;
6129da14cebeSEric Cheng 
6130da14cebeSEric Cheng 	if (mcip == NULL)
6131da14cebeSEric Cheng 		return (0);
6132da14cebeSEric Cheng 
6133da14cebeSEric Cheng 	/*
6134da14cebeSEric Cheng 	 * If the name starts with "vnic", and fe_user_generated is true (to
6135da14cebeSEric Cheng 	 * exclude the mcast and active flow entries created implicitly for
6136da14cebeSEric Cheng 	 * a vnic, it is a VNIC flow.  i.e. vnic1 is a vnic flow,
6137da14cebeSEric Cheng 	 * vnic/bge1/mcast1 is not and neither is vnic/bge1/active.
6138da14cebeSEric Cheng 	 */
6139da14cebeSEric Cheng 	if (strncasecmp(flent->fe_flow_name, "vnic", 4) == 0 &&
6140da14cebeSEric Cheng 	    (flent->fe_type & FLOW_USER) != 0) {
6141da14cebeSEric Cheng 		return (0);
6142da14cebeSEric Cheng 	}
6143da14cebeSEric Cheng 
6144da14cebeSEric Cheng 	if (!flent->fe_desc_logged) {
6145da14cebeSEric Cheng 		/*
6146c228408bSMichael Lim 		 * We don't return error because we want to continue the
6147da14cebeSEric Cheng 		 * walk in case this is the last walk which means we
6148da14cebeSEric Cheng 		 * need to reset fe_desc_logged in all the flows.
6149da14cebeSEric Cheng 		 */
6150c228408bSMichael Lim 		if ((ninfo = mac_write_flow_desc(flent, mcip)) == NULL)
6151da14cebeSEric Cheng 			return (0);
6152c228408bSMichael Lim 		list_insert_tail(lstate->mi_list, ninfo);
6153da14cebeSEric Cheng 		flent->fe_desc_logged = B_TRUE;
6154da14cebeSEric Cheng 	}
6155da14cebeSEric Cheng 
6156da14cebeSEric Cheng 	/*
6157da14cebeSEric Cheng 	 * Regardless of the error, we want to proceed in case we have to
6158da14cebeSEric Cheng 	 * reset fe_desc_logged.
6159da14cebeSEric Cheng 	 */
6160c228408bSMichael Lim 	ninfo = mac_write_flow_stats(flent);
6161c228408bSMichael Lim 	if (ninfo == NULL)
6162c228408bSMichael Lim 		return (-1);
6163c228408bSMichael Lim 
6164c228408bSMichael Lim 	list_insert_tail(lstate->mi_list, ninfo);
6165da14cebeSEric Cheng 
6166da14cebeSEric Cheng 	if (mcip != NULL && !(mcip->mci_state_flags & MCIS_DESC_LOGGED))
6167da14cebeSEric Cheng 		flent->fe_desc_logged = B_FALSE;
6168da14cebeSEric Cheng 
6169da14cebeSEric Cheng 	return (0);
6170da14cebeSEric Cheng }
6171da14cebeSEric Cheng 
6172da14cebeSEric Cheng /*
6173c228408bSMichael Lim  * Log the description for each mac client of this mac_impl_t, if it
6174c228408bSMichael Lim  * hasn't already been done. Additionally, log statistics for the link as
6175da14cebeSEric Cheng  * well. Walk the flow table and log information for each flow as well.
6176da14cebeSEric Cheng  * If it is the last walk (mci_last), then we turn off mci_desc_logged (and
6177da14cebeSEric Cheng  * also fe_desc_logged, if flow logging is on) since we want to log the
6178da14cebeSEric Cheng  * description if and when logging is restarted.
6179c228408bSMichael Lim  *
6180c228408bSMichael Lim  * Return 0 upon success or -1 upon failure
6181da14cebeSEric Cheng  */
6182c228408bSMichael Lim static int
i_mac_impl_log(mac_impl_t * mip,i_mac_log_state_t * lstate)6183c228408bSMichael Lim i_mac_impl_log(mac_impl_t *mip, i_mac_log_state_t *lstate)
6184da14cebeSEric Cheng {
6185da14cebeSEric Cheng 	mac_client_impl_t	*mcip;
6186c228408bSMichael Lim 	netinfo_t		*ninfo;
6187da14cebeSEric Cheng 
6188c228408bSMichael Lim 	i_mac_perim_enter(mip);
6189da14cebeSEric Cheng 	/*
6190da14cebeSEric Cheng 	 * Only walk the client list for NIC and etherstub
6191da14cebeSEric Cheng 	 */
6192da14cebeSEric Cheng 	if ((mip->mi_state_flags & MIS_DISABLED) ||
6193da14cebeSEric Cheng 	    ((mip->mi_state_flags & MIS_IS_VNIC) &&
6194c228408bSMichael Lim 	    (mac_get_lower_mac_handle((mac_handle_t)mip) != NULL))) {
6195c228408bSMichael Lim 		i_mac_perim_exit(mip);
6196c228408bSMichael Lim 		return (0);
6197c228408bSMichael Lim 	}
6198da14cebeSEric Cheng 
6199da14cebeSEric Cheng 	for (mcip = mip->mi_clients_list; mcip != NULL;
6200da14cebeSEric Cheng 	    mcip = mcip->mci_client_next) {
6201da14cebeSEric Cheng 		if (!MCIP_DATAPATH_SETUP(mcip))
6202da14cebeSEric Cheng 			continue;
6203da14cebeSEric Cheng 		if (lstate->mi_lenable) {
6204da14cebeSEric Cheng 			if (!(mcip->mci_state_flags & MCIS_DESC_LOGGED)) {
6205c228408bSMichael Lim 				ninfo = mac_write_link_desc(mcip);
6206c228408bSMichael Lim 				if (ninfo == NULL) {
6207da14cebeSEric Cheng 				/*
6208da14cebeSEric Cheng 				 * We can't terminate it if this is the last
6209da14cebeSEric Cheng 				 * walk, else there might be some links with
6210da14cebeSEric Cheng 				 * mi_desc_logged set to true, which means
6211da14cebeSEric Cheng 				 * their description won't be logged the next
6212da14cebeSEric Cheng 				 * time logging is started (similarly for the
6213da14cebeSEric Cheng 				 * flows within such links). We can continue
6214da14cebeSEric Cheng 				 * without walking the flow table (i.e. to
6215da14cebeSEric Cheng 				 * set fe_desc_logged to false) because we
6216da14cebeSEric Cheng 				 * won't have written any flow stuff for this
6217da14cebeSEric Cheng 				 * link as we haven't logged the link itself.
6218da14cebeSEric Cheng 				 */
6219c228408bSMichael Lim 					i_mac_perim_exit(mip);
6220da14cebeSEric Cheng 					if (lstate->mi_last)
6221c228408bSMichael Lim 						return (0);
6222da14cebeSEric Cheng 					else
6223c228408bSMichael Lim 						return (-1);
6224da14cebeSEric Cheng 				}
6225da14cebeSEric Cheng 				mcip->mci_state_flags |= MCIS_DESC_LOGGED;
6226c228408bSMichael Lim 				list_insert_tail(lstate->mi_list, ninfo);
6227da14cebeSEric Cheng 			}
6228da14cebeSEric Cheng 		}
6229da14cebeSEric Cheng 
6230c228408bSMichael Lim 		ninfo = mac_write_link_stats(mcip);
6231c228408bSMichael Lim 		if (ninfo == NULL && !lstate->mi_last) {
6232c228408bSMichael Lim 			i_mac_perim_exit(mip);
6233c228408bSMichael Lim 			return (-1);
6234c228408bSMichael Lim 		}
6235c228408bSMichael Lim 		list_insert_tail(lstate->mi_list, ninfo);
6236da14cebeSEric Cheng 
6237da14cebeSEric Cheng 		if (lstate->mi_last)
6238da14cebeSEric Cheng 			mcip->mci_state_flags &= ~MCIS_DESC_LOGGED;
6239da14cebeSEric Cheng 
6240da14cebeSEric Cheng 		if (lstate->mi_fenable) {
6241da14cebeSEric Cheng 			if (mcip->mci_subflow_tab != NULL) {
6242c228408bSMichael Lim 				(void) mac_flow_walk_nolock(
6243c228408bSMichael Lim 				    mcip->mci_subflow_tab, mac_log_flowinfo,
6244c228408bSMichael Lim 				    lstate);
6245da14cebeSEric Cheng 			}
6246da14cebeSEric Cheng 		}
6247da14cebeSEric Cheng 	}
6248c228408bSMichael Lim 	i_mac_perim_exit(mip);
6249c228408bSMichael Lim 	return (0);
6250c228408bSMichael Lim }
6251c228408bSMichael Lim 
6252c228408bSMichael Lim /*
6253c228408bSMichael Lim  * modhash walker function to add a mac_impl_t to a list
6254c228408bSMichael Lim  */
6255c228408bSMichael Lim /*ARGSUSED*/
6256c228408bSMichael Lim static uint_t
i_mac_impl_list_walker(mod_hash_key_t key,mod_hash_val_t * val,void * arg)6257c228408bSMichael Lim i_mac_impl_list_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
6258c228408bSMichael Lim {
6259c228408bSMichael Lim 	list_t			*list = (list_t *)arg;
6260c228408bSMichael Lim 	mac_impl_t		*mip = (mac_impl_t *)val;
6261c228408bSMichael Lim 
6262c228408bSMichael Lim 	if ((mip->mi_state_flags & MIS_DISABLED) == 0) {
6263c228408bSMichael Lim 		list_insert_tail(list, mip);
6264c228408bSMichael Lim 		mip->mi_ref++;
6265c228408bSMichael Lim 	}
6266c228408bSMichael Lim 
6267da14cebeSEric Cheng 	return (MH_WALK_CONTINUE);
6268da14cebeSEric Cheng }
6269da14cebeSEric Cheng 
6270c228408bSMichael Lim void
i_mac_log_info(list_t * net_log_list,i_mac_log_state_t * lstate)6271c228408bSMichael Lim i_mac_log_info(list_t *net_log_list, i_mac_log_state_t *lstate)
6272c228408bSMichael Lim {
6273c228408bSMichael Lim 	list_t			mac_impl_list;
6274c228408bSMichael Lim 	mac_impl_t		*mip;
6275c228408bSMichael Lim 	netinfo_t		*ninfo;
6276c228408bSMichael Lim 
6277c228408bSMichael Lim 	/* Create list of mac_impls */
6278c228408bSMichael Lim 	ASSERT(RW_LOCK_HELD(&i_mac_impl_lock));
6279c228408bSMichael Lim 	list_create(&mac_impl_list, sizeof (mac_impl_t), offsetof(mac_impl_t,
6280c228408bSMichael Lim 	    mi_node));
6281c228408bSMichael Lim 	mod_hash_walk(i_mac_impl_hash, i_mac_impl_list_walker, &mac_impl_list);
6282c228408bSMichael Lim 	rw_exit(&i_mac_impl_lock);
6283c228408bSMichael Lim 
6284c228408bSMichael Lim 	/* Create log entries for each mac_impl */
6285c228408bSMichael Lim 	for (mip = list_head(&mac_impl_list); mip != NULL;
6286c228408bSMichael Lim 	    mip = list_next(&mac_impl_list, mip)) {
6287c228408bSMichael Lim 		if (i_mac_impl_log(mip, lstate) != 0)
6288c228408bSMichael Lim 			continue;
6289c228408bSMichael Lim 	}
6290c228408bSMichael Lim 
6291c228408bSMichael Lim 	/* Remove elements and destroy list of mac_impls */
6292c228408bSMichael Lim 	rw_enter(&i_mac_impl_lock, RW_WRITER);
6293c228408bSMichael Lim 	while ((mip = list_remove_tail(&mac_impl_list)) != NULL) {
6294c228408bSMichael Lim 		mip->mi_ref--;
6295c228408bSMichael Lim 	}
6296c228408bSMichael Lim 	rw_exit(&i_mac_impl_lock);
6297c228408bSMichael Lim 	list_destroy(&mac_impl_list);
6298c228408bSMichael Lim 
6299c228408bSMichael Lim 	/*
6300c228408bSMichael Lim 	 * Write log entries to files outside of locks, free associated
6301c228408bSMichael Lim 	 * structures, and remove entries from the list.
6302c228408bSMichael Lim 	 */
6303c228408bSMichael Lim 	while ((ninfo = list_head(net_log_list)) != NULL) {
6304c228408bSMichael Lim 		(void) exacct_commit_netinfo(ninfo->ni_record, ninfo->ni_type);
6305c228408bSMichael Lim 		list_remove(net_log_list, ninfo);
6306c228408bSMichael Lim 		kmem_free(ninfo->ni_record, ninfo->ni_size);
6307c228408bSMichael Lim 		kmem_free(ninfo, sizeof (*ninfo));
6308c228408bSMichael Lim 	}
6309c228408bSMichael Lim 	list_destroy(net_log_list);
6310c228408bSMichael Lim }
6311c228408bSMichael Lim 
6312da14cebeSEric Cheng /*
6313da14cebeSEric Cheng  * The timer thread that runs every mac_logging_interval seconds and logs
6314da14cebeSEric Cheng  * link and/or flow information.
6315da14cebeSEric Cheng  */
6316da14cebeSEric Cheng /* ARGSUSED */
6317da14cebeSEric Cheng void
mac_log_linkinfo(void * arg)6318da14cebeSEric Cheng mac_log_linkinfo(void *arg)
6319da14cebeSEric Cheng {
6320da14cebeSEric Cheng 	i_mac_log_state_t	lstate;
6321c228408bSMichael Lim 	list_t			net_log_list;
6322c228408bSMichael Lim 
6323c228408bSMichael Lim 	list_create(&net_log_list, sizeof (netinfo_t),
6324c228408bSMichael Lim 	    offsetof(netinfo_t, ni_link));
6325da14cebeSEric Cheng 
6326da14cebeSEric Cheng 	rw_enter(&i_mac_impl_lock, RW_READER);
6327da14cebeSEric Cheng 	if (!mac_flow_log_enable && !mac_link_log_enable) {
6328da14cebeSEric Cheng 		rw_exit(&i_mac_impl_lock);
6329da14cebeSEric Cheng 		return;
6330da14cebeSEric Cheng 	}
6331da14cebeSEric Cheng 	lstate.mi_fenable = mac_flow_log_enable;
6332da14cebeSEric Cheng 	lstate.mi_lenable = mac_link_log_enable;
6333da14cebeSEric Cheng 	lstate.mi_last = B_FALSE;
6334c228408bSMichael Lim 	lstate.mi_list = &net_log_list;
6335da14cebeSEric Cheng 
6336c228408bSMichael Lim 	/* Write log entries for each mac_impl in the list */
6337c228408bSMichael Lim 	i_mac_log_info(&net_log_list, &lstate);
6338da14cebeSEric Cheng 
6339da14cebeSEric Cheng 	if (mac_flow_log_enable || mac_link_log_enable) {
6340da14cebeSEric Cheng 		mac_logging_timer = timeout(mac_log_linkinfo, NULL,
6341da14cebeSEric Cheng 		    SEC_TO_TICK(mac_logging_interval));
6342da14cebeSEric Cheng 	}
6343da14cebeSEric Cheng }
6344da14cebeSEric Cheng 
63455d460eafSCathy Zhou typedef struct i_mac_fastpath_state_s {
63465d460eafSCathy Zhou 	boolean_t	mf_disable;
63475d460eafSCathy Zhou 	int		mf_err;
63485d460eafSCathy Zhou } i_mac_fastpath_state_t;
63495d460eafSCathy Zhou 
6350c228408bSMichael Lim /* modhash walker function to enable or disable fastpath */
63515d460eafSCathy Zhou /*ARGSUSED*/
63525d460eafSCathy Zhou static uint_t
i_mac_fastpath_walker(mod_hash_key_t key,mod_hash_val_t * val,void * arg)6353c228408bSMichael Lim i_mac_fastpath_walker(mod_hash_key_t key, mod_hash_val_t *val,
63545d460eafSCathy Zhou     void *arg)
63555d460eafSCathy Zhou {
63565d460eafSCathy Zhou 	i_mac_fastpath_state_t	*state = arg;
63575d460eafSCathy Zhou 	mac_handle_t		mh = (mac_handle_t)val;
63585d460eafSCathy Zhou 
63595d460eafSCathy Zhou 	if (state->mf_disable)
63605d460eafSCathy Zhou 		state->mf_err = mac_fastpath_disable(mh);
63615d460eafSCathy Zhou 	else
63625d460eafSCathy Zhou 		mac_fastpath_enable(mh);
63635d460eafSCathy Zhou 
63645d460eafSCathy Zhou 	return (state->mf_err == 0 ? MH_WALK_CONTINUE : MH_WALK_TERMINATE);
63655d460eafSCathy Zhou }
63665d460eafSCathy Zhou 
6367da14cebeSEric Cheng /*
6368da14cebeSEric Cheng  * Start the logging timer.
6369da14cebeSEric Cheng  */
63705d460eafSCathy Zhou int
mac_start_logusage(mac_logtype_t type,uint_t interval)6371da14cebeSEric Cheng mac_start_logusage(mac_logtype_t type, uint_t interval)
6372da14cebeSEric Cheng {
6373c228408bSMichael Lim 	i_mac_fastpath_state_t	dstate = {B_TRUE, 0};
6374c228408bSMichael Lim 	i_mac_fastpath_state_t	estate = {B_FALSE, 0};
63755d460eafSCathy Zhou 	int			err;
63765d460eafSCathy Zhou 
6377da14cebeSEric Cheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
6378da14cebeSEric Cheng 	switch (type) {
6379da14cebeSEric Cheng 	case MAC_LOGTYPE_FLOW:
6380da14cebeSEric Cheng 		if (mac_flow_log_enable) {
6381da14cebeSEric Cheng 			rw_exit(&i_mac_impl_lock);
63825d460eafSCathy Zhou 			return (0);
6383da14cebeSEric Cheng 		}
6384da14cebeSEric Cheng 		/* FALLTHRU */
6385da14cebeSEric Cheng 	case MAC_LOGTYPE_LINK:
6386da14cebeSEric Cheng 		if (mac_link_log_enable) {
6387da14cebeSEric Cheng 			rw_exit(&i_mac_impl_lock);
63885d460eafSCathy Zhou 			return (0);
6389da14cebeSEric Cheng 		}
6390da14cebeSEric Cheng 		break;
6391da14cebeSEric Cheng 	default:
6392da14cebeSEric Cheng 		ASSERT(0);
6393da14cebeSEric Cheng 	}
63945d460eafSCathy Zhou 
63955d460eafSCathy Zhou 	/* Disable fastpath */
6396c228408bSMichael Lim 	mod_hash_walk(i_mac_impl_hash, i_mac_fastpath_walker, &dstate);
6397c228408bSMichael Lim 	if ((err = dstate.mf_err) != 0) {
63985d460eafSCathy Zhou 		/* Reenable fastpath  */
6399c228408bSMichael Lim 		mod_hash_walk(i_mac_impl_hash, i_mac_fastpath_walker, &estate);
64005d460eafSCathy Zhou 		rw_exit(&i_mac_impl_lock);
64015d460eafSCathy Zhou 		return (err);
64025d460eafSCathy Zhou 	}
64035d460eafSCathy Zhou 
64045d460eafSCathy Zhou 	switch (type) {
64055d460eafSCathy Zhou 	case MAC_LOGTYPE_FLOW:
64065d460eafSCathy Zhou 		mac_flow_log_enable = B_TRUE;
64075d460eafSCathy Zhou 		/* FALLTHRU */
64085d460eafSCathy Zhou 	case MAC_LOGTYPE_LINK:
64095d460eafSCathy Zhou 		mac_link_log_enable = B_TRUE;
64105d460eafSCathy Zhou 		break;
64115d460eafSCathy Zhou 	}
64125d460eafSCathy Zhou 
6413da14cebeSEric Cheng 	mac_logging_interval = interval;
6414da14cebeSEric Cheng 	rw_exit(&i_mac_impl_lock);
6415da14cebeSEric Cheng 	mac_log_linkinfo(NULL);
64165d460eafSCathy Zhou 	return (0);
6417da14cebeSEric Cheng }
6418da14cebeSEric Cheng 
6419da14cebeSEric Cheng /*
6420c228408bSMichael Lim  * Stop the logging timer if both link and flow logging are turned off.
6421da14cebeSEric Cheng  */
6422da14cebeSEric Cheng void
mac_stop_logusage(mac_logtype_t type)6423da14cebeSEric Cheng mac_stop_logusage(mac_logtype_t type)
6424da14cebeSEric Cheng {
6425da14cebeSEric Cheng 	i_mac_log_state_t	lstate;
6426c228408bSMichael Lim 	i_mac_fastpath_state_t	estate = {B_FALSE, 0};
6427c228408bSMichael Lim 	list_t			net_log_list;
6428c228408bSMichael Lim 
6429c228408bSMichael Lim 	list_create(&net_log_list, sizeof (netinfo_t),
6430c228408bSMichael Lim 	    offsetof(netinfo_t, ni_link));
6431da14cebeSEric Cheng 
6432da14cebeSEric Cheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
6433c228408bSMichael Lim 
6434da14cebeSEric Cheng 	lstate.mi_fenable = mac_flow_log_enable;
6435da14cebeSEric Cheng 	lstate.mi_lenable = mac_link_log_enable;
6436c228408bSMichael Lim 	lstate.mi_list = &net_log_list;
6437da14cebeSEric Cheng 
6438da14cebeSEric Cheng 	/* Last walk */
6439da14cebeSEric Cheng 	lstate.mi_last = B_TRUE;
6440da14cebeSEric Cheng 
6441da14cebeSEric Cheng 	switch (type) {
6442da14cebeSEric Cheng 	case MAC_LOGTYPE_FLOW:
6443da14cebeSEric Cheng 		if (lstate.mi_fenable) {
6444da14cebeSEric Cheng 			ASSERT(mac_link_log_enable);
6445da14cebeSEric Cheng 			mac_flow_log_enable = B_FALSE;
6446da14cebeSEric Cheng 			mac_link_log_enable = B_FALSE;
6447da14cebeSEric Cheng 			break;
6448da14cebeSEric Cheng 		}
6449da14cebeSEric Cheng 		/* FALLTHRU */
6450da14cebeSEric Cheng 	case MAC_LOGTYPE_LINK:
6451da14cebeSEric Cheng 		if (!lstate.mi_lenable || mac_flow_log_enable) {
6452da14cebeSEric Cheng 			rw_exit(&i_mac_impl_lock);
6453da14cebeSEric Cheng 			return;
6454da14cebeSEric Cheng 		}
6455da14cebeSEric Cheng 		mac_link_log_enable = B_FALSE;
6456da14cebeSEric Cheng 		break;
6457da14cebeSEric Cheng 	default:
6458da14cebeSEric Cheng 		ASSERT(0);
6459da14cebeSEric Cheng 	}
64605d460eafSCathy Zhou 
64615d460eafSCathy Zhou 	/* Reenable fastpath */
6462c228408bSMichael Lim 	mod_hash_walk(i_mac_impl_hash, i_mac_fastpath_walker, &estate);
64635d460eafSCathy Zhou 
6464da14cebeSEric Cheng 	(void) untimeout(mac_logging_timer);
646584de666eSRyan Zezeski 	mac_logging_timer = NULL;
6466da14cebeSEric Cheng 
6467c228408bSMichael Lim 	/* Write log entries for each mac_impl in the list */
6468c228408bSMichael Lim 	i_mac_log_info(&net_log_list, &lstate);
6469da14cebeSEric Cheng }
6470da14cebeSEric Cheng 
6471da14cebeSEric Cheng /*
6472da14cebeSEric Cheng  * Walk the rx and tx SRS/SRs for a flow and update the priority value.
6473da14cebeSEric Cheng  */
6474da14cebeSEric Cheng void
mac_flow_update_priority(mac_client_impl_t * mcip,flow_entry_t * flent)6475da14cebeSEric Cheng mac_flow_update_priority(mac_client_impl_t *mcip, flow_entry_t *flent)
6476da14cebeSEric Cheng {
6477da14cebeSEric Cheng 	pri_t			pri;
6478da14cebeSEric Cheng 	int			count;
6479da14cebeSEric Cheng 	mac_soft_ring_set_t	*mac_srs;
6480da14cebeSEric Cheng 
6481da14cebeSEric Cheng 	if (flent->fe_rx_srs_cnt <= 0)
6482da14cebeSEric Cheng 		return;
6483da14cebeSEric Cheng 
6484da14cebeSEric Cheng 	if (((mac_soft_ring_set_t *)flent->fe_rx_srs[0])->srs_type ==
6485da14cebeSEric Cheng 	    SRST_FLOW) {
6486da14cebeSEric Cheng 		pri = FLOW_PRIORITY(mcip->mci_min_pri,
6487da14cebeSEric Cheng 		    mcip->mci_max_pri,
6488da14cebeSEric Cheng 		    flent->fe_resource_props.mrp_priority);
6489da14cebeSEric Cheng 	} else {
6490da14cebeSEric Cheng 		pri = mcip->mci_max_pri;
6491da14cebeSEric Cheng 	}
6492da14cebeSEric Cheng 
6493da14cebeSEric Cheng 	for (count = 0; count < flent->fe_rx_srs_cnt; count++) {
6494da14cebeSEric Cheng 		mac_srs = flent->fe_rx_srs[count];
6495da14cebeSEric Cheng 		mac_update_srs_priority(mac_srs, pri);
6496da14cebeSEric Cheng 	}
6497da14cebeSEric Cheng 	/*
6498da14cebeSEric Cheng 	 * If we have a Tx SRS, we need to modify all the threads associated
6499da14cebeSEric Cheng 	 * with it.
6500da14cebeSEric Cheng 	 */
6501da14cebeSEric Cheng 	if (flent->fe_tx_srs != NULL)
6502da14cebeSEric Cheng 		mac_update_srs_priority(flent->fe_tx_srs, pri);
6503da14cebeSEric Cheng }
6504da14cebeSEric Cheng 
6505da14cebeSEric Cheng /*
6506da14cebeSEric Cheng  * RX and TX rings are reserved according to different semantics depending
6507da14cebeSEric Cheng  * on the requests from the MAC clients and type of rings:
6508da14cebeSEric Cheng  *
6509da14cebeSEric Cheng  * On the Tx side, by default we reserve individual rings, independently from
6510da14cebeSEric Cheng  * the groups.
6511da14cebeSEric Cheng  *
6512da14cebeSEric Cheng  * On the Rx side, the reservation is at the granularity of the group
6513da14cebeSEric Cheng  * of rings, and used for v12n level 1 only. It has a special case for the
6514da14cebeSEric Cheng  * primary client.
6515da14cebeSEric Cheng  *
6516da14cebeSEric Cheng  * If a share is allocated to a MAC client, we allocate a TX group and an
6517da14cebeSEric Cheng  * RX group to the client, and assign TX rings and RX rings to these
6518da14cebeSEric Cheng  * groups according to information gathered from the driver through
6519da14cebeSEric Cheng  * the share capability.
6520da14cebeSEric Cheng  *
6521da14cebeSEric Cheng  * The foreseable evolution of Rx rings will handle v12n level 2 and higher
6522da14cebeSEric Cheng  * to allocate individual rings out of a group and program the hw classifier
6523da14cebeSEric Cheng  * based on IP address or higher level criteria.
6524da14cebeSEric Cheng  */
6525da14cebeSEric Cheng 
6526da14cebeSEric Cheng /*
6527da14cebeSEric Cheng  * mac_reserve_tx_ring()
6528da14cebeSEric Cheng  * Reserve a unused ring by marking it with MR_INUSE state.
6529da14cebeSEric Cheng  * As reserved, the ring is ready to function.
6530da14cebeSEric Cheng  *
6531da14cebeSEric Cheng  * Notes for Hybrid I/O:
6532da14cebeSEric Cheng  *
6533da14cebeSEric Cheng  * If a specific ring is needed, it is specified through the desired_ring
6534da14cebeSEric Cheng  * argument. Otherwise that argument is set to NULL.
6535da14cebeSEric Cheng  * If the desired ring was previous allocated to another client, this
6536da14cebeSEric Cheng  * function swaps it with a new ring from the group of unassigned rings.
6537da14cebeSEric Cheng  */
6538da14cebeSEric Cheng mac_ring_t *
mac_reserve_tx_ring(mac_impl_t * mip,mac_ring_t * desired_ring)6539da14cebeSEric Cheng mac_reserve_tx_ring(mac_impl_t *mip, mac_ring_t *desired_ring)
6540da14cebeSEric Cheng {
6541da14cebeSEric Cheng 	mac_group_t		*group;
65420dc2366fSVenugopal Iyer 	mac_grp_client_t	*mgcp;
65430dc2366fSVenugopal Iyer 	mac_client_impl_t	*mcip;
65440dc2366fSVenugopal Iyer 	mac_soft_ring_set_t	*srs;
6545da14cebeSEric Cheng 
6546da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
6547da14cebeSEric Cheng 
6548da14cebeSEric Cheng 	/*
6549da14cebeSEric Cheng 	 * Find an available ring and start it before changing its status.
6550da14cebeSEric Cheng 	 * The unassigned rings are at the end of the mi_tx_groups
6551da14cebeSEric Cheng 	 * array.
6552da14cebeSEric Cheng 	 */
65530dc2366fSVenugopal Iyer 	group = MAC_DEFAULT_TX_GROUP(mip);
6554da14cebeSEric Cheng 
65550dc2366fSVenugopal Iyer 	/* Can't take the default ring out of the default group */
65560dc2366fSVenugopal Iyer 	ASSERT(desired_ring != (mac_ring_t *)mip->mi_default_tx_ring);
65570dc2366fSVenugopal Iyer 
65580dc2366fSVenugopal Iyer 	if (desired_ring->mr_state == MR_FREE) {
65590dc2366fSVenugopal Iyer 		ASSERT(MAC_GROUP_NO_CLIENT(group));
65600dc2366fSVenugopal Iyer 		if (mac_start_ring(desired_ring) != 0)
65610dc2366fSVenugopal Iyer 			return (NULL);
65620dc2366fSVenugopal Iyer 		return (desired_ring);
65630dc2366fSVenugopal Iyer 	}
65640dc2366fSVenugopal Iyer 	/*
65650dc2366fSVenugopal Iyer 	 * There are clients using this ring, so let's move the clients
65660dc2366fSVenugopal Iyer 	 * away from using this ring.
65670dc2366fSVenugopal Iyer 	 */
65680dc2366fSVenugopal Iyer 	for (mgcp = group->mrg_clients; mgcp != NULL; mgcp = mgcp->mgc_next) {
65690dc2366fSVenugopal Iyer 		mcip = mgcp->mgc_client;
65700dc2366fSVenugopal Iyer 		mac_tx_client_quiesce((mac_client_handle_t)mcip);
65710dc2366fSVenugopal Iyer 		srs = MCIP_TX_SRS(mcip);
65720dc2366fSVenugopal Iyer 		ASSERT(mac_tx_srs_ring_present(srs, desired_ring));
65730dc2366fSVenugopal Iyer 		mac_tx_invoke_callbacks(mcip,
65740dc2366fSVenugopal Iyer 		    (mac_tx_cookie_t)mac_tx_srs_get_soft_ring(srs,
65750dc2366fSVenugopal Iyer 		    desired_ring));
65760dc2366fSVenugopal Iyer 		mac_tx_srs_del_ring(srs, desired_ring);
65770dc2366fSVenugopal Iyer 		mac_tx_client_restart((mac_client_handle_t)mcip);
65780dc2366fSVenugopal Iyer 	}
65790dc2366fSVenugopal Iyer 	return (desired_ring);
65800dc2366fSVenugopal Iyer }
65810dc2366fSVenugopal Iyer 
65820dc2366fSVenugopal Iyer /*
658384de666eSRyan Zezeski  * For a non-default group with multiple clients, return the primary client.
65840dc2366fSVenugopal Iyer  */
65850dc2366fSVenugopal Iyer static mac_client_impl_t *
mac_get_grp_primary(mac_group_t * grp)65860dc2366fSVenugopal Iyer mac_get_grp_primary(mac_group_t *grp)
65870dc2366fSVenugopal Iyer {
65880dc2366fSVenugopal Iyer 	mac_grp_client_t	*mgcp = grp->mrg_clients;
65890dc2366fSVenugopal Iyer 	mac_client_impl_t	*mcip;
65900dc2366fSVenugopal Iyer 
65910dc2366fSVenugopal Iyer 	while (mgcp != NULL) {
65920dc2366fSVenugopal Iyer 		mcip = mgcp->mgc_client;
65930dc2366fSVenugopal Iyer 		if (mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC)
65940dc2366fSVenugopal Iyer 			return (mcip);
65950dc2366fSVenugopal Iyer 		mgcp = mgcp->mgc_next;
65960dc2366fSVenugopal Iyer 	}
65970dc2366fSVenugopal Iyer 	return (NULL);
65980dc2366fSVenugopal Iyer }
65990dc2366fSVenugopal Iyer 
66000dc2366fSVenugopal Iyer /*
66010dc2366fSVenugopal Iyer  * Hybrid I/O specifies the ring that should be given to a share.
66020dc2366fSVenugopal Iyer  * If the ring is already used by clients, then we need to release
66030dc2366fSVenugopal Iyer  * the ring back to the default group so that we can give it to
66040dc2366fSVenugopal Iyer  * the share. This means the clients using this ring now get a
66050dc2366fSVenugopal Iyer  * replacement ring. If there aren't any replacement rings, this
66060dc2366fSVenugopal Iyer  * function returns a failure.
66070dc2366fSVenugopal Iyer  */
66080dc2366fSVenugopal Iyer static int
mac_reclaim_ring_from_grp(mac_impl_t * mip,mac_ring_type_t ring_type,mac_ring_t * ring,mac_ring_t ** rings,int nrings)66090dc2366fSVenugopal Iyer mac_reclaim_ring_from_grp(mac_impl_t *mip, mac_ring_type_t ring_type,
66100dc2366fSVenugopal Iyer     mac_ring_t *ring, mac_ring_t **rings, int nrings)
66110dc2366fSVenugopal Iyer {
66120dc2366fSVenugopal Iyer 	mac_group_t		*group = (mac_group_t *)ring->mr_gh;
66130dc2366fSVenugopal Iyer 	mac_resource_props_t	*mrp;
66140dc2366fSVenugopal Iyer 	mac_client_impl_t	*mcip;
66150dc2366fSVenugopal Iyer 	mac_group_t		*defgrp;
66160dc2366fSVenugopal Iyer 	mac_ring_t		*tring;
66170dc2366fSVenugopal Iyer 	mac_group_t		*tgrp;
66180dc2366fSVenugopal Iyer 	int			i;
66190dc2366fSVenugopal Iyer 	int			j;
66200dc2366fSVenugopal Iyer 
66210dc2366fSVenugopal Iyer 	mcip = MAC_GROUP_ONLY_CLIENT(group);
66220dc2366fSVenugopal Iyer 	if (mcip == NULL)
66230dc2366fSVenugopal Iyer 		mcip = mac_get_grp_primary(group);
66240dc2366fSVenugopal Iyer 	ASSERT(mcip != NULL);
66256895f6f4SToomas Soome 	ASSERT(mcip->mci_share == 0);
66260dc2366fSVenugopal Iyer 
66270dc2366fSVenugopal Iyer 	mrp = MCIP_RESOURCE_PROPS(mcip);
66280dc2366fSVenugopal Iyer 	if (ring_type == MAC_RING_TYPE_RX) {
66290dc2366fSVenugopal Iyer 		defgrp = mip->mi_rx_donor_grp;
66300dc2366fSVenugopal Iyer 		if ((mrp->mrp_mask & MRP_RX_RINGS) == 0) {
66310dc2366fSVenugopal Iyer 			/* Need to put this mac client in the default group */
66320dc2366fSVenugopal Iyer 			if (mac_rx_switch_group(mcip, group, defgrp) != 0)
66330dc2366fSVenugopal Iyer 				return (ENOSPC);
6634da14cebeSEric Cheng 		} else {
66350dc2366fSVenugopal Iyer 			/*
66360dc2366fSVenugopal Iyer 			 * Switch this ring with some other ring from
66370dc2366fSVenugopal Iyer 			 * the default group.
66380dc2366fSVenugopal Iyer 			 */
66390dc2366fSVenugopal Iyer 			for (tring = defgrp->mrg_rings; tring != NULL;
66400dc2366fSVenugopal Iyer 			    tring = tring->mr_next) {
66410dc2366fSVenugopal Iyer 				if (tring->mr_index == 0)
6642da14cebeSEric Cheng 					continue;
66430dc2366fSVenugopal Iyer 				for (j = 0; j < nrings; j++) {
66440dc2366fSVenugopal Iyer 					if (rings[j] == tring)
6645da14cebeSEric Cheng 						break;
6646da14cebeSEric Cheng 				}
66470dc2366fSVenugopal Iyer 				if (j >= nrings)
664808ac1c49SNicolas Droux 					break;
664908ac1c49SNicolas Droux 			}
66500dc2366fSVenugopal Iyer 			if (tring == NULL)
66510dc2366fSVenugopal Iyer 				return (ENOSPC);
66520dc2366fSVenugopal Iyer 			if (mac_group_mov_ring(mip, group, tring) != 0)
66530dc2366fSVenugopal Iyer 				return (ENOSPC);
66540dc2366fSVenugopal Iyer 			if (mac_group_mov_ring(mip, defgrp, ring) != 0) {
66550dc2366fSVenugopal Iyer 				(void) mac_group_mov_ring(mip, defgrp, tring);
66560dc2366fSVenugopal Iyer 				return (ENOSPC);
66570dc2366fSVenugopal Iyer 			}
66580dc2366fSVenugopal Iyer 		}
66590dc2366fSVenugopal Iyer 		ASSERT(ring->mr_gh == (mac_group_handle_t)defgrp);
66600dc2366fSVenugopal Iyer 		return (0);
66610dc2366fSVenugopal Iyer 	}
6662da14cebeSEric Cheng 
66630dc2366fSVenugopal Iyer 	defgrp = MAC_DEFAULT_TX_GROUP(mip);
66640dc2366fSVenugopal Iyer 	if (ring == (mac_ring_t *)mip->mi_default_tx_ring) {
6665da14cebeSEric Cheng 		/*
66660dc2366fSVenugopal Iyer 		 * See if we can get a spare ring to replace the default
6667da14cebeSEric Cheng 		 * ring.
6668da14cebeSEric Cheng 		 */
66690dc2366fSVenugopal Iyer 		if (defgrp->mrg_cur_count == 1) {
667008ac1c49SNicolas Droux 			/*
66710dc2366fSVenugopal Iyer 			 * Need to get a ring from another client, see if
66720dc2366fSVenugopal Iyer 			 * there are any clients that can be moved to
66730dc2366fSVenugopal Iyer 			 * the default group, thereby freeing some rings.
667408ac1c49SNicolas Droux 			 */
66750dc2366fSVenugopal Iyer 			for (i = 0; i < mip->mi_tx_group_count; i++) {
66760dc2366fSVenugopal Iyer 				tgrp = &mip->mi_tx_groups[i];
66770dc2366fSVenugopal Iyer 				if (tgrp->mrg_state ==
66780dc2366fSVenugopal Iyer 				    MAC_GROUP_STATE_REGISTERED) {
66790dc2366fSVenugopal Iyer 					continue;
66800dc2366fSVenugopal Iyer 				}
66810dc2366fSVenugopal Iyer 				mcip = MAC_GROUP_ONLY_CLIENT(tgrp);
66820dc2366fSVenugopal Iyer 				if (mcip == NULL)
66830dc2366fSVenugopal Iyer 					mcip = mac_get_grp_primary(tgrp);
66840dc2366fSVenugopal Iyer 				ASSERT(mcip != NULL);
66850dc2366fSVenugopal Iyer 				mrp = MCIP_RESOURCE_PROPS(mcip);
66860dc2366fSVenugopal Iyer 				if ((mrp->mrp_mask & MRP_TX_RINGS) == 0) {
66870dc2366fSVenugopal Iyer 					ASSERT(tgrp->mrg_cur_count == 1);
668808ac1c49SNicolas Droux 					/*
66890dc2366fSVenugopal Iyer 					 * If this ring is part of the
66900dc2366fSVenugopal Iyer 					 * rings asked by the share we cannot
66910dc2366fSVenugopal Iyer 					 * use it as the default ring.
669208ac1c49SNicolas Droux 					 */
66930dc2366fSVenugopal Iyer 					for (j = 0; j < nrings; j++) {
66940dc2366fSVenugopal Iyer 						if (rings[j] == tgrp->mrg_rings)
66950dc2366fSVenugopal Iyer 							break;
669608ac1c49SNicolas Droux 					}
66970dc2366fSVenugopal Iyer 					if (j < nrings)
66980dc2366fSVenugopal Iyer 						continue;
66990dc2366fSVenugopal Iyer 					mac_tx_client_quiesce(
67000dc2366fSVenugopal Iyer 					    (mac_client_handle_t)mcip);
67010dc2366fSVenugopal Iyer 					mac_tx_switch_group(mcip, tgrp,
67020dc2366fSVenugopal Iyer 					    defgrp);
67030dc2366fSVenugopal Iyer 					mac_tx_client_restart(
67040dc2366fSVenugopal Iyer 					    (mac_client_handle_t)mcip);
6705da14cebeSEric Cheng 					break;
6706da14cebeSEric Cheng 				}
6707da14cebeSEric Cheng 			}
6708da14cebeSEric Cheng 			/*
67090dc2366fSVenugopal Iyer 			 * All the rings are reserved, can't give up the
67100dc2366fSVenugopal Iyer 			 * default ring.
6711da14cebeSEric Cheng 			 */
67120dc2366fSVenugopal Iyer 			if (defgrp->mrg_cur_count <= 1)
67130dc2366fSVenugopal Iyer 				return (ENOSPC);
67140dc2366fSVenugopal Iyer 		}
67150dc2366fSVenugopal Iyer 		/*
67160dc2366fSVenugopal Iyer 		 * Swap the default ring with another.
67170dc2366fSVenugopal Iyer 		 */
67180dc2366fSVenugopal Iyer 		for (tring = defgrp->mrg_rings; tring != NULL;
67190dc2366fSVenugopal Iyer 		    tring = tring->mr_next) {
67200dc2366fSVenugopal Iyer 			/*
67210dc2366fSVenugopal Iyer 			 * If this ring is part of the rings asked by the
67220dc2366fSVenugopal Iyer 			 * share we cannot use it as the default ring.
67230dc2366fSVenugopal Iyer 			 */
67240dc2366fSVenugopal Iyer 			for (j = 0; j < nrings; j++) {
67250dc2366fSVenugopal Iyer 				if (rings[j] == tring)
67260dc2366fSVenugopal Iyer 					break;
67270dc2366fSVenugopal Iyer 			}
67280dc2366fSVenugopal Iyer 			if (j >= nrings)
67290dc2366fSVenugopal Iyer 				break;
67300dc2366fSVenugopal Iyer 		}
67310dc2366fSVenugopal Iyer 		ASSERT(tring != NULL);
67320dc2366fSVenugopal Iyer 		mip->mi_default_tx_ring = (mac_ring_handle_t)tring;
67330dc2366fSVenugopal Iyer 		return (0);
67340dc2366fSVenugopal Iyer 	}
67350dc2366fSVenugopal Iyer 	/*
67360dc2366fSVenugopal Iyer 	 * The Tx ring is with a group reserved by a MAC client. See if
67370dc2366fSVenugopal Iyer 	 * we can swap it.
67380dc2366fSVenugopal Iyer 	 */
67390dc2366fSVenugopal Iyer 	ASSERT(group->mrg_state == MAC_GROUP_STATE_RESERVED);
67400dc2366fSVenugopal Iyer 	mcip = MAC_GROUP_ONLY_CLIENT(group);
67410dc2366fSVenugopal Iyer 	if (mcip == NULL)
67420dc2366fSVenugopal Iyer 		mcip = mac_get_grp_primary(group);
67430dc2366fSVenugopal Iyer 	ASSERT(mcip !=  NULL);
67440dc2366fSVenugopal Iyer 	mrp = MCIP_RESOURCE_PROPS(mcip);
67450dc2366fSVenugopal Iyer 	mac_tx_client_quiesce((mac_client_handle_t)mcip);
67460dc2366fSVenugopal Iyer 	if ((mrp->mrp_mask & MRP_TX_RINGS) == 0) {
67470dc2366fSVenugopal Iyer 		ASSERT(group->mrg_cur_count == 1);
67480dc2366fSVenugopal Iyer 		/* Put this mac client in the default group */
67490dc2366fSVenugopal Iyer 		mac_tx_switch_group(mcip, group, defgrp);
67500dc2366fSVenugopal Iyer 	} else {
67510dc2366fSVenugopal Iyer 		/*
67520dc2366fSVenugopal Iyer 		 * Switch this ring with some other ring from
67530dc2366fSVenugopal Iyer 		 * the default group.
67540dc2366fSVenugopal Iyer 		 */
67550dc2366fSVenugopal Iyer 		for (tring = defgrp->mrg_rings; tring != NULL;
67560dc2366fSVenugopal Iyer 		    tring = tring->mr_next) {
67570dc2366fSVenugopal Iyer 			if (tring == (mac_ring_t *)mip->mi_default_tx_ring)
67580dc2366fSVenugopal Iyer 				continue;
67590dc2366fSVenugopal Iyer 			/*
67600dc2366fSVenugopal Iyer 			 * If this ring is part of the rings asked by the
67610dc2366fSVenugopal Iyer 			 * share we cannot use it for swapping.
67620dc2366fSVenugopal Iyer 			 */
67630dc2366fSVenugopal Iyer 			for (j = 0; j < nrings; j++) {
67640dc2366fSVenugopal Iyer 				if (rings[j] == tring)
67650dc2366fSVenugopal Iyer 					break;
67660dc2366fSVenugopal Iyer 			}
67670dc2366fSVenugopal Iyer 			if (j >= nrings)
67680dc2366fSVenugopal Iyer 				break;
67690dc2366fSVenugopal Iyer 		}
67700dc2366fSVenugopal Iyer 		if (tring == NULL) {
67710dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)mcip);
67720dc2366fSVenugopal Iyer 			return (ENOSPC);
67730dc2366fSVenugopal Iyer 		}
67740dc2366fSVenugopal Iyer 		if (mac_group_mov_ring(mip, group, tring) != 0) {
67750dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)mcip);
67760dc2366fSVenugopal Iyer 			return (ENOSPC);
67770dc2366fSVenugopal Iyer 		}
67780dc2366fSVenugopal Iyer 		if (mac_group_mov_ring(mip, defgrp, ring) != 0) {
67790dc2366fSVenugopal Iyer 			(void) mac_group_mov_ring(mip, defgrp, tring);
67800dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)mcip);
67810dc2366fSVenugopal Iyer 			return (ENOSPC);
67820dc2366fSVenugopal Iyer 		}
67830dc2366fSVenugopal Iyer 	}
67840dc2366fSVenugopal Iyer 	mac_tx_client_restart((mac_client_handle_t)mcip);
67850dc2366fSVenugopal Iyer 	ASSERT(ring->mr_gh == (mac_group_handle_t)defgrp);
67860dc2366fSVenugopal Iyer 	return (0);
67870dc2366fSVenugopal Iyer }
6788da14cebeSEric Cheng 
6789da14cebeSEric Cheng /*
6790da14cebeSEric Cheng  * Populate a zero-ring group with rings. If the share is non-NULL,
6791da14cebeSEric Cheng  * the rings are chosen according to that share.
6792da14cebeSEric Cheng  * Invoked after allocating a new RX or TX group through
6793da14cebeSEric Cheng  * mac_reserve_rx_group() or mac_reserve_tx_group(), respectively.
6794da14cebeSEric Cheng  * Returns zero on success, an errno otherwise.
6795da14cebeSEric Cheng  */
6796da14cebeSEric Cheng int
i_mac_group_allocate_rings(mac_impl_t * mip,mac_ring_type_t ring_type,mac_group_t * src_group,mac_group_t * new_group,mac_share_handle_t share,uint32_t ringcnt)6797da14cebeSEric Cheng i_mac_group_allocate_rings(mac_impl_t *mip, mac_ring_type_t ring_type,
67980dc2366fSVenugopal Iyer     mac_group_t *src_group, mac_group_t *new_group, mac_share_handle_t share,
67990dc2366fSVenugopal Iyer     uint32_t ringcnt)
6800da14cebeSEric Cheng {
68010dc2366fSVenugopal Iyer 	mac_ring_t **rings, *ring;
6802da14cebeSEric Cheng 	uint_t nrings;
68030dc2366fSVenugopal Iyer 	int rv = 0, i = 0, j;
6804da14cebeSEric Cheng 
68050dc2366fSVenugopal Iyer 	ASSERT((ring_type == MAC_RING_TYPE_RX &&
68060dc2366fSVenugopal Iyer 	    mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) ||
68070dc2366fSVenugopal Iyer 	    (ring_type == MAC_RING_TYPE_TX &&
68080dc2366fSVenugopal Iyer 	    mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC));
6809da14cebeSEric Cheng 
6810da14cebeSEric Cheng 	/*
6811da14cebeSEric Cheng 	 * First find the rings to allocate to the group.
6812da14cebeSEric Cheng 	 */
681336f99a58SToomas Soome 	if (share != 0) {
6814da14cebeSEric Cheng 		/* get rings through ms_squery() */
6815da14cebeSEric Cheng 		mip->mi_share_capab.ms_squery(share, ring_type, NULL, &nrings);
6816da14cebeSEric Cheng 		ASSERT(nrings != 0);
6817da14cebeSEric Cheng 		rings = kmem_alloc(nrings * sizeof (mac_ring_handle_t),
6818da14cebeSEric Cheng 		    KM_SLEEP);
6819da14cebeSEric Cheng 		mip->mi_share_capab.ms_squery(share, ring_type,
6820da14cebeSEric Cheng 		    (mac_ring_handle_t *)rings, &nrings);
68210dc2366fSVenugopal Iyer 		for (i = 0; i < nrings; i++) {
68220dc2366fSVenugopal Iyer 			/*
68230dc2366fSVenugopal Iyer 			 * If we have given this ring to a non-default
68240dc2366fSVenugopal Iyer 			 * group, we need to check if we can get this
68250dc2366fSVenugopal Iyer 			 * ring.
68260dc2366fSVenugopal Iyer 			 */
68270dc2366fSVenugopal Iyer 			ring = rings[i];
68280dc2366fSVenugopal Iyer 			if (ring->mr_gh != (mac_group_handle_t)src_group ||
68290dc2366fSVenugopal Iyer 			    ring == (mac_ring_t *)mip->mi_default_tx_ring) {
68300dc2366fSVenugopal Iyer 				if (mac_reclaim_ring_from_grp(mip, ring_type,
68310dc2366fSVenugopal Iyer 				    ring, rings, nrings) != 0) {
68320dc2366fSVenugopal Iyer 					rv = ENOSPC;
68330dc2366fSVenugopal Iyer 					goto bail;
68340dc2366fSVenugopal Iyer 				}
68350dc2366fSVenugopal Iyer 			}
68360dc2366fSVenugopal Iyer 		}
6837da14cebeSEric Cheng 	} else {
6838da14cebeSEric Cheng 		/*
6839da14cebeSEric Cheng 		 * Pick one ring from default group.
6840da14cebeSEric Cheng 		 *
6841da14cebeSEric Cheng 		 * for now pick the second ring which requires the first ring
6842da14cebeSEric Cheng 		 * at index 0 to stay in the default group, since it is the
6843da14cebeSEric Cheng 		 * ring which carries the multicast traffic.
6844da14cebeSEric Cheng 		 * We need a better way for a driver to indicate this,
6845da14cebeSEric Cheng 		 * for example a per-ring flag.
6846da14cebeSEric Cheng 		 */
68470dc2366fSVenugopal Iyer 		rings = kmem_alloc(ringcnt * sizeof (mac_ring_handle_t),
68480dc2366fSVenugopal Iyer 		    KM_SLEEP);
6849da14cebeSEric Cheng 		for (ring = src_group->mrg_rings; ring != NULL;
6850da14cebeSEric Cheng 		    ring = ring->mr_next) {
68510dc2366fSVenugopal Iyer 			if (ring_type == MAC_RING_TYPE_RX &&
68520dc2366fSVenugopal Iyer 			    ring->mr_index == 0) {
68530dc2366fSVenugopal Iyer 				continue;
68540dc2366fSVenugopal Iyer 			}
68550dc2366fSVenugopal Iyer 			if (ring_type == MAC_RING_TYPE_TX &&
68560dc2366fSVenugopal Iyer 			    ring == (mac_ring_t *)mip->mi_default_tx_ring) {
68570dc2366fSVenugopal Iyer 				continue;
68580dc2366fSVenugopal Iyer 			}
68590dc2366fSVenugopal Iyer 			rings[i++] = ring;
68600dc2366fSVenugopal Iyer 			if (i == ringcnt)
6861da14cebeSEric Cheng 				break;
6862da14cebeSEric Cheng 		}
6863da14cebeSEric Cheng 		ASSERT(ring != NULL);
68640dc2366fSVenugopal Iyer 		nrings = i;
68650dc2366fSVenugopal Iyer 		/* Not enough rings as required */
68660dc2366fSVenugopal Iyer 		if (nrings != ringcnt) {
68670dc2366fSVenugopal Iyer 			rv = ENOSPC;
68680dc2366fSVenugopal Iyer 			goto bail;
68690dc2366fSVenugopal Iyer 		}
6870da14cebeSEric Cheng 	}
6871da14cebeSEric Cheng 
6872da14cebeSEric Cheng 	switch (ring_type) {
6873da14cebeSEric Cheng 	case MAC_RING_TYPE_RX:
68740dc2366fSVenugopal Iyer 		if (src_group->mrg_cur_count - nrings < 1) {
6875da14cebeSEric Cheng 			/* we ran out of rings */
68760dc2366fSVenugopal Iyer 			rv = ENOSPC;
68770dc2366fSVenugopal Iyer 			goto bail;
6878da14cebeSEric Cheng 		}
6879da14cebeSEric Cheng 
6880da14cebeSEric Cheng 		/* move receive rings to new group */
6881da14cebeSEric Cheng 		for (i = 0; i < nrings; i++) {
6882da14cebeSEric Cheng 			rv = mac_group_mov_ring(mip, new_group, rings[i]);
6883da14cebeSEric Cheng 			if (rv != 0) {
6884da14cebeSEric Cheng 				/* move rings back on failure */
6885da14cebeSEric Cheng 				for (j = 0; j < i; j++) {
6886da14cebeSEric Cheng 					(void) mac_group_mov_ring(mip,
6887da14cebeSEric Cheng 					    src_group, rings[j]);
6888da14cebeSEric Cheng 				}
68890dc2366fSVenugopal Iyer 				goto bail;
6890da14cebeSEric Cheng 			}
6891da14cebeSEric Cheng 		}
6892da14cebeSEric Cheng 		break;
6893da14cebeSEric Cheng 
6894da14cebeSEric Cheng 	case MAC_RING_TYPE_TX: {
6895da14cebeSEric Cheng 		mac_ring_t *tmp_ring;
6896da14cebeSEric Cheng 
6897da14cebeSEric Cheng 		/* move the TX rings to the new group */
6898da14cebeSEric Cheng 		for (i = 0; i < nrings; i++) {
6899da14cebeSEric Cheng 			/* get the desired ring */
6900da14cebeSEric Cheng 			tmp_ring = mac_reserve_tx_ring(mip, rings[i]);
69010dc2366fSVenugopal Iyer 			if (tmp_ring == NULL) {
69020dc2366fSVenugopal Iyer 				rv = ENOSPC;
69030dc2366fSVenugopal Iyer 				goto bail;
69040dc2366fSVenugopal Iyer 			}
6905da14cebeSEric Cheng 			ASSERT(tmp_ring == rings[i]);
6906da14cebeSEric Cheng 			rv = mac_group_mov_ring(mip, new_group, rings[i]);
6907da14cebeSEric Cheng 			if (rv != 0) {
6908da14cebeSEric Cheng 				/* cleanup on failure */
6909da14cebeSEric Cheng 				for (j = 0; j < i; j++) {
6910da14cebeSEric Cheng 					(void) mac_group_mov_ring(mip,
69110dc2366fSVenugopal Iyer 					    MAC_DEFAULT_TX_GROUP(mip),
69120dc2366fSVenugopal Iyer 					    rings[j]);
6913da14cebeSEric Cheng 				}
69140dc2366fSVenugopal Iyer 				goto bail;
6915da14cebeSEric Cheng 			}
6916da14cebeSEric Cheng 		}
6917da14cebeSEric Cheng 		break;
6918da14cebeSEric Cheng 	}
6919da14cebeSEric Cheng 	}
6920da14cebeSEric Cheng 
6921da14cebeSEric Cheng 	/* add group to share */
692236f99a58SToomas Soome 	if (share != 0)
6923da14cebeSEric Cheng 		mip->mi_share_capab.ms_sadd(share, new_group->mrg_driver);
69240dc2366fSVenugopal Iyer 
69250dc2366fSVenugopal Iyer bail:
6926da14cebeSEric Cheng 	/* free temporary array of rings */
6927da14cebeSEric Cheng 	kmem_free(rings, nrings * sizeof (mac_ring_handle_t));
6928da14cebeSEric Cheng 
69290dc2366fSVenugopal Iyer 	return (rv);
6930da14cebeSEric Cheng }
6931da14cebeSEric Cheng 
6932da14cebeSEric Cheng void
mac_group_add_client(mac_group_t * grp,mac_client_impl_t * mcip)69330dc2366fSVenugopal Iyer mac_group_add_client(mac_group_t *grp, mac_client_impl_t *mcip)
6934da14cebeSEric Cheng {
6935da14cebeSEric Cheng 	mac_grp_client_t *mgcp;
6936da14cebeSEric Cheng 
6937da14cebeSEric Cheng 	for (mgcp = grp->mrg_clients; mgcp != NULL; mgcp = mgcp->mgc_next) {
6938da14cebeSEric Cheng 		if (mgcp->mgc_client == mcip)
6939da14cebeSEric Cheng 			break;
6940da14cebeSEric Cheng 	}
6941da14cebeSEric Cheng 
694284de666eSRyan Zezeski 	ASSERT(mgcp == NULL);
6943da14cebeSEric Cheng 
6944da14cebeSEric Cheng 	mgcp = kmem_zalloc(sizeof (mac_grp_client_t), KM_SLEEP);
6945da14cebeSEric Cheng 	mgcp->mgc_client = mcip;
6946da14cebeSEric Cheng 	mgcp->mgc_next = grp->mrg_clients;
6947da14cebeSEric Cheng 	grp->mrg_clients = mgcp;
6948da14cebeSEric Cheng }
6949da14cebeSEric Cheng 
6950da14cebeSEric Cheng void
mac_group_remove_client(mac_group_t * grp,mac_client_impl_t * mcip)69510dc2366fSVenugopal Iyer mac_group_remove_client(mac_group_t *grp, mac_client_impl_t *mcip)
6952da14cebeSEric Cheng {
6953da14cebeSEric Cheng 	mac_grp_client_t *mgcp, **pprev;
6954da14cebeSEric Cheng 
6955da14cebeSEric Cheng 	for (pprev = &grp->mrg_clients, mgcp = *pprev; mgcp != NULL;
6956da14cebeSEric Cheng 	    pprev = &mgcp->mgc_next, mgcp = *pprev) {
6957da14cebeSEric Cheng 		if (mgcp->mgc_client == mcip)
6958da14cebeSEric Cheng 			break;
6959da14cebeSEric Cheng 	}
6960da14cebeSEric Cheng 
6961da14cebeSEric Cheng 	ASSERT(mgcp != NULL);
6962da14cebeSEric Cheng 
6963da14cebeSEric Cheng 	*pprev = mgcp->mgc_next;
6964da14cebeSEric Cheng 	kmem_free(mgcp, sizeof (mac_grp_client_t));
6965da14cebeSEric Cheng }
6966da14cebeSEric Cheng 
6967da14cebeSEric Cheng /*
696884de666eSRyan Zezeski  * Return true if any client on this group explicitly asked for HW
696984de666eSRyan Zezeski  * rings (of type mask) or have a bound share.
697084de666eSRyan Zezeski  */
697184de666eSRyan Zezeski static boolean_t
i_mac_clients_hw(mac_group_t * grp,uint32_t mask)697284de666eSRyan Zezeski i_mac_clients_hw(mac_group_t *grp, uint32_t mask)
697384de666eSRyan Zezeski {
697484de666eSRyan Zezeski 	mac_grp_client_t	*mgcip;
697584de666eSRyan Zezeski 	mac_client_impl_t	*mcip;
697684de666eSRyan Zezeski 	mac_resource_props_t	*mrp;
697784de666eSRyan Zezeski 
697884de666eSRyan Zezeski 	for (mgcip = grp->mrg_clients; mgcip != NULL; mgcip = mgcip->mgc_next) {
697984de666eSRyan Zezeski 		mcip = mgcip->mgc_client;
698084de666eSRyan Zezeski 		mrp = MCIP_RESOURCE_PROPS(mcip);
698184de666eSRyan Zezeski 		if (mcip->mci_share != 0 || (mrp->mrp_mask & mask) != 0)
698284de666eSRyan Zezeski 			return (B_TRUE);
698384de666eSRyan Zezeski 	}
698484de666eSRyan Zezeski 
698584de666eSRyan Zezeski 	return (B_FALSE);
698684de666eSRyan Zezeski }
698784de666eSRyan Zezeski 
698884de666eSRyan Zezeski /*
6989da14cebeSEric Cheng  * Finds an available group and exclusively reserves it for a client.
6990da14cebeSEric Cheng  * The group is chosen to suit the flow's resource controls (bandwidth and
6991da14cebeSEric Cheng  * fanout requirements) and the address type.
6992da14cebeSEric Cheng  * If the requestor is the pimary MAC then return the group with the
6993da14cebeSEric Cheng  * largest number of rings, otherwise the default ring when available.
6994da14cebeSEric Cheng  */
6995da14cebeSEric Cheng mac_group_t *
mac_reserve_rx_group(mac_client_impl_t * mcip,uint8_t * mac_addr,boolean_t move)69960dc2366fSVenugopal Iyer mac_reserve_rx_group(mac_client_impl_t *mcip, uint8_t *mac_addr, boolean_t move)
6997da14cebeSEric Cheng {
6998da14cebeSEric Cheng 	mac_share_handle_t	share = mcip->mci_share;
6999da14cebeSEric Cheng 	mac_impl_t		*mip = mcip->mci_mip;
7000da14cebeSEric Cheng 	mac_group_t		*grp = NULL;
70010dc2366fSVenugopal Iyer 	int			i;
70020dc2366fSVenugopal Iyer 	int			err = 0;
7003da14cebeSEric Cheng 	mac_address_t		*map;
70040dc2366fSVenugopal Iyer 	mac_resource_props_t	*mrp = MCIP_RESOURCE_PROPS(mcip);
70050dc2366fSVenugopal Iyer 	int			nrings;
70060dc2366fSVenugopal Iyer 	int			donor_grp_rcnt;
70070dc2366fSVenugopal Iyer 	boolean_t		need_exclgrp = B_FALSE;
70080dc2366fSVenugopal Iyer 	int			need_rings = 0;
70090dc2366fSVenugopal Iyer 	mac_group_t		*candidate_grp = NULL;
70100dc2366fSVenugopal Iyer 	mac_client_impl_t	*gclient;
70110dc2366fSVenugopal Iyer 	mac_group_t		*donorgrp = NULL;
70120dc2366fSVenugopal Iyer 	boolean_t		rxhw = mrp->mrp_mask & MRP_RX_RINGS;
70130dc2366fSVenugopal Iyer 	boolean_t		unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC;
70140dc2366fSVenugopal Iyer 	boolean_t		isprimary;
7015da14cebeSEric Cheng 
7016da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
7017da14cebeSEric Cheng 
70180dc2366fSVenugopal Iyer 	isprimary = mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC;
7019da14cebeSEric Cheng 
70200dc2366fSVenugopal Iyer 	/*
702184de666eSRyan Zezeski 	 * Check if a group already has this MAC address (case of VLANs)
70220dc2366fSVenugopal Iyer 	 * unless we are moving this MAC client from one group to another.
70230dc2366fSVenugopal Iyer 	 */
70240dc2366fSVenugopal Iyer 	if (!move && (map = mac_find_macaddr(mip, mac_addr)) != NULL) {
70250dc2366fSVenugopal Iyer 		if (map->ma_group != NULL)
70260dc2366fSVenugopal Iyer 			return (map->ma_group);
70270dc2366fSVenugopal Iyer 	}
702884de666eSRyan Zezeski 
70290dc2366fSVenugopal Iyer 	if (mip->mi_rx_groups == NULL || mip->mi_rx_group_count == 0)
7030da14cebeSEric Cheng 		return (NULL);
703184de666eSRyan Zezeski 
70320dc2366fSVenugopal Iyer 	/*
703384de666eSRyan Zezeski 	 * If this client is requesting exclusive MAC access then
703484de666eSRyan Zezeski 	 * return NULL to ensure the client uses the default group.
70350dc2366fSVenugopal Iyer 	 */
70360dc2366fSVenugopal Iyer 	if (mcip->mci_state_flags & MCIS_EXCLUSIVE)
70370dc2366fSVenugopal Iyer 		return (NULL);
70380dc2366fSVenugopal Iyer 
70390dc2366fSVenugopal Iyer 	/* For dynamic groups default unspecified to 1 */
70400dc2366fSVenugopal Iyer 	if (rxhw && unspec &&
70410dc2366fSVenugopal Iyer 	    mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
70420dc2366fSVenugopal Iyer 		mrp->mrp_nrxrings = 1;
70430dc2366fSVenugopal Iyer 	}
704484de666eSRyan Zezeski 
70450dc2366fSVenugopal Iyer 	/*
70460dc2366fSVenugopal Iyer 	 * For static grouping we allow only specifying rings=0 and
70470dc2366fSVenugopal Iyer 	 * unspecified
70480dc2366fSVenugopal Iyer 	 */
70490dc2366fSVenugopal Iyer 	if (rxhw && mrp->mrp_nrxrings > 0 &&
70500dc2366fSVenugopal Iyer 	    mip->mi_rx_group_type == MAC_GROUP_TYPE_STATIC) {
70510dc2366fSVenugopal Iyer 		return (NULL);
70520dc2366fSVenugopal Iyer 	}
705384de666eSRyan Zezeski 
70540dc2366fSVenugopal Iyer 	if (rxhw) {
70550dc2366fSVenugopal Iyer 		/*
70560dc2366fSVenugopal Iyer 		 * We have explicitly asked for a group (with nrxrings,
70570dc2366fSVenugopal Iyer 		 * if unspec).
70580dc2366fSVenugopal Iyer 		 */
70590dc2366fSVenugopal Iyer 		if (unspec || mrp->mrp_nrxrings > 0) {
70600dc2366fSVenugopal Iyer 			need_exclgrp = B_TRUE;
70610dc2366fSVenugopal Iyer 			need_rings = mrp->mrp_nrxrings;
70620dc2366fSVenugopal Iyer 		} else if (mrp->mrp_nrxrings == 0) {
70630dc2366fSVenugopal Iyer 			/*
70640dc2366fSVenugopal Iyer 			 * We have asked for a software group.
70650dc2366fSVenugopal Iyer 			 */
70660dc2366fSVenugopal Iyer 			return (NULL);
70670dc2366fSVenugopal Iyer 		}
70680dc2366fSVenugopal Iyer 	} else if (isprimary && mip->mi_nactiveclients == 1 &&
70690dc2366fSVenugopal Iyer 	    mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
70700dc2366fSVenugopal Iyer 		/*
70710dc2366fSVenugopal Iyer 		 * If the primary is the only active client on this
70720dc2366fSVenugopal Iyer 		 * mip and we have not asked for any rings, we give
70730dc2366fSVenugopal Iyer 		 * it the default group so that the primary gets to
70740dc2366fSVenugopal Iyer 		 * use all the rings.
70750dc2366fSVenugopal Iyer 		 */
70760dc2366fSVenugopal Iyer 		return (NULL);
70770dc2366fSVenugopal Iyer 	}
70780dc2366fSVenugopal Iyer 
70790dc2366fSVenugopal Iyer 	/* The group that can donate rings */
70800dc2366fSVenugopal Iyer 	donorgrp = mip->mi_rx_donor_grp;
70810dc2366fSVenugopal Iyer 
70820dc2366fSVenugopal Iyer 	/*
70830dc2366fSVenugopal Iyer 	 * The number of rings that the default group can donate.
70840dc2366fSVenugopal Iyer 	 * We need to leave at least one ring.
70850dc2366fSVenugopal Iyer 	 */
70860dc2366fSVenugopal Iyer 	donor_grp_rcnt = donorgrp->mrg_cur_count - 1;
7087da14cebeSEric Cheng 
7088da14cebeSEric Cheng 	/*
7089da14cebeSEric Cheng 	 * Try to exclusively reserve a RX group.
7090da14cebeSEric Cheng 	 *
70910dc2366fSVenugopal Iyer 	 * For flows requiring HW_DEFAULT_RING (unicast flow of the primary
70920dc2366fSVenugopal Iyer 	 * client), try to reserve the a non-default RX group and give
70930dc2366fSVenugopal Iyer 	 * it all the rings from the donor group, except the default ring
7094da14cebeSEric Cheng 	 *
70950dc2366fSVenugopal Iyer 	 * For flows requiring HW_RING (unicast flow of other clients), try
70960dc2366fSVenugopal Iyer 	 * to reserve non-default RX group with the specified number of
70970dc2366fSVenugopal Iyer 	 * rings, if available.
7098da14cebeSEric Cheng 	 *
70990dc2366fSVenugopal Iyer 	 * For flows that have not asked for software or hardware ring,
71000dc2366fSVenugopal Iyer 	 * try to reserve a non-default group with 1 ring, if available.
7101da14cebeSEric Cheng 	 */
71020dc2366fSVenugopal Iyer 	for (i = 1; i < mip->mi_rx_group_count; i++) {
71030dc2366fSVenugopal Iyer 		grp = &mip->mi_rx_groups[i];
7104da14cebeSEric Cheng 
7105da14cebeSEric Cheng 		DTRACE_PROBE3(rx__group__trying, char *, mip->mi_name,
7106da14cebeSEric Cheng 		    int, grp->mrg_index, mac_group_state_t, grp->mrg_state);
7107da14cebeSEric Cheng 
7108da14cebeSEric Cheng 		/*
71090dc2366fSVenugopal Iyer 		 * Check if this group could be a candidate group for
71100dc2366fSVenugopal Iyer 		 * eviction if we need a group for this MAC client,
71110dc2366fSVenugopal Iyer 		 * but there aren't any. A candidate group is one
71120dc2366fSVenugopal Iyer 		 * that didn't ask for an exclusive group, but got
71130dc2366fSVenugopal Iyer 		 * one and it has enough rings (combined with what
71140dc2366fSVenugopal Iyer 		 * the donor group can donate) for the new MAC
711584de666eSRyan Zezeski 		 * client.
7116da14cebeSEric Cheng 		 */
71170dc2366fSVenugopal Iyer 		if (grp->mrg_state >= MAC_GROUP_STATE_RESERVED) {
71180dc2366fSVenugopal Iyer 			/*
711984de666eSRyan Zezeski 			 * If the donor group is not the default
712084de666eSRyan Zezeski 			 * group, don't bother looking for a candidate
712184de666eSRyan Zezeski 			 * group. If we don't have enough rings we
712284de666eSRyan Zezeski 			 * will check if the primary group can be
712384de666eSRyan Zezeski 			 * vacated.
71240dc2366fSVenugopal Iyer 			 */
71250dc2366fSVenugopal Iyer 			if (candidate_grp == NULL &&
71260dc2366fSVenugopal Iyer 			    donorgrp == MAC_DEFAULT_RX_GROUP(mip)) {
712784de666eSRyan Zezeski 				if (!i_mac_clients_hw(grp, MRP_RX_RINGS) &&
71280dc2366fSVenugopal Iyer 				    (unspec ||
71290dc2366fSVenugopal Iyer 				    (grp->mrg_cur_count + donor_grp_rcnt >=
71300dc2366fSVenugopal Iyer 				    need_rings))) {
71310dc2366fSVenugopal Iyer 					candidate_grp = grp;
71320dc2366fSVenugopal Iyer 				}
71330dc2366fSVenugopal Iyer 			}
7134da14cebeSEric Cheng 			continue;
7135da14cebeSEric Cheng 		}
7136da14cebeSEric Cheng 		/*
7137da14cebeSEric Cheng 		 * This group could already be SHARED by other multicast
7138da14cebeSEric Cheng 		 * flows on this client. In that case, the group would
7139da14cebeSEric Cheng 		 * be shared and has already been started.
7140da14cebeSEric Cheng 		 */
7141da14cebeSEric Cheng 		ASSERT(grp->mrg_state != MAC_GROUP_STATE_UNINIT);
7142da14cebeSEric Cheng 
7143da14cebeSEric Cheng 		if ((grp->mrg_state == MAC_GROUP_STATE_REGISTERED) &&
7144da14cebeSEric Cheng 		    (mac_start_group(grp) != 0)) {
7145da14cebeSEric Cheng 			continue;
7146da14cebeSEric Cheng 		}
7147da14cebeSEric Cheng 
71480dc2366fSVenugopal Iyer 		if (mip->mi_rx_group_type != MAC_GROUP_TYPE_DYNAMIC)
7149da14cebeSEric Cheng 			break;
7150da14cebeSEric Cheng 		ASSERT(grp->mrg_cur_count == 0);
7151da14cebeSEric Cheng 
7152da14cebeSEric Cheng 		/*
7153da14cebeSEric Cheng 		 * Populate the group. Rings should be taken
71540dc2366fSVenugopal Iyer 		 * from the donor group.
7155da14cebeSEric Cheng 		 */
71560dc2366fSVenugopal Iyer 		nrings = rxhw ? need_rings : isprimary ? donor_grp_rcnt: 1;
7157da14cebeSEric Cheng 
71580dc2366fSVenugopal Iyer 		/*
71590dc2366fSVenugopal Iyer 		 * If the donor group can't donate, let's just walk and
71600dc2366fSVenugopal Iyer 		 * see if someone can vacate a group, so that we have
71610dc2366fSVenugopal Iyer 		 * enough rings for this, unless we already have
71620dc2366fSVenugopal Iyer 		 * identified a candiate group..
71630dc2366fSVenugopal Iyer 		 */
71640dc2366fSVenugopal Iyer 		if (nrings <= donor_grp_rcnt) {
7165da14cebeSEric Cheng 			err = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_RX,
71660dc2366fSVenugopal Iyer 			    donorgrp, grp, share, nrings);
71670dc2366fSVenugopal Iyer 			if (err == 0) {
71680dc2366fSVenugopal Iyer 				/*
71690dc2366fSVenugopal Iyer 				 * For a share i_mac_group_allocate_rings gets
71700dc2366fSVenugopal Iyer 				 * the rings from the driver, let's populate
71710dc2366fSVenugopal Iyer 				 * the property for the client now.
71720dc2366fSVenugopal Iyer 				 */
717336f99a58SToomas Soome 				if (share != 0) {
71740dc2366fSVenugopal Iyer 					mac_client_set_rings(
71750dc2366fSVenugopal Iyer 					    (mac_client_handle_t)mcip,
71760dc2366fSVenugopal Iyer 					    grp->mrg_cur_count, -1);
71770dc2366fSVenugopal Iyer 				}
71780dc2366fSVenugopal Iyer 				if (mac_is_primary_client(mcip) && !rxhw)
71790dc2366fSVenugopal Iyer 					mip->mi_rx_donor_grp = grp;
7180da14cebeSEric Cheng 				break;
71810dc2366fSVenugopal Iyer 			}
71820dc2366fSVenugopal Iyer 		}
7183da14cebeSEric Cheng 
7184da14cebeSEric Cheng 		DTRACE_PROBE3(rx__group__reserve__alloc__rings, char *,
7185da14cebeSEric Cheng 		    mip->mi_name, int, grp->mrg_index, int, err);
7186da14cebeSEric Cheng 
7187da14cebeSEric Cheng 		/*
71880dc2366fSVenugopal Iyer 		 * It's a dynamic group but the grouping operation
71890dc2366fSVenugopal Iyer 		 * failed.
7190da14cebeSEric Cheng 		 */
7191da14cebeSEric Cheng 		mac_stop_group(grp);
7192da14cebeSEric Cheng 	}
719384de666eSRyan Zezeski 
71940dc2366fSVenugopal Iyer 	/* We didn't find an exclusive group for this MAC client */
71950dc2366fSVenugopal Iyer 	if (i >= mip->mi_rx_group_count) {
7196da14cebeSEric Cheng 
71970dc2366fSVenugopal Iyer 		if (!need_exclgrp)
7198da14cebeSEric Cheng 			return (NULL);
7199da14cebeSEric Cheng 
72000dc2366fSVenugopal Iyer 		/*
720184de666eSRyan Zezeski 		 * If we found a candidate group then move the
720284de666eSRyan Zezeski 		 * existing MAC client from the candidate_group to the
720384de666eSRyan Zezeski 		 * default group and give the candidate_group to the
720484de666eSRyan Zezeski 		 * new MAC client. If we didn't find a candidate
720584de666eSRyan Zezeski 		 * group, then check if the primary is in its own
720684de666eSRyan Zezeski 		 * group and if it can make way for this MAC client.
72070dc2366fSVenugopal Iyer 		 */
72080dc2366fSVenugopal Iyer 		if (candidate_grp == NULL &&
72090dc2366fSVenugopal Iyer 		    donorgrp != MAC_DEFAULT_RX_GROUP(mip) &&
72100dc2366fSVenugopal Iyer 		    donorgrp->mrg_cur_count >= need_rings) {
72110dc2366fSVenugopal Iyer 			candidate_grp = donorgrp;
72120dc2366fSVenugopal Iyer 		}
72130dc2366fSVenugopal Iyer 		if (candidate_grp != NULL) {
72140dc2366fSVenugopal Iyer 			boolean_t	prim_grp = B_FALSE;
72150dc2366fSVenugopal Iyer 
72160dc2366fSVenugopal Iyer 			/*
721784de666eSRyan Zezeski 			 * Switch the existing MAC client from the
721884de666eSRyan Zezeski 			 * candidate group to the default group. If
721984de666eSRyan Zezeski 			 * the candidate group is the donor group,
722084de666eSRyan Zezeski 			 * then after the switch we need to update the
722184de666eSRyan Zezeski 			 * donor group too.
72220dc2366fSVenugopal Iyer 			 */
72230dc2366fSVenugopal Iyer 			grp = candidate_grp;
722484de666eSRyan Zezeski 			gclient = grp->mrg_clients->mgc_client;
722584de666eSRyan Zezeski 			VERIFY3P(gclient, !=, NULL);
72260dc2366fSVenugopal Iyer 			if (grp == mip->mi_rx_donor_grp)
72270dc2366fSVenugopal Iyer 				prim_grp = B_TRUE;
72280dc2366fSVenugopal Iyer 			if (mac_rx_switch_group(gclient, grp,
72290dc2366fSVenugopal Iyer 			    MAC_DEFAULT_RX_GROUP(mip)) != 0) {
72300dc2366fSVenugopal Iyer 				return (NULL);
72310dc2366fSVenugopal Iyer 			}
72320dc2366fSVenugopal Iyer 			if (prim_grp) {
72330dc2366fSVenugopal Iyer 				mip->mi_rx_donor_grp =
72340dc2366fSVenugopal Iyer 				    MAC_DEFAULT_RX_GROUP(mip);
72350dc2366fSVenugopal Iyer 				donorgrp = MAC_DEFAULT_RX_GROUP(mip);
72360dc2366fSVenugopal Iyer 			}
72370dc2366fSVenugopal Iyer 
72380dc2366fSVenugopal Iyer 			/*
72390dc2366fSVenugopal Iyer 			 * Now give this group with the required rings
72400dc2366fSVenugopal Iyer 			 * to this MAC client.
72410dc2366fSVenugopal Iyer 			 */
72420dc2366fSVenugopal Iyer 			ASSERT(grp->mrg_state == MAC_GROUP_STATE_REGISTERED);
72430dc2366fSVenugopal Iyer 			if (mac_start_group(grp) != 0)
72440dc2366fSVenugopal Iyer 				return (NULL);
72450dc2366fSVenugopal Iyer 
72460dc2366fSVenugopal Iyer 			if (mip->mi_rx_group_type != MAC_GROUP_TYPE_DYNAMIC)
72470dc2366fSVenugopal Iyer 				return (grp);
72480dc2366fSVenugopal Iyer 
72490dc2366fSVenugopal Iyer 			donor_grp_rcnt = donorgrp->mrg_cur_count - 1;
72500dc2366fSVenugopal Iyer 			ASSERT(grp->mrg_cur_count == 0);
72510dc2366fSVenugopal Iyer 			ASSERT(donor_grp_rcnt >= need_rings);
72520dc2366fSVenugopal Iyer 			err = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_RX,
72530dc2366fSVenugopal Iyer 			    donorgrp, grp, share, need_rings);
72540dc2366fSVenugopal Iyer 			if (err == 0) {
72550dc2366fSVenugopal Iyer 				/*
72560dc2366fSVenugopal Iyer 				 * For a share i_mac_group_allocate_rings gets
72570dc2366fSVenugopal Iyer 				 * the rings from the driver, let's populate
72580dc2366fSVenugopal Iyer 				 * the property for the client now.
72590dc2366fSVenugopal Iyer 				 */
726036f99a58SToomas Soome 				if (share != 0) {
72610dc2366fSVenugopal Iyer 					mac_client_set_rings(
72620dc2366fSVenugopal Iyer 					    (mac_client_handle_t)mcip,
72630dc2366fSVenugopal Iyer 					    grp->mrg_cur_count, -1);
72640dc2366fSVenugopal Iyer 				}
72650dc2366fSVenugopal Iyer 				DTRACE_PROBE2(rx__group__reserved,
72660dc2366fSVenugopal Iyer 				    char *, mip->mi_name, int, grp->mrg_index);
72670dc2366fSVenugopal Iyer 				return (grp);
72680dc2366fSVenugopal Iyer 			}
72690dc2366fSVenugopal Iyer 			DTRACE_PROBE3(rx__group__reserve__alloc__rings, char *,
72700dc2366fSVenugopal Iyer 			    mip->mi_name, int, grp->mrg_index, int, err);
72710dc2366fSVenugopal Iyer 			mac_stop_group(grp);
72720dc2366fSVenugopal Iyer 		}
72730dc2366fSVenugopal Iyer 		return (NULL);
72740dc2366fSVenugopal Iyer 	}
7275da14cebeSEric Cheng 	ASSERT(grp != NULL);
7276da14cebeSEric Cheng 
7277da14cebeSEric Cheng 	DTRACE_PROBE2(rx__group__reserved,
7278da14cebeSEric Cheng 	    char *, mip->mi_name, int, grp->mrg_index);
7279da14cebeSEric Cheng 	return (grp);
7280da14cebeSEric Cheng }
7281da14cebeSEric Cheng 
7282da14cebeSEric Cheng /*
7283da14cebeSEric Cheng  * mac_rx_release_group()
7284da14cebeSEric Cheng  *
728584de666eSRyan Zezeski  * Release the group when it has no remaining clients. The group is
728684de666eSRyan Zezeski  * stopped and its shares are removed and all rings are assigned back
728784de666eSRyan Zezeski  * to default group. This should never be called against the default
728884de666eSRyan Zezeski  * group.
7289da14cebeSEric Cheng  */
7290da14cebeSEric Cheng void
mac_release_rx_group(mac_client_impl_t * mcip,mac_group_t * group)7291da14cebeSEric Cheng mac_release_rx_group(mac_client_impl_t *mcip, mac_group_t *group)
7292da14cebeSEric Cheng {
7293da14cebeSEric Cheng 	mac_impl_t		*mip = mcip->mci_mip;
7294da14cebeSEric Cheng 	mac_ring_t		*ring;
7295da14cebeSEric Cheng 
72960dc2366fSVenugopal Iyer 	ASSERT(group != MAC_DEFAULT_RX_GROUP(mip));
729784de666eSRyan Zezeski 	ASSERT(MAC_GROUP_NO_CLIENT(group) == B_TRUE);
72980dc2366fSVenugopal Iyer 
72990dc2366fSVenugopal Iyer 	if (mip->mi_rx_donor_grp == group)
73000dc2366fSVenugopal Iyer 		mip->mi_rx_donor_grp = MAC_DEFAULT_RX_GROUP(mip);
7301da14cebeSEric Cheng 
7302da14cebeSEric Cheng 	/*
7303da14cebeSEric Cheng 	 * This is the case where there are no clients left. Any
7304da14cebeSEric Cheng 	 * SRS etc on this group have also be quiesced.
7305da14cebeSEric Cheng 	 */
7306da14cebeSEric Cheng 	for (ring = group->mrg_rings; ring != NULL; ring = ring->mr_next) {
7307da14cebeSEric Cheng 		if (ring->mr_classify_type == MAC_HW_CLASSIFIER) {
7308da14cebeSEric Cheng 			ASSERT(group->mrg_state == MAC_GROUP_STATE_RESERVED);
7309da14cebeSEric Cheng 			/*
7310da14cebeSEric Cheng 			 * Remove the SRS associated with the HW ring.
7311da14cebeSEric Cheng 			 * As a result, polling will be disabled.
7312da14cebeSEric Cheng 			 */
7313da14cebeSEric Cheng 			ring->mr_srs = NULL;
7314da14cebeSEric Cheng 		}
73150dc2366fSVenugopal Iyer 		ASSERT(group->mrg_state < MAC_GROUP_STATE_RESERVED ||
73160dc2366fSVenugopal Iyer 		    ring->mr_state == MR_INUSE);
73170dc2366fSVenugopal Iyer 		if (ring->mr_state == MR_INUSE) {
7318da14cebeSEric Cheng 			mac_stop_ring(ring);
7319da14cebeSEric Cheng 			ring->mr_flag = 0;
7320da14cebeSEric Cheng 		}
73210dc2366fSVenugopal Iyer 	}
7322da14cebeSEric Cheng 
7323da14cebeSEric Cheng 	/* remove group from share */
732436f99a58SToomas Soome 	if (mcip->mci_share != 0) {
7325da14cebeSEric Cheng 		mip->mi_share_capab.ms_sremove(mcip->mci_share,
7326da14cebeSEric Cheng 		    group->mrg_driver);
7327da14cebeSEric Cheng 	}
7328da14cebeSEric Cheng 
7329da14cebeSEric Cheng 	if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
7330da14cebeSEric Cheng 		mac_ring_t *ring;
7331da14cebeSEric Cheng 
7332da14cebeSEric Cheng 		/*
7333da14cebeSEric Cheng 		 * Rings were dynamically allocated to group.
7334da14cebeSEric Cheng 		 * Move rings back to default group.
7335da14cebeSEric Cheng 		 */
7336da14cebeSEric Cheng 		while ((ring = group->mrg_rings) != NULL) {
73370dc2366fSVenugopal Iyer 			(void) mac_group_mov_ring(mip, mip->mi_rx_donor_grp,
73380dc2366fSVenugopal Iyer 			    ring);
7339da14cebeSEric Cheng 		}
7340da14cebeSEric Cheng 	}
7341da14cebeSEric Cheng 	mac_stop_group(group);
7342da14cebeSEric Cheng 	/*
7343da14cebeSEric Cheng 	 * Possible improvement: See if we can assign the group just released
7344da14cebeSEric Cheng 	 * to a another client of the mip
7345da14cebeSEric Cheng 	 */
7346da14cebeSEric Cheng }
7347da14cebeSEric Cheng 
7348da14cebeSEric Cheng /*
734984de666eSRyan Zezeski  * Move the MAC address from fgrp to tgrp.
73500dc2366fSVenugopal Iyer  */
73510dc2366fSVenugopal Iyer static int
mac_rx_move_macaddr(mac_client_impl_t * mcip,mac_group_t * fgrp,mac_group_t * tgrp)73520dc2366fSVenugopal Iyer mac_rx_move_macaddr(mac_client_impl_t *mcip, mac_group_t *fgrp,
73530dc2366fSVenugopal Iyer     mac_group_t *tgrp)
73540dc2366fSVenugopal Iyer {
73550dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
73560dc2366fSVenugopal Iyer 	uint8_t			maddr[MAXMACADDRLEN];
73570dc2366fSVenugopal Iyer 	int			err = 0;
735884de666eSRyan Zezeski 	uint16_t		vid;
735984de666eSRyan Zezeski 	mac_unicast_impl_t	*muip;
736084de666eSRyan Zezeski 	boolean_t		use_hw;
73610dc2366fSVenugopal Iyer 
73620dc2366fSVenugopal Iyer 	mac_rx_client_quiesce((mac_client_handle_t)mcip);
736384de666eSRyan Zezeski 	VERIFY3P(mcip->mci_unicast, !=, NULL);
73640dc2366fSVenugopal Iyer 	bcopy(mcip->mci_unicast->ma_addr, maddr, mcip->mci_unicast->ma_len);
73650dc2366fSVenugopal Iyer 
736684de666eSRyan Zezeski 	/*
736784de666eSRyan Zezeski 	 * Does the client require MAC address hardware classifiction?
736884de666eSRyan Zezeski 	 */
736984de666eSRyan Zezeski 	use_hw = (mcip->mci_state_flags & MCIS_UNICAST_HW) != 0;
737084de666eSRyan Zezeski 	vid = i_mac_flow_vid(mcip->mci_flent);
737184de666eSRyan Zezeski 
737284de666eSRyan Zezeski 	/*
737384de666eSRyan Zezeski 	 * You can never move an address that is shared by multiple
737484de666eSRyan Zezeski 	 * clients. mac_datapath_setup() ensures that clients sharing
737584de666eSRyan Zezeski 	 * an address are placed on the default group. This guarantees
737684de666eSRyan Zezeski 	 * that a non-default group will only ever have one client and
737784de666eSRyan Zezeski 	 * thus make full use of HW filters.
737884de666eSRyan Zezeski 	 */
737984de666eSRyan Zezeski 	if (mac_check_macaddr_shared(mcip->mci_unicast))
738084de666eSRyan Zezeski 		return (EINVAL);
738184de666eSRyan Zezeski 
738284de666eSRyan Zezeski 	err = mac_remove_macaddr_vlan(mcip->mci_unicast, vid);
738384de666eSRyan Zezeski 
73840dc2366fSVenugopal Iyer 	if (err != 0) {
73850dc2366fSVenugopal Iyer 		mac_rx_client_restart((mac_client_handle_t)mcip);
73860dc2366fSVenugopal Iyer 		return (err);
73870dc2366fSVenugopal Iyer 	}
738884de666eSRyan Zezeski 
73890dc2366fSVenugopal Iyer 	/*
739084de666eSRyan Zezeski 	 * If this isn't the primary MAC address then the
739184de666eSRyan Zezeski 	 * mac_address_t has been freed by the last call to
739284de666eSRyan Zezeski 	 * mac_remove_macaddr_vlan(). In any case, NULL the reference
739384de666eSRyan Zezeski 	 * to avoid a dangling pointer.
73940dc2366fSVenugopal Iyer 	 */
739584de666eSRyan Zezeski 	mcip->mci_unicast = NULL;
739684de666eSRyan Zezeski 
739784de666eSRyan Zezeski 	/*
739884de666eSRyan Zezeski 	 * We also have to NULL all the mui_map references -- sun4v
739984de666eSRyan Zezeski 	 * strikes again!
740084de666eSRyan Zezeski 	 */
740184de666eSRyan Zezeski 	rw_enter(&mcip->mci_rw_lock, RW_WRITER);
740284de666eSRyan Zezeski 	for (muip = mcip->mci_unicast_list; muip != NULL; muip = muip->mui_next)
740384de666eSRyan Zezeski 		muip->mui_map = NULL;
740484de666eSRyan Zezeski 	rw_exit(&mcip->mci_rw_lock);
740584de666eSRyan Zezeski 
740684de666eSRyan Zezeski 	/*
740784de666eSRyan Zezeski 	 * Program the H/W Classifier first, if this fails we need not
740884de666eSRyan Zezeski 	 * proceed with the other stuff.
740984de666eSRyan Zezeski 	 */
741084de666eSRyan Zezeski 	if ((err = mac_add_macaddr_vlan(mip, tgrp, maddr, vid, use_hw)) != 0) {
741184de666eSRyan Zezeski 		int err2;
741284de666eSRyan Zezeski 
74130dc2366fSVenugopal Iyer 		/* Revert back the H/W Classifier */
741484de666eSRyan Zezeski 		err2 = mac_add_macaddr_vlan(mip, fgrp, maddr, vid, use_hw);
741584de666eSRyan Zezeski 
741684de666eSRyan Zezeski 		if (err2 != 0) {
741784de666eSRyan Zezeski 			cmn_err(CE_WARN, "Failed to revert HW classification"
741884de666eSRyan Zezeski 			    " on MAC %s, for client %s: %d.", mip->mi_name,
741984de666eSRyan Zezeski 			    mcip->mci_name, err2);
742084de666eSRyan Zezeski 		}
742184de666eSRyan Zezeski 
742284de666eSRyan Zezeski 		mac_rx_client_restart((mac_client_handle_t)mcip);
742384de666eSRyan Zezeski 		return (err);
742484de666eSRyan Zezeski 	}
742584de666eSRyan Zezeski 
74260dc2366fSVenugopal Iyer 	/*
742784de666eSRyan Zezeski 	 * Get a reference to the new mac_address_t and update the
742884de666eSRyan Zezeski 	 * client's reference. Then restart the client and add the
742984de666eSRyan Zezeski 	 * other clients of this MAC addr (if they exsit).
74300dc2366fSVenugopal Iyer 	 */
74310dc2366fSVenugopal Iyer 	mcip->mci_unicast = mac_find_macaddr(mip, maddr);
743284de666eSRyan Zezeski 	rw_enter(&mcip->mci_rw_lock, RW_WRITER);
743384de666eSRyan Zezeski 	for (muip = mcip->mci_unicast_list; muip != NULL; muip = muip->mui_next)
743484de666eSRyan Zezeski 		muip->mui_map = mcip->mci_unicast;
743584de666eSRyan Zezeski 	rw_exit(&mcip->mci_rw_lock);
74360dc2366fSVenugopal Iyer 	mac_rx_client_restart((mac_client_handle_t)mcip);
743784de666eSRyan Zezeski 	return (0);
74380dc2366fSVenugopal Iyer }
74390dc2366fSVenugopal Iyer 
74400dc2366fSVenugopal Iyer /*
74410dc2366fSVenugopal Iyer  * Switch the MAC client from one group to another. This means we need
74420dc2366fSVenugopal Iyer  * to remove the MAC address from the group, remove the MAC client,
74430dc2366fSVenugopal Iyer  * teardown the SRSs and revert the group state. Then, we add the client
74440dc2366fSVenugopal Iyer  * to the destination group, set the SRSs, and add the MAC address to the
74450dc2366fSVenugopal Iyer  * group.
74460dc2366fSVenugopal Iyer  */
74470dc2366fSVenugopal Iyer int
mac_rx_switch_group(mac_client_impl_t * mcip,mac_group_t * fgrp,mac_group_t * tgrp)74480dc2366fSVenugopal Iyer mac_rx_switch_group(mac_client_impl_t *mcip, mac_group_t *fgrp,
74490dc2366fSVenugopal Iyer     mac_group_t *tgrp)
74500dc2366fSVenugopal Iyer {
74510dc2366fSVenugopal Iyer 	int			err;
74520dc2366fSVenugopal Iyer 	mac_group_state_t	next_state;
74530dc2366fSVenugopal Iyer 	mac_client_impl_t	*group_only_mcip;
74540dc2366fSVenugopal Iyer 	mac_client_impl_t	*gmcip;
74550dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
74560dc2366fSVenugopal Iyer 	mac_grp_client_t	*mgcp;
74570dc2366fSVenugopal Iyer 
745884de666eSRyan Zezeski 	VERIFY3P(fgrp, ==, mcip->mci_flent->fe_rx_ring_group);
74590dc2366fSVenugopal Iyer 
74600dc2366fSVenugopal Iyer 	if ((err = mac_rx_move_macaddr(mcip, fgrp, tgrp)) != 0)
74610dc2366fSVenugopal Iyer 		return (err);
74620dc2366fSVenugopal Iyer 
74630dc2366fSVenugopal Iyer 	/*
746484de666eSRyan Zezeski 	 * If the group is marked as reserved and in use by a single
746584de666eSRyan Zezeski 	 * client, then there is an SRS to teardown.
74660dc2366fSVenugopal Iyer 	 */
74670dc2366fSVenugopal Iyer 	if (fgrp->mrg_state == MAC_GROUP_STATE_RESERVED &&
74680dc2366fSVenugopal Iyer 	    MAC_GROUP_ONLY_CLIENT(fgrp) != NULL) {
74690dc2366fSVenugopal Iyer 		mac_rx_srs_group_teardown(mcip->mci_flent, B_TRUE);
74700dc2366fSVenugopal Iyer 	}
747184de666eSRyan Zezeski 
747284de666eSRyan Zezeski 	/*
747384de666eSRyan Zezeski 	 * If we are moving the client from a non-default group, then
747484de666eSRyan Zezeski 	 * we know that any additional clients on this group share the
747584de666eSRyan Zezeski 	 * same MAC address. Since we moved the MAC address filter, we
747684de666eSRyan Zezeski 	 * need to move these clients too.
747784de666eSRyan Zezeski 	 *
747884de666eSRyan Zezeski 	 * If we are moving the client from the default group and its
747984de666eSRyan Zezeski 	 * MAC address has VLAN clients, then we must move those
748084de666eSRyan Zezeski 	 * clients as well.
748184de666eSRyan Zezeski 	 *
748284de666eSRyan Zezeski 	 * In both cases the idea is the same: we moved the MAC
748384de666eSRyan Zezeski 	 * address filter to the tgrp, so we must move all clients
748484de666eSRyan Zezeski 	 * using that MAC address to tgrp as well.
748584de666eSRyan Zezeski 	 */
74860dc2366fSVenugopal Iyer 	if (fgrp != MAC_DEFAULT_RX_GROUP(mip)) {
74870dc2366fSVenugopal Iyer 		mgcp = fgrp->mrg_clients;
74880dc2366fSVenugopal Iyer 		while (mgcp != NULL) {
74890dc2366fSVenugopal Iyer 			gmcip = mgcp->mgc_client;
74900dc2366fSVenugopal Iyer 			mgcp = mgcp->mgc_next;
74910dc2366fSVenugopal Iyer 			mac_group_remove_client(fgrp, gmcip);
74920dc2366fSVenugopal Iyer 			mac_group_add_client(tgrp, gmcip);
74930dc2366fSVenugopal Iyer 			gmcip->mci_flent->fe_rx_ring_group = tgrp;
74940dc2366fSVenugopal Iyer 		}
74950dc2366fSVenugopal Iyer 		mac_release_rx_group(mcip, fgrp);
749684de666eSRyan Zezeski 		VERIFY3B(MAC_GROUP_NO_CLIENT(fgrp), ==, B_TRUE);
74970dc2366fSVenugopal Iyer 		mac_set_group_state(fgrp, MAC_GROUP_STATE_REGISTERED);
74980dc2366fSVenugopal Iyer 	} else {
74990dc2366fSVenugopal Iyer 		mac_group_remove_client(fgrp, mcip);
75000dc2366fSVenugopal Iyer 		mac_group_add_client(tgrp, mcip);
75010dc2366fSVenugopal Iyer 		mcip->mci_flent->fe_rx_ring_group = tgrp;
750284de666eSRyan Zezeski 
75030dc2366fSVenugopal Iyer 		/*
75040dc2366fSVenugopal Iyer 		 * If there are other clients (VLANs) sharing this address
750584de666eSRyan Zezeski 		 * then move them too.
75060dc2366fSVenugopal Iyer 		 */
750784de666eSRyan Zezeski 		if (mac_check_macaddr_shared(mcip->mci_unicast)) {
75080dc2366fSVenugopal Iyer 			/*
75090dc2366fSVenugopal Iyer 			 * We need to move all the clients that are using
751084de666eSRyan Zezeski 			 * this MAC address.
75110dc2366fSVenugopal Iyer 			 */
75120dc2366fSVenugopal Iyer 			mgcp = fgrp->mrg_clients;
75130dc2366fSVenugopal Iyer 			while (mgcp != NULL) {
75140dc2366fSVenugopal Iyer 				gmcip = mgcp->mgc_client;
75150dc2366fSVenugopal Iyer 				mgcp = mgcp->mgc_next;
75160dc2366fSVenugopal Iyer 				if (mcip->mci_unicast == gmcip->mci_unicast) {
75170dc2366fSVenugopal Iyer 					mac_group_remove_client(fgrp, gmcip);
75180dc2366fSVenugopal Iyer 					mac_group_add_client(tgrp, gmcip);
75190dc2366fSVenugopal Iyer 					gmcip->mci_flent->fe_rx_ring_group =
75200dc2366fSVenugopal Iyer 					    tgrp;
75210dc2366fSVenugopal Iyer 				}
75220dc2366fSVenugopal Iyer 			}
75230dc2366fSVenugopal Iyer 		}
752484de666eSRyan Zezeski 
75250dc2366fSVenugopal Iyer 		/*
752684de666eSRyan Zezeski 		 * The default group still handles multicast and
752784de666eSRyan Zezeski 		 * broadcast traffic; it won't transition to
75280dc2366fSVenugopal Iyer 		 * MAC_GROUP_STATE_REGISTERED.
75290dc2366fSVenugopal Iyer 		 */
75300dc2366fSVenugopal Iyer 		if (fgrp->mrg_state == MAC_GROUP_STATE_RESERVED)
75310dc2366fSVenugopal Iyer 			mac_rx_group_unmark(fgrp, MR_CONDEMNED);
75320dc2366fSVenugopal Iyer 		mac_set_group_state(fgrp, MAC_GROUP_STATE_SHARED);
75330dc2366fSVenugopal Iyer 	}
753484de666eSRyan Zezeski 
75350dc2366fSVenugopal Iyer 	next_state = mac_group_next_state(tgrp, &group_only_mcip,
75360dc2366fSVenugopal Iyer 	    MAC_DEFAULT_RX_GROUP(mip), B_TRUE);
75370dc2366fSVenugopal Iyer 	mac_set_group_state(tgrp, next_state);
753884de666eSRyan Zezeski 
75390dc2366fSVenugopal Iyer 	/*
754084de666eSRyan Zezeski 	 * If the destination group is reserved, then setup the SRSes.
754184de666eSRyan Zezeski 	 * Otherwise make sure to use SW classification.
75420dc2366fSVenugopal Iyer 	 */
75430dc2366fSVenugopal Iyer 	if (tgrp->mrg_state == MAC_GROUP_STATE_RESERVED) {
75440dc2366fSVenugopal Iyer 		mac_rx_srs_group_setup(mcip, mcip->mci_flent, SRST_LINK);
75450dc2366fSVenugopal Iyer 		mac_fanout_setup(mcip, mcip->mci_flent,
75460dc2366fSVenugopal Iyer 		    MCIP_RESOURCE_PROPS(mcip), mac_rx_deliver, mcip, NULL,
75470dc2366fSVenugopal Iyer 		    NULL);
75480dc2366fSVenugopal Iyer 		mac_rx_group_unmark(tgrp, MR_INCIPIENT);
75490dc2366fSVenugopal Iyer 	} else {
75500dc2366fSVenugopal Iyer 		mac_rx_switch_grp_to_sw(tgrp);
75510dc2366fSVenugopal Iyer 	}
755284de666eSRyan Zezeski 
75530dc2366fSVenugopal Iyer 	return (0);
75540dc2366fSVenugopal Iyer }
75550dc2366fSVenugopal Iyer 
75560dc2366fSVenugopal Iyer /*
7557da14cebeSEric Cheng  * Reserves a TX group for the specified share. Invoked by mac_tx_srs_setup()
7558da14cebeSEric Cheng  * when a share was allocated to the client.
7559da14cebeSEric Cheng  */
7560da14cebeSEric Cheng mac_group_t *
mac_reserve_tx_group(mac_client_impl_t * mcip,boolean_t move)75610dc2366fSVenugopal Iyer mac_reserve_tx_group(mac_client_impl_t *mcip, boolean_t move)
7562da14cebeSEric Cheng {
75630dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
75640dc2366fSVenugopal Iyer 	mac_group_t		*grp = NULL;
75650dc2366fSVenugopal Iyer 	int			rv;
75660dc2366fSVenugopal Iyer 	int			i;
75670dc2366fSVenugopal Iyer 	int			err;
75680dc2366fSVenugopal Iyer 	mac_group_t		*defgrp;
75690dc2366fSVenugopal Iyer 	mac_share_handle_t	share = mcip->mci_share;
75700dc2366fSVenugopal Iyer 	mac_resource_props_t	*mrp = MCIP_RESOURCE_PROPS(mcip);
75710dc2366fSVenugopal Iyer 	int			nrings;
75720dc2366fSVenugopal Iyer 	int			defnrings;
75730dc2366fSVenugopal Iyer 	boolean_t		need_exclgrp = B_FALSE;
75740dc2366fSVenugopal Iyer 	int			need_rings = 0;
75750dc2366fSVenugopal Iyer 	mac_group_t		*candidate_grp = NULL;
75760dc2366fSVenugopal Iyer 	mac_client_impl_t	*gclient;
75770dc2366fSVenugopal Iyer 	mac_resource_props_t	*gmrp;
75780dc2366fSVenugopal Iyer 	boolean_t		txhw = mrp->mrp_mask & MRP_TX_RINGS;
75790dc2366fSVenugopal Iyer 	boolean_t		unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC;
75800dc2366fSVenugopal Iyer 	boolean_t		isprimary;
7581da14cebeSEric Cheng 
75820dc2366fSVenugopal Iyer 	isprimary = mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC;
758384de666eSRyan Zezeski 
7584da14cebeSEric Cheng 	/*
75850dc2366fSVenugopal Iyer 	 * When we come here for a VLAN on the primary (dladm create-vlan),
75860dc2366fSVenugopal Iyer 	 * we need to pair it along with the primary (to keep it consistent
75870dc2366fSVenugopal Iyer 	 * with the RX side). So, we check if the primary is already assigned
75880dc2366fSVenugopal Iyer 	 * to a group and return the group if so. The other way is also
75890dc2366fSVenugopal Iyer 	 * true, i.e. the VLAN is already created and now we are plumbing
75900dc2366fSVenugopal Iyer 	 * the primary.
7591da14cebeSEric Cheng 	 */
75920dc2366fSVenugopal Iyer 	if (!move && isprimary) {
75930dc2366fSVenugopal Iyer 		for (gclient = mip->mi_clients_list; gclient != NULL;
75940dc2366fSVenugopal Iyer 		    gclient = gclient->mci_client_next) {
75950dc2366fSVenugopal Iyer 			if (gclient->mci_flent->fe_type & FLOW_PRIMARY_MAC &&
75960dc2366fSVenugopal Iyer 			    gclient->mci_flent->fe_tx_ring_group != NULL) {
75970dc2366fSVenugopal Iyer 				return (gclient->mci_flent->fe_tx_ring_group);
75980dc2366fSVenugopal Iyer 			}
75990dc2366fSVenugopal Iyer 		}
7600da14cebeSEric Cheng 	}
7601da14cebeSEric Cheng 
76020dc2366fSVenugopal Iyer 	if (mip->mi_tx_groups == NULL || mip->mi_tx_group_count == 0)
76030dc2366fSVenugopal Iyer 		return (NULL);
7604da14cebeSEric Cheng 
76050dc2366fSVenugopal Iyer 	/* For dynamic groups, default unspec to 1 */
76060dc2366fSVenugopal Iyer 	if (txhw && unspec &&
76070dc2366fSVenugopal Iyer 	    mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
76080dc2366fSVenugopal Iyer 		mrp->mrp_ntxrings = 1;
76090dc2366fSVenugopal Iyer 	}
7610da14cebeSEric Cheng 	/*
76110dc2366fSVenugopal Iyer 	 * For static grouping we allow only specifying rings=0 and
76120dc2366fSVenugopal Iyer 	 * unspecified
7613da14cebeSEric Cheng 	 */
76140dc2366fSVenugopal Iyer 	if (txhw && mrp->mrp_ntxrings > 0 &&
76150dc2366fSVenugopal Iyer 	    mip->mi_tx_group_type == MAC_GROUP_TYPE_STATIC) {
7616da14cebeSEric Cheng 		return (NULL);
7617da14cebeSEric Cheng 	}
7618da14cebeSEric Cheng 
76190dc2366fSVenugopal Iyer 	if (txhw) {
76200dc2366fSVenugopal Iyer 		/*
76210dc2366fSVenugopal Iyer 		 * We have explicitly asked for a group (with ntxrings,
76220dc2366fSVenugopal Iyer 		 * if unspec).
76230dc2366fSVenugopal Iyer 		 */
76240dc2366fSVenugopal Iyer 		if (unspec || mrp->mrp_ntxrings > 0) {
76250dc2366fSVenugopal Iyer 			need_exclgrp = B_TRUE;
76260dc2366fSVenugopal Iyer 			need_rings = mrp->mrp_ntxrings;
76270dc2366fSVenugopal Iyer 		} else if (mrp->mrp_ntxrings == 0) {
76280dc2366fSVenugopal Iyer 			/*
76290dc2366fSVenugopal Iyer 			 * We have asked for a software group.
76300dc2366fSVenugopal Iyer 			 */
76310dc2366fSVenugopal Iyer 			return (NULL);
76320dc2366fSVenugopal Iyer 		}
76330dc2366fSVenugopal Iyer 	}
76340dc2366fSVenugopal Iyer 	defgrp = MAC_DEFAULT_TX_GROUP(mip);
76350dc2366fSVenugopal Iyer 	/*
76360dc2366fSVenugopal Iyer 	 * The number of rings that the default group can donate.
76370dc2366fSVenugopal Iyer 	 * We need to leave at least one ring - the default ring - in
76380dc2366fSVenugopal Iyer 	 * this group.
76390dc2366fSVenugopal Iyer 	 */
76400dc2366fSVenugopal Iyer 	defnrings = defgrp->mrg_cur_count - 1;
7641da14cebeSEric Cheng 
76420dc2366fSVenugopal Iyer 	/*
76430dc2366fSVenugopal Iyer 	 * Primary gets default group unless explicitly told not
76440dc2366fSVenugopal Iyer 	 * to  (i.e. rings > 0).
76450dc2366fSVenugopal Iyer 	 */
76460dc2366fSVenugopal Iyer 	if (isprimary && !need_exclgrp)
76470dc2366fSVenugopal Iyer 		return (NULL);
76480dc2366fSVenugopal Iyer 
76490dc2366fSVenugopal Iyer 	nrings = (mrp->mrp_mask & MRP_TX_RINGS) != 0 ? mrp->mrp_ntxrings : 1;
76500dc2366fSVenugopal Iyer 	for (i = 0; i <  mip->mi_tx_group_count; i++) {
76510dc2366fSVenugopal Iyer 		grp = &mip->mi_tx_groups[i];
76520dc2366fSVenugopal Iyer 		if ((grp->mrg_state == MAC_GROUP_STATE_RESERVED) ||
76530dc2366fSVenugopal Iyer 		    (grp->mrg_state == MAC_GROUP_STATE_UNINIT)) {
76540dc2366fSVenugopal Iyer 			/*
76550dc2366fSVenugopal Iyer 			 * Select a candidate for replacement if we don't
76560dc2366fSVenugopal Iyer 			 * get an exclusive group. A candidate group is one
76570dc2366fSVenugopal Iyer 			 * that didn't ask for an exclusive group, but got
76580dc2366fSVenugopal Iyer 			 * one and it has enough rings (combined with what
76590dc2366fSVenugopal Iyer 			 * the default group can donate) for the new MAC
76600dc2366fSVenugopal Iyer 			 * client.
76610dc2366fSVenugopal Iyer 			 */
76620dc2366fSVenugopal Iyer 			if (grp->mrg_state == MAC_GROUP_STATE_RESERVED &&
76630dc2366fSVenugopal Iyer 			    candidate_grp == NULL) {
76640dc2366fSVenugopal Iyer 				gclient = MAC_GROUP_ONLY_CLIENT(grp);
766584de666eSRyan Zezeski 				VERIFY3P(gclient, !=, NULL);
76660dc2366fSVenugopal Iyer 				gmrp = MCIP_RESOURCE_PROPS(gclient);
766736f99a58SToomas Soome 				if (gclient->mci_share == 0 &&
76680dc2366fSVenugopal Iyer 				    (gmrp->mrp_mask & MRP_TX_RINGS) == 0 &&
76690dc2366fSVenugopal Iyer 				    (unspec ||
76700dc2366fSVenugopal Iyer 				    (grp->mrg_cur_count + defnrings) >=
76710dc2366fSVenugopal Iyer 				    need_rings)) {
76720dc2366fSVenugopal Iyer 					candidate_grp = grp;
76730dc2366fSVenugopal Iyer 				}
76740dc2366fSVenugopal Iyer 			}
76750dc2366fSVenugopal Iyer 			continue;
76760dc2366fSVenugopal Iyer 		}
76770dc2366fSVenugopal Iyer 		/*
76780dc2366fSVenugopal Iyer 		 * If the default can't donate let's just walk and
76790dc2366fSVenugopal Iyer 		 * see if someone can vacate a group, so that we have
76800dc2366fSVenugopal Iyer 		 * enough rings for this.
76810dc2366fSVenugopal Iyer 		 */
76820dc2366fSVenugopal Iyer 		if (mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC ||
76830dc2366fSVenugopal Iyer 		    nrings <= defnrings) {
76840dc2366fSVenugopal Iyer 			if (grp->mrg_state == MAC_GROUP_STATE_REGISTERED) {
76850dc2366fSVenugopal Iyer 				rv = mac_start_group(grp);
76860dc2366fSVenugopal Iyer 				ASSERT(rv == 0);
76870dc2366fSVenugopal Iyer 			}
76880dc2366fSVenugopal Iyer 			break;
76890dc2366fSVenugopal Iyer 		}
76900dc2366fSVenugopal Iyer 	}
76910dc2366fSVenugopal Iyer 
76920dc2366fSVenugopal Iyer 	/* The default group */
76930dc2366fSVenugopal Iyer 	if (i >= mip->mi_tx_group_count) {
76940dc2366fSVenugopal Iyer 		/*
76950dc2366fSVenugopal Iyer 		 * If we need an exclusive group and have identified a
76960dc2366fSVenugopal Iyer 		 * candidate group we switch the MAC client from the
76970dc2366fSVenugopal Iyer 		 * candidate group to the default group and give the
76980dc2366fSVenugopal Iyer 		 * candidate group to this client.
76990dc2366fSVenugopal Iyer 		 */
77000dc2366fSVenugopal Iyer 		if (need_exclgrp && candidate_grp != NULL) {
77010dc2366fSVenugopal Iyer 			/*
770284de666eSRyan Zezeski 			 * Switch the MAC client from the candidate
770384de666eSRyan Zezeski 			 * group to the default group. We know the
770484de666eSRyan Zezeski 			 * candidate_grp came from a reserved group
770584de666eSRyan Zezeski 			 * and thus only has one client.
77060dc2366fSVenugopal Iyer 			 */
77070dc2366fSVenugopal Iyer 			grp = candidate_grp;
77080dc2366fSVenugopal Iyer 			gclient = MAC_GROUP_ONLY_CLIENT(grp);
770984de666eSRyan Zezeski 			VERIFY3P(gclient, !=, NULL);
77100dc2366fSVenugopal Iyer 			mac_tx_client_quiesce((mac_client_handle_t)gclient);
77110dc2366fSVenugopal Iyer 			mac_tx_switch_group(gclient, grp, defgrp);
77120dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)gclient);
77130dc2366fSVenugopal Iyer 
77140dc2366fSVenugopal Iyer 			/*
77150dc2366fSVenugopal Iyer 			 * Give the candidate group with the specified number
77160dc2366fSVenugopal Iyer 			 * of rings to this MAC client.
77170dc2366fSVenugopal Iyer 			 */
77180dc2366fSVenugopal Iyer 			ASSERT(grp->mrg_state == MAC_GROUP_STATE_REGISTERED);
77190dc2366fSVenugopal Iyer 			rv = mac_start_group(grp);
77200dc2366fSVenugopal Iyer 			ASSERT(rv == 0);
77210dc2366fSVenugopal Iyer 
77220dc2366fSVenugopal Iyer 			if (mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC)
77230dc2366fSVenugopal Iyer 				return (grp);
77240dc2366fSVenugopal Iyer 
77250dc2366fSVenugopal Iyer 			ASSERT(grp->mrg_cur_count == 0);
77260dc2366fSVenugopal Iyer 			ASSERT(defgrp->mrg_cur_count > need_rings);
77270dc2366fSVenugopal Iyer 
77280dc2366fSVenugopal Iyer 			err = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_TX,
77290dc2366fSVenugopal Iyer 			    defgrp, grp, share, need_rings);
77300dc2366fSVenugopal Iyer 			if (err == 0) {
77310dc2366fSVenugopal Iyer 				/*
77320dc2366fSVenugopal Iyer 				 * For a share i_mac_group_allocate_rings gets
77330dc2366fSVenugopal Iyer 				 * the rings from the driver, let's populate
77340dc2366fSVenugopal Iyer 				 * the property for the client now.
77350dc2366fSVenugopal Iyer 				 */
773636f99a58SToomas Soome 				if (share != 0) {
77370dc2366fSVenugopal Iyer 					mac_client_set_rings(
77380dc2366fSVenugopal Iyer 					    (mac_client_handle_t)mcip, -1,
77390dc2366fSVenugopal Iyer 					    grp->mrg_cur_count);
77400dc2366fSVenugopal Iyer 				}
77410dc2366fSVenugopal Iyer 				mip->mi_tx_group_free--;
77420dc2366fSVenugopal Iyer 				return (grp);
77430dc2366fSVenugopal Iyer 			}
77440dc2366fSVenugopal Iyer 			DTRACE_PROBE3(tx__group__reserve__alloc__rings, char *,
77450dc2366fSVenugopal Iyer 			    mip->mi_name, int, grp->mrg_index, int, err);
77460dc2366fSVenugopal Iyer 			mac_stop_group(grp);
77470dc2366fSVenugopal Iyer 		}
77480dc2366fSVenugopal Iyer 		return (NULL);
77490dc2366fSVenugopal Iyer 	}
77500dc2366fSVenugopal Iyer 	/*
77510dc2366fSVenugopal Iyer 	 * We got an exclusive group, but it is not dynamic.
77520dc2366fSVenugopal Iyer 	 */
77530dc2366fSVenugopal Iyer 	if (mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) {
77540dc2366fSVenugopal Iyer 		mip->mi_tx_group_free--;
77550dc2366fSVenugopal Iyer 		return (grp);
77560dc2366fSVenugopal Iyer 	}
77570dc2366fSVenugopal Iyer 
77580dc2366fSVenugopal Iyer 	rv = i_mac_group_allocate_rings(mip, MAC_RING_TYPE_TX, defgrp, grp,
77590dc2366fSVenugopal Iyer 	    share, nrings);
77600dc2366fSVenugopal Iyer 	if (rv != 0) {
77610dc2366fSVenugopal Iyer 		DTRACE_PROBE3(tx__group__reserve__alloc__rings,
77620dc2366fSVenugopal Iyer 		    char *, mip->mi_name, int, grp->mrg_index, int, rv);
77630dc2366fSVenugopal Iyer 		mac_stop_group(grp);
77640dc2366fSVenugopal Iyer 		return (NULL);
77650dc2366fSVenugopal Iyer 	}
77660dc2366fSVenugopal Iyer 	/*
77670dc2366fSVenugopal Iyer 	 * For a share i_mac_group_allocate_rings gets the rings from the
77680dc2366fSVenugopal Iyer 	 * driver, let's populate the property for the client now.
77690dc2366fSVenugopal Iyer 	 */
777036f99a58SToomas Soome 	if (share != 0) {
77710dc2366fSVenugopal Iyer 		mac_client_set_rings((mac_client_handle_t)mcip, -1,
77720dc2366fSVenugopal Iyer 		    grp->mrg_cur_count);
77730dc2366fSVenugopal Iyer 	}
77740dc2366fSVenugopal Iyer 	mip->mi_tx_group_free--;
7775da14cebeSEric Cheng 	return (grp);
7776da14cebeSEric Cheng }
7777da14cebeSEric Cheng 
7778da14cebeSEric Cheng void
mac_release_tx_group(mac_client_impl_t * mcip,mac_group_t * grp)77790dc2366fSVenugopal Iyer mac_release_tx_group(mac_client_impl_t *mcip, mac_group_t *grp)
7780da14cebeSEric Cheng {
77810dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
7782da14cebeSEric Cheng 	mac_share_handle_t	share = mcip->mci_share;
7783da14cebeSEric Cheng 	mac_ring_t		*ring;
77840dc2366fSVenugopal Iyer 	mac_soft_ring_set_t	*srs = MCIP_TX_SRS(mcip);
77850dc2366fSVenugopal Iyer 	mac_group_t		*defgrp;
7786da14cebeSEric Cheng 
77870dc2366fSVenugopal Iyer 	defgrp = MAC_DEFAULT_TX_GROUP(mip);
77880dc2366fSVenugopal Iyer 	if (srs != NULL) {
77890dc2366fSVenugopal Iyer 		if (srs->srs_soft_ring_count > 0) {
77900dc2366fSVenugopal Iyer 			for (ring = grp->mrg_rings; ring != NULL;
77910dc2366fSVenugopal Iyer 			    ring = ring->mr_next) {
77920dc2366fSVenugopal Iyer 				ASSERT(mac_tx_srs_ring_present(srs, ring));
77930dc2366fSVenugopal Iyer 				mac_tx_invoke_callbacks(mcip,
77940dc2366fSVenugopal Iyer 				    (mac_tx_cookie_t)
77950dc2366fSVenugopal Iyer 				    mac_tx_srs_get_soft_ring(srs, ring));
77960dc2366fSVenugopal Iyer 				mac_tx_srs_del_ring(srs, ring);
77970dc2366fSVenugopal Iyer 			}
77980dc2366fSVenugopal Iyer 		} else {
77990dc2366fSVenugopal Iyer 			ASSERT(srs->srs_tx.st_arg2 != NULL);
78000dc2366fSVenugopal Iyer 			srs->srs_tx.st_arg2 = NULL;
78010dc2366fSVenugopal Iyer 			mac_srs_stat_delete(srs);
78020dc2366fSVenugopal Iyer 		}
78030dc2366fSVenugopal Iyer 	}
780436f99a58SToomas Soome 	if (share != 0)
7805da14cebeSEric Cheng 		mip->mi_share_capab.ms_sremove(share, grp->mrg_driver);
78060dc2366fSVenugopal Iyer 
7807da14cebeSEric Cheng 	/* move the ring back to the pool */
78080dc2366fSVenugopal Iyer 	if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) {
78090dc2366fSVenugopal Iyer 		while ((ring = grp->mrg_rings) != NULL)
78100dc2366fSVenugopal Iyer 			(void) mac_group_mov_ring(mip, defgrp, ring);
7811da14cebeSEric Cheng 	}
7812da14cebeSEric Cheng 	mac_stop_group(grp);
7813da14cebeSEric Cheng 	mip->mi_tx_group_free++;
7814da14cebeSEric Cheng }
7815da14cebeSEric Cheng 
7816da14cebeSEric Cheng /*
78170dc2366fSVenugopal Iyer  * Disassociate a MAC client from a group, i.e go through the rings in the
78180dc2366fSVenugopal Iyer  * group and delete all the soft rings tied to them.
78190dc2366fSVenugopal Iyer  */
78200dc2366fSVenugopal Iyer static void
mac_tx_dismantle_soft_rings(mac_group_t * fgrp,flow_entry_t * flent)78210dc2366fSVenugopal Iyer mac_tx_dismantle_soft_rings(mac_group_t *fgrp, flow_entry_t *flent)
78220dc2366fSVenugopal Iyer {
78230dc2366fSVenugopal Iyer 	mac_client_impl_t	*mcip = flent->fe_mcip;
78240dc2366fSVenugopal Iyer 	mac_soft_ring_set_t	*tx_srs;
78250dc2366fSVenugopal Iyer 	mac_srs_tx_t		*tx;
78260dc2366fSVenugopal Iyer 	mac_ring_t		*ring;
78270dc2366fSVenugopal Iyer 
78280dc2366fSVenugopal Iyer 	tx_srs = flent->fe_tx_srs;
78290dc2366fSVenugopal Iyer 	tx = &tx_srs->srs_tx;
78300dc2366fSVenugopal Iyer 
78310dc2366fSVenugopal Iyer 	/* Single ring case we haven't created any soft rings */
78320dc2366fSVenugopal Iyer 	if (tx->st_mode == SRS_TX_BW || tx->st_mode == SRS_TX_SERIALIZE ||
78330dc2366fSVenugopal Iyer 	    tx->st_mode == SRS_TX_DEFAULT) {
78340dc2366fSVenugopal Iyer 		tx->st_arg2 = NULL;
78350dc2366fSVenugopal Iyer 		mac_srs_stat_delete(tx_srs);
78360dc2366fSVenugopal Iyer 	/* Fanout case, where we have to dismantle the soft rings */
78370dc2366fSVenugopal Iyer 	} else {
78380dc2366fSVenugopal Iyer 		for (ring = fgrp->mrg_rings; ring != NULL;
78390dc2366fSVenugopal Iyer 		    ring = ring->mr_next) {
78400dc2366fSVenugopal Iyer 			ASSERT(mac_tx_srs_ring_present(tx_srs, ring));
78410dc2366fSVenugopal Iyer 			mac_tx_invoke_callbacks(mcip,
78420dc2366fSVenugopal Iyer 			    (mac_tx_cookie_t)mac_tx_srs_get_soft_ring(tx_srs,
78430dc2366fSVenugopal Iyer 			    ring));
78440dc2366fSVenugopal Iyer 			mac_tx_srs_del_ring(tx_srs, ring);
78450dc2366fSVenugopal Iyer 		}
78460dc2366fSVenugopal Iyer 		ASSERT(tx->st_arg2 == NULL);
78470dc2366fSVenugopal Iyer 	}
78480dc2366fSVenugopal Iyer }
78490dc2366fSVenugopal Iyer 
78500dc2366fSVenugopal Iyer /*
78510dc2366fSVenugopal Iyer  * Switch the MAC client from one group to another. This means we need
78520dc2366fSVenugopal Iyer  * to remove the MAC client, teardown the SRSs and revert the group state.
78530dc2366fSVenugopal Iyer  * Then, we add the client to the destination roup, set the SRSs etc.
78540dc2366fSVenugopal Iyer  */
78550dc2366fSVenugopal Iyer void
mac_tx_switch_group(mac_client_impl_t * mcip,mac_group_t * fgrp,mac_group_t * tgrp)78560dc2366fSVenugopal Iyer mac_tx_switch_group(mac_client_impl_t *mcip, mac_group_t *fgrp,
78570dc2366fSVenugopal Iyer     mac_group_t *tgrp)
78580dc2366fSVenugopal Iyer {
78590dc2366fSVenugopal Iyer 	mac_client_impl_t	*group_only_mcip;
78600dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
78610dc2366fSVenugopal Iyer 	flow_entry_t		*flent = mcip->mci_flent;
78620dc2366fSVenugopal Iyer 	mac_group_t		*defgrp;
78630dc2366fSVenugopal Iyer 	mac_grp_client_t	*mgcp;
78640dc2366fSVenugopal Iyer 	mac_client_impl_t	*gmcip;
78650dc2366fSVenugopal Iyer 	flow_entry_t		*gflent;
78660dc2366fSVenugopal Iyer 
78670dc2366fSVenugopal Iyer 	defgrp = MAC_DEFAULT_TX_GROUP(mip);
78680dc2366fSVenugopal Iyer 	ASSERT(fgrp == flent->fe_tx_ring_group);
78690dc2366fSVenugopal Iyer 
78700dc2366fSVenugopal Iyer 	if (fgrp == defgrp) {
78710dc2366fSVenugopal Iyer 		/*
78720dc2366fSVenugopal Iyer 		 * If this is the primary we need to find any VLANs on
78730dc2366fSVenugopal Iyer 		 * the primary and move them too.
78740dc2366fSVenugopal Iyer 		 */
78750dc2366fSVenugopal Iyer 		mac_group_remove_client(fgrp, mcip);
78760dc2366fSVenugopal Iyer 		mac_tx_dismantle_soft_rings(fgrp, flent);
787784de666eSRyan Zezeski 		if (mac_check_macaddr_shared(mcip->mci_unicast)) {
78780dc2366fSVenugopal Iyer 			mgcp = fgrp->mrg_clients;
78790dc2366fSVenugopal Iyer 			while (mgcp != NULL) {
78800dc2366fSVenugopal Iyer 				gmcip = mgcp->mgc_client;
78810dc2366fSVenugopal Iyer 				mgcp = mgcp->mgc_next;
78820dc2366fSVenugopal Iyer 				if (mcip->mci_unicast != gmcip->mci_unicast)
78830dc2366fSVenugopal Iyer 					continue;
78840dc2366fSVenugopal Iyer 				mac_tx_client_quiesce(
78850dc2366fSVenugopal Iyer 				    (mac_client_handle_t)gmcip);
78860dc2366fSVenugopal Iyer 
78870dc2366fSVenugopal Iyer 				gflent = gmcip->mci_flent;
78880dc2366fSVenugopal Iyer 				mac_group_remove_client(fgrp, gmcip);
78890dc2366fSVenugopal Iyer 				mac_tx_dismantle_soft_rings(fgrp, gflent);
78900dc2366fSVenugopal Iyer 
78910dc2366fSVenugopal Iyer 				mac_group_add_client(tgrp, gmcip);
78920dc2366fSVenugopal Iyer 				gflent->fe_tx_ring_group = tgrp;
78930dc2366fSVenugopal Iyer 				/* We could directly set this to SHARED */
78940dc2366fSVenugopal Iyer 				tgrp->mrg_state = mac_group_next_state(tgrp,
78950dc2366fSVenugopal Iyer 				    &group_only_mcip, defgrp, B_FALSE);
78960dc2366fSVenugopal Iyer 
78970dc2366fSVenugopal Iyer 				mac_tx_srs_group_setup(gmcip, gflent,
78980dc2366fSVenugopal Iyer 				    SRST_LINK);
78990dc2366fSVenugopal Iyer 				mac_fanout_setup(gmcip, gflent,
79000dc2366fSVenugopal Iyer 				    MCIP_RESOURCE_PROPS(gmcip), mac_rx_deliver,
79010dc2366fSVenugopal Iyer 				    gmcip, NULL, NULL);
79020dc2366fSVenugopal Iyer 
79030dc2366fSVenugopal Iyer 				mac_tx_client_restart(
79040dc2366fSVenugopal Iyer 				    (mac_client_handle_t)gmcip);
79050dc2366fSVenugopal Iyer 			}
79060dc2366fSVenugopal Iyer 		}
79070dc2366fSVenugopal Iyer 		if (MAC_GROUP_NO_CLIENT(fgrp)) {
79080dc2366fSVenugopal Iyer 			mac_ring_t	*ring;
79090dc2366fSVenugopal Iyer 			int		cnt;
79100dc2366fSVenugopal Iyer 			int		ringcnt;
79110dc2366fSVenugopal Iyer 
79120dc2366fSVenugopal Iyer 			fgrp->mrg_state = MAC_GROUP_STATE_REGISTERED;
79130dc2366fSVenugopal Iyer 			/*
79140dc2366fSVenugopal Iyer 			 * Additionally, we also need to stop all
79150dc2366fSVenugopal Iyer 			 * the rings in the default group, except
79160dc2366fSVenugopal Iyer 			 * the default ring. The reason being
79170dc2366fSVenugopal Iyer 			 * this group won't be released since it is
79180dc2366fSVenugopal Iyer 			 * the default group, so the rings won't
79190dc2366fSVenugopal Iyer 			 * be stopped otherwise.
79200dc2366fSVenugopal Iyer 			 */
79210dc2366fSVenugopal Iyer 			ringcnt = fgrp->mrg_cur_count;
79220dc2366fSVenugopal Iyer 			ring = fgrp->mrg_rings;
79230dc2366fSVenugopal Iyer 			for (cnt = 0; cnt < ringcnt; cnt++) {
79240dc2366fSVenugopal Iyer 				if (ring->mr_state == MR_INUSE &&
79250dc2366fSVenugopal Iyer 				    ring !=
79260dc2366fSVenugopal Iyer 				    (mac_ring_t *)mip->mi_default_tx_ring) {
79270dc2366fSVenugopal Iyer 					mac_stop_ring(ring);
79280dc2366fSVenugopal Iyer 					ring->mr_flag = 0;
79290dc2366fSVenugopal Iyer 				}
79300dc2366fSVenugopal Iyer 				ring = ring->mr_next;
79310dc2366fSVenugopal Iyer 			}
79320dc2366fSVenugopal Iyer 		} else if (MAC_GROUP_ONLY_CLIENT(fgrp) != NULL) {
79330dc2366fSVenugopal Iyer 			fgrp->mrg_state = MAC_GROUP_STATE_RESERVED;
79340dc2366fSVenugopal Iyer 		} else {
79350dc2366fSVenugopal Iyer 			ASSERT(fgrp->mrg_state == MAC_GROUP_STATE_SHARED);
79360dc2366fSVenugopal Iyer 		}
79370dc2366fSVenugopal Iyer 	} else {
79380dc2366fSVenugopal Iyer 		/*
79390dc2366fSVenugopal Iyer 		 * We could have VLANs sharing the non-default group with
79400dc2366fSVenugopal Iyer 		 * the primary.
79410dc2366fSVenugopal Iyer 		 */
79420dc2366fSVenugopal Iyer 		mgcp = fgrp->mrg_clients;
79430dc2366fSVenugopal Iyer 		while (mgcp != NULL) {
79440dc2366fSVenugopal Iyer 			gmcip = mgcp->mgc_client;
79450dc2366fSVenugopal Iyer 			mgcp = mgcp->mgc_next;
79460dc2366fSVenugopal Iyer 			if (gmcip == mcip)
79470dc2366fSVenugopal Iyer 				continue;
79480dc2366fSVenugopal Iyer 			mac_tx_client_quiesce((mac_client_handle_t)gmcip);
79490dc2366fSVenugopal Iyer 			gflent = gmcip->mci_flent;
79500dc2366fSVenugopal Iyer 
79510dc2366fSVenugopal Iyer 			mac_group_remove_client(fgrp, gmcip);
79520dc2366fSVenugopal Iyer 			mac_tx_dismantle_soft_rings(fgrp, gflent);
79530dc2366fSVenugopal Iyer 
79540dc2366fSVenugopal Iyer 			mac_group_add_client(tgrp, gmcip);
79550dc2366fSVenugopal Iyer 			gflent->fe_tx_ring_group = tgrp;
79560dc2366fSVenugopal Iyer 			/* We could directly set this to SHARED */
79570dc2366fSVenugopal Iyer 			tgrp->mrg_state = mac_group_next_state(tgrp,
79580dc2366fSVenugopal Iyer 			    &group_only_mcip, defgrp, B_FALSE);
79590dc2366fSVenugopal Iyer 			mac_tx_srs_group_setup(gmcip, gflent, SRST_LINK);
79600dc2366fSVenugopal Iyer 			mac_fanout_setup(gmcip, gflent,
79610dc2366fSVenugopal Iyer 			    MCIP_RESOURCE_PROPS(gmcip), mac_rx_deliver,
79620dc2366fSVenugopal Iyer 			    gmcip, NULL, NULL);
79630dc2366fSVenugopal Iyer 
79640dc2366fSVenugopal Iyer 			mac_tx_client_restart((mac_client_handle_t)gmcip);
79650dc2366fSVenugopal Iyer 		}
79660dc2366fSVenugopal Iyer 		mac_group_remove_client(fgrp, mcip);
79670dc2366fSVenugopal Iyer 		mac_release_tx_group(mcip, fgrp);
79680dc2366fSVenugopal Iyer 		fgrp->mrg_state = MAC_GROUP_STATE_REGISTERED;
79690dc2366fSVenugopal Iyer 	}
79700dc2366fSVenugopal Iyer 
79710dc2366fSVenugopal Iyer 	/* Add it to the tgroup */
79720dc2366fSVenugopal Iyer 	mac_group_add_client(tgrp, mcip);
79730dc2366fSVenugopal Iyer 	flent->fe_tx_ring_group = tgrp;
79740dc2366fSVenugopal Iyer 	tgrp->mrg_state = mac_group_next_state(tgrp, &group_only_mcip,
79750dc2366fSVenugopal Iyer 	    defgrp, B_FALSE);
79760dc2366fSVenugopal Iyer 
79770dc2366fSVenugopal Iyer 	mac_tx_srs_group_setup(mcip, flent, SRST_LINK);
79780dc2366fSVenugopal Iyer 	mac_fanout_setup(mcip, flent, MCIP_RESOURCE_PROPS(mcip),
79790dc2366fSVenugopal Iyer 	    mac_rx_deliver, mcip, NULL, NULL);
79800dc2366fSVenugopal Iyer }
79810dc2366fSVenugopal Iyer 
79820dc2366fSVenugopal Iyer /*
7983da14cebeSEric Cheng  * This is a 1-time control path activity initiated by the client (IP).
7984da14cebeSEric Cheng  * The mac perimeter protects against other simultaneous control activities,
7985da14cebeSEric Cheng  * for example an ioctl that attempts to change the degree of fanout and
7986da14cebeSEric Cheng  * increase or decrease the number of softrings associated with this Tx SRS.
7987da14cebeSEric Cheng  */
7988da14cebeSEric Cheng static mac_tx_notify_cb_t *
mac_client_tx_notify_add(mac_client_impl_t * mcip,mac_tx_notify_t notify,void * arg)7989da14cebeSEric Cheng mac_client_tx_notify_add(mac_client_impl_t *mcip,
7990da14cebeSEric Cheng     mac_tx_notify_t notify, void *arg)
7991da14cebeSEric Cheng {
7992da14cebeSEric Cheng 	mac_cb_info_t *mcbi;
7993da14cebeSEric Cheng 	mac_tx_notify_cb_t *mtnfp;
7994da14cebeSEric Cheng 
7995da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
7996da14cebeSEric Cheng 
7997da14cebeSEric Cheng 	mtnfp = kmem_zalloc(sizeof (mac_tx_notify_cb_t), KM_SLEEP);
7998da14cebeSEric Cheng 	mtnfp->mtnf_fn = notify;
7999da14cebeSEric Cheng 	mtnfp->mtnf_arg = arg;
8000da14cebeSEric Cheng 	mtnfp->mtnf_link.mcb_objp = mtnfp;
8001da14cebeSEric Cheng 	mtnfp->mtnf_link.mcb_objsize = sizeof (mac_tx_notify_cb_t);
8002da14cebeSEric Cheng 	mtnfp->mtnf_link.mcb_flags = MCB_TX_NOTIFY_CB_T;
8003da14cebeSEric Cheng 
8004da14cebeSEric Cheng 	mcbi = &mcip->mci_tx_notify_cb_info;
8005da14cebeSEric Cheng 	mutex_enter(mcbi->mcbi_lockp);
8006da14cebeSEric Cheng 	mac_callback_add(mcbi, &mcip->mci_tx_notify_cb_list, &mtnfp->mtnf_link);
8007da14cebeSEric Cheng 	mutex_exit(mcbi->mcbi_lockp);
8008da14cebeSEric Cheng 	return (mtnfp);
8009da14cebeSEric Cheng }
8010da14cebeSEric Cheng 
8011da14cebeSEric Cheng static void
mac_client_tx_notify_remove(mac_client_impl_t * mcip,mac_tx_notify_cb_t * mtnfp)8012da14cebeSEric Cheng mac_client_tx_notify_remove(mac_client_impl_t *mcip, mac_tx_notify_cb_t *mtnfp)
8013da14cebeSEric Cheng {
8014da14cebeSEric Cheng 	mac_cb_info_t	*mcbi;
8015da14cebeSEric Cheng 	mac_cb_t	**cblist;
8016da14cebeSEric Cheng 
8017da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip));
8018da14cebeSEric Cheng 
8019da14cebeSEric Cheng 	if (!mac_callback_find(&mcip->mci_tx_notify_cb_info,
8020da14cebeSEric Cheng 	    &mcip->mci_tx_notify_cb_list, &mtnfp->mtnf_link)) {
8021da14cebeSEric Cheng 		cmn_err(CE_WARN,
8022da14cebeSEric Cheng 		    "mac_client_tx_notify_remove: callback not "
8023da14cebeSEric Cheng 		    "found, mcip 0x%p mtnfp 0x%p", (void *)mcip, (void *)mtnfp);
8024da14cebeSEric Cheng 		return;
8025da14cebeSEric Cheng 	}
8026da14cebeSEric Cheng 
8027da14cebeSEric Cheng 	mcbi = &mcip->mci_tx_notify_cb_info;
8028da14cebeSEric Cheng 	cblist = &mcip->mci_tx_notify_cb_list;
8029da14cebeSEric Cheng 	mutex_enter(mcbi->mcbi_lockp);
8030da14cebeSEric Cheng 	if (mac_callback_remove(mcbi, cblist, &mtnfp->mtnf_link))
8031da14cebeSEric Cheng 		kmem_free(mtnfp, sizeof (mac_tx_notify_cb_t));
8032da14cebeSEric Cheng 	else
8033da14cebeSEric Cheng 		mac_callback_remove_wait(&mcip->mci_tx_notify_cb_info);
8034da14cebeSEric Cheng 	mutex_exit(mcbi->mcbi_lockp);
8035da14cebeSEric Cheng }
8036da14cebeSEric Cheng 
8037da14cebeSEric Cheng /*
8038da14cebeSEric Cheng  * mac_client_tx_notify():
8039da14cebeSEric Cheng  * call to add and remove flow control callback routine.
8040da14cebeSEric Cheng  */
8041da14cebeSEric Cheng mac_tx_notify_handle_t
mac_client_tx_notify(mac_client_handle_t mch,mac_tx_notify_t callb_func,void * ptr)8042da14cebeSEric Cheng mac_client_tx_notify(mac_client_handle_t mch, mac_tx_notify_t callb_func,
8043da14cebeSEric Cheng     void *ptr)
8044da14cebeSEric Cheng {
8045da14cebeSEric Cheng 	mac_client_impl_t	*mcip = (mac_client_impl_t *)mch;
8046da14cebeSEric Cheng 	mac_tx_notify_cb_t	*mtnfp = NULL;
8047da14cebeSEric Cheng 
8048da14cebeSEric Cheng 	i_mac_perim_enter(mcip->mci_mip);
8049da14cebeSEric Cheng 
8050da14cebeSEric Cheng 	if (callb_func != NULL) {
8051da14cebeSEric Cheng 		/* Add a notify callback */
8052da14cebeSEric Cheng 		mtnfp = mac_client_tx_notify_add(mcip, callb_func, ptr);
8053da14cebeSEric Cheng 	} else {
8054da14cebeSEric Cheng 		mac_client_tx_notify_remove(mcip, (mac_tx_notify_cb_t *)ptr);
8055da14cebeSEric Cheng 	}
8056da14cebeSEric Cheng 	i_mac_perim_exit(mcip->mci_mip);
8057da14cebeSEric Cheng 
8058da14cebeSEric Cheng 	return ((mac_tx_notify_handle_t)mtnfp);
8059da14cebeSEric Cheng }
80604eaa4710SRishi Srivatsavai 
80614eaa4710SRishi Srivatsavai void
mac_bridge_vectors(mac_bridge_tx_t txf,mac_bridge_rx_t rxf,mac_bridge_ref_t reff,mac_bridge_ls_t lsf)80624eaa4710SRishi Srivatsavai mac_bridge_vectors(mac_bridge_tx_t txf, mac_bridge_rx_t rxf,
80634eaa4710SRishi Srivatsavai     mac_bridge_ref_t reff, mac_bridge_ls_t lsf)
80644eaa4710SRishi Srivatsavai {
80654eaa4710SRishi Srivatsavai 	mac_bridge_tx_cb = txf;
80664eaa4710SRishi Srivatsavai 	mac_bridge_rx_cb = rxf;
80674eaa4710SRishi Srivatsavai 	mac_bridge_ref_cb = reff;
80684eaa4710SRishi Srivatsavai 	mac_bridge_ls_cb = lsf;
80694eaa4710SRishi Srivatsavai }
80704eaa4710SRishi Srivatsavai 
80714eaa4710SRishi Srivatsavai int
mac_bridge_set(mac_handle_t mh,mac_handle_t link)80724eaa4710SRishi Srivatsavai mac_bridge_set(mac_handle_t mh, mac_handle_t link)
80734eaa4710SRishi Srivatsavai {
80744eaa4710SRishi Srivatsavai 	mac_impl_t *mip = (mac_impl_t *)mh;
80754eaa4710SRishi Srivatsavai 	int retv;
80764eaa4710SRishi Srivatsavai 
80774eaa4710SRishi Srivatsavai 	mutex_enter(&mip->mi_bridge_lock);
80784eaa4710SRishi Srivatsavai 	if (mip->mi_bridge_link == NULL) {
80794eaa4710SRishi Srivatsavai 		mip->mi_bridge_link = link;
80804eaa4710SRishi Srivatsavai 		retv = 0;
80814eaa4710SRishi Srivatsavai 	} else {
80824eaa4710SRishi Srivatsavai 		retv = EBUSY;
80834eaa4710SRishi Srivatsavai 	}
80844eaa4710SRishi Srivatsavai 	mutex_exit(&mip->mi_bridge_lock);
80854eaa4710SRishi Srivatsavai 	if (retv == 0) {
80864eaa4710SRishi Srivatsavai 		mac_poll_state_change(mh, B_FALSE);
80874eaa4710SRishi Srivatsavai 		mac_capab_update(mh);
80884eaa4710SRishi Srivatsavai 	}
80894eaa4710SRishi Srivatsavai 	return (retv);
80904eaa4710SRishi Srivatsavai }
80914eaa4710SRishi Srivatsavai 
80924eaa4710SRishi Srivatsavai /*
80934eaa4710SRishi Srivatsavai  * Disable bridging on the indicated link.
80944eaa4710SRishi Srivatsavai  */
80954eaa4710SRishi Srivatsavai void
mac_bridge_clear(mac_handle_t mh,mac_handle_t link)80964eaa4710SRishi Srivatsavai mac_bridge_clear(mac_handle_t mh, mac_handle_t link)
80974eaa4710SRishi Srivatsavai {
80984eaa4710SRishi Srivatsavai 	mac_impl_t *mip = (mac_impl_t *)mh;
80994eaa4710SRishi Srivatsavai 
81004eaa4710SRishi Srivatsavai 	mutex_enter(&mip->mi_bridge_lock);
81014eaa4710SRishi Srivatsavai 	ASSERT(mip->mi_bridge_link == link);
81024eaa4710SRishi Srivatsavai 	mip->mi_bridge_link = NULL;
81034eaa4710SRishi Srivatsavai 	mutex_exit(&mip->mi_bridge_lock);
81044eaa4710SRishi Srivatsavai 	mac_poll_state_change(mh, B_TRUE);
81054eaa4710SRishi Srivatsavai 	mac_capab_update(mh);
81064eaa4710SRishi Srivatsavai }
81074eaa4710SRishi Srivatsavai 
81084eaa4710SRishi Srivatsavai void
mac_no_active(mac_handle_t mh)81094eaa4710SRishi Srivatsavai mac_no_active(mac_handle_t mh)
81104eaa4710SRishi Srivatsavai {
81114eaa4710SRishi Srivatsavai 	mac_impl_t *mip = (mac_impl_t *)mh;
81124eaa4710SRishi Srivatsavai 
81134eaa4710SRishi Srivatsavai 	i_mac_perim_enter(mip);
81144eaa4710SRishi Srivatsavai 	mip->mi_state_flags |= MIS_NO_ACTIVE;
81154eaa4710SRishi Srivatsavai 	i_mac_perim_exit(mip);
81164eaa4710SRishi Srivatsavai }
81170dc2366fSVenugopal Iyer 
81180dc2366fSVenugopal Iyer /*
81190dc2366fSVenugopal Iyer  * Walk the primary VLAN clients whenever the primary's rings property
81200dc2366fSVenugopal Iyer  * changes and update the mac_resource_props_t for the VLAN's client.
81210dc2366fSVenugopal Iyer  * We need to do this since we don't support setting these properties
81220dc2366fSVenugopal Iyer  * on the primary's VLAN clients, but the VLAN clients have to
812384de666eSRyan Zezeski  * follow the primary w.r.t the rings property.
81240dc2366fSVenugopal Iyer  */
81250dc2366fSVenugopal Iyer void
mac_set_prim_vlan_rings(mac_impl_t * mip,mac_resource_props_t * mrp)81260dc2366fSVenugopal Iyer mac_set_prim_vlan_rings(mac_impl_t  *mip, mac_resource_props_t *mrp)
81270dc2366fSVenugopal Iyer {
81280dc2366fSVenugopal Iyer 	mac_client_impl_t	*vmcip;
81290dc2366fSVenugopal Iyer 	mac_resource_props_t	*vmrp;
81300dc2366fSVenugopal Iyer 
81310dc2366fSVenugopal Iyer 	for (vmcip = mip->mi_clients_list; vmcip != NULL;
81320dc2366fSVenugopal Iyer 	    vmcip = vmcip->mci_client_next) {
81330dc2366fSVenugopal Iyer 		if (!(vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) ||
81340dc2366fSVenugopal Iyer 		    mac_client_vid((mac_client_handle_t)vmcip) ==
81350dc2366fSVenugopal Iyer 		    VLAN_ID_NONE) {
81360dc2366fSVenugopal Iyer 			continue;
81370dc2366fSVenugopal Iyer 		}
81380dc2366fSVenugopal Iyer 		vmrp = MCIP_RESOURCE_PROPS(vmcip);
81390dc2366fSVenugopal Iyer 
81400dc2366fSVenugopal Iyer 		vmrp->mrp_nrxrings =  mrp->mrp_nrxrings;
81410dc2366fSVenugopal Iyer 		if (mrp->mrp_mask & MRP_RX_RINGS)
81420dc2366fSVenugopal Iyer 			vmrp->mrp_mask |= MRP_RX_RINGS;
81430dc2366fSVenugopal Iyer 		else if (vmrp->mrp_mask & MRP_RX_RINGS)
81440dc2366fSVenugopal Iyer 			vmrp->mrp_mask &= ~MRP_RX_RINGS;
81450dc2366fSVenugopal Iyer 
81460dc2366fSVenugopal Iyer 		vmrp->mrp_ntxrings =  mrp->mrp_ntxrings;
81470dc2366fSVenugopal Iyer 		if (mrp->mrp_mask & MRP_TX_RINGS)
81480dc2366fSVenugopal Iyer 			vmrp->mrp_mask |= MRP_TX_RINGS;
81490dc2366fSVenugopal Iyer 		else if (vmrp->mrp_mask & MRP_TX_RINGS)
81500dc2366fSVenugopal Iyer 			vmrp->mrp_mask &= ~MRP_TX_RINGS;
81510dc2366fSVenugopal Iyer 
81520dc2366fSVenugopal Iyer 		if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC)
81530dc2366fSVenugopal Iyer 			vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC;
81540dc2366fSVenugopal Iyer 		else
81550dc2366fSVenugopal Iyer 			vmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC;
81560dc2366fSVenugopal Iyer 
81570dc2366fSVenugopal Iyer 		if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC)
81580dc2366fSVenugopal Iyer 			vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC;
81590dc2366fSVenugopal Iyer 		else
81600dc2366fSVenugopal Iyer 			vmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC;
81610dc2366fSVenugopal Iyer 	}
81620dc2366fSVenugopal Iyer }
81630dc2366fSVenugopal Iyer 
81640dc2366fSVenugopal Iyer /*
81650dc2366fSVenugopal Iyer  * We are adding or removing ring(s) from a group. The source for taking
81660dc2366fSVenugopal Iyer  * rings is the default group. The destination for giving rings back is
81670dc2366fSVenugopal Iyer  * the default group.
81680dc2366fSVenugopal Iyer  */
81690dc2366fSVenugopal Iyer int
mac_group_ring_modify(mac_client_impl_t * mcip,mac_group_t * group,mac_group_t * defgrp)81700dc2366fSVenugopal Iyer mac_group_ring_modify(mac_client_impl_t *mcip, mac_group_t *group,
81710dc2366fSVenugopal Iyer     mac_group_t *defgrp)
81720dc2366fSVenugopal Iyer {
81730dc2366fSVenugopal Iyer 	mac_resource_props_t	*mrp = MCIP_RESOURCE_PROPS(mcip);
81740dc2366fSVenugopal Iyer 	uint_t			modify;
81750dc2366fSVenugopal Iyer 	int			count;
81760dc2366fSVenugopal Iyer 	mac_ring_t		*ring;
81770dc2366fSVenugopal Iyer 	mac_ring_t		*next;
81780dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
81790dc2366fSVenugopal Iyer 	mac_ring_t		**rings;
81800dc2366fSVenugopal Iyer 	uint_t			ringcnt;
81810dc2366fSVenugopal Iyer 	int			i = 0;
81820dc2366fSVenugopal Iyer 	boolean_t		rx_group = group->mrg_type == MAC_RING_TYPE_RX;
81830dc2366fSVenugopal Iyer 	int			start;
81840dc2366fSVenugopal Iyer 	int			end;
81850dc2366fSVenugopal Iyer 	mac_group_t		*tgrp;
81860dc2366fSVenugopal Iyer 	int			j;
81870dc2366fSVenugopal Iyer 	int			rv = 0;
81880dc2366fSVenugopal Iyer 
81890dc2366fSVenugopal Iyer 	/*
81900dc2366fSVenugopal Iyer 	 * If we are asked for just a group, we give 1 ring, else
81910dc2366fSVenugopal Iyer 	 * the specified number of rings.
81920dc2366fSVenugopal Iyer 	 */
81930dc2366fSVenugopal Iyer 	if (rx_group) {
81940dc2366fSVenugopal Iyer 		ringcnt = (mrp->mrp_mask & MRP_RXRINGS_UNSPEC) ? 1:
81950dc2366fSVenugopal Iyer 		    mrp->mrp_nrxrings;
81960dc2366fSVenugopal Iyer 	} else {
81970dc2366fSVenugopal Iyer 		ringcnt = (mrp->mrp_mask & MRP_TXRINGS_UNSPEC) ? 1:
81980dc2366fSVenugopal Iyer 		    mrp->mrp_ntxrings;
81990dc2366fSVenugopal Iyer 	}
82000dc2366fSVenugopal Iyer 
82010dc2366fSVenugopal Iyer 	/* don't allow modifying rings for a share for now. */
82026895f6f4SToomas Soome 	ASSERT(mcip->mci_share == 0);
82030dc2366fSVenugopal Iyer 
82040dc2366fSVenugopal Iyer 	if (ringcnt == group->mrg_cur_count)
82050dc2366fSVenugopal Iyer 		return (0);
82060dc2366fSVenugopal Iyer 
82070dc2366fSVenugopal Iyer 	if (group->mrg_cur_count > ringcnt) {
82080dc2366fSVenugopal Iyer 		modify = group->mrg_cur_count - ringcnt;
82090dc2366fSVenugopal Iyer 		if (rx_group) {
82100dc2366fSVenugopal Iyer 			if (mip->mi_rx_donor_grp == group) {
82110dc2366fSVenugopal Iyer 				ASSERT(mac_is_primary_client(mcip));
82120dc2366fSVenugopal Iyer 				mip->mi_rx_donor_grp = defgrp;
82130dc2366fSVenugopal Iyer 			} else {
82140dc2366fSVenugopal Iyer 				defgrp = mip->mi_rx_donor_grp;
82150dc2366fSVenugopal Iyer 			}
82160dc2366fSVenugopal Iyer 		}
82170dc2366fSVenugopal Iyer 		ring = group->mrg_rings;
82180dc2366fSVenugopal Iyer 		rings = kmem_alloc(modify * sizeof (mac_ring_handle_t),
82190dc2366fSVenugopal Iyer 		    KM_SLEEP);
82200dc2366fSVenugopal Iyer 		j = 0;
82210dc2366fSVenugopal Iyer 		for (count = 0; count < modify; count++) {
82220dc2366fSVenugopal Iyer 			next = ring->mr_next;
82230dc2366fSVenugopal Iyer 			rv = mac_group_mov_ring(mip, defgrp, ring);
82240dc2366fSVenugopal Iyer 			if (rv != 0) {
82250dc2366fSVenugopal Iyer 				/* cleanup on failure */
82260dc2366fSVenugopal Iyer 				for (j = 0; j < count; j++) {
82270dc2366fSVenugopal Iyer 					(void) mac_group_mov_ring(mip, group,
82280dc2366fSVenugopal Iyer 					    rings[j]);
82290dc2366fSVenugopal Iyer 				}
82300dc2366fSVenugopal Iyer 				break;
82310dc2366fSVenugopal Iyer 			}
82320dc2366fSVenugopal Iyer 			rings[j++] = ring;
82330dc2366fSVenugopal Iyer 			ring = next;
82340dc2366fSVenugopal Iyer 		}
82350dc2366fSVenugopal Iyer 		kmem_free(rings, modify * sizeof (mac_ring_handle_t));
82360dc2366fSVenugopal Iyer 		return (rv);
82370dc2366fSVenugopal Iyer 	}
82380dc2366fSVenugopal Iyer 	if (ringcnt >= MAX_RINGS_PER_GROUP)
82390dc2366fSVenugopal Iyer 		return (EINVAL);
82400dc2366fSVenugopal Iyer 
82410dc2366fSVenugopal Iyer 	modify = ringcnt - group->mrg_cur_count;
82420dc2366fSVenugopal Iyer 
82430dc2366fSVenugopal Iyer 	if (rx_group) {
82440dc2366fSVenugopal Iyer 		if (group != mip->mi_rx_donor_grp)
82450dc2366fSVenugopal Iyer 			defgrp = mip->mi_rx_donor_grp;
82460dc2366fSVenugopal Iyer 		else
82470dc2366fSVenugopal Iyer 			/*
82480dc2366fSVenugopal Iyer 			 * This is the donor group with all the remaining
82490dc2366fSVenugopal Iyer 			 * rings. Default group now gets to be the donor
82500dc2366fSVenugopal Iyer 			 */
82510dc2366fSVenugopal Iyer 			mip->mi_rx_donor_grp = defgrp;
82520dc2366fSVenugopal Iyer 		start = 1;
82530dc2366fSVenugopal Iyer 		end = mip->mi_rx_group_count;
82540dc2366fSVenugopal Iyer 	} else {
82550dc2366fSVenugopal Iyer 		start = 0;
82560dc2366fSVenugopal Iyer 		end = mip->mi_tx_group_count - 1;
82570dc2366fSVenugopal Iyer 	}
82580dc2366fSVenugopal Iyer 	/*
82590dc2366fSVenugopal Iyer 	 * If the default doesn't have any rings, lets see if we can
82600dc2366fSVenugopal Iyer 	 * take rings given to an h/w client that doesn't need it.
82610dc2366fSVenugopal Iyer 	 * For now, we just see if there is  any one client that can donate
82620dc2366fSVenugopal Iyer 	 * all the required rings.
82630dc2366fSVenugopal Iyer 	 */
82640dc2366fSVenugopal Iyer 	if (defgrp->mrg_cur_count < (modify + 1)) {
82650dc2366fSVenugopal Iyer 		for (i = start; i < end; i++) {
82660dc2366fSVenugopal Iyer 			if (rx_group) {
82670dc2366fSVenugopal Iyer 				tgrp = &mip->mi_rx_groups[i];
82680dc2366fSVenugopal Iyer 				if (tgrp == group || tgrp->mrg_state <
82690dc2366fSVenugopal Iyer 				    MAC_GROUP_STATE_RESERVED) {
82700dc2366fSVenugopal Iyer 					continue;
82710dc2366fSVenugopal Iyer 				}
827284de666eSRyan Zezeski 				if (i_mac_clients_hw(tgrp, MRP_RX_RINGS))
82730dc2366fSVenugopal Iyer 					continue;
827484de666eSRyan Zezeski 				mcip = tgrp->mrg_clients->mgc_client;
827584de666eSRyan Zezeski 				VERIFY3P(mcip, !=, NULL);
82760dc2366fSVenugopal Iyer 				if ((tgrp->mrg_cur_count +
82770dc2366fSVenugopal Iyer 				    defgrp->mrg_cur_count) < (modify + 1)) {
82780dc2366fSVenugopal Iyer 					continue;
82790dc2366fSVenugopal Iyer 				}
82800dc2366fSVenugopal Iyer 				if (mac_rx_switch_group(mcip, tgrp,
82810dc2366fSVenugopal Iyer 				    defgrp) != 0) {
82820dc2366fSVenugopal Iyer 					return (ENOSPC);
82830dc2366fSVenugopal Iyer 				}
82840dc2366fSVenugopal Iyer 			} else {
82850dc2366fSVenugopal Iyer 				tgrp = &mip->mi_tx_groups[i];
82860dc2366fSVenugopal Iyer 				if (tgrp == group || tgrp->mrg_state <
82870dc2366fSVenugopal Iyer 				    MAC_GROUP_STATE_RESERVED) {
82880dc2366fSVenugopal Iyer 					continue;
82890dc2366fSVenugopal Iyer 				}
829084de666eSRyan Zezeski 				if (i_mac_clients_hw(tgrp, MRP_TX_RINGS))
82910dc2366fSVenugopal Iyer 					continue;
829284de666eSRyan Zezeski 				mcip = tgrp->mrg_clients->mgc_client;
829384de666eSRyan Zezeski 				VERIFY3P(mcip, !=, NULL);
82940dc2366fSVenugopal Iyer 				if ((tgrp->mrg_cur_count +
82950dc2366fSVenugopal Iyer 				    defgrp->mrg_cur_count) < (modify + 1)) {
82960dc2366fSVenugopal Iyer 					continue;
82970dc2366fSVenugopal Iyer 				}
82980dc2366fSVenugopal Iyer 				/* OK, we can switch this to s/w */
82990dc2366fSVenugopal Iyer 				mac_tx_client_quiesce(
83000dc2366fSVenugopal Iyer 				    (mac_client_handle_t)mcip);
83010dc2366fSVenugopal Iyer 				mac_tx_switch_group(mcip, tgrp, defgrp);
83020dc2366fSVenugopal Iyer 				mac_tx_client_restart(
83030dc2366fSVenugopal Iyer 				    (mac_client_handle_t)mcip);
83040dc2366fSVenugopal Iyer 			}
83050dc2366fSVenugopal Iyer 		}
83060dc2366fSVenugopal Iyer 		if (defgrp->mrg_cur_count < (modify + 1))
83070dc2366fSVenugopal Iyer 			return (ENOSPC);
83080dc2366fSVenugopal Iyer 	}
83090dc2366fSVenugopal Iyer 	if ((rv = i_mac_group_allocate_rings(mip, group->mrg_type, defgrp,
83100dc2366fSVenugopal Iyer 	    group, mcip->mci_share, modify)) != 0) {
83110dc2366fSVenugopal Iyer 		return (rv);
83120dc2366fSVenugopal Iyer 	}
83130dc2366fSVenugopal Iyer 	return (0);
83140dc2366fSVenugopal Iyer }
83150dc2366fSVenugopal Iyer 
83160dc2366fSVenugopal Iyer /*
83170dc2366fSVenugopal Iyer  * Given the poolname in mac_resource_props, find the cpupart
83180dc2366fSVenugopal Iyer  * that is associated with this pool.  The cpupart will be used
83190dc2366fSVenugopal Iyer  * later for finding the cpus to be bound to the networking threads.
83200dc2366fSVenugopal Iyer  *
83210dc2366fSVenugopal Iyer  * use_default is set B_TRUE if pools are enabled and pool_default
83220dc2366fSVenugopal Iyer  * is returned.  This avoids a 2nd lookup to set the poolname
83230dc2366fSVenugopal Iyer  * for pool-effective.
83240dc2366fSVenugopal Iyer  *
83250dc2366fSVenugopal Iyer  * returns:
83260dc2366fSVenugopal Iyer  *
83270dc2366fSVenugopal Iyer  *    NULL -   pools are disabled or if the 'cpus' property is set.
83280dc2366fSVenugopal Iyer  *    cpupart of pool_default  - pools are enabled and the pool
83290dc2366fSVenugopal Iyer  *             is not available or poolname is blank
83300dc2366fSVenugopal Iyer  *    cpupart of named pool    - pools are enabled and the pool
83310dc2366fSVenugopal Iyer  *             is available.
83320dc2366fSVenugopal Iyer  */
83330dc2366fSVenugopal Iyer cpupart_t *
mac_pset_find(mac_resource_props_t * mrp,boolean_t * use_default)83340dc2366fSVenugopal Iyer mac_pset_find(mac_resource_props_t *mrp, boolean_t *use_default)
83350dc2366fSVenugopal Iyer {
83360dc2366fSVenugopal Iyer 	pool_t		*pool;
83370dc2366fSVenugopal Iyer 	cpupart_t	*cpupart;
83380dc2366fSVenugopal Iyer 
83390dc2366fSVenugopal Iyer 	*use_default = B_FALSE;
83400dc2366fSVenugopal Iyer 
83410dc2366fSVenugopal Iyer 	/* CPUs property is set */
83420dc2366fSVenugopal Iyer 	if (mrp->mrp_mask & MRP_CPUS)
83430dc2366fSVenugopal Iyer 		return (NULL);
83440dc2366fSVenugopal Iyer 
83450dc2366fSVenugopal Iyer 	ASSERT(pool_lock_held());
83460dc2366fSVenugopal Iyer 
83470dc2366fSVenugopal Iyer 	/* Pools are disabled, no pset */
83480dc2366fSVenugopal Iyer 	if (pool_state == POOL_DISABLED)
83490dc2366fSVenugopal Iyer 		return (NULL);
83500dc2366fSVenugopal Iyer 
83510dc2366fSVenugopal Iyer 	/* Pools property is set */
83520dc2366fSVenugopal Iyer 	if (mrp->mrp_mask & MRP_POOL) {
83530dc2366fSVenugopal Iyer 		if ((pool = pool_lookup_pool_by_name(mrp->mrp_pool)) == NULL) {
83540dc2366fSVenugopal Iyer 			/* Pool not found */
83550dc2366fSVenugopal Iyer 			DTRACE_PROBE1(mac_pset_find_no_pool, char *,
83560dc2366fSVenugopal Iyer 			    mrp->mrp_pool);
83570dc2366fSVenugopal Iyer 			*use_default = B_TRUE;
83580dc2366fSVenugopal Iyer 			pool = pool_default;
83590dc2366fSVenugopal Iyer 		}
83600dc2366fSVenugopal Iyer 	/* Pools property is not set */
83610dc2366fSVenugopal Iyer 	} else {
83620dc2366fSVenugopal Iyer 		*use_default = B_TRUE;
83630dc2366fSVenugopal Iyer 		pool = pool_default;
83640dc2366fSVenugopal Iyer 	}
83650dc2366fSVenugopal Iyer 
83660dc2366fSVenugopal Iyer 	/* Find the CPU pset that corresponds to the pool */
83670dc2366fSVenugopal Iyer 	mutex_enter(&cpu_lock);
83680dc2366fSVenugopal Iyer 	if ((cpupart = cpupart_find(pool->pool_pset->pset_id)) == NULL) {
83690dc2366fSVenugopal Iyer 		DTRACE_PROBE1(mac_find_pset_no_pset, psetid_t,
83700dc2366fSVenugopal Iyer 		    pool->pool_pset->pset_id);
83710dc2366fSVenugopal Iyer 	}
83720dc2366fSVenugopal Iyer 	mutex_exit(&cpu_lock);
83730dc2366fSVenugopal Iyer 
83740dc2366fSVenugopal Iyer 	return (cpupart);
83750dc2366fSVenugopal Iyer }
83760dc2366fSVenugopal Iyer 
83770dc2366fSVenugopal Iyer void
mac_set_pool_effective(boolean_t use_default,cpupart_t * cpupart,mac_resource_props_t * mrp,mac_resource_props_t * emrp)83780dc2366fSVenugopal Iyer mac_set_pool_effective(boolean_t use_default, cpupart_t *cpupart,
83790dc2366fSVenugopal Iyer     mac_resource_props_t *mrp, mac_resource_props_t *emrp)
83800dc2366fSVenugopal Iyer {
83810dc2366fSVenugopal Iyer 	ASSERT(pool_lock_held());
83820dc2366fSVenugopal Iyer 
83830dc2366fSVenugopal Iyer 	if (cpupart != NULL) {
83840dc2366fSVenugopal Iyer 		emrp->mrp_mask |= MRP_POOL;
83850dc2366fSVenugopal Iyer 		if (use_default) {
83860dc2366fSVenugopal Iyer 			(void) strcpy(emrp->mrp_pool,
83870dc2366fSVenugopal Iyer 			    "pool_default");
83880dc2366fSVenugopal Iyer 		} else {
83890dc2366fSVenugopal Iyer 			ASSERT(strlen(mrp->mrp_pool) != 0);
83900dc2366fSVenugopal Iyer 			(void) strcpy(emrp->mrp_pool,
83910dc2366fSVenugopal Iyer 			    mrp->mrp_pool);
83920dc2366fSVenugopal Iyer 		}
83930dc2366fSVenugopal Iyer 	} else {
83940dc2366fSVenugopal Iyer 		emrp->mrp_mask &= ~MRP_POOL;
83950dc2366fSVenugopal Iyer 		bzero(emrp->mrp_pool, MAXPATHLEN);
83960dc2366fSVenugopal Iyer 	}
83970dc2366fSVenugopal Iyer }
83980dc2366fSVenugopal Iyer 
83990dc2366fSVenugopal Iyer struct mac_pool_arg {
84000dc2366fSVenugopal Iyer 	char		mpa_poolname[MAXPATHLEN];
84010dc2366fSVenugopal Iyer 	pool_event_t	mpa_what;
84020dc2366fSVenugopal Iyer };
84030dc2366fSVenugopal Iyer 
84040dc2366fSVenugopal Iyer /*ARGSUSED*/
84050dc2366fSVenugopal Iyer static uint_t
mac_pool_link_update(mod_hash_key_t key,mod_hash_val_t * val,void * arg)84060dc2366fSVenugopal Iyer mac_pool_link_update(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
84070dc2366fSVenugopal Iyer {
84080dc2366fSVenugopal Iyer 	struct mac_pool_arg	*mpa = arg;
84090dc2366fSVenugopal Iyer 	mac_impl_t		*mip = (mac_impl_t *)val;
84100dc2366fSVenugopal Iyer 	mac_client_impl_t	*mcip;
84110dc2366fSVenugopal Iyer 	mac_resource_props_t	*mrp, *emrp;
84120dc2366fSVenugopal Iyer 	boolean_t		pool_update = B_FALSE;
84130dc2366fSVenugopal Iyer 	boolean_t		pool_clear = B_FALSE;
84140dc2366fSVenugopal Iyer 	boolean_t		use_default = B_FALSE;
84150dc2366fSVenugopal Iyer 	cpupart_t		*cpupart = NULL;
84160dc2366fSVenugopal Iyer 
84170dc2366fSVenugopal Iyer 	mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
84180dc2366fSVenugopal Iyer 	i_mac_perim_enter(mip);
84190dc2366fSVenugopal Iyer 	for (mcip = mip->mi_clients_list; mcip != NULL;
84200dc2366fSVenugopal Iyer 	    mcip = mcip->mci_client_next) {
84210dc2366fSVenugopal Iyer 		pool_update = B_FALSE;
84220dc2366fSVenugopal Iyer 		pool_clear = B_FALSE;
84230dc2366fSVenugopal Iyer 		use_default = B_FALSE;
84240dc2366fSVenugopal Iyer 		mac_client_get_resources((mac_client_handle_t)mcip, mrp);
84250dc2366fSVenugopal Iyer 		emrp = MCIP_EFFECTIVE_PROPS(mcip);
84260dc2366fSVenugopal Iyer 
84270dc2366fSVenugopal Iyer 		/*
84280dc2366fSVenugopal Iyer 		 * When pools are enabled
84290dc2366fSVenugopal Iyer 		 */
84300dc2366fSVenugopal Iyer 		if ((mpa->mpa_what == POOL_E_ENABLE) &&
84310dc2366fSVenugopal Iyer 		    ((mrp->mrp_mask & MRP_CPUS) == 0)) {
84320dc2366fSVenugopal Iyer 			mrp->mrp_mask |= MRP_POOL;
84330dc2366fSVenugopal Iyer 			pool_update = B_TRUE;
84340dc2366fSVenugopal Iyer 		}
84350dc2366fSVenugopal Iyer 
84360dc2366fSVenugopal Iyer 		/*
84370dc2366fSVenugopal Iyer 		 * When pools are disabled
84380dc2366fSVenugopal Iyer 		 */
84390dc2366fSVenugopal Iyer 		if ((mpa->mpa_what == POOL_E_DISABLE) &&
84400dc2366fSVenugopal Iyer 		    ((mrp->mrp_mask & MRP_CPUS) == 0)) {
84410dc2366fSVenugopal Iyer 			mrp->mrp_mask |= MRP_POOL;
84420dc2366fSVenugopal Iyer 			pool_clear = B_TRUE;
84430dc2366fSVenugopal Iyer 		}
84440dc2366fSVenugopal Iyer 
84450dc2366fSVenugopal Iyer 		/*
84460dc2366fSVenugopal Iyer 		 * Look for links with the pool property set and the poolname
84470dc2366fSVenugopal Iyer 		 * matching the one which is changing.
84480dc2366fSVenugopal Iyer 		 */
84490dc2366fSVenugopal Iyer 		if (strcmp(mrp->mrp_pool, mpa->mpa_poolname) == 0) {
84500dc2366fSVenugopal Iyer 			/*
84510dc2366fSVenugopal Iyer 			 * The pool associated with the link has changed.
84520dc2366fSVenugopal Iyer 			 */
84530dc2366fSVenugopal Iyer 			if (mpa->mpa_what == POOL_E_CHANGE) {
84540dc2366fSVenugopal Iyer 				mrp->mrp_mask |= MRP_POOL;
84550dc2366fSVenugopal Iyer 				pool_update = B_TRUE;
84560dc2366fSVenugopal Iyer 			}
84570dc2366fSVenugopal Iyer 		}
84580dc2366fSVenugopal Iyer 
84590dc2366fSVenugopal Iyer 		/*
84600dc2366fSVenugopal Iyer 		 * This link is associated with pool_default and
84610dc2366fSVenugopal Iyer 		 * pool_default has changed.
84620dc2366fSVenugopal Iyer 		 */
84630dc2366fSVenugopal Iyer 		if ((mpa->mpa_what == POOL_E_CHANGE) &&
84640dc2366fSVenugopal Iyer 		    (strcmp(emrp->mrp_pool, "pool_default") == 0) &&
84650dc2366fSVenugopal Iyer 		    (strcmp(mpa->mpa_poolname, "pool_default") == 0)) {
84660dc2366fSVenugopal Iyer 			mrp->mrp_mask |= MRP_POOL;
84670dc2366fSVenugopal Iyer 			pool_update = B_TRUE;
84680dc2366fSVenugopal Iyer 		}
84690dc2366fSVenugopal Iyer 
84700dc2366fSVenugopal Iyer 		/*
84710dc2366fSVenugopal Iyer 		 * Get new list of cpus for the pool, bind network
84720dc2366fSVenugopal Iyer 		 * threads to new list of cpus and update resources.
84730dc2366fSVenugopal Iyer 		 */
84740dc2366fSVenugopal Iyer 		if (pool_update) {
84750dc2366fSVenugopal Iyer 			if (MCIP_DATAPATH_SETUP(mcip)) {
84760dc2366fSVenugopal Iyer 				pool_lock();
84770dc2366fSVenugopal Iyer 				cpupart = mac_pset_find(mrp, &use_default);
84780dc2366fSVenugopal Iyer 				mac_fanout_setup(mcip, mcip->mci_flent, mrp,
84790dc2366fSVenugopal Iyer 				    mac_rx_deliver, mcip, NULL, cpupart);
84800dc2366fSVenugopal Iyer 				mac_set_pool_effective(use_default, cpupart,
84810dc2366fSVenugopal Iyer 				    mrp, emrp);
84820dc2366fSVenugopal Iyer 				pool_unlock();
84830dc2366fSVenugopal Iyer 			}
84840dc2366fSVenugopal Iyer 			mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip),
84850dc2366fSVenugopal Iyer 			    B_FALSE);
84860dc2366fSVenugopal Iyer 		}
84870dc2366fSVenugopal Iyer 
84880dc2366fSVenugopal Iyer 		/*
84890dc2366fSVenugopal Iyer 		 * Clear the effective pool and bind network threads
84900dc2366fSVenugopal Iyer 		 * to any available CPU.
84910dc2366fSVenugopal Iyer 		 */
84920dc2366fSVenugopal Iyer 		if (pool_clear) {
84930dc2366fSVenugopal Iyer 			if (MCIP_DATAPATH_SETUP(mcip)) {
84940dc2366fSVenugopal Iyer 				emrp->mrp_mask &= ~MRP_POOL;
84950dc2366fSVenugopal Iyer 				bzero(emrp->mrp_pool, MAXPATHLEN);
84960dc2366fSVenugopal Iyer 				mac_fanout_setup(mcip, mcip->mci_flent, mrp,
84970dc2366fSVenugopal Iyer 				    mac_rx_deliver, mcip, NULL, NULL);
84980dc2366fSVenugopal Iyer 			}
84990dc2366fSVenugopal Iyer 			mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip),
85000dc2366fSVenugopal Iyer 			    B_FALSE);
85010dc2366fSVenugopal Iyer 		}
85020dc2366fSVenugopal Iyer 	}
85030dc2366fSVenugopal Iyer 	i_mac_perim_exit(mip);
85040dc2366fSVenugopal Iyer 	kmem_free(mrp, sizeof (*mrp));
85050dc2366fSVenugopal Iyer 	return (MH_WALK_CONTINUE);
85060dc2366fSVenugopal Iyer }
85070dc2366fSVenugopal Iyer 
85080dc2366fSVenugopal Iyer static void
mac_pool_update(void * arg)85090dc2366fSVenugopal Iyer mac_pool_update(void *arg)
85100dc2366fSVenugopal Iyer {
85110dc2366fSVenugopal Iyer 	mod_hash_walk(i_mac_impl_hash, mac_pool_link_update, arg);
85120dc2366fSVenugopal Iyer 	kmem_free(arg, sizeof (struct mac_pool_arg));
85130dc2366fSVenugopal Iyer }
85140dc2366fSVenugopal Iyer 
85150dc2366fSVenugopal Iyer /*
85160dc2366fSVenugopal Iyer  * Callback function to be executed when a noteworthy pool event
85170dc2366fSVenugopal Iyer  * takes place.
85180dc2366fSVenugopal Iyer  */
85190dc2366fSVenugopal Iyer /* ARGSUSED */
85200dc2366fSVenugopal Iyer static void
mac_pool_event_cb(pool_event_t what,poolid_t id,void * arg)85210dc2366fSVenugopal Iyer mac_pool_event_cb(pool_event_t what, poolid_t id, void *arg)
85220dc2366fSVenugopal Iyer {
85230dc2366fSVenugopal Iyer 	pool_t			*pool;
85240dc2366fSVenugopal Iyer 	char			*poolname = NULL;
85250dc2366fSVenugopal Iyer 	struct mac_pool_arg	*mpa;
85260dc2366fSVenugopal Iyer 
85270dc2366fSVenugopal Iyer 	pool_lock();
85280dc2366fSVenugopal Iyer 	mpa = kmem_zalloc(sizeof (struct mac_pool_arg), KM_SLEEP);
85290dc2366fSVenugopal Iyer 
85300dc2366fSVenugopal Iyer 	switch (what) {
85310dc2366fSVenugopal Iyer 	case POOL_E_ENABLE:
85320dc2366fSVenugopal Iyer 	case POOL_E_DISABLE:
85330dc2366fSVenugopal Iyer 		break;
85340dc2366fSVenugopal Iyer 
85350dc2366fSVenugopal Iyer 	case POOL_E_CHANGE:
85360dc2366fSVenugopal Iyer 		pool = pool_lookup_pool_by_id(id);
85370dc2366fSVenugopal Iyer 		if (pool == NULL) {
85380dc2366fSVenugopal Iyer 			kmem_free(mpa, sizeof (struct mac_pool_arg));
85390dc2366fSVenugopal Iyer 			pool_unlock();
85400dc2366fSVenugopal Iyer 			return;
85410dc2366fSVenugopal Iyer 		}
85420dc2366fSVenugopal Iyer 		pool_get_name(pool, &poolname);
85430dc2366fSVenugopal Iyer 		(void) strlcpy(mpa->mpa_poolname, poolname,
85440dc2366fSVenugopal Iyer 		    sizeof (mpa->mpa_poolname));
85450dc2366fSVenugopal Iyer 		break;
85460dc2366fSVenugopal Iyer 
85470dc2366fSVenugopal Iyer 	default:
85480dc2366fSVenugopal Iyer 		kmem_free(mpa, sizeof (struct mac_pool_arg));
85490dc2366fSVenugopal Iyer 		pool_unlock();
85500dc2366fSVenugopal Iyer 		return;
85510dc2366fSVenugopal Iyer 	}
85520dc2366fSVenugopal Iyer 	pool_unlock();
85530dc2366fSVenugopal Iyer 
85540dc2366fSVenugopal Iyer 	mpa->mpa_what = what;
85550dc2366fSVenugopal Iyer 
85560dc2366fSVenugopal Iyer 	mac_pool_update(mpa);
85570dc2366fSVenugopal Iyer }
85580dc2366fSVenugopal Iyer 
85590dc2366fSVenugopal Iyer /*
85600dc2366fSVenugopal Iyer  * Set effective rings property. This could be called from datapath_setup/
85610dc2366fSVenugopal Iyer  * datapath_teardown or set-linkprop.
85620dc2366fSVenugopal Iyer  * If the group is reserved we just go ahead and set the effective rings.
85630dc2366fSVenugopal Iyer  * Additionally, for TX this could mean the default group has lost/gained
85640dc2366fSVenugopal Iyer  * some rings, so if the default group is reserved, we need to adjust the
85650dc2366fSVenugopal Iyer  * effective rings for the default group clients. For RX, if we are working
856684de666eSRyan Zezeski  * with the non-default group, we just need to reset the effective props
85670dc2366fSVenugopal Iyer  * for the default group clients.
85680dc2366fSVenugopal Iyer  */
85690dc2366fSVenugopal Iyer void
mac_set_rings_effective(mac_client_impl_t * mcip)85700dc2366fSVenugopal Iyer mac_set_rings_effective(mac_client_impl_t *mcip)
85710dc2366fSVenugopal Iyer {
85720dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
85730dc2366fSVenugopal Iyer 	mac_group_t		*grp;
85740dc2366fSVenugopal Iyer 	mac_group_t		*defgrp;
85750dc2366fSVenugopal Iyer 	flow_entry_t		*flent = mcip->mci_flent;
85760dc2366fSVenugopal Iyer 	mac_resource_props_t	*emrp = MCIP_EFFECTIVE_PROPS(mcip);
85770dc2366fSVenugopal Iyer 	mac_grp_client_t	*mgcp;
85780dc2366fSVenugopal Iyer 	mac_client_impl_t	*gmcip;
85790dc2366fSVenugopal Iyer 
85800dc2366fSVenugopal Iyer 	grp = flent->fe_rx_ring_group;
85810dc2366fSVenugopal Iyer 	if (grp != NULL) {
85820dc2366fSVenugopal Iyer 		defgrp = MAC_DEFAULT_RX_GROUP(mip);
85830dc2366fSVenugopal Iyer 		/*
85840dc2366fSVenugopal Iyer 		 * If we have reserved a group, set the effective rings
85850dc2366fSVenugopal Iyer 		 * to the ring count in the group.
85860dc2366fSVenugopal Iyer 		 */
85870dc2366fSVenugopal Iyer 		if (grp->mrg_state == MAC_GROUP_STATE_RESERVED) {
85880dc2366fSVenugopal Iyer 			emrp->mrp_mask |= MRP_RX_RINGS;
85890dc2366fSVenugopal Iyer 			emrp->mrp_nrxrings = grp->mrg_cur_count;
85900dc2366fSVenugopal Iyer 		}
85910dc2366fSVenugopal Iyer 
85920dc2366fSVenugopal Iyer 		/*
85930dc2366fSVenugopal Iyer 		 * We go through the clients in the shared group and
85940dc2366fSVenugopal Iyer 		 * reset the effective properties. It is possible this
85950dc2366fSVenugopal Iyer 		 * might have already been done for some client (i.e.
85960dc2366fSVenugopal Iyer 		 * if some client is being moved to a group that is
85970dc2366fSVenugopal Iyer 		 * already shared). The case where the default group is
85980dc2366fSVenugopal Iyer 		 * RESERVED is taken care of above (note in the RX side if
85990dc2366fSVenugopal Iyer 		 * there is a non-default group, the default group is always
86000dc2366fSVenugopal Iyer 		 * SHARED).
86010dc2366fSVenugopal Iyer 		 */
86020dc2366fSVenugopal Iyer 		if (grp != defgrp || grp->mrg_state == MAC_GROUP_STATE_SHARED) {
86030dc2366fSVenugopal Iyer 			if (grp->mrg_state == MAC_GROUP_STATE_SHARED)
86040dc2366fSVenugopal Iyer 				mgcp = grp->mrg_clients;
86050dc2366fSVenugopal Iyer 			else
86060dc2366fSVenugopal Iyer 				mgcp = defgrp->mrg_clients;
86070dc2366fSVenugopal Iyer 			while (mgcp != NULL) {
86080dc2366fSVenugopal Iyer 				gmcip = mgcp->mgc_client;
86090dc2366fSVenugopal Iyer 				emrp = MCIP_EFFECTIVE_PROPS(gmcip);
86100dc2366fSVenugopal Iyer 				if (emrp->mrp_mask & MRP_RX_RINGS) {
86110dc2366fSVenugopal Iyer 					emrp->mrp_mask &= ~MRP_RX_RINGS;
86120dc2366fSVenugopal Iyer 					emrp->mrp_nrxrings = 0;
86130dc2366fSVenugopal Iyer 				}
86140dc2366fSVenugopal Iyer 				mgcp = mgcp->mgc_next;
86150dc2366fSVenugopal Iyer 			}
86160dc2366fSVenugopal Iyer 		}
86170dc2366fSVenugopal Iyer 	}
86180dc2366fSVenugopal Iyer 
86190dc2366fSVenugopal Iyer 	/* Now the TX side */
86200dc2366fSVenugopal Iyer 	grp = flent->fe_tx_ring_group;
86210dc2366fSVenugopal Iyer 	if (grp != NULL) {
86220dc2366fSVenugopal Iyer 		defgrp = MAC_DEFAULT_TX_GROUP(mip);
86230dc2366fSVenugopal Iyer 
86240dc2366fSVenugopal Iyer 		if (grp->mrg_state == MAC_GROUP_STATE_RESERVED) {
86250dc2366fSVenugopal Iyer 			emrp->mrp_mask |= MRP_TX_RINGS;
86260dc2366fSVenugopal Iyer 			emrp->mrp_ntxrings = grp->mrg_cur_count;
86270dc2366fSVenugopal Iyer 		} else if (grp->mrg_state == MAC_GROUP_STATE_SHARED) {
86280dc2366fSVenugopal Iyer 			mgcp = grp->mrg_clients;
86290dc2366fSVenugopal Iyer 			while (mgcp != NULL) {
86300dc2366fSVenugopal Iyer 				gmcip = mgcp->mgc_client;
86310dc2366fSVenugopal Iyer 				emrp = MCIP_EFFECTIVE_PROPS(gmcip);
86320dc2366fSVenugopal Iyer 				if (emrp->mrp_mask & MRP_TX_RINGS) {
86330dc2366fSVenugopal Iyer 					emrp->mrp_mask &= ~MRP_TX_RINGS;
86340dc2366fSVenugopal Iyer 					emrp->mrp_ntxrings = 0;
86350dc2366fSVenugopal Iyer 				}
86360dc2366fSVenugopal Iyer 				mgcp = mgcp->mgc_next;
86370dc2366fSVenugopal Iyer 			}
86380dc2366fSVenugopal Iyer 		}
86390dc2366fSVenugopal Iyer 
86400dc2366fSVenugopal Iyer 		/*
86410dc2366fSVenugopal Iyer 		 * If the group is not the default group and the default
86420dc2366fSVenugopal Iyer 		 * group is reserved, the ring count in the default group
86430dc2366fSVenugopal Iyer 		 * might have changed, update it.
86440dc2366fSVenugopal Iyer 		 */
86450dc2366fSVenugopal Iyer 		if (grp != defgrp &&
86460dc2366fSVenugopal Iyer 		    defgrp->mrg_state == MAC_GROUP_STATE_RESERVED) {
86470dc2366fSVenugopal Iyer 			gmcip = MAC_GROUP_ONLY_CLIENT(defgrp);
86480dc2366fSVenugopal Iyer 			emrp = MCIP_EFFECTIVE_PROPS(gmcip);
86490dc2366fSVenugopal Iyer 			emrp->mrp_ntxrings = defgrp->mrg_cur_count;
86500dc2366fSVenugopal Iyer 		}
86510dc2366fSVenugopal Iyer 	}
86520dc2366fSVenugopal Iyer 	emrp = MCIP_EFFECTIVE_PROPS(mcip);
86530dc2366fSVenugopal Iyer }
86540dc2366fSVenugopal Iyer 
86550dc2366fSVenugopal Iyer /*
86560dc2366fSVenugopal Iyer  * Check if the primary is in the default group. If so, see if we
86570dc2366fSVenugopal Iyer  * can give it a an exclusive group now that another client is
86580dc2366fSVenugopal Iyer  * being configured. We take the primary out of the default group
86590dc2366fSVenugopal Iyer  * because the multicast/broadcast packets for the all the clients
86600dc2366fSVenugopal Iyer  * will land in the default ring in the default group which means
86610dc2366fSVenugopal Iyer  * any client in the default group, even if it is the only on in
86620dc2366fSVenugopal Iyer  * the group, will lose exclusive access to the rings, hence
86630dc2366fSVenugopal Iyer  * polling.
86640dc2366fSVenugopal Iyer  */
86650dc2366fSVenugopal Iyer mac_client_impl_t *
mac_check_primary_relocation(mac_client_impl_t * mcip,boolean_t rxhw)86660dc2366fSVenugopal Iyer mac_check_primary_relocation(mac_client_impl_t *mcip, boolean_t rxhw)
86670dc2366fSVenugopal Iyer {
86680dc2366fSVenugopal Iyer 	mac_impl_t		*mip = mcip->mci_mip;
86690dc2366fSVenugopal Iyer 	mac_group_t		*defgrp = MAC_DEFAULT_RX_GROUP(mip);
86700dc2366fSVenugopal Iyer 	flow_entry_t		*flent = mcip->mci_flent;
86710dc2366fSVenugopal Iyer 	mac_resource_props_t	*mrp = MCIP_RESOURCE_PROPS(mcip);
86720dc2366fSVenugopal Iyer 	uint8_t			*mac_addr;
86730dc2366fSVenugopal Iyer 	mac_group_t		*ngrp;
86740dc2366fSVenugopal Iyer 
86750dc2366fSVenugopal Iyer 	/*
86760dc2366fSVenugopal Iyer 	 * Check if the primary is in the default group, if not
86770dc2366fSVenugopal Iyer 	 * or if it is explicitly configured to be in the default
86780dc2366fSVenugopal Iyer 	 * group OR set the RX rings property, return.
86790dc2366fSVenugopal Iyer 	 */
86800dc2366fSVenugopal Iyer 	if (flent->fe_rx_ring_group != defgrp || mrp->mrp_mask & MRP_RX_RINGS)
86810dc2366fSVenugopal Iyer 		return (NULL);
86820dc2366fSVenugopal Iyer 
86830dc2366fSVenugopal Iyer 	/*
86840dc2366fSVenugopal Iyer 	 * If the new client needs an exclusive group and we
86850dc2366fSVenugopal Iyer 	 * don't have another for the primary, return.
86860dc2366fSVenugopal Iyer 	 */
86870dc2366fSVenugopal Iyer 	if (rxhw && mip->mi_rxhwclnt_avail < 2)
86880dc2366fSVenugopal Iyer 		return (NULL);
86890dc2366fSVenugopal Iyer 
86900dc2366fSVenugopal Iyer 	mac_addr = flent->fe_flow_desc.fd_dst_mac;
86910dc2366fSVenugopal Iyer 	/*
86920dc2366fSVenugopal Iyer 	 * We call this when we are setting up the datapath for
86930dc2366fSVenugopal Iyer 	 * the first non-primary.
86940dc2366fSVenugopal Iyer 	 */
86950dc2366fSVenugopal Iyer 	ASSERT(mip->mi_nactiveclients == 2);
869684de666eSRyan Zezeski 
86970dc2366fSVenugopal Iyer 	/*
86980dc2366fSVenugopal Iyer 	 * OK, now we have the primary that needs to be relocated.
86990dc2366fSVenugopal Iyer 	 */
87000dc2366fSVenugopal Iyer 	ngrp =  mac_reserve_rx_group(mcip, mac_addr, B_TRUE);
87010dc2366fSVenugopal Iyer 	if (ngrp == NULL)
87020dc2366fSVenugopal Iyer 		return (NULL);
87030dc2366fSVenugopal Iyer 	if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) {
87040dc2366fSVenugopal Iyer 		mac_stop_group(ngrp);
87050dc2366fSVenugopal Iyer 		return (NULL);
87060dc2366fSVenugopal Iyer 	}
87070dc2366fSVenugopal Iyer 	return (mcip);
87080dc2366fSVenugopal Iyer }
870945d3dd98SRobert Mustacchi 
871045d3dd98SRobert Mustacchi void
mac_transceiver_init(mac_impl_t * mip)871145d3dd98SRobert Mustacchi mac_transceiver_init(mac_impl_t *mip)
871245d3dd98SRobert Mustacchi {
871345d3dd98SRobert Mustacchi 	if (mac_capab_get((mac_handle_t)mip, MAC_CAPAB_TRANSCEIVER,
871445d3dd98SRobert Mustacchi 	    &mip->mi_transceiver)) {
871545d3dd98SRobert Mustacchi 		/*
871645d3dd98SRobert Mustacchi 		 * The driver set a flag that we don't know about. In this case,
871745d3dd98SRobert Mustacchi 		 * we need to warn about that case and ignore this capability.
871845d3dd98SRobert Mustacchi 		 */
871945d3dd98SRobert Mustacchi 		if (mip->mi_transceiver.mct_flags != 0) {
872045d3dd98SRobert Mustacchi 			dev_err(mip->mi_dip, CE_WARN, "driver set transceiver "
872145d3dd98SRobert Mustacchi 			    "flags to invalid value: 0x%x, ignoring "
872245d3dd98SRobert Mustacchi 			    "capability", mip->mi_transceiver.mct_flags);
872345d3dd98SRobert Mustacchi 			bzero(&mip->mi_transceiver,
872445d3dd98SRobert Mustacchi 			    sizeof (mac_capab_transceiver_t));
872545d3dd98SRobert Mustacchi 		}
872645d3dd98SRobert Mustacchi 	} else {
872745d3dd98SRobert Mustacchi 			bzero(&mip->mi_transceiver,
872845d3dd98SRobert Mustacchi 			    sizeof (mac_capab_transceiver_t));
872945d3dd98SRobert Mustacchi 	}
873045d3dd98SRobert Mustacchi }
873145d3dd98SRobert Mustacchi 
873245d3dd98SRobert Mustacchi int
mac_transceiver_count(mac_handle_t mh,uint_t * countp)873345d3dd98SRobert Mustacchi mac_transceiver_count(mac_handle_t mh, uint_t *countp)
873445d3dd98SRobert Mustacchi {
873545d3dd98SRobert Mustacchi 	mac_impl_t *mip = (mac_impl_t *)mh;
873645d3dd98SRobert Mustacchi 
873745d3dd98SRobert Mustacchi 	ASSERT(MAC_PERIM_HELD(mh));
873845d3dd98SRobert Mustacchi 
873945d3dd98SRobert Mustacchi 	if (mip->mi_transceiver.mct_ntransceivers == 0)
874045d3dd98SRobert Mustacchi 		return (ENOTSUP);
874145d3dd98SRobert Mustacchi 
874245d3dd98SRobert Mustacchi 	*countp = mip->mi_transceiver.mct_ntransceivers;
874345d3dd98SRobert Mustacchi 	return (0);
874445d3dd98SRobert Mustacchi }
874545d3dd98SRobert Mustacchi 
874645d3dd98SRobert Mustacchi int
mac_transceiver_info(mac_handle_t mh,uint_t tranid,boolean_t * present,boolean_t * usable)874745d3dd98SRobert Mustacchi mac_transceiver_info(mac_handle_t mh, uint_t tranid, boolean_t *present,
874845d3dd98SRobert Mustacchi     boolean_t *usable)
874945d3dd98SRobert Mustacchi {
875045d3dd98SRobert Mustacchi 	int ret;
875145d3dd98SRobert Mustacchi 	mac_transceiver_info_t info;
875245d3dd98SRobert Mustacchi 
875345d3dd98SRobert Mustacchi 	mac_impl_t *mip = (mac_impl_t *)mh;
875445d3dd98SRobert Mustacchi 
875545d3dd98SRobert Mustacchi 	ASSERT(MAC_PERIM_HELD(mh));
875645d3dd98SRobert Mustacchi 
875745d3dd98SRobert Mustacchi 	if (mip->mi_transceiver.mct_info == NULL ||
875845d3dd98SRobert Mustacchi 	    mip->mi_transceiver.mct_ntransceivers == 0)
875945d3dd98SRobert Mustacchi 		return (ENOTSUP);
876045d3dd98SRobert Mustacchi 
876145d3dd98SRobert Mustacchi 	if (tranid >= mip->mi_transceiver.mct_ntransceivers)
876245d3dd98SRobert Mustacchi 		return (EINVAL);
876345d3dd98SRobert Mustacchi 
876445d3dd98SRobert Mustacchi 	bzero(&info, sizeof (mac_transceiver_info_t));
876545d3dd98SRobert Mustacchi 	if ((ret = mip->mi_transceiver.mct_info(mip->mi_driver, tranid,
876645d3dd98SRobert Mustacchi 	    &info)) != 0) {
876745d3dd98SRobert Mustacchi 		return (ret);
876845d3dd98SRobert Mustacchi 	}
876945d3dd98SRobert Mustacchi 
877045d3dd98SRobert Mustacchi 	*present = info.mti_present;
877145d3dd98SRobert Mustacchi 	*usable = info.mti_usable;
877245d3dd98SRobert Mustacchi 	return (0);
877345d3dd98SRobert Mustacchi }
877445d3dd98SRobert Mustacchi 
877545d3dd98SRobert Mustacchi int
mac_transceiver_read(mac_handle_t mh,uint_t tranid,uint_t page,void * buf,size_t nbytes,off_t offset,size_t * nread)877645d3dd98SRobert Mustacchi mac_transceiver_read(mac_handle_t mh, uint_t tranid, uint_t page, void *buf,
877745d3dd98SRobert Mustacchi     size_t nbytes, off_t offset, size_t *nread)
877845d3dd98SRobert Mustacchi {
877945d3dd98SRobert Mustacchi 	int ret;
878045d3dd98SRobert Mustacchi 	size_t nr;
878145d3dd98SRobert Mustacchi 	mac_impl_t *mip = (mac_impl_t *)mh;
878245d3dd98SRobert Mustacchi 
878345d3dd98SRobert Mustacchi 	ASSERT(MAC_PERIM_HELD(mh));
878445d3dd98SRobert Mustacchi 
878545d3dd98SRobert Mustacchi 	if (mip->mi_transceiver.mct_read == NULL)
878645d3dd98SRobert Mustacchi 		return (ENOTSUP);
878745d3dd98SRobert Mustacchi 
878845d3dd98SRobert Mustacchi 	if (tranid >= mip->mi_transceiver.mct_ntransceivers)
878945d3dd98SRobert Mustacchi 		return (EINVAL);
879045d3dd98SRobert Mustacchi 
879145d3dd98SRobert Mustacchi 	/*
879245d3dd98SRobert Mustacchi 	 * All supported pages today are 256 bytes wide. Make sure offset +
879345d3dd98SRobert Mustacchi 	 * nbytes never exceeds that.
879445d3dd98SRobert Mustacchi 	 */
879545d3dd98SRobert Mustacchi 	if (offset < 0 || offset >= 256 || nbytes > 256 ||
879645d3dd98SRobert Mustacchi 	    offset + nbytes > 256)
879745d3dd98SRobert Mustacchi 		return (EINVAL);
879845d3dd98SRobert Mustacchi 
879945d3dd98SRobert Mustacchi 	if (nread == NULL)
880045d3dd98SRobert Mustacchi 		nread = &nr;
880145d3dd98SRobert Mustacchi 	ret = mip->mi_transceiver.mct_read(mip->mi_driver, tranid, page, buf,
880245d3dd98SRobert Mustacchi 	    nbytes, offset, nread);
880345d3dd98SRobert Mustacchi 	if (ret == 0 && *nread > nbytes) {
880445d3dd98SRobert Mustacchi 		dev_err(mip->mi_dip, CE_PANIC, "driver wrote %lu bytes into "
880545d3dd98SRobert Mustacchi 		    "%lu byte sized buffer, possible memory corruption",
880645d3dd98SRobert Mustacchi 		    *nread, nbytes);
880745d3dd98SRobert Mustacchi 	}
880845d3dd98SRobert Mustacchi 
880945d3dd98SRobert Mustacchi 	return (ret);
881045d3dd98SRobert Mustacchi }
8811c1e9c696SRobert Mustacchi 
8812c1e9c696SRobert Mustacchi void
mac_led_init(mac_impl_t * mip)8813c1e9c696SRobert Mustacchi mac_led_init(mac_impl_t *mip)
8814c1e9c696SRobert Mustacchi {
8815c1e9c696SRobert Mustacchi 	mip->mi_led_modes = MAC_LED_DEFAULT;
8816c1e9c696SRobert Mustacchi 
8817c1e9c696SRobert Mustacchi 	if (!mac_capab_get((mac_handle_t)mip, MAC_CAPAB_LED, &mip->mi_led)) {
8818c1e9c696SRobert Mustacchi 		bzero(&mip->mi_led, sizeof (mac_capab_led_t));
8819c1e9c696SRobert Mustacchi 		return;
8820c1e9c696SRobert Mustacchi 	}
8821c1e9c696SRobert Mustacchi 
8822c1e9c696SRobert Mustacchi 	if (mip->mi_led.mcl_flags != 0) {
8823c1e9c696SRobert Mustacchi 		dev_err(mip->mi_dip, CE_WARN, "driver set led capability "
8824c1e9c696SRobert Mustacchi 		    "flags to invalid value: 0x%x, ignoring "
8825c1e9c696SRobert Mustacchi 		    "capability", mip->mi_transceiver.mct_flags);
8826c1e9c696SRobert Mustacchi 		bzero(&mip->mi_led, sizeof (mac_capab_led_t));
8827c1e9c696SRobert Mustacchi 		return;
8828c1e9c696SRobert Mustacchi 	}
8829c1e9c696SRobert Mustacchi 
8830c1e9c696SRobert Mustacchi 	if ((mip->mi_led.mcl_modes & ~MAC_LED_ALL) != 0) {
8831c1e9c696SRobert Mustacchi 		dev_err(mip->mi_dip, CE_WARN, "driver set led capability "
8832c1e9c696SRobert Mustacchi 		    "supported modes to invalid value: 0x%x, ignoring "
8833c1e9c696SRobert Mustacchi 		    "capability", mip->mi_transceiver.mct_flags);
8834c1e9c696SRobert Mustacchi 		bzero(&mip->mi_led, sizeof (mac_capab_led_t));
8835c1e9c696SRobert Mustacchi 		return;
8836c1e9c696SRobert Mustacchi 	}
8837c1e9c696SRobert Mustacchi }
8838c1e9c696SRobert Mustacchi 
8839c1e9c696SRobert Mustacchi int
mac_led_get(mac_handle_t mh,mac_led_mode_t * supported,mac_led_mode_t * active)8840c1e9c696SRobert Mustacchi mac_led_get(mac_handle_t mh, mac_led_mode_t *supported, mac_led_mode_t *active)
8841c1e9c696SRobert Mustacchi {
8842c1e9c696SRobert Mustacchi 	mac_impl_t *mip = (mac_impl_t *)mh;
8843c1e9c696SRobert Mustacchi 
8844c1e9c696SRobert Mustacchi 	ASSERT(MAC_PERIM_HELD(mh));
8845c1e9c696SRobert Mustacchi 
8846c1e9c696SRobert Mustacchi 	if (mip->mi_led.mcl_set == NULL)
8847c1e9c696SRobert Mustacchi 		return (ENOTSUP);
8848c1e9c696SRobert Mustacchi 
8849c1e9c696SRobert Mustacchi 	*supported = mip->mi_led.mcl_modes;
8850c1e9c696SRobert Mustacchi 	*active = mip->mi_led_modes;
8851c1e9c696SRobert Mustacchi 
8852c1e9c696SRobert Mustacchi 	return (0);
8853c1e9c696SRobert Mustacchi }
8854c1e9c696SRobert Mustacchi 
8855c1e9c696SRobert Mustacchi /*
8856c1e9c696SRobert Mustacchi  * Update and multiplex the various LED requests. We only ever send one LED to
8857c1e9c696SRobert Mustacchi  * the underlying driver at a time. As such, we end up multiplexing all
8858c1e9c696SRobert Mustacchi  * requested states and picking one to send down to the driver.
8859c1e9c696SRobert Mustacchi  */
8860c1e9c696SRobert Mustacchi int
mac_led_set(mac_handle_t mh,mac_led_mode_t desired)8861c1e9c696SRobert Mustacchi mac_led_set(mac_handle_t mh, mac_led_mode_t desired)
8862c1e9c696SRobert Mustacchi {
8863c1e9c696SRobert Mustacchi 	int ret;
8864c1e9c696SRobert Mustacchi 	mac_led_mode_t driver;
8865c1e9c696SRobert Mustacchi 
8866c1e9c696SRobert Mustacchi 	mac_impl_t *mip = (mac_impl_t *)mh;
8867c1e9c696SRobert Mustacchi 
8868c1e9c696SRobert Mustacchi 	ASSERT(MAC_PERIM_HELD(mh));
8869c1e9c696SRobert Mustacchi 
8870c1e9c696SRobert Mustacchi 	/*
8871c1e9c696SRobert Mustacchi 	 * If we've been passed a desired value of zero, that indicates that
8872c1e9c696SRobert Mustacchi 	 * we're basically resetting to the value of zero, which is our default
8873c1e9c696SRobert Mustacchi 	 * value.
8874c1e9c696SRobert Mustacchi 	 */
8875c1e9c696SRobert Mustacchi 	if (desired == 0)
8876c1e9c696SRobert Mustacchi 		desired = MAC_LED_DEFAULT;
8877c1e9c696SRobert Mustacchi 
8878c1e9c696SRobert Mustacchi 	if (mip->mi_led.mcl_set == NULL)
8879c1e9c696SRobert Mustacchi 		return (ENOTSUP);
8880c1e9c696SRobert Mustacchi 
8881c1e9c696SRobert Mustacchi 	/*
8882c1e9c696SRobert Mustacchi 	 * Catch both values that we don't know about and those that the driver
8883c1e9c696SRobert Mustacchi 	 * doesn't support.
8884c1e9c696SRobert Mustacchi 	 */
8885c1e9c696SRobert Mustacchi 	if ((desired & ~MAC_LED_ALL) != 0)
8886c1e9c696SRobert Mustacchi 		return (EINVAL);
8887c1e9c696SRobert Mustacchi 
8888c1e9c696SRobert Mustacchi 	if ((desired & ~mip->mi_led.mcl_modes) != 0)
8889c1e9c696SRobert Mustacchi 		return (ENOTSUP);
8890c1e9c696SRobert Mustacchi 
8891c1e9c696SRobert Mustacchi 	/*
8892c1e9c696SRobert Mustacchi 	 * If we have the same value, then there is nothing to do.
8893c1e9c696SRobert Mustacchi 	 */
8894c1e9c696SRobert Mustacchi 	if (desired == mip->mi_led_modes)
8895c1e9c696SRobert Mustacchi 		return (0);
8896c1e9c696SRobert Mustacchi 
8897c1e9c696SRobert Mustacchi 	/*
8898c1e9c696SRobert Mustacchi 	 * Based on the desired value, determine what to send to the driver. We
8899c1e9c696SRobert Mustacchi 	 * only will send a single bit to the driver at any given time. IDENT
8900c1e9c696SRobert Mustacchi 	 * takes priority over OFF or ON. We also let OFF take priority over the
8901c1e9c696SRobert Mustacchi 	 * rest.
8902c1e9c696SRobert Mustacchi 	 */
8903c1e9c696SRobert Mustacchi 	if (desired & MAC_LED_IDENT) {
8904c1e9c696SRobert Mustacchi 		driver = MAC_LED_IDENT;
8905c1e9c696SRobert Mustacchi 	} else if (desired & MAC_LED_OFF) {
8906c1e9c696SRobert Mustacchi 		driver = MAC_LED_OFF;
8907c1e9c696SRobert Mustacchi 	} else if (desired & MAC_LED_ON) {
8908c1e9c696SRobert Mustacchi 		driver = MAC_LED_ON;
8909c1e9c696SRobert Mustacchi 	} else {
8910c1e9c696SRobert Mustacchi 		driver = MAC_LED_DEFAULT;
8911c1e9c696SRobert Mustacchi 	}
8912c1e9c696SRobert Mustacchi 
8913c1e9c696SRobert Mustacchi 	if ((ret = mip->mi_led.mcl_set(mip->mi_driver, driver, 0)) == 0) {
8914c1e9c696SRobert Mustacchi 		mip->mi_led_modes = desired;
8915c1e9c696SRobert Mustacchi 	}
8916c1e9c696SRobert Mustacchi 
8917c1e9c696SRobert Mustacchi 	return (ret);
8918c1e9c696SRobert Mustacchi }
8919c61a1653SRyan Zezeski 
8920c61a1653SRyan Zezeski /*
8921c61a1653SRyan Zezeski  * Send packets through the Tx ring ('mrh') or through the default
8922c61a1653SRyan Zezeski  * handler if no ring is specified. Before passing the packet down to
8923c61a1653SRyan Zezeski  * the MAC provider, emulate any hardware offloads which have been
8924c61a1653SRyan Zezeski  * requested but are not supported by the provider.
8925c61a1653SRyan Zezeski  */
8926c61a1653SRyan Zezeski mblk_t *
mac_ring_tx(mac_handle_t mh,mac_ring_handle_t mrh,mblk_t * mp)8927c61a1653SRyan Zezeski mac_ring_tx(mac_handle_t mh, mac_ring_handle_t mrh, mblk_t *mp)
8928c61a1653SRyan Zezeski {
8929c61a1653SRyan Zezeski 	mac_impl_t *mip = (mac_impl_t *)mh;
8930c61a1653SRyan Zezeski 
8931c61a1653SRyan Zezeski 	if (mrh == NULL)
8932c61a1653SRyan Zezeski 		mrh = mip->mi_default_tx_ring;
8933c61a1653SRyan Zezeski 
8934c61a1653SRyan Zezeski 	if (mrh == NULL)
8935c61a1653SRyan Zezeski 		return (mip->mi_tx(mip->mi_driver, mp));
8936c61a1653SRyan Zezeski 	else
8937c61a1653SRyan Zezeski 		return (mac_hwring_tx(mrh, mp));
8938c61a1653SRyan Zezeski }
8939c61a1653SRyan Zezeski 
8940c61a1653SRyan Zezeski /*
8941c61a1653SRyan Zezeski  * This is the final stop before reaching the underlying MAC provider.
8942c61a1653SRyan Zezeski  * This is also where the bridging hook is inserted. Packets that are
8943c61a1653SRyan Zezeski  * bridged will return through mac_bridge_tx(), with rh nulled out if
8944c61a1653SRyan Zezeski  * the bridge chooses to send output on a different link due to
8945c61a1653SRyan Zezeski  * forwarding.
8946c61a1653SRyan Zezeski  */
8947c61a1653SRyan Zezeski mblk_t *
mac_provider_tx(mac_impl_t * mip,mac_ring_handle_t rh,mblk_t * mp,mac_client_impl_t * mcip)8948c61a1653SRyan Zezeski mac_provider_tx(mac_impl_t *mip, mac_ring_handle_t rh, mblk_t *mp,
8949c61a1653SRyan Zezeski     mac_client_impl_t *mcip)
8950c61a1653SRyan Zezeski {
8951c61a1653SRyan Zezeski 	/*
8952c61a1653SRyan Zezeski 	 * If there is a bound Hybrid I/O share, send packets through
8953c61a1653SRyan Zezeski 	 * the default tx ring. When there's a bound Hybrid I/O share,
8954c61a1653SRyan Zezeski 	 * the tx rings of this client are mapped in the guest domain
8955c61a1653SRyan Zezeski 	 * and not accessible from here.
8956c61a1653SRyan Zezeski 	 */
8957c61a1653SRyan Zezeski 	if (mcip->mci_state_flags & MCIS_SHARE_BOUND)
8958c61a1653SRyan Zezeski 		rh = mip->mi_default_tx_ring;
8959c61a1653SRyan Zezeski 
8960c61a1653SRyan Zezeski 	if (mip->mi_promisc_list != NULL)
8961c61a1653SRyan Zezeski 		mac_promisc_dispatch(mip, mp, mcip, B_FALSE);
8962c61a1653SRyan Zezeski 
8963c61a1653SRyan Zezeski 	if (mip->mi_bridge_link == NULL)
8964c61a1653SRyan Zezeski 		return (mac_ring_tx((mac_handle_t)mip, rh, mp));
8965c61a1653SRyan Zezeski 	else
8966c61a1653SRyan Zezeski 		return (mac_bridge_tx(mip, rh, mp));
8967c61a1653SRyan Zezeski }
8968