diff options
Diffstat (limited to 'drivers/net/enic/enic_main.c')
-rw-r--r-- | drivers/net/enic/enic_main.c | 196 |
1 files changed, 49 insertions, 147 deletions
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 8b9cad5e9712..9a3a0277bf21 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -45,6 +45,7 @@ #include "enic_res.h" #include "enic.h" #include "enic_dev.h" +#include "enic_pp.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) #define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) @@ -874,7 +875,7 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev) return net_stats; } -static void enic_reset_addr_lists(struct enic *enic) +void enic_reset_addr_lists(struct enic *enic) { enic->mc_count = 0; enic->uc_count = 0; @@ -1112,157 +1113,77 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) return -EINVAL; } -static int enic_set_port_profile(struct enic *enic, u8 *mac) -{ - struct vic_provinfo *vp; - u8 oui[3] = VIC_PROVINFO_CISCO_OUI; - u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX; - char uuid_str[38]; - char client_mac_str[18]; - u8 *client_mac; - int err; - - err = enic_vnic_dev_deinit(enic); - if (err) - return err; - - enic_reset_addr_lists(enic); - - switch (enic->pp.request) { - - case PORT_REQUEST_ASSOCIATE: - - if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) - return -EINVAL; - - if (!is_valid_ether_addr(mac)) - return -EADDRNOTAVAIL; - - vp = vic_provinfo_alloc(GFP_KERNEL, oui, - VIC_PROVINFO_GENERIC_TYPE); - if (!vp) - return -ENOMEM; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, - strlen(enic->pp.name) + 1, enic->pp.name); - - if (!is_zero_ether_addr(enic->pp.mac_addr)) - client_mac = enic->pp.mac_addr; - else - client_mac = mac; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, - ETH_ALEN, client_mac); - - sprintf(client_mac_str, "%pM", client_mac); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, - sizeof(client_mac_str), client_mac_str); - - if (enic->pp.set & ENIC_SET_INSTANCE) { - sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - if (enic->pp.set & ENIC_SET_HOST) { - sprintf(uuid_str, "%pUB", enic->pp.host_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_HOST_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - os_type = htons(os_type); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_OS_TYPE, - sizeof(os_type), &os_type); - - err = enic_dev_init_prov(enic, vp); - vic_provinfo_free(vp); - if (err) - return err; - break; - - case PORT_REQUEST_DISASSOCIATE: - break; - - default: - return -EINVAL; - } - - /* Set flag to indicate that the port assoc/disassoc - * request has been sent out to fw - */ - enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - - return 0; -} - static int enic_set_vf_port(struct net_device *netdev, int vf, struct nlattr *port[]) { struct enic *enic = netdev_priv(netdev); - struct enic_port_profile new_pp; - int err = 0; + struct enic_port_profile prev_pp; + int err = 0, restore_pp = 1; - memset(&new_pp, 0, sizeof(new_pp)); + /* don't support VFs, yet */ + if (vf != PORT_SELF_VF) + return -EOPNOTSUPP; - if (port[IFLA_PORT_REQUEST]) { - new_pp.set |= ENIC_SET_REQUEST; - new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); - } + if (!port[IFLA_PORT_REQUEST]) + return -EOPNOTSUPP; + + memcpy(&prev_pp, &enic->pp, sizeof(enic->pp)); + memset(&enic->pp, 0, sizeof(enic->pp)); + + enic->pp.set |= ENIC_SET_REQUEST; + enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); if (port[IFLA_PORT_PROFILE]) { - new_pp.set |= ENIC_SET_NAME; - memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]), + enic->pp.set |= ENIC_SET_NAME; + memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]), PORT_PROFILE_MAX); } if (port[IFLA_PORT_INSTANCE_UUID]) { - new_pp.set |= ENIC_SET_INSTANCE; - memcpy(new_pp.instance_uuid, + enic->pp.set |= ENIC_SET_INSTANCE; + memcpy(enic->pp.instance_uuid, nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); } if (port[IFLA_PORT_HOST_UUID]) { - new_pp.set |= ENIC_SET_HOST; - memcpy(new_pp.host_uuid, + enic->pp.set |= ENIC_SET_HOST; + memcpy(enic->pp.host_uuid, nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); } - /* don't support VFs, yet */ - if (vf != PORT_SELF_VF) - return -EOPNOTSUPP; - - if (!(new_pp.set & ENIC_SET_REQUEST)) - return -EOPNOTSUPP; - - if (new_pp.request == PORT_REQUEST_ASSOCIATE) { - /* Special case handling */ - if (!is_zero_ether_addr(enic->pp.vf_mac)) - memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN); + /* Special case handling: mac came from IFLA_VF_MAC */ + if (!is_zero_ether_addr(prev_pp.vf_mac)) + memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN); if (is_zero_ether_addr(netdev->dev_addr)) random_ether_addr(netdev->dev_addr); - } - memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile)); + err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp); + if (err) { + if (restore_pp) { + /* Things are still the way they were: Implicit + * DISASSOCIATE failed + */ + memcpy(&enic->pp, &prev_pp, sizeof(enic->pp)); + } else { + memset(&enic->pp, 0, sizeof(enic->pp)); + memset(netdev->dev_addr, 0, ETH_ALEN); + } + } else { + /* Set flag to indicate that the port assoc/disassoc + * request has been sent out to fw + */ + enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - err = enic_set_port_profile(enic, netdev->dev_addr); - if (err) - goto set_port_profile_cleanup; + /* If DISASSOCIATE, clean up all assigned/saved macaddresses */ + if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) { + memset(enic->pp.mac_addr, 0, ETH_ALEN); + memset(netdev->dev_addr, 0, ETH_ALEN); + } + } -set_port_profile_cleanup: memset(enic->pp.vf_mac, 0, ETH_ALEN); - if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) { - memset(netdev->dev_addr, 0, ETH_ALEN); - memset(enic->pp.mac_addr, 0, ETH_ALEN); - } - return err; } @@ -1270,34 +1191,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, struct sk_buff *skb) { struct enic *enic = netdev_priv(netdev); - int err, error, done; u16 response = PORT_PROFILE_RESPONSE_SUCCESS; + int err; if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED)) return -ENODATA; - err = enic_dev_init_done(enic, &done, &error); + err = enic_process_get_pp_request(enic, enic->pp.request, &response); if (err) - error = err; - - switch (error) { - case ERR_SUCCESS: - if (!done) - response = PORT_PROFILE_RESPONSE_INPROGRESS; - break; - case ERR_EINVAL: - response = PORT_PROFILE_RESPONSE_INVALID; - break; - case ERR_EBADSTATE: - response = PORT_PROFILE_RESPONSE_BADSTATE; - break; - case ERR_ENOMEM: - response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; - break; - default: - response = PORT_PROFILE_RESPONSE_ERROR; - break; - } + return err; NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); |