root/drivers/net/ethernet/cisco/enic/enic_pp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. enic_is_valid_pp_vf
  2. enic_set_port_profile
  3. enic_unset_port_profile
  4. enic_are_pp_different
  5. enic_pp_preassociate
  6. enic_pp_disassociate
  7. enic_pp_preassociate_rr
  8. enic_pp_associate
  9. enic_process_set_pp_request
  10. enic_process_get_pp_request

   1 /*
   2  * Copyright 2011 Cisco Systems, Inc.  All rights reserved.
   3  *
   4  * This program is free software; you may redistribute it and/or modify
   5  * it under the terms of the GNU General Public License as published by
   6  * the Free Software Foundation; version 2 of the License.
   7  *
   8  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   9  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  10  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  11  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  12  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  13  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  14  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  15  * SOFTWARE.
  16  *
  17  */
  18 
  19 #include <linux/kernel.h>
  20 #include <linux/string.h>
  21 #include <linux/errno.h>
  22 #include <linux/types.h>
  23 #include <linux/netdevice.h>
  24 #include <linux/etherdevice.h>
  25 #include <linux/rtnetlink.h>
  26 #include <net/ip.h>
  27 
  28 #include "vnic_vic.h"
  29 #include "enic_res.h"
  30 #include "enic.h"
  31 #include "enic_dev.h"
  32 #include "enic_pp.h"
  33 
  34 /*
  35  * Checks validity of vf index that came in
  36  * port profile request
  37  */
  38 int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
  39 {
  40         if (vf != PORT_SELF_VF) {
  41 #ifdef CONFIG_PCI_IOV
  42                 if (enic_sriov_enabled(enic)) {
  43                         if (vf < 0 || vf >= enic->num_vfs) {
  44                                 *err = -EINVAL;
  45                                 goto err_out;
  46                         }
  47                 } else {
  48                         *err = -EOPNOTSUPP;
  49                         goto err_out;
  50                 }
  51 #else
  52                 *err = -EOPNOTSUPP;
  53                 goto err_out;
  54 #endif
  55         }
  56 
  57         if (vf == PORT_SELF_VF && !enic_is_dynamic(enic)) {
  58                 *err = -EOPNOTSUPP;
  59                 goto err_out;
  60         }
  61 
  62         *err = 0;
  63         return 1;
  64 
  65 err_out:
  66         return 0;
  67 }
  68 
  69 static int enic_set_port_profile(struct enic *enic, int vf)
  70 {
  71         struct net_device *netdev = enic->netdev;
  72         struct enic_port_profile *pp;
  73         struct vic_provinfo *vp;
  74         const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
  75         const __be16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
  76         char uuid_str[38];
  77         char client_mac_str[18];
  78         u8 *client_mac;
  79         int err;
  80 
  81         ENIC_PP_BY_INDEX(enic, vf, pp, &err);
  82         if (err)
  83                 return err;
  84 
  85         if (!(pp->set & ENIC_SET_NAME) || !strlen(pp->name))
  86                 return -EINVAL;
  87 
  88         vp = vic_provinfo_alloc(GFP_KERNEL, oui,
  89                 VIC_PROVINFO_GENERIC_TYPE);
  90         if (!vp)
  91                 return -ENOMEM;
  92 
  93         VIC_PROVINFO_ADD_TLV(vp,
  94                 VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
  95                 strlen(pp->name) + 1, pp->name);
  96 
  97         if (!is_zero_ether_addr(pp->mac_addr)) {
  98                 client_mac = pp->mac_addr;
  99         } else if (vf == PORT_SELF_VF) {
 100                 client_mac = netdev->dev_addr;
 101         } else {
 102                 netdev_err(netdev, "Cannot find pp mac address "
 103                         "for VF %d\n", vf);
 104                 err = -EINVAL;
 105                 goto add_tlv_failure;
 106         }
 107 
 108         VIC_PROVINFO_ADD_TLV(vp,
 109                 VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
 110                 ETH_ALEN, client_mac);
 111 
 112         snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac);
 113         VIC_PROVINFO_ADD_TLV(vp,
 114                 VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
 115                 sizeof(client_mac_str), client_mac_str);
 116 
 117         if (pp->set & ENIC_SET_INSTANCE) {
 118                 sprintf(uuid_str, "%pUB", pp->instance_uuid);
 119                 VIC_PROVINFO_ADD_TLV(vp,
 120                         VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
 121                         sizeof(uuid_str), uuid_str);
 122         }
 123 
 124         if (pp->set & ENIC_SET_HOST) {
 125                 sprintf(uuid_str, "%pUB", pp->host_uuid);
 126                 VIC_PROVINFO_ADD_TLV(vp,
 127                         VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
 128                         sizeof(uuid_str), uuid_str);
 129         }
 130 
 131         VIC_PROVINFO_ADD_TLV(vp,
 132                 VIC_GENERIC_PROV_TLV_OS_TYPE,
 133                 sizeof(os_type), &os_type);
 134 
 135         ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_init_prov2, (u8 *)vp,
 136                 vic_provinfo_size(vp));
 137         err = enic_dev_status_to_errno(err);
 138 
 139 add_tlv_failure:
 140         vic_provinfo_free(vp);
 141 
 142         return err;
 143 }
 144 
 145 static int enic_unset_port_profile(struct enic *enic, int vf)
 146 {
 147         int err;
 148 
 149         ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_deinit);
 150         if (err)
 151                 return enic_dev_status_to_errno(err);
 152 
 153         if (vf == PORT_SELF_VF)
 154                 enic_reset_addr_lists(enic);
 155 
 156         return 0;
 157 }
 158 
 159 static int enic_are_pp_different(struct enic_port_profile *pp1,
 160                 struct enic_port_profile *pp2)
 161 {
 162         return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid,
 163                 pp2->instance_uuid, PORT_UUID_MAX) |
 164                 !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) |
 165                 !ether_addr_equal(pp1->mac_addr, pp2->mac_addr);
 166 }
 167 
 168 static int enic_pp_preassociate(struct enic *enic, int vf,
 169         struct enic_port_profile *prev_pp, int *restore_pp);
 170 static int enic_pp_disassociate(struct enic *enic, int vf,
 171         struct enic_port_profile *prev_pp, int *restore_pp);
 172 static int enic_pp_preassociate_rr(struct enic *enic, int vf,
 173         struct enic_port_profile *prev_pp, int *restore_pp);
 174 static int enic_pp_associate(struct enic *enic, int vf,
 175         struct enic_port_profile *prev_pp, int *restore_pp);
 176 
 177 static int (*enic_pp_handlers[])(struct enic *enic, int vf,
 178                 struct enic_port_profile *prev_state,
 179                 int *restore_pp) = {
 180         [PORT_REQUEST_PREASSOCIATE]     = enic_pp_preassociate,
 181         [PORT_REQUEST_PREASSOCIATE_RR]  = enic_pp_preassociate_rr,
 182         [PORT_REQUEST_ASSOCIATE]        = enic_pp_associate,
 183         [PORT_REQUEST_DISASSOCIATE]     = enic_pp_disassociate,
 184 };
 185 
 186 static const int enic_pp_handlers_count =
 187                         ARRAY_SIZE(enic_pp_handlers);
 188 
 189 static int enic_pp_preassociate(struct enic *enic, int vf,
 190         struct enic_port_profile *prev_pp, int *restore_pp)
 191 {
 192         return -EOPNOTSUPP;
 193 }
 194 
 195 static int enic_pp_disassociate(struct enic *enic, int vf,
 196         struct enic_port_profile *prev_pp, int *restore_pp)
 197 {
 198         struct net_device *netdev = enic->netdev;
 199         struct enic_port_profile *pp;
 200         int err;
 201 
 202         ENIC_PP_BY_INDEX(enic, vf, pp, &err);
 203         if (err)
 204                 return err;
 205 
 206         /* Deregister mac addresses */
 207         if (!is_zero_ether_addr(pp->mac_addr))
 208                 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
 209                         pp->mac_addr);
 210         else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
 211                 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
 212                         netdev->dev_addr);
 213 
 214         return enic_unset_port_profile(enic, vf);
 215 }
 216 
 217 static int enic_pp_preassociate_rr(struct enic *enic, int vf,
 218         struct enic_port_profile *prev_pp, int *restore_pp)
 219 {
 220         struct enic_port_profile *pp;
 221         int err;
 222         int active = 0;
 223 
 224         ENIC_PP_BY_INDEX(enic, vf, pp, &err);
 225         if (err)
 226                 return err;
 227 
 228         if (pp->request != PORT_REQUEST_ASSOCIATE) {
 229                 /* If pre-associate is not part of an associate.
 230                 We always disassociate first */
 231                 err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, vf,
 232                         prev_pp, restore_pp);
 233                 if (err)
 234                         return err;
 235 
 236                 *restore_pp = 0;
 237         }
 238 
 239         *restore_pp = 0;
 240 
 241         err = enic_set_port_profile(enic, vf);
 242         if (err)
 243                 return err;
 244 
 245         /* If pre-associate is not part of an associate. */
 246         if (pp->request != PORT_REQUEST_ASSOCIATE) {
 247                 /* Enable device as standby */
 248                 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2,
 249                         active);
 250                 err = enic_dev_status_to_errno(err);
 251         }
 252 
 253         return err;
 254 }
 255 
 256 static int enic_pp_associate(struct enic *enic, int vf,
 257         struct enic_port_profile *prev_pp, int *restore_pp)
 258 {
 259         struct net_device *netdev = enic->netdev;
 260         struct enic_port_profile *pp;
 261         int err;
 262         int active = 1;
 263 
 264         ENIC_PP_BY_INDEX(enic, vf, pp, &err);
 265         if (err)
 266                 return err;
 267 
 268         /* Check if a pre-associate was called before */
 269         if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
 270                 (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
 271                         enic_are_pp_different(prev_pp, pp))) {
 272                 err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
 273                         enic, vf, prev_pp, restore_pp);
 274                 if (err)
 275                         return err;
 276 
 277                 *restore_pp = 0;
 278         }
 279 
 280         err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
 281                         enic, vf, prev_pp, restore_pp);
 282         if (err)
 283                 return err;
 284 
 285         *restore_pp = 0;
 286 
 287         /* Enable device as active */
 288         ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2, active);
 289         err = enic_dev_status_to_errno(err);
 290         if (err)
 291                 return err;
 292 
 293         /* Register mac address */
 294         if (!is_zero_ether_addr(pp->mac_addr))
 295                 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
 296                         pp->mac_addr);
 297         else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
 298                 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
 299                         netdev->dev_addr);
 300 
 301         return 0;
 302 }
 303 
 304 int enic_process_set_pp_request(struct enic *enic, int vf,
 305         struct enic_port_profile *prev_pp, int *restore_pp)
 306 {
 307         struct enic_port_profile *pp;
 308         int err;
 309 
 310         ENIC_PP_BY_INDEX(enic, vf, pp, &err);
 311         if (err)
 312                 return err;
 313 
 314         if (pp->request >= enic_pp_handlers_count
 315                 || !enic_pp_handlers[pp->request])
 316                 return -EOPNOTSUPP;
 317 
 318         return enic_pp_handlers[pp->request](enic, vf, prev_pp, restore_pp);
 319 }
 320 
 321 int enic_process_get_pp_request(struct enic *enic, int vf,
 322         int request, u16 *response)
 323 {
 324         int err, status = ERR_SUCCESS;
 325 
 326         switch (request) {
 327 
 328         case PORT_REQUEST_PREASSOCIATE_RR:
 329         case PORT_REQUEST_ASSOCIATE:
 330                 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
 331                         vnic_dev_enable2_done, &status);
 332                 break;
 333 
 334         case PORT_REQUEST_DISASSOCIATE:
 335                 ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
 336                         vnic_dev_deinit_done, &status);
 337                 break;
 338 
 339         default:
 340                 return -EINVAL;
 341         }
 342 
 343         if (err)
 344                 status = err;
 345 
 346         switch (status) {
 347         case ERR_SUCCESS:
 348                 *response = PORT_PROFILE_RESPONSE_SUCCESS;
 349                 break;
 350         case ERR_EINVAL:
 351                 *response = PORT_PROFILE_RESPONSE_INVALID;
 352                 break;
 353         case ERR_EBADSTATE:
 354                 *response = PORT_PROFILE_RESPONSE_BADSTATE;
 355                 break;
 356         case ERR_ENOMEM:
 357                 *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
 358                 break;
 359         case ERR_EINPROGRESS:
 360                 *response = PORT_PROFILE_RESPONSE_INPROGRESS;
 361                 break;
 362         default:
 363                 *response = PORT_PROFILE_RESPONSE_ERROR;
 364                 break;
 365         }
 366 
 367         return 0;
 368 }

/* [<][>][^][v][top][bottom][index][help] */