/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/mac_provider.h>
#include <sys/mac_ether.h>
/*
* Declarations private to this file
*/
/*
* caller is about to do something that affects the state of the nic.
* If there's already someone doing either a start or a stop (possibly
* due to the async handler, a plumb or a dlpi_open happening, or an
* unplumb or dlpi_close coming in), we wait until that's done.
*/
void
{
}
}
void
{
}
void
{
}
{
return (nic_state);
}
void
{
/*
* We track the link state only if the current link state is
* not unknown. Obviously therefore, the first calls to set
* the link state from eib_mac_start() have to pass an explicit
* 'force' flag to force the state change tracking.
*/
}
if (state_changed) {
"eib_mac_link_state: changing link state to %d",
} else {
"eib_mac_link_state: link state already %d",
}
}
void
{
}
void
{
}
int
{
int err;
/*
* Perform HCA related initializations
*/
goto start_fail;
/*
* Make sure port is up. Also record the port base lid if it's up.
*/
&err) != EIB_E_SUCCESS) {
goto start_fail;
}
/*
* Set up tx and rx buffer pools
*/
goto start_fail;
/*
* Set up admin qp for logins and logouts
*/
goto start_fail;
/*
* Create the vnic for physlink (instance 0)
*/
goto start_fail;
/*
* Update the mac layer about the correct values for MTU and
* unicast MAC address. Note that we've already verified that the
* vhub mtu (plus the eoib encapsulation header) is not greater
* than our port mtu, so we can go ahead and report the vhub mtu
* (of vnic0) directly.
*/
/*
* Report that the link is up and ready
*/
return (0);
return (err);
}
void
{
int ndx;
/*
* Stopping an EoIB device instance is somewhat different from starting
* it. Between the time the device instance was started and the call to
* eib_m_stop() now, a number of vnics could've been created. All of
* these will need to be destroyed before we can stop the device.
*/
}
/*
* And now, to undo the things we did in start (other than creation
* of vnics itself)
*/
/*
* Now that we're completed stopped, there's no mac address assigned
* to us. Update the mac layer with this information. Note that we
* can let the old max mtu information remain as-is, since we're likely
* to get that same mtu on a later plumb.
*/
/*
* If our link state was up when the eib_m_stop() callback was called,
* we'll mark the link state as unknown now. Otherwise, we'll leave
* the link state as-is (down).
*/
if (cur_link_state == LINK_STATE_UP)
}
int
{
int err = 0;
/*
* If it's a broadcast group join, each vnic needs to and is always
* joined to the broadcast address, so we return success immediately.
* If it's a broadcast group leave, we fail immediately for the same
* reason as above.
*/
if (add)
return (0);
else
return (EINVAL);
}
if (add) {
} else {
ret = EIB_E_SUCCESS;
}
}
if (ret == EIB_E_SUCCESS)
return (0);
else
return (err);
}
int
{
int err = 0;
if (set) {
} else {
ret = EIB_E_SUCCESS;
}
}
if (ret == EIB_E_SUCCESS)
return (0);
else
return (err);
}
int
{
int found;
int ret;
/*
* Grab a send wqe. If we cannot get one, wake up a service
* thread to monitor the swqe status and let the mac layer know
* as soon as we have enough tx wqes to start the traffic again.
*/
"no swqe available, holding tx until resource "
"becomes available");
return (EIB_E_FAILURE);
}
/*
* Determine dmac, smac and vlan information
*/
/*
* Lookup the {smac, vlan} tuple in our vnic list. If it isn't
* we haven't been informed about. So go ahead and file a request
* to create a new vnic. This is obviously not a clean thing to
* and should be given a proper opportunity to login to the gateway
* and do the creation. But we don't have that luxury now, and
* this is the next best thing to do. Note that we return failure
* from here, so tx flow control should prevent further packets
* from coming in until the vnic creation has completed.
*/
&failed_vnic);
if (found != EIB_E_SUCCESS) {
/*
* Return the swqe back to the pool
*/
/*
* If we had previously tried creating this vnic and had
* failed, we'll simply drop the packets on this vnic.
* Otherwise, we'll queue up a request to create this vnic.
*/
if (failed_vnic) {
"vnic creation for mac=%x:%x:%x:%x:%x:%x "
"vlan=0x%x failed previously, dropping pkt",
return (EIB_E_SUCCESS);
} else {
return (EIB_E_FAILURE);
}
}
/*
* We'll try to setup the destination in the swqe for this dmac
* and vlan. If we don't succeed, there's no need to undo any
* vnic-creation we might've made above (if we didn't find the
* vnic corresponding to the {smac, vlan} originally). Note that
* this is not a resource issue, so we'll issue a warning and
* drop the packet, but won't return failure from here.
*/
if (ret != EIB_E_SUCCESS) {
"eib_vnic_setup_dest() failed for mac=%x:%x:%x:%x:%x:%x, "
return (EIB_E_SUCCESS);
}
/*
* The only reason why this would fail is if we needed LSO buffer(s)
* to prepare this frame and couldn't find enough of those.
*/
if (ret != EIB_E_SUCCESS) {
"eib_data_prepare_frame() failed (no LSO bufs?), "
"holding tx until resource becomes available");
return (EIB_E_FAILURE);
}
return (EIB_E_SUCCESS);
}
int
{
if (ret != IBT_SUCCESS) {
"ibt_query_hca_ports(hca_hdl=0x%llx, "
goto mac_hca_portstate_fail;
}
if (num_pi != 1) {
"ibt_query_hca_ports(hca_hdl=0x%llx, "
goto mac_hca_portstate_fail;
}
goto mac_hca_portstate_fail;
/*
* Return the port's base lid if asked
*/
if (blid) {
}
return (EIB_E_SUCCESS);
if (pi) {
}
if (err) {
}
return (EIB_E_FAILURE);
}
static void
{
int ntries;
/*
* If vnic0 is non-null, delete it
*/
if (vnic0) {
}
/*
* At this point, we're pretty much done with all communication that
* we need to do for vnic-logout, etc. so we can get rid of any address
*/
/*
* Tear down the rest of it
*/
if (ss->ei_admin_chan) {
}
/*
* If (say) the network layer has been holding onto our rx buffers, we
* wait a reasonable time for it to hand them back to us. If we don't
* get it still, we have nothing to do but avoid rolling back hca init
* since we cannot unregister the memory, release the pd or close the
* hca. We'll try to reuse it if there's a plumb again.
*/
break;
}
}
if (ntries == EIB_MAX_ATTEMPTS) {
"bufs outstanding, tx=0x%llx, rx=0x%llx, lso=0x%llx",
} else if (ss->ei_hca_hdl) {
eib_rb_ibt_hca_init(ss, ~0);
}
/*
* Pending vnic creation requests (and failed-vnic records) will have
* to be cleaned up in any case
*/
}