1*b494511aSVenki Rajagopalan /*
2*b494511aSVenki Rajagopalan  * CDDL HEADER START
3*b494511aSVenki Rajagopalan  *
4*b494511aSVenki Rajagopalan  * The contents of this file are subject to the terms of the
5*b494511aSVenki Rajagopalan  * Common Development and Distribution License (the "License").
6*b494511aSVenki Rajagopalan  * You may not use this file except in compliance with the License.
7*b494511aSVenki Rajagopalan  *
8*b494511aSVenki Rajagopalan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*b494511aSVenki Rajagopalan  * or http://www.opensolaris.org/os/licensing.
10*b494511aSVenki Rajagopalan  * See the License for the specific language governing permissions
11*b494511aSVenki Rajagopalan  * and limitations under the License.
12*b494511aSVenki Rajagopalan  *
13*b494511aSVenki Rajagopalan  * When distributing Covered Code, include this CDDL HEADER in each
14*b494511aSVenki Rajagopalan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*b494511aSVenki Rajagopalan  * If applicable, add the following below this CDDL HEADER, with the
16*b494511aSVenki Rajagopalan  * fields enclosed by brackets "[]" replaced with your own identifying
17*b494511aSVenki Rajagopalan  * information: Portions Copyright [yyyy] [name of copyright owner]
18*b494511aSVenki Rajagopalan  *
19*b494511aSVenki Rajagopalan  * CDDL HEADER END
20*b494511aSVenki Rajagopalan  */
21*b494511aSVenki Rajagopalan 
22*b494511aSVenki Rajagopalan /*
23*b494511aSVenki Rajagopalan  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*b494511aSVenki Rajagopalan  */
25*b494511aSVenki Rajagopalan 
26*b494511aSVenki Rajagopalan #include <sys/types.h>
27*b494511aSVenki Rajagopalan #include <sys/conf.h>
28*b494511aSVenki Rajagopalan #include <sys/devops.h>
29*b494511aSVenki Rajagopalan #include <sys/kmem.h>
30*b494511aSVenki Rajagopalan #include <sys/ksynch.h>
31*b494511aSVenki Rajagopalan #include <sys/modctl.h>
32*b494511aSVenki Rajagopalan #include <sys/stat.h>
33*b494511aSVenki Rajagopalan #include <sys/ddi.h>
34*b494511aSVenki Rajagopalan #include <sys/sunddi.h>
35*b494511aSVenki Rajagopalan #include <sys/mac_provider.h>
36*b494511aSVenki Rajagopalan #include <sys/mac_ether.h>
37*b494511aSVenki Rajagopalan 
38*b494511aSVenki Rajagopalan #include <sys/ib/clients/eoib/eib_impl.h>
39*b494511aSVenki Rajagopalan 
40*b494511aSVenki Rajagopalan /*
41*b494511aSVenki Rajagopalan  * Declarations private to this file
42*b494511aSVenki Rajagopalan  */
43*b494511aSVenki Rajagopalan static void eib_rb_mac_start(eib_t *, eib_vnic_t *);
44*b494511aSVenki Rajagopalan 
45*b494511aSVenki Rajagopalan /*
46*b494511aSVenki Rajagopalan  * This set of routines are used to set/clear the condition that the
47*b494511aSVenki Rajagopalan  * caller is about to do something that affects the state of the nic.
48*b494511aSVenki Rajagopalan  * If there's already someone doing either a start or a stop (possibly
49*b494511aSVenki Rajagopalan  * due to the async handler, a plumb or a dlpi_open happening, or an
50*b494511aSVenki Rajagopalan  * unplumb or dlpi_close coming in), we wait until that's done.
51*b494511aSVenki Rajagopalan  */
52*b494511aSVenki Rajagopalan void
eib_mac_set_nic_state(eib_t * ss,uint_t flags)53*b494511aSVenki Rajagopalan eib_mac_set_nic_state(eib_t *ss, uint_t flags)
54*b494511aSVenki Rajagopalan {
55*b494511aSVenki Rajagopalan 	eib_node_state_t *ns = ss->ei_node_state;
56*b494511aSVenki Rajagopalan 
57*b494511aSVenki Rajagopalan 	mutex_enter(&ns->ns_lock);
58*b494511aSVenki Rajagopalan 
59*b494511aSVenki Rajagopalan 	while ((ns->ns_nic_state & EIB_NIC_STARTING) ||
60*b494511aSVenki Rajagopalan 	    (ns->ns_nic_state & EIB_NIC_STOPPING)) {
61*b494511aSVenki Rajagopalan 		cv_wait(&ns->ns_cv, &ns->ns_lock);
62*b494511aSVenki Rajagopalan 	}
63*b494511aSVenki Rajagopalan 	ns->ns_nic_state |= flags;
64*b494511aSVenki Rajagopalan 
65*b494511aSVenki Rajagopalan 	mutex_exit(&ns->ns_lock);
66*b494511aSVenki Rajagopalan }
67*b494511aSVenki Rajagopalan 
68*b494511aSVenki Rajagopalan void
eib_mac_clr_nic_state(eib_t * ss,uint_t flags)69*b494511aSVenki Rajagopalan eib_mac_clr_nic_state(eib_t *ss, uint_t flags)
70*b494511aSVenki Rajagopalan {
71*b494511aSVenki Rajagopalan 	eib_node_state_t *ns = ss->ei_node_state;
72*b494511aSVenki Rajagopalan 
73*b494511aSVenki Rajagopalan 	mutex_enter(&ns->ns_lock);
74*b494511aSVenki Rajagopalan 
75*b494511aSVenki Rajagopalan 	ns->ns_nic_state &= (~flags);
76*b494511aSVenki Rajagopalan 
77*b494511aSVenki Rajagopalan 	cv_broadcast(&ns->ns_cv);
78*b494511aSVenki Rajagopalan 	mutex_exit(&ns->ns_lock);
79*b494511aSVenki Rajagopalan }
80*b494511aSVenki Rajagopalan 
81*b494511aSVenki Rajagopalan void
eib_mac_upd_nic_state(eib_t * ss,uint_t clr_flags,uint_t set_flags)82*b494511aSVenki Rajagopalan eib_mac_upd_nic_state(eib_t *ss, uint_t clr_flags, uint_t set_flags)
83*b494511aSVenki Rajagopalan {
84*b494511aSVenki Rajagopalan 	eib_node_state_t *ns = ss->ei_node_state;
85*b494511aSVenki Rajagopalan 
86*b494511aSVenki Rajagopalan 	mutex_enter(&ns->ns_lock);
87*b494511aSVenki Rajagopalan 
88*b494511aSVenki Rajagopalan 	ns->ns_nic_state &= (~clr_flags);
89*b494511aSVenki Rajagopalan 	ns->ns_nic_state |= set_flags;
90*b494511aSVenki Rajagopalan 
91*b494511aSVenki Rajagopalan 	cv_broadcast(&ns->ns_cv);
92*b494511aSVenki Rajagopalan 	mutex_exit(&ns->ns_lock);
93*b494511aSVenki Rajagopalan }
94*b494511aSVenki Rajagopalan 
95*b494511aSVenki Rajagopalan uint_t
eib_mac_get_nic_state(eib_t * ss)96*b494511aSVenki Rajagopalan eib_mac_get_nic_state(eib_t *ss)
97*b494511aSVenki Rajagopalan {
98*b494511aSVenki Rajagopalan 	eib_node_state_t *ns = ss->ei_node_state;
99*b494511aSVenki Rajagopalan 	uint_t nic_state;
100*b494511aSVenki Rajagopalan 
101*b494511aSVenki Rajagopalan 	mutex_enter(&ns->ns_lock);
102*b494511aSVenki Rajagopalan 	nic_state = ns->ns_nic_state;
103*b494511aSVenki Rajagopalan 	mutex_exit(&ns->ns_lock);
104*b494511aSVenki Rajagopalan 
105*b494511aSVenki Rajagopalan 	return (nic_state);
106*b494511aSVenki Rajagopalan }
107*b494511aSVenki Rajagopalan 
108*b494511aSVenki Rajagopalan void
eib_mac_link_state(eib_t * ss,link_state_t new_link_state,boolean_t force)109*b494511aSVenki Rajagopalan eib_mac_link_state(eib_t *ss, link_state_t new_link_state,
110*b494511aSVenki Rajagopalan     boolean_t force)
111*b494511aSVenki Rajagopalan {
112*b494511aSVenki Rajagopalan 	eib_node_state_t *ns = ss->ei_node_state;
113*b494511aSVenki Rajagopalan 	boolean_t state_changed = B_FALSE;
114*b494511aSVenki Rajagopalan 
115*b494511aSVenki Rajagopalan 	mutex_enter(&ns->ns_lock);
116*b494511aSVenki Rajagopalan 
117*b494511aSVenki Rajagopalan 	/*
118*b494511aSVenki Rajagopalan 	 * We track the link state only if the current link state is
119*b494511aSVenki Rajagopalan 	 * not unknown.  Obviously therefore, the first calls to set
120*b494511aSVenki Rajagopalan 	 * the link state from eib_mac_start() have to pass an explicit
121*b494511aSVenki Rajagopalan 	 * 'force' flag to force the state change tracking.
122*b494511aSVenki Rajagopalan 	 */
123*b494511aSVenki Rajagopalan 	if (ns->ns_link_state != LINK_STATE_UNKNOWN)
124*b494511aSVenki Rajagopalan 		force = B_TRUE;
125*b494511aSVenki Rajagopalan 
126*b494511aSVenki Rajagopalan 	if ((force) && (new_link_state != ns->ns_link_state)) {
127*b494511aSVenki Rajagopalan 		ns->ns_link_state = new_link_state;
128*b494511aSVenki Rajagopalan 		state_changed = B_TRUE;
129*b494511aSVenki Rajagopalan 	}
130*b494511aSVenki Rajagopalan 	mutex_exit(&ns->ns_lock);
131*b494511aSVenki Rajagopalan 
132*b494511aSVenki Rajagopalan 	if (state_changed) {
133*b494511aSVenki Rajagopalan 		EIB_DPRINTF_DEBUG(ss->ei_instance,
134*b494511aSVenki Rajagopalan 		    "eib_mac_link_state: changing link state to %d",
135*b494511aSVenki Rajagopalan 		    new_link_state);
136*b494511aSVenki Rajagopalan 
137*b494511aSVenki Rajagopalan 		mac_link_update(ss->ei_mac_hdl, new_link_state);
138*b494511aSVenki Rajagopalan 	} else  {
139*b494511aSVenki Rajagopalan 		EIB_DPRINTF_DEBUG(ss->ei_instance,
140*b494511aSVenki Rajagopalan 		    "eib_mac_link_state: link state already %d",
141*b494511aSVenki Rajagopalan 		    new_link_state);
142*b494511aSVenki Rajagopalan 	}
143*b494511aSVenki Rajagopalan }
144*b494511aSVenki Rajagopalan 
145*b494511aSVenki Rajagopalan void
eib_mac_link_up(eib_t * ss,boolean_t force)146*b494511aSVenki Rajagopalan eib_mac_link_up(eib_t *ss, boolean_t force)
147*b494511aSVenki Rajagopalan {
148*b494511aSVenki Rajagopalan 	eib_mac_link_state(ss, LINK_STATE_UP, force);
149*b494511aSVenki Rajagopalan }
150*b494511aSVenki Rajagopalan 
151*b494511aSVenki Rajagopalan void
eib_mac_link_down(eib_t * ss,boolean_t force)152*b494511aSVenki Rajagopalan eib_mac_link_down(eib_t *ss, boolean_t force)
153*b494511aSVenki Rajagopalan {
154*b494511aSVenki Rajagopalan 	eib_mac_link_state(ss, LINK_STATE_DOWN, force);
155*b494511aSVenki Rajagopalan }
156*b494511aSVenki Rajagopalan 
157*b494511aSVenki Rajagopalan int
eib_mac_start(eib_t * ss)158*b494511aSVenki Rajagopalan eib_mac_start(eib_t *ss)
159*b494511aSVenki Rajagopalan {
160*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic0 = NULL;
161*b494511aSVenki Rajagopalan 	eib_login_data_t *ld;
162*b494511aSVenki Rajagopalan 	int err;
163*b494511aSVenki Rajagopalan 
164*b494511aSVenki Rajagopalan 	/*
165*b494511aSVenki Rajagopalan 	 * Perform HCA related initializations
166*b494511aSVenki Rajagopalan 	 */
167*b494511aSVenki Rajagopalan 	if (eib_ibt_hca_init(ss) != EIB_E_SUCCESS)
168*b494511aSVenki Rajagopalan 		goto start_fail;
169*b494511aSVenki Rajagopalan 
170*b494511aSVenki Rajagopalan 	/*
171*b494511aSVenki Rajagopalan 	 * Make sure port is up. Also record the port base lid if it's up.
172*b494511aSVenki Rajagopalan 	 */
173*b494511aSVenki Rajagopalan 	if (eib_mac_hca_portstate(ss, &ss->ei_props->ep_blid,
174*b494511aSVenki Rajagopalan 	    &err) != EIB_E_SUCCESS) {
175*b494511aSVenki Rajagopalan 		goto start_fail;
176*b494511aSVenki Rajagopalan 	}
177*b494511aSVenki Rajagopalan 
178*b494511aSVenki Rajagopalan 	/*
179*b494511aSVenki Rajagopalan 	 * Set up tx and rx buffer pools
180*b494511aSVenki Rajagopalan 	 */
181*b494511aSVenki Rajagopalan 	if (eib_rsrc_setup_bufs(ss, &err) != EIB_E_SUCCESS)
182*b494511aSVenki Rajagopalan 		goto start_fail;
183*b494511aSVenki Rajagopalan 
184*b494511aSVenki Rajagopalan 	/*
185*b494511aSVenki Rajagopalan 	 * Set up admin qp for logins and logouts
186*b494511aSVenki Rajagopalan 	 */
187*b494511aSVenki Rajagopalan 	if (eib_adm_setup_qp(ss, &err) != EIB_E_SUCCESS)
188*b494511aSVenki Rajagopalan 		goto start_fail;
189*b494511aSVenki Rajagopalan 
190*b494511aSVenki Rajagopalan 	/*
191*b494511aSVenki Rajagopalan 	 * Create the vnic for physlink (instance 0)
192*b494511aSVenki Rajagopalan 	 */
193*b494511aSVenki Rajagopalan 	if (eib_vnic_create(ss, 0, 0, &vnic0, &err) != EIB_E_SUCCESS)
194*b494511aSVenki Rajagopalan 		goto start_fail;
195*b494511aSVenki Rajagopalan 
196*b494511aSVenki Rajagopalan 	/*
197*b494511aSVenki Rajagopalan 	 * Update the mac layer about the correct values for MTU and
198*b494511aSVenki Rajagopalan 	 * unicast MAC address.  Note that we've already verified that the
199*b494511aSVenki Rajagopalan 	 * vhub mtu (plus the eoib encapsulation header) is not greater
200*b494511aSVenki Rajagopalan 	 * than our port mtu, so we can go ahead and report the vhub mtu
201*b494511aSVenki Rajagopalan 	 * (of vnic0) directly.
202*b494511aSVenki Rajagopalan 	 */
203*b494511aSVenki Rajagopalan 	ld = &(vnic0->vn_login_data);
204*b494511aSVenki Rajagopalan 	(void) mac_maxsdu_update(ss->ei_mac_hdl, ld->ld_vhub_mtu);
205*b494511aSVenki Rajagopalan 	mac_unicst_update(ss->ei_mac_hdl, ld->ld_assigned_mac);
206*b494511aSVenki Rajagopalan 
207*b494511aSVenki Rajagopalan 	/*
208*b494511aSVenki Rajagopalan 	 * Report that the link is up and ready
209*b494511aSVenki Rajagopalan 	 */
210*b494511aSVenki Rajagopalan 	eib_mac_link_up(ss, B_TRUE);
211*b494511aSVenki Rajagopalan 	return (0);
212*b494511aSVenki Rajagopalan 
213*b494511aSVenki Rajagopalan start_fail:
214*b494511aSVenki Rajagopalan 	eib_rb_mac_start(ss, vnic0);
215*b494511aSVenki Rajagopalan 	eib_mac_link_down(ss, B_TRUE);
216*b494511aSVenki Rajagopalan 	return (err);
217*b494511aSVenki Rajagopalan }
218*b494511aSVenki Rajagopalan 
219*b494511aSVenki Rajagopalan void
eib_mac_stop(eib_t * ss)220*b494511aSVenki Rajagopalan eib_mac_stop(eib_t *ss)
221*b494511aSVenki Rajagopalan {
222*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic;
223*b494511aSVenki Rajagopalan 	link_state_t cur_link_state = ss->ei_node_state->ns_link_state;
224*b494511aSVenki Rajagopalan 	int ndx;
225*b494511aSVenki Rajagopalan 
226*b494511aSVenki Rajagopalan 	/*
227*b494511aSVenki Rajagopalan 	 * Stopping an EoIB device instance is somewhat different from starting
228*b494511aSVenki Rajagopalan 	 * it. Between the time the device instance was started and the call to
229*b494511aSVenki Rajagopalan 	 * eib_m_stop() now, a number of vnics could've been created. All of
230*b494511aSVenki Rajagopalan 	 * these will need to be destroyed before we can stop the device.
231*b494511aSVenki Rajagopalan 	 */
232*b494511aSVenki Rajagopalan 	for (ndx = EIB_MAX_VNICS - 1; ndx >= 0; ndx--) {
233*b494511aSVenki Rajagopalan 		if ((vnic = ss->ei_vnic[ndx]) != NULL)
234*b494511aSVenki Rajagopalan 			eib_vnic_delete(ss, vnic);
235*b494511aSVenki Rajagopalan 	}
236*b494511aSVenki Rajagopalan 
237*b494511aSVenki Rajagopalan 	/*
238*b494511aSVenki Rajagopalan 	 * And now, to undo the things we did in start (other than creation
239*b494511aSVenki Rajagopalan 	 * of vnics itself)
240*b494511aSVenki Rajagopalan 	 */
241*b494511aSVenki Rajagopalan 	eib_rb_mac_start(ss, NULL);
242*b494511aSVenki Rajagopalan 
243*b494511aSVenki Rajagopalan 	/*
244*b494511aSVenki Rajagopalan 	 * Now that we're completed stopped, there's no mac address assigned
245*b494511aSVenki Rajagopalan 	 * to us.  Update the mac layer with this information. Note that we
246*b494511aSVenki Rajagopalan 	 * can let the old max mtu information remain as-is, since we're likely
247*b494511aSVenki Rajagopalan 	 * to get that same mtu on a later plumb.
248*b494511aSVenki Rajagopalan 	 */
249*b494511aSVenki Rajagopalan 	mac_unicst_update(ss->ei_mac_hdl, eib_zero_mac);
250*b494511aSVenki Rajagopalan 
251*b494511aSVenki Rajagopalan 	/*
252*b494511aSVenki Rajagopalan 	 * If our link state was up when the eib_m_stop() callback was called,
253*b494511aSVenki Rajagopalan 	 * we'll mark the link state as unknown now.  Otherwise, we'll leave
254*b494511aSVenki Rajagopalan 	 * the link state as-is (down).
255*b494511aSVenki Rajagopalan 	 */
256*b494511aSVenki Rajagopalan 	if (cur_link_state == LINK_STATE_UP)
257*b494511aSVenki Rajagopalan 		eib_mac_link_state(ss, LINK_STATE_UNKNOWN, B_TRUE);
258*b494511aSVenki Rajagopalan }
259*b494511aSVenki Rajagopalan 
260*b494511aSVenki Rajagopalan int
eib_mac_multicast(eib_t * ss,boolean_t add,uint8_t * mcast_mac)261*b494511aSVenki Rajagopalan eib_mac_multicast(eib_t *ss, boolean_t add, uint8_t *mcast_mac)
262*b494511aSVenki Rajagopalan {
263*b494511aSVenki Rajagopalan 	int ret = EIB_E_SUCCESS;
264*b494511aSVenki Rajagopalan 	int err = 0;
265*b494511aSVenki Rajagopalan 
266*b494511aSVenki Rajagopalan 	/*
267*b494511aSVenki Rajagopalan 	 * If it's a broadcast group join, each vnic needs to and is always
268*b494511aSVenki Rajagopalan 	 * joined to the broadcast address, so we return success immediately.
269*b494511aSVenki Rajagopalan 	 * If it's a broadcast group leave, we fail immediately for the same
270*b494511aSVenki Rajagopalan 	 * reason as above.
271*b494511aSVenki Rajagopalan 	 */
272*b494511aSVenki Rajagopalan 	if (bcmp(mcast_mac, eib_broadcast_mac, ETHERADDRL) == 0) {
273*b494511aSVenki Rajagopalan 		if (add)
274*b494511aSVenki Rajagopalan 			return (0);
275*b494511aSVenki Rajagopalan 		else
276*b494511aSVenki Rajagopalan 			return (EINVAL);
277*b494511aSVenki Rajagopalan 	}
278*b494511aSVenki Rajagopalan 
279*b494511aSVenki Rajagopalan 	if (ss->ei_vnic[0]) {
280*b494511aSVenki Rajagopalan 		if (add) {
281*b494511aSVenki Rajagopalan 			ret = eib_vnic_join_data_mcg(ss, ss->ei_vnic[0],
282*b494511aSVenki Rajagopalan 			    mcast_mac, B_FALSE, &err);
283*b494511aSVenki Rajagopalan 		} else {
284*b494511aSVenki Rajagopalan 			eib_vnic_leave_data_mcg(ss, ss->ei_vnic[0], mcast_mac);
285*b494511aSVenki Rajagopalan 			ret = EIB_E_SUCCESS;
286*b494511aSVenki Rajagopalan 		}
287*b494511aSVenki Rajagopalan 	}
288*b494511aSVenki Rajagopalan 
289*b494511aSVenki Rajagopalan 	if (ret == EIB_E_SUCCESS)
290*b494511aSVenki Rajagopalan 		return (0);
291*b494511aSVenki Rajagopalan 	else
292*b494511aSVenki Rajagopalan 		return (err);
293*b494511aSVenki Rajagopalan }
294*b494511aSVenki Rajagopalan 
295*b494511aSVenki Rajagopalan int
eib_mac_promisc(eib_t * ss,boolean_t set)296*b494511aSVenki Rajagopalan eib_mac_promisc(eib_t *ss, boolean_t set)
297*b494511aSVenki Rajagopalan {
298*b494511aSVenki Rajagopalan 	int ret = EIB_E_SUCCESS;
299*b494511aSVenki Rajagopalan 	int err = 0;
300*b494511aSVenki Rajagopalan 
301*b494511aSVenki Rajagopalan 	if (ss->ei_vnic[0]) {
302*b494511aSVenki Rajagopalan 		if (set) {
303*b494511aSVenki Rajagopalan 			ret = eib_vnic_join_data_mcg(ss, ss->ei_vnic[0],
304*b494511aSVenki Rajagopalan 			    eib_zero_mac, B_FALSE, &err);
305*b494511aSVenki Rajagopalan 		} else {
306*b494511aSVenki Rajagopalan 			eib_vnic_leave_data_mcg(ss, ss->ei_vnic[0],
307*b494511aSVenki Rajagopalan 			    eib_zero_mac);
308*b494511aSVenki Rajagopalan 			ret = EIB_E_SUCCESS;
309*b494511aSVenki Rajagopalan 		}
310*b494511aSVenki Rajagopalan 	}
311*b494511aSVenki Rajagopalan 
312*b494511aSVenki Rajagopalan 	if (ret == EIB_E_SUCCESS)
313*b494511aSVenki Rajagopalan 		return (0);
314*b494511aSVenki Rajagopalan 	else
315*b494511aSVenki Rajagopalan 		return (err);
316*b494511aSVenki Rajagopalan }
317*b494511aSVenki Rajagopalan 
318*b494511aSVenki Rajagopalan int
eib_mac_tx(eib_t * ss,mblk_t * mp)319*b494511aSVenki Rajagopalan eib_mac_tx(eib_t *ss, mblk_t *mp)
320*b494511aSVenki Rajagopalan {
321*b494511aSVenki Rajagopalan 	eib_ether_hdr_t evh;
322*b494511aSVenki Rajagopalan 	eib_vnic_t *vnic = NULL;
323*b494511aSVenki Rajagopalan 	eib_wqe_t *swqe = NULL;
324*b494511aSVenki Rajagopalan 	boolean_t failed_vnic;
325*b494511aSVenki Rajagopalan 	int found;
326*b494511aSVenki Rajagopalan 	int ret;
327*b494511aSVenki Rajagopalan 
328*b494511aSVenki Rajagopalan 	/*
329*b494511aSVenki Rajagopalan 	 * Grab a send wqe.  If we cannot get one, wake up a service
330*b494511aSVenki Rajagopalan 	 * thread to monitor the swqe status and let the mac layer know
331*b494511aSVenki Rajagopalan 	 * as soon as we have enough tx wqes to start the traffic again.
332*b494511aSVenki Rajagopalan 	 */
333*b494511aSVenki Rajagopalan 	if ((swqe = eib_rsrc_grab_swqe(ss, EIB_WPRI_LO)) == NULL) {
334*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_mac_tx: "
335*b494511aSVenki Rajagopalan 		    "no swqe available, holding tx until resource "
336*b494511aSVenki Rajagopalan 		    "becomes available");
337*b494511aSVenki Rajagopalan 		eib_rsrc_txwqes_needed(ss);
338*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
339*b494511aSVenki Rajagopalan 	}
340*b494511aSVenki Rajagopalan 
341*b494511aSVenki Rajagopalan 	/*
342*b494511aSVenki Rajagopalan 	 * Determine dmac, smac and vlan information
343*b494511aSVenki Rajagopalan 	 */
344*b494511aSVenki Rajagopalan 	eib_data_parse_ether_hdr(mp, &evh);
345*b494511aSVenki Rajagopalan 
346*b494511aSVenki Rajagopalan 	/*
347*b494511aSVenki Rajagopalan 	 * Lookup the {smac, vlan} tuple in our vnic list. If it isn't
348*b494511aSVenki Rajagopalan 	 * there, this is obviously a new packet on a vnic/vlan that
349*b494511aSVenki Rajagopalan 	 * we haven't been informed about. So go ahead and file a request
350*b494511aSVenki Rajagopalan 	 * to create a new vnic. This is obviously not a clean thing to
351*b494511aSVenki Rajagopalan 	 * do - we should be informed when a vnic/vlan is being created
352*b494511aSVenki Rajagopalan 	 * and should be given a proper opportunity to login to the gateway
353*b494511aSVenki Rajagopalan 	 * and do the creation.  But we don't have that luxury now, and
354*b494511aSVenki Rajagopalan 	 * this is the next best thing to do.  Note that we return failure
355*b494511aSVenki Rajagopalan 	 * from here, so tx flow control should prevent further packets
356*b494511aSVenki Rajagopalan 	 * from coming in until the vnic creation has completed.
357*b494511aSVenki Rajagopalan 	 */
358*b494511aSVenki Rajagopalan 	found = eib_data_lookup_vnic(ss, evh.eh_smac, evh.eh_vlan, &vnic,
359*b494511aSVenki Rajagopalan 	    &failed_vnic);
360*b494511aSVenki Rajagopalan 	if (found != EIB_E_SUCCESS) {
361*b494511aSVenki Rajagopalan 		uint8_t *m = evh.eh_smac;
362*b494511aSVenki Rajagopalan 
363*b494511aSVenki Rajagopalan 		/*
364*b494511aSVenki Rajagopalan 		 * Return the swqe back to the pool
365*b494511aSVenki Rajagopalan 		 */
366*b494511aSVenki Rajagopalan 		eib_rsrc_return_swqe(ss, swqe, NULL);
367*b494511aSVenki Rajagopalan 
368*b494511aSVenki Rajagopalan 		/*
369*b494511aSVenki Rajagopalan 		 * If we had previously tried creating this vnic and had
370*b494511aSVenki Rajagopalan 		 * failed, we'll simply drop the packets on this vnic.
371*b494511aSVenki Rajagopalan 		 * Otherwise, we'll queue up a request to create this vnic.
372*b494511aSVenki Rajagopalan 		 */
373*b494511aSVenki Rajagopalan 		if (failed_vnic) {
374*b494511aSVenki Rajagopalan 			EIB_DPRINTF_VERBOSE(ss->ei_instance, "eib_mac_tx: "
375*b494511aSVenki Rajagopalan 			    "vnic creation for mac=%x:%x:%x:%x:%x:%x "
376*b494511aSVenki Rajagopalan 			    "vlan=0x%x failed previously, dropping pkt",
377*b494511aSVenki Rajagopalan 			    m[0], m[1], m[2], m[3], m[4], m[5], evh.eh_vlan);
378*b494511aSVenki Rajagopalan 			return (EIB_E_SUCCESS);
379*b494511aSVenki Rajagopalan 		} else {
380*b494511aSVenki Rajagopalan 			eib_vnic_need_new(ss, evh.eh_smac, evh.eh_vlan);
381*b494511aSVenki Rajagopalan 			return (EIB_E_FAILURE);
382*b494511aSVenki Rajagopalan 		}
383*b494511aSVenki Rajagopalan 	}
384*b494511aSVenki Rajagopalan 
385*b494511aSVenki Rajagopalan 	/*
386*b494511aSVenki Rajagopalan 	 * We'll try to setup the destination in the swqe for this dmac
387*b494511aSVenki Rajagopalan 	 * and vlan.  If we don't succeed, there's no need to undo any
388*b494511aSVenki Rajagopalan 	 * vnic-creation we might've made above (if we didn't find the
389*b494511aSVenki Rajagopalan 	 * vnic corresponding to the {smac, vlan} originally). Note that
390*b494511aSVenki Rajagopalan 	 * this is not a resource issue, so we'll issue a warning and
391*b494511aSVenki Rajagopalan 	 * drop the packet, but won't return failure from here.
392*b494511aSVenki Rajagopalan 	 */
393*b494511aSVenki Rajagopalan 	ret = eib_vnic_setup_dest(vnic, swqe, evh.eh_dmac, evh.eh_vlan);
394*b494511aSVenki Rajagopalan 	if (ret != EIB_E_SUCCESS) {
395*b494511aSVenki Rajagopalan 		uint8_t *dmac;
396*b494511aSVenki Rajagopalan 
397*b494511aSVenki Rajagopalan 		dmac = evh.eh_dmac;
398*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_mac_tx: "
399*b494511aSVenki Rajagopalan 		    "eib_vnic_setup_dest() failed for mac=%x:%x:%x:%x:%x:%x, "
400*b494511aSVenki Rajagopalan 		    "vlan=0x%x, dropping pkt", dmac[0], dmac[1], dmac[2],
401*b494511aSVenki Rajagopalan 		    dmac[3], dmac[4], dmac[5]);
402*b494511aSVenki Rajagopalan 
403*b494511aSVenki Rajagopalan 		eib_rsrc_return_swqe(ss, swqe, NULL);
404*b494511aSVenki Rajagopalan 		return (EIB_E_SUCCESS);
405*b494511aSVenki Rajagopalan 	}
406*b494511aSVenki Rajagopalan 
407*b494511aSVenki Rajagopalan 	/*
408*b494511aSVenki Rajagopalan 	 * The only reason why this would fail is if we needed LSO buffer(s)
409*b494511aSVenki Rajagopalan 	 * to prepare this frame and couldn't find enough of those.
410*b494511aSVenki Rajagopalan 	 */
411*b494511aSVenki Rajagopalan 	ret = eib_data_prepare_frame(vnic, swqe, mp, &evh);
412*b494511aSVenki Rajagopalan 	if (ret != EIB_E_SUCCESS) {
413*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_mac_tx: "
414*b494511aSVenki Rajagopalan 		    "eib_data_prepare_frame() failed (no LSO bufs?), "
415*b494511aSVenki Rajagopalan 		    "holding tx until resource becomes available");
416*b494511aSVenki Rajagopalan 
417*b494511aSVenki Rajagopalan 		eib_rsrc_return_swqe(ss, swqe, NULL);
418*b494511aSVenki Rajagopalan 		eib_rsrc_lsobufs_needed(ss);
419*b494511aSVenki Rajagopalan 		return (EIB_E_FAILURE);
420*b494511aSVenki Rajagopalan 	}
421*b494511aSVenki Rajagopalan 
422*b494511aSVenki Rajagopalan 	eib_data_post_tx(vnic, swqe);
423*b494511aSVenki Rajagopalan 
424*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
425*b494511aSVenki Rajagopalan }
426*b494511aSVenki Rajagopalan 
427*b494511aSVenki Rajagopalan int
eib_mac_hca_portstate(eib_t * ss,ib_lid_t * blid,int * err)428*b494511aSVenki Rajagopalan eib_mac_hca_portstate(eib_t *ss, ib_lid_t *blid, int *err)
429*b494511aSVenki Rajagopalan {
430*b494511aSVenki Rajagopalan 	ibt_hca_portinfo_t *pi;
431*b494511aSVenki Rajagopalan 	ibt_status_t ret;
432*b494511aSVenki Rajagopalan 	uint_t num_pi;
433*b494511aSVenki Rajagopalan 	uint_t sz_pi;
434*b494511aSVenki Rajagopalan 
435*b494511aSVenki Rajagopalan 	ret = ibt_query_hca_ports(ss->ei_hca_hdl, ss->ei_props->ep_port_num,
436*b494511aSVenki Rajagopalan 	    &pi, &num_pi, &sz_pi);
437*b494511aSVenki Rajagopalan 	if (ret != IBT_SUCCESS) {
438*b494511aSVenki Rajagopalan 		EIB_DPRINTF_ERR(ss->ei_instance,
439*b494511aSVenki Rajagopalan 		    "ibt_query_hca_ports(hca_hdl=0x%llx, "
440*b494511aSVenki Rajagopalan 		    "port=0x%x) failed, ret=%d", ss->ei_hca_hdl,
441*b494511aSVenki Rajagopalan 		    ss->ei_props->ep_port_num, ret);
442*b494511aSVenki Rajagopalan 		goto mac_hca_portstate_fail;
443*b494511aSVenki Rajagopalan 	}
444*b494511aSVenki Rajagopalan 	if (num_pi != 1) {
445*b494511aSVenki Rajagopalan 		EIB_DPRINTF_ERR(ss->ei_instance,
446*b494511aSVenki Rajagopalan 		    "ibt_query_hca_ports(hca_hdl=0x%llx, "
447*b494511aSVenki Rajagopalan 		    "port=0x%x) returned num_pi=%d", ss->ei_hca_hdl,
448*b494511aSVenki Rajagopalan 		    ss->ei_props->ep_port_num, num_pi);
449*b494511aSVenki Rajagopalan 		goto mac_hca_portstate_fail;
450*b494511aSVenki Rajagopalan 	}
451*b494511aSVenki Rajagopalan 
452*b494511aSVenki Rajagopalan 	if (pi->p_linkstate != IBT_PORT_ACTIVE)
453*b494511aSVenki Rajagopalan 		goto mac_hca_portstate_fail;
454*b494511aSVenki Rajagopalan 
455*b494511aSVenki Rajagopalan 	/*
456*b494511aSVenki Rajagopalan 	 * Return the port's base lid if asked
457*b494511aSVenki Rajagopalan 	 */
458*b494511aSVenki Rajagopalan 	if (blid) {
459*b494511aSVenki Rajagopalan 		*blid = pi->p_base_lid;
460*b494511aSVenki Rajagopalan 	}
461*b494511aSVenki Rajagopalan 
462*b494511aSVenki Rajagopalan 	ibt_free_portinfo(pi, sz_pi);
463*b494511aSVenki Rajagopalan 	return (EIB_E_SUCCESS);
464*b494511aSVenki Rajagopalan 
465*b494511aSVenki Rajagopalan mac_hca_portstate_fail:
466*b494511aSVenki Rajagopalan 	if (pi) {
467*b494511aSVenki Rajagopalan 		ibt_free_portinfo(pi, sz_pi);
468*b494511aSVenki Rajagopalan 	}
469*b494511aSVenki Rajagopalan 	if (err) {
470*b494511aSVenki Rajagopalan 		*err = ENETDOWN;
471*b494511aSVenki Rajagopalan 	}
472*b494511aSVenki Rajagopalan 	return (EIB_E_FAILURE);
473*b494511aSVenki Rajagopalan }
474*b494511aSVenki Rajagopalan 
475*b494511aSVenki Rajagopalan static void
eib_rb_mac_start(eib_t * ss,eib_vnic_t * vnic0)476*b494511aSVenki Rajagopalan eib_rb_mac_start(eib_t *ss, eib_vnic_t *vnic0)
477*b494511aSVenki Rajagopalan {
478*b494511aSVenki Rajagopalan 	int ntries;
479*b494511aSVenki Rajagopalan 
480*b494511aSVenki Rajagopalan 	/*
481*b494511aSVenki Rajagopalan 	 * If vnic0 is non-null, delete it
482*b494511aSVenki Rajagopalan 	 */
483*b494511aSVenki Rajagopalan 	if (vnic0) {
484*b494511aSVenki Rajagopalan 		eib_rb_vnic_create(ss, vnic0, ~0);
485*b494511aSVenki Rajagopalan 	}
486*b494511aSVenki Rajagopalan 
487*b494511aSVenki Rajagopalan 	/*
488*b494511aSVenki Rajagopalan 	 * At this point, we're pretty much done with all communication that
489*b494511aSVenki Rajagopalan 	 * we need to do for vnic-logout, etc. so we can get rid of any address
490*b494511aSVenki Rajagopalan 	 * vectors we might've allocated to send control/data packets.
491*b494511aSVenki Rajagopalan 	 */
492*b494511aSVenki Rajagopalan 	eib_ibt_free_avects(ss);
493*b494511aSVenki Rajagopalan 
494*b494511aSVenki Rajagopalan 	/*
495*b494511aSVenki Rajagopalan 	 * Tear down the rest of it
496*b494511aSVenki Rajagopalan 	 */
497*b494511aSVenki Rajagopalan 	if (ss->ei_admin_chan) {
498*b494511aSVenki Rajagopalan 		eib_rb_adm_setup_qp(ss);
499*b494511aSVenki Rajagopalan 	}
500*b494511aSVenki Rajagopalan 
501*b494511aSVenki Rajagopalan 	/*
502*b494511aSVenki Rajagopalan 	 * If (say) the network layer has been holding onto our rx buffers, we
503*b494511aSVenki Rajagopalan 	 * wait a reasonable time for it to hand them back to us.  If we don't
504*b494511aSVenki Rajagopalan 	 * get it still, we have nothing to do but avoid rolling back hca init
505*b494511aSVenki Rajagopalan 	 * since we cannot unregister the memory, release the pd or close the
506*b494511aSVenki Rajagopalan 	 * hca.  We'll try to reuse it if there's a plumb again.
507*b494511aSVenki Rajagopalan 	 */
508*b494511aSVenki Rajagopalan 	for (ntries = 0; ntries < EIB_MAX_ATTEMPTS; ntries++) {
509*b494511aSVenki Rajagopalan 		eib_rb_rsrc_setup_bufs(ss, B_FALSE);
510*b494511aSVenki Rajagopalan 		if ((ss->ei_tx == NULL) && (ss->ei_rx == NULL) &&
511*b494511aSVenki Rajagopalan 		    (ss->ei_lso == NULL)) {
512*b494511aSVenki Rajagopalan 			break;
513*b494511aSVenki Rajagopalan 		}
514*b494511aSVenki Rajagopalan 
515*b494511aSVenki Rajagopalan 		delay(drv_usectohz(EIB_DELAY_HALF_SECOND));
516*b494511aSVenki Rajagopalan 	}
517*b494511aSVenki Rajagopalan 
518*b494511aSVenki Rajagopalan 	if (ntries == EIB_MAX_ATTEMPTS) {
519*b494511aSVenki Rajagopalan 		EIB_DPRINTF_WARN(ss->ei_instance, "eib_rb_mac_start: "
520*b494511aSVenki Rajagopalan 		    "bufs outstanding, tx=0x%llx, rx=0x%llx, lso=0x%llx",
521*b494511aSVenki Rajagopalan 		    ss->ei_tx, ss->ei_rx, ss->ei_lso);
522*b494511aSVenki Rajagopalan 	} else if (ss->ei_hca_hdl) {
523*b494511aSVenki Rajagopalan 		eib_rb_ibt_hca_init(ss, ~0);
524*b494511aSVenki Rajagopalan 	}
525*b494511aSVenki Rajagopalan 	ss->ei_props->ep_blid = 0;
526*b494511aSVenki Rajagopalan 
527*b494511aSVenki Rajagopalan 	/*
528*b494511aSVenki Rajagopalan 	 * Pending vnic creation requests (and failed-vnic records) will have
529*b494511aSVenki Rajagopalan 	 * to be cleaned up in any case
530*b494511aSVenki Rajagopalan 	 */
531*b494511aSVenki Rajagopalan 	eib_flush_vnic_reqs(ss);
532*b494511aSVenki Rajagopalan }
533