eib_main.c revision b494511a9cf72b1fc4eb13a0e593f55c624ab829
/*
* 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
*/
/*
*/
/*
* The Ethernet Over Infiniband driver
*/
#include <sys/mac_provider.h>
#include <sys/mac_ether.h>
/*
* Driver entry point declarations
*/
/*
* MAC callbacks
*/
static int eib_m_start(void *);
static void eib_m_stop(void *);
static int eib_m_promisc(void *, boolean_t);
static int eib_m_unicast(void *, const uint8_t *);
const void *);
static void eib_m_propinfo(void *, const char *, mac_prop_id_t,
/*
* Devops definition
*/
/*
* Module Driver Info
*/
static struct modldrv eib_modldrv = {
&mod_driverops, /* Driver module */
"EoIB Driver", /* Driver name and version */
&eib_ops, /* Driver ops */
};
/*
* Module Linkage
*/
static struct modlinkage eib_modlinkage = {
};
/*
* GLDv3 entry points
*/
#define EIB_M_CALLBACK_FLAGS \
static mac_callbacks_t eib_m_callbacks = {
NULL,
NULL,
NULL,
NULL,
};
/*
* Async handler callback for ibt events
*/
static ibt_clnt_modinfo_t eib_clnt_modinfo = {
NULL,
};
/*
* Driver State Pointer
*/
void *eib_state;
/*
* Declarations private to this file
*/
static int eib_state_init(eib_t *);
static int eib_add_event_callbacks(eib_t *);
static void eib_rb_state_init(eib_t *);
static void eib_rb_add_event_callbacks(eib_t *);
static void eib_rb_register_with_mac(eib_t *);
/*
* Definitions private to this file
*/
#define EIB_ATTACH_STATE_ALLOCD 0x01
#define EIB_ATTACH_PROPS_PARSED 0x02
#define EIB_ATTACH_STATE_INIT_DONE 0x04
#define EIB_ATTACH_IBT_ATT_DONE 0x08
#define EIB_ATTACH_EV_CBS_ADDED 0x10
#define EIB_ATTACH_REGISTER_MAC_DONE 0x20
int
_init()
{
int ret;
return (ENODEV);
return (ret);
return (ret);
}
return (ret);
}
int
{
}
int
_fini()
{
int ret;
return (ret);
return (ret);
}
static int
{
int instance;
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
/*
* Allocate softstate for this instance
*/
goto attach_fail;
/*
* Parse the node properties and get the gateway parameters
* for this instance
*/
"eib_attach: eib_get_props() failed");
goto attach_fail;
}
/*
* Do per-state initialization
*/
"eib_attach: eib_state_init() failed");
goto attach_fail;
}
/*
* Attach to IBTL
*/
"eib_attach: ibt_attach() failed, ret=%d", ret);
goto attach_fail;
}
/*
* Register NDI event callbacks with EoIB nexus
*/
"eib_attach: eib_add_event_callbacks() failed");
goto attach_fail;
}
/*
* Register with mac layer
*/
"eib_attach: eib_register_with_mac() failed");
goto attach_fail;
}
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
static int
{
int instance;
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
/*
* If we had not cleaned up rx buffers (and hca resources) during
* unplumb because they were stuck with the nw layer at the time,
* we can try to clean them up now before doing the detach.
*/
"eib_detach: buffers still not returned "
"(tx=0x%llx, rx=0x%llx, lso=0x%llx), could "
return (DDI_FAILURE);
}
if (ss->ei_hca_hdl) {
eib_rb_ibt_hca_init(ss, ~0);
}
eib_rb_attach(ss, ~0);
return (DDI_SUCCESS);
}
static int
{
switch (stat) {
case MAC_STAT_IFSPEED:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case MAC_STAT_BRDCSTXMT:
break;
case MAC_STAT_MULTIXMT:
break;
case MAC_STAT_OERRORS:
break;
case MAC_STAT_NOXMTBUF:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_BRDCSTRCV:
break;
case MAC_STAT_MULTIRCV:
break;
case MAC_STAT_IERRORS:
break;
case MAC_STAT_NORCVBUF:
break;
case ETHER_STAT_LINK_DUPLEX:
*val = LINK_DUPLEX_FULL;
break;
default:
return (ENOTSUP);
}
return (0);
}
static int
eib_m_start(void *arg)
{
int ret = -1;
if (ret == 0)
else
return (ret);
}
static void
eib_m_stop(void *arg)
{
}
static int
{
return (0);
}
static int
{
return (0);
/*
* We don't have any knowledge which of the vnics built on top of
* the physlink is this multicast group relevant for. We'll join
* it for vnic0 for now.
*
* Since the tx routine in EoIB currently piggy backs all multicast
* traffic over the broadcast channel, and all vnics are joined to
* the broadcast address when they're created, everyone should receive
* all multicast traffic anyway.
*
* On the rx side, we'll check if the incoming multicast address is
* either on the vnic's list of mcgs joined to (which will only be the
* broadcast address) or on vnic0's list of mcgs. If we find a match,
* we let the packet come through.
*
* This isn't perfect, but it's the best we can do given that we don't
* have any vlan information corresponding to this multicast address.
*
* Also, for now we'll use the synchronous multicast joins and
* leaves instead of the asynchronous mechanism provided by
* ibt_join_mcg() since that involves additional complexity for failed
* joins and removals.
*/
}
static int
{
return (0);
ETHERADDRL) == 0) {
return (0);
}
return (EINVAL);
}
static mblk_t *
{
/*
* If the nic hasn't been started, drop the message(s)
*/
return (NULL);
}
/*
* Detach this message from the message chain
*/
/*
* Attempt to send the message; if we fail (likely due
* to lack of resources), reattach this message to the
* chain and return the unsent chain back. When we're
* ready to send again, we'll issue a mac_tx_update().
*/
break;
}
}
return (mp);
}
static boolean_t
{
/*
* If we haven't been plumbed yet, try getting the hca attributes
* and figure out the capabilities now
*/
&hca_attrs);
if (ret == IBT_SUCCESS) {
}
}
if (caps->cp_cksum_flags == 0) {
"eib_m_getcapab: hw cksum disabled, cksum_flags=0");
return (B_FALSE);
}
return (B_TRUE);
/*
* If the HCA supports LSO, it will advertise a non-zero
* "max lso size" parameter. Also, LSO relies on hw
* checksum being available. Finally, if the HCA
* doesn't provide the reserved-lkey capability, LSO
* will adversely affect the performance. So, we'll
* enable LSO only if we have a non-zero max lso size,
* support checksum offload and provide reserved lkey.
*/
if (caps->cp_lso_maxlen == 0 ||
caps->cp_cksum_flags == 0 ||
caps->cp_resv_lkey_capab == 0) {
"LSO disabled, lso_maxlen=0x%lx, "
"cksum_flags=0x%lx, resv_lkey_capab=%d",
return (B_FALSE);
}
return (B_TRUE);
}
return (B_FALSE);
}
/*ARGSUSED*/
static int
{
return (ENOTSUP);
}
static int
{
int err = 0;
switch (pr_num) {
case MAC_PROP_DUPLEX:
break;
case MAC_PROP_SPEED:
break;
case MAC_PROP_PRIVATE:
"%s", "up");
} else {
"%s", "down");
}
}
break;
default:
break;
}
return (err);
}
/*ARGSUSED*/
static void
{
switch (pr_num) {
case MAC_PROP_DUPLEX:
case MAC_PROP_SPEED:
break;
case MAC_PROP_MTU:
break;
case MAC_PROP_PRIVATE:
}
break;
}
}
static int
{
/*
* Initialize synchronization primitives
*/
/*
* Create a node state structure and initialize
*/
/*
* Allocate for gathering statistics
*/
/*
* Start up service threads
*/
/*
* Set default state of gw eport
*/
/*
* Do static initializations of common structures
*/
eib_reserved_gid.gid_guid = 0;
return (EIB_E_SUCCESS);
}
static int
{
int ret;
/*
* Add callback for receiving vnic login acks from the gateway
*/
&login_ack_evc)) != DDI_SUCCESS) {
"ddi_get_eventcookie(LOGIN_ACK) failed, ret=%d", ret);
return (EIB_E_FAILURE);
}
"ddi_add_event_handler(LOGIN_ACK) failed, ret=%d", ret);
return (EIB_E_FAILURE);
}
/*
* Add callback for receiving status on gateway transitioning from
* not-available to available
*/
&gw_alive_evc)) != DDI_SUCCESS) {
"ddi_get_eventcookie(GW_AVAILABLE) failed, ret=%d", ret);
return (EIB_E_FAILURE);
}
"ddi_add_event_handler(GW_AVAILABLE) failed, ret=%d", ret);
return (EIB_E_FAILURE);
}
/*
* Add callback for receiving gateway info update
*/
&gw_info_evc)) != DDI_SUCCESS) {
"ddi_get_eventcookie(GW_INFO_UPDATE) failed, ret=%d", ret);
return (EIB_E_FAILURE);
}
"ddi_add_event_handler(GW_INFO) failed, ret=%d", ret);
return (EIB_E_FAILURE);
}
return (EIB_E_SUCCESS);
}
static int
{
int ret;
"mac_alloc(MAC_VERSION=%d) failed", MAC_VERSION);
return (EIB_E_FAILURE);
}
/*
* Note that when we register with mac during attach, we don't
* have the mac address yet (we'll get that after we login into
* the gateway) so we'll simply register a zero macaddr that
* we'll overwrite later during plumb, in eib_m_start(). Likewise,
* we'll also update the max-sdu with the correct MTU after we
* figure it out when we login to the gateway during plumb.
*/
if (ret != 0) {
"mac_register() failed, ret=%d", ret);
return (EIB_E_FAILURE);
}
return (EIB_E_SUCCESS);
}
static void
{
int instance;
if (progress & EIB_ATTACH_EV_CBS_ADDED)
if (progress & EIB_ATTACH_IBT_ATT_DONE) {
if (ret != IBT_SUCCESS) {
"ibt_detach() failed, ret=%d", ret);
}
}
if (progress & EIB_ATTACH_PROPS_PARSED)
if (progress & EIB_ATTACH_STATE_ALLOCD) {
}
}
static void
{
/*
* Terminate service threads
*/
if (ss->ei_keepalives_manager) {
ss->ei_keepalives_manager = 0;
}
if (ss->ei_vnic_creator) {
ss->ei_vnic_creator = 0;
}
if (ss->ei_rwqes_refiller) {
ss->ei_rwqes_refiller = 0;
}
if (ss->ei_events_handler) {
ss->ei_events_handler = 0;
}
/*
* Remove space allocated for gathering statistics
*/
}
/*
* Remove space allocated for keeping node state
*/
if (ss->ei_node_state) {
}
/*
* Finally, destroy all synchronization resources
*/
}
static void
{
&evc) == DDI_SUCCESS) {
}
&evc) == DDI_SUCCESS) {
}
&evc) == DDI_SUCCESS) {
}
}
static void
{
int ret;
"eib_rb_register_with_mac: "
"mac_unregister() failed, ret=%d", ret);
}
}