/* * 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 * or http://www.opensolaris.org/os/licensing. * 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 */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include /* * Definitions private to this file */ ib_gid_t eib_reserved_gid; uint8_t eib_zero_mac[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; uint8_t eib_broadcast_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int eib_setbit_mod67[] = { -1, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, -1, 13, 10, 17, 62, 60, 28, 42, 30, 20, 51, 25, 44, 55, 47, 5, 32, -1, 38, 14, 22, 11, 58, 18, 53, 63, 9, 61, 27, 29, 50, 43, 46, 31, 37, 21, 57, 52, 8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33 }; char *eib_pvt_props[] = { EIB_DLPROP_GW_EPORT_STATE, EIB_DLPROP_HCA_GUID, EIB_DLPROP_PORT_GUID, NULL }; #define eib_prop_get_and_test(inst, dp, propname, propval) \ { \ (propval) = ddi_prop_get_int(DDI_DEV_T_ANY, (dp), \ DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, (propname), -1); \ if ((propval) == -1) { \ EIB_DPRINTF_WARN((inst), "eib_get_props: " \ "ddi_prop_get_int() could not find " \ "property '%s'", (propname)); \ goto get_props_fail; \ } \ } #define eib_prop64_get_and_test(inst, dp, propname, propval) \ { \ (propval) = ddi_prop_get_int64(DDI_DEV_T_ANY, (dp), \ DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, (propname), -1); \ if ((propval) == -1) { \ EIB_DPRINTF_WARN((inst), "eib_get_props: " \ "ddi_prop_get_int64() could not find " \ "property '%s'", (propname)); \ goto get_props_fail; \ } \ } #define eib_propstr_get_and_test(inst, dp, propname, propval_p) \ { \ int rv; \ \ *(propval_p) = NULL; \ \ rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, (dp), \ DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, (propname), \ (propval_p)); \ if (rv != DDI_PROP_SUCCESS) { \ EIB_DPRINTF_WARN((inst), "eib_get_props: " \ "ddi_prop_lookup_string() could not find " \ "property '%s'", (propname)); \ goto get_props_fail; \ } \ } /* * HW/FW workarounds */ /* * 1. Verification of descriptor list length in the received packets is * disabled, since experimentation shows that BX does not set the desc * list length correctly. True for EoIB nexus as well. */ int eib_wa_no_desc_list_len = 1; /* * 2. LSO/Checksum_Offload for EoIB packets does not seem to be supported * currently, so we'll disable both temporarily. */ int eib_wa_no_cksum_offload = 1; int eib_wa_no_lso = 1; /* * 3. The "multicast entry" types are not clearly defined in the spec * at the moment. The current BX software/firmware appears to ignore * the type of the context table entries, so we will treat these * addresses just like regular vnic addresses. */ int eib_wa_no_mcast_entries = 1; /* * 4. VHUB updates from the gateways provide us with destination LIDs, * and we will hand-create these address vectors. */ int eib_wa_no_av_discover = 1; /* * 5. The older BX software does not seem to set the VP flag correctly * in the login acknowledgements even when it successfully allocates * a vlan, so we will ignore it for now. */ int eib_wa_no_good_vp_flag = 1; /* * 6. Each vhub table is expected to carry a checksum at the end to * verify the contents of the received vhub table. The current BX * software/firmware does not seem to fill this field with the * correct value (and/or the spec description is ambiguous). We * will ignore the vhub table checksum verification for now. */ int eib_wa_no_good_vhub_cksum = 1; int eib_get_props(eib_t *ss) { int val; int64_t val64; char *str; clock_t gw_ka_usecs; clock_t vnic_ka_usecs; ss->ei_gw_props = kmem_zalloc(sizeof (eib_gw_props_t), KM_SLEEP); ss->ei_props = kmem_zalloc(sizeof (eib_props_t), KM_SLEEP); mutex_init(&ss->ei_gw_props->pp_gw_lock, NULL, MUTEX_DRIVER, NULL); /* * The interface speed is currently set to 10Gb/s, since we don't * have a way yet to figure this virtual-wire specific data from * the gateway. The rest of the properties are handed over to us * by the EoIB nexus. */ ss->ei_props->ep_ifspeed = 10000000000; eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_HCA_GUID, val64); ss->ei_props->ep_hca_guid = (ib_guid_t)val64; eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_SYS_GUID, val64); ss->ei_gw_props->pp_gw_system_guid = (ib_guid_t)val64; eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_GUID, val64); ss->ei_gw_props->pp_gw_guid = (ib_guid_t)val64; eib_prop64_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_SN_PREFIX, val64); ss->ei_gw_props->pp_gw_sn_prefix = (ib_sn_prefix_t)val64; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_ADV_PERIOD, val); ss->ei_gw_props->pp_gw_adv_period = (uint_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_KA_PERIOD, val); ss->ei_gw_props->pp_gw_ka_period = (uint_t)val; gw_ka_usecs = ss->ei_gw_props->pp_gw_ka_period * 1000; gw_ka_usecs = ((gw_ka_usecs << 2) + gw_ka_usecs) >> 1; ss->ei_gw_props->pp_gw_ka_ticks = drv_usectohz(gw_ka_usecs); eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_VNIC_KA_PERIOD, val); ss->ei_gw_props->pp_vnic_ka_period = (uint_t)val; vnic_ka_usecs = ss->ei_gw_props->pp_vnic_ka_period * 1000; ss->ei_gw_props->pp_vnic_ka_ticks = drv_usectohz(vnic_ka_usecs); eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_CTRL_QPN, val); ss->ei_gw_props->pp_gw_ctrl_qpn = (ib_qpn_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_LID, val); ss->ei_gw_props->pp_gw_lid = (ib_lid_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_PORTID, val); ss->ei_gw_props->pp_gw_portid = (uint16_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_NUM_NET_VNICS, val); ss->ei_gw_props->pp_gw_num_net_vnics = (uint16_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_AVAILABLE, val); ss->ei_gw_props->pp_gw_flag_available = (uint8_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_HOST_VNICS, val); ss->ei_gw_props->pp_gw_is_host_adm_vnics = (uint8_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_SL, val); ss->ei_gw_props->pp_gw_sl = (uint8_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_N_RSS_QPN, val); ss->ei_gw_props->pp_gw_n_rss_qpn = (uint8_t)val; eib_prop_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_HCA_PORTNUM, val); ss->ei_props->ep_port_num = (uint8_t)val; eib_propstr_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_SYS_NAME, &str); ss->ei_gw_props->pp_gw_system_name = (uint8_t *)str; eib_propstr_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_PORT_NAME, &str); ss->ei_gw_props->pp_gw_port_name = (uint8_t *)str; eib_propstr_get_and_test(ss->ei_instance, ss->ei_dip, EIB_PROP_GW_VENDOR_ID, &str); ss->ei_gw_props->pp_gw_vendor_id = (uint8_t *)str; return (EIB_E_SUCCESS); get_props_fail: eib_rb_get_props(ss); return (EIB_E_FAILURE); } void eib_update_props(eib_t *ss, eib_gw_info_t *new_gw_info) { eib_gw_props_t *gwp = ss->ei_gw_props; dev_info_t *dip = ss->ei_dip; char *str; ASSERT(gwp != NULL && dip != NULL); mutex_enter(&gwp->pp_gw_lock); gwp->pp_gw_system_guid = new_gw_info->gi_system_guid; (void) ddi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SYS_GUID, gwp->pp_gw_system_guid); gwp->pp_gw_guid = new_gw_info->gi_guid; (void) ddi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_GUID, gwp->pp_gw_guid); gwp->pp_gw_sn_prefix = new_gw_info->gi_sn_prefix; (void) ddi_prop_update_int64(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SN_PREFIX, gwp->pp_gw_sn_prefix); gwp->pp_gw_adv_period = new_gw_info->gi_adv_period; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_ADV_PERIOD, gwp->pp_gw_adv_period); gwp->pp_gw_ka_period = new_gw_info->gi_ka_period; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_KA_PERIOD, gwp->pp_gw_ka_period); gwp->pp_vnic_ka_period = new_gw_info->gi_vnic_ka_period; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_VNIC_KA_PERIOD, gwp->pp_vnic_ka_period); gwp->pp_gw_ctrl_qpn = new_gw_info->gi_ctrl_qpn; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_CTRL_QPN, gwp->pp_gw_ctrl_qpn); gwp->pp_gw_lid = new_gw_info->gi_lid; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_LID, gwp->pp_gw_lid); gwp->pp_gw_portid = new_gw_info->gi_portid; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_PORTID, gwp->pp_gw_portid); gwp->pp_gw_num_net_vnics = new_gw_info->gi_num_net_vnics; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_NUM_NET_VNICS, gwp->pp_gw_num_net_vnics); gwp->pp_gw_flag_available = new_gw_info->gi_flag_available; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_AVAILABLE, gwp->pp_gw_flag_available); gwp->pp_gw_is_host_adm_vnics = new_gw_info->gi_is_host_adm_vnics; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_HOST_VNICS, gwp->pp_gw_is_host_adm_vnics); gwp->pp_gw_sl = new_gw_info->gi_sl; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SL, gwp->pp_gw_sl); gwp->pp_gw_n_rss_qpn = new_gw_info->gi_n_rss_qpn; (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, EIB_PROP_GW_N_RSS_QPN, gwp->pp_gw_n_rss_qpn); (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, EIB_PROP_GW_SYS_NAME, (char *)(new_gw_info->gi_system_name)); (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, EIB_PROP_GW_SYS_NAME, &str); if (gwp->pp_gw_system_name) { ddi_prop_free(gwp->pp_gw_system_name); } gwp->pp_gw_system_name = (uint8_t *)str; (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, EIB_PROP_GW_PORT_NAME, (char *)(new_gw_info->gi_port_name)); (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, EIB_PROP_GW_PORT_NAME, &str); if (gwp->pp_gw_port_name) { ddi_prop_free(gwp->pp_gw_port_name); } gwp->pp_gw_port_name = (uint8_t *)str; (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, EIB_PROP_GW_VENDOR_ID, (char *)(new_gw_info->gi_vendor_id)); (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, EIB_PROP_GW_VENDOR_ID, &str); if (gwp->pp_gw_vendor_id) { ddi_prop_free(gwp->pp_gw_vendor_id); } gwp->pp_gw_vendor_id = (uint8_t *)str; mutex_exit(&gwp->pp_gw_lock); } void eib_rb_get_props(eib_t *ss) { /* * Free any allocations */ if (ss->ei_gw_props->pp_gw_vendor_id) { ddi_prop_free(ss->ei_gw_props->pp_gw_vendor_id); ss->ei_gw_props->pp_gw_vendor_id = NULL; } if (ss->ei_gw_props->pp_gw_port_name) { ddi_prop_free(ss->ei_gw_props->pp_gw_port_name); ss->ei_gw_props->pp_gw_port_name = NULL; } if (ss->ei_gw_props->pp_gw_system_name) { ddi_prop_free(ss->ei_gw_props->pp_gw_system_name); ss->ei_gw_props->pp_gw_system_name = NULL; } mutex_destroy(&ss->ei_gw_props->pp_gw_lock); /* * Free space allocated for holding the props */ kmem_free(ss->ei_props, sizeof (eib_props_t)); kmem_free(ss->ei_gw_props, sizeof (eib_gw_props_t)); ss->ei_props = NULL; ss->ei_gw_props = NULL; }