diff options
author | Roopa Prabhu <roprabhu@cisco.com> | 2011-03-29 16:36:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-31 00:39:26 -0400 |
commit | b3abfbd2951102f5f5b8fe251a672e5223ac972b (patch) | |
tree | 96b0ffc27526cd72e18ca06d6950236c9e95c311 /drivers/net/enic | |
parent | 756462f3434ec4807a61f884d59358092a03fc15 (diff) |
enic: Add support for PORT_REQUEST_PREASSOCIATE_RR
Current enic code only supports ASSOCIATE and DISASSOCIATE port profile
operations. This patch adds enic support for port profile
PORT_REQUEST_PREASSOCIATE_RR operation. The VIC adapter (8021qbh) is capable
of handling port profile requests done in two steps namely PREASSOCIATE_RR
and ASSOCIATE today. The motivation to support PREASSOCIATE_RR comes mainly
from its use as an optimization during VM migration ie, to do resource
reservation on destination host before resources on source host are released.
PREASSOCIATE_RR is a VDP operation and according to the latest at IEEE,
8021qbh will also need to support VDP commands.
In addition to handling the new PORT_REQUEST_PREASSOCIATE_RR operation
this patch also does the below:
- Introduces handlers for PORT_REQUEST operations
- Moves most of the port profile handling code to new files enic_pp.[ch]
- Uses new fw devcmds for port profile operations
Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/enic')
-rw-r--r-- | drivers/net/enic/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/enic/enic.h | 4 | ||||
-rw-r--r-- | drivers/net/enic/enic_main.c | 196 | ||||
-rw-r--r-- | drivers/net/enic/enic_pp.c | 264 | ||||
-rw-r--r-- | drivers/net/enic/enic_pp.h | 27 |
5 files changed, 344 insertions, 149 deletions
diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile index 2e573be16c13..9d4974bba247 100644 --- a/drivers/net/enic/Makefile +++ b/drivers/net/enic/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-$(CONFIG_ENIC) := enic.o | 1 | obj-$(CONFIG_ENIC) := enic.o |
2 | 2 | ||
3 | enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ | 3 | enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ |
4 | enic_res.o enic_dev.o vnic_dev.o vnic_rq.o vnic_vic.o | 4 | enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o |
5 | 5 | ||
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 3a3c3c8a3a9b..178b94d7f89b 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #define DRV_NAME "enic" | 33 | #define DRV_NAME "enic" |
34 | #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" | 34 | #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" |
35 | #define DRV_VERSION "2.1.1.12" | 35 | #define DRV_VERSION "2.1.1.13" |
36 | #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" | 36 | #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" |
37 | 37 | ||
38 | #define ENIC_BARS_MAX 6 | 38 | #define ENIC_BARS_MAX 6 |
@@ -120,4 +120,6 @@ static inline struct device *enic_get_dev(struct enic *enic) | |||
120 | return &(enic->pdev->dev); | 120 | return &(enic->pdev->dev); |
121 | } | 121 | } |
122 | 122 | ||
123 | void enic_reset_addr_lists(struct enic *enic); | ||
124 | |||
123 | #endif /* _ENIC_H_ */ | 125 | #endif /* _ENIC_H_ */ |
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 @@ | |||
45 | #include "enic_res.h" | 45 | #include "enic_res.h" |
46 | #include "enic.h" | 46 | #include "enic.h" |
47 | #include "enic_dev.h" | 47 | #include "enic_dev.h" |
48 | #include "enic_pp.h" | ||
48 | 49 | ||
49 | #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) | 50 | #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) |
50 | #define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) | 51 | #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) | |||
874 | return net_stats; | 875 | return net_stats; |
875 | } | 876 | } |
876 | 877 | ||
877 | static void enic_reset_addr_lists(struct enic *enic) | 878 | void enic_reset_addr_lists(struct enic *enic) |
878 | { | 879 | { |
879 | enic->mc_count = 0; | 880 | enic->mc_count = 0; |
880 | enic->uc_count = 0; | 881 | enic->uc_count = 0; |
@@ -1112,157 +1113,77 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) | |||
1112 | return -EINVAL; | 1113 | return -EINVAL; |
1113 | } | 1114 | } |
1114 | 1115 | ||
1115 | static int enic_set_port_profile(struct enic *enic, u8 *mac) | ||
1116 | { | ||
1117 | struct vic_provinfo *vp; | ||
1118 | u8 oui[3] = VIC_PROVINFO_CISCO_OUI; | ||
1119 | u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX; | ||
1120 | char uuid_str[38]; | ||
1121 | char client_mac_str[18]; | ||
1122 | u8 *client_mac; | ||
1123 | int err; | ||
1124 | |||
1125 | err = enic_vnic_dev_deinit(enic); | ||
1126 | if (err) | ||
1127 | return err; | ||
1128 | |||
1129 | enic_reset_addr_lists(enic); | ||
1130 | |||
1131 | switch (enic->pp.request) { | ||
1132 | |||
1133 | case PORT_REQUEST_ASSOCIATE: | ||
1134 | |||
1135 | if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) | ||
1136 | return -EINVAL; | ||
1137 | |||
1138 | if (!is_valid_ether_addr(mac)) | ||
1139 | return -EADDRNOTAVAIL; | ||
1140 | |||
1141 | vp = vic_provinfo_alloc(GFP_KERNEL, oui, | ||
1142 | VIC_PROVINFO_GENERIC_TYPE); | ||
1143 | if (!vp) | ||
1144 | return -ENOMEM; | ||
1145 | |||
1146 | vic_provinfo_add_tlv(vp, | ||
1147 | VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, | ||
1148 | strlen(enic->pp.name) + 1, enic->pp.name); | ||
1149 | |||
1150 | if (!is_zero_ether_addr(enic->pp.mac_addr)) | ||
1151 | client_mac = enic->pp.mac_addr; | ||
1152 | else | ||
1153 | client_mac = mac; | ||
1154 | |||
1155 | vic_provinfo_add_tlv(vp, | ||
1156 | VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, | ||
1157 | ETH_ALEN, client_mac); | ||
1158 | |||
1159 | sprintf(client_mac_str, "%pM", client_mac); | ||
1160 | vic_provinfo_add_tlv(vp, | ||
1161 | VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, | ||
1162 | sizeof(client_mac_str), client_mac_str); | ||
1163 | |||
1164 | if (enic->pp.set & ENIC_SET_INSTANCE) { | ||
1165 | sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); | ||
1166 | vic_provinfo_add_tlv(vp, | ||
1167 | VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, | ||
1168 | sizeof(uuid_str), uuid_str); | ||
1169 | } | ||
1170 | |||
1171 | if (enic->pp.set & ENIC_SET_HOST) { | ||
1172 | sprintf(uuid_str, "%pUB", enic->pp.host_uuid); | ||
1173 | vic_provinfo_add_tlv(vp, | ||
1174 | VIC_GENERIC_PROV_TLV_HOST_UUID_STR, | ||
1175 | sizeof(uuid_str), uuid_str); | ||
1176 | } | ||
1177 | |||
1178 | os_type = htons(os_type); | ||
1179 | vic_provinfo_add_tlv(vp, | ||
1180 | VIC_GENERIC_PROV_TLV_OS_TYPE, | ||
1181 | sizeof(os_type), &os_type); | ||
1182 | |||
1183 | err = enic_dev_init_prov(enic, vp); | ||
1184 | vic_provinfo_free(vp); | ||
1185 | if (err) | ||
1186 | return err; | ||
1187 | break; | ||
1188 | |||
1189 | case PORT_REQUEST_DISASSOCIATE: | ||
1190 | break; | ||
1191 | |||
1192 | default: | ||
1193 | return -EINVAL; | ||
1194 | } | ||
1195 | |||
1196 | /* Set flag to indicate that the port assoc/disassoc | ||
1197 | * request has been sent out to fw | ||
1198 | */ | ||
1199 | enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | static int enic_set_vf_port(struct net_device *netdev, int vf, | 1116 | static int enic_set_vf_port(struct net_device *netdev, int vf, |
1205 | struct nlattr *port[]) | 1117 | struct nlattr *port[]) |
1206 | { | 1118 | { |
1207 | struct enic *enic = netdev_priv(netdev); | 1119 | struct enic *enic = netdev_priv(netdev); |
1208 | struct enic_port_profile new_pp; | 1120 | struct enic_port_profile prev_pp; |
1209 | int err = 0; | 1121 | int err = 0, restore_pp = 1; |
1210 | 1122 | ||
1211 | memset(&new_pp, 0, sizeof(new_pp)); | 1123 | /* don't support VFs, yet */ |
1124 | if (vf != PORT_SELF_VF) | ||
1125 | return -EOPNOTSUPP; | ||
1212 | 1126 | ||
1213 | if (port[IFLA_PORT_REQUEST]) { | 1127 | if (!port[IFLA_PORT_REQUEST]) |
1214 | new_pp.set |= ENIC_SET_REQUEST; | 1128 | return -EOPNOTSUPP; |
1215 | new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); | 1129 | |
1216 | } | 1130 | memcpy(&prev_pp, &enic->pp, sizeof(enic->pp)); |
1131 | memset(&enic->pp, 0, sizeof(enic->pp)); | ||
1132 | |||
1133 | enic->pp.set |= ENIC_SET_REQUEST; | ||
1134 | enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); | ||
1217 | 1135 | ||
1218 | if (port[IFLA_PORT_PROFILE]) { | 1136 | if (port[IFLA_PORT_PROFILE]) { |
1219 | new_pp.set |= ENIC_SET_NAME; | 1137 | enic->pp.set |= ENIC_SET_NAME; |
1220 | memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]), | 1138 | memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]), |
1221 | PORT_PROFILE_MAX); | 1139 | PORT_PROFILE_MAX); |
1222 | } | 1140 | } |
1223 | 1141 | ||
1224 | if (port[IFLA_PORT_INSTANCE_UUID]) { | 1142 | if (port[IFLA_PORT_INSTANCE_UUID]) { |
1225 | new_pp.set |= ENIC_SET_INSTANCE; | 1143 | enic->pp.set |= ENIC_SET_INSTANCE; |
1226 | memcpy(new_pp.instance_uuid, | 1144 | memcpy(enic->pp.instance_uuid, |
1227 | nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); | 1145 | nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); |
1228 | } | 1146 | } |
1229 | 1147 | ||
1230 | if (port[IFLA_PORT_HOST_UUID]) { | 1148 | if (port[IFLA_PORT_HOST_UUID]) { |
1231 | new_pp.set |= ENIC_SET_HOST; | 1149 | enic->pp.set |= ENIC_SET_HOST; |
1232 | memcpy(new_pp.host_uuid, | 1150 | memcpy(enic->pp.host_uuid, |
1233 | nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); | 1151 | nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); |
1234 | } | 1152 | } |
1235 | 1153 | ||
1236 | /* don't support VFs, yet */ | 1154 | /* Special case handling: mac came from IFLA_VF_MAC */ |
1237 | if (vf != PORT_SELF_VF) | 1155 | if (!is_zero_ether_addr(prev_pp.vf_mac)) |
1238 | return -EOPNOTSUPP; | 1156 | memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN); |
1239 | |||
1240 | if (!(new_pp.set & ENIC_SET_REQUEST)) | ||
1241 | return -EOPNOTSUPP; | ||
1242 | |||
1243 | if (new_pp.request == PORT_REQUEST_ASSOCIATE) { | ||
1244 | /* Special case handling */ | ||
1245 | if (!is_zero_ether_addr(enic->pp.vf_mac)) | ||
1246 | memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN); | ||
1247 | 1157 | ||
1248 | if (is_zero_ether_addr(netdev->dev_addr)) | 1158 | if (is_zero_ether_addr(netdev->dev_addr)) |
1249 | random_ether_addr(netdev->dev_addr); | 1159 | random_ether_addr(netdev->dev_addr); |
1250 | } | ||
1251 | 1160 | ||
1252 | memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile)); | 1161 | err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp); |
1162 | if (err) { | ||
1163 | if (restore_pp) { | ||
1164 | /* Things are still the way they were: Implicit | ||
1165 | * DISASSOCIATE failed | ||
1166 | */ | ||
1167 | memcpy(&enic->pp, &prev_pp, sizeof(enic->pp)); | ||
1168 | } else { | ||
1169 | memset(&enic->pp, 0, sizeof(enic->pp)); | ||
1170 | memset(netdev->dev_addr, 0, ETH_ALEN); | ||
1171 | } | ||
1172 | } else { | ||
1173 | /* Set flag to indicate that the port assoc/disassoc | ||
1174 | * request has been sent out to fw | ||
1175 | */ | ||
1176 | enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; | ||
1253 | 1177 | ||
1254 | err = enic_set_port_profile(enic, netdev->dev_addr); | 1178 | /* If DISASSOCIATE, clean up all assigned/saved macaddresses */ |
1255 | if (err) | 1179 | if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) { |
1256 | goto set_port_profile_cleanup; | 1180 | memset(enic->pp.mac_addr, 0, ETH_ALEN); |
1181 | memset(netdev->dev_addr, 0, ETH_ALEN); | ||
1182 | } | ||
1183 | } | ||
1257 | 1184 | ||
1258 | set_port_profile_cleanup: | ||
1259 | memset(enic->pp.vf_mac, 0, ETH_ALEN); | 1185 | memset(enic->pp.vf_mac, 0, ETH_ALEN); |
1260 | 1186 | ||
1261 | if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) { | ||
1262 | memset(netdev->dev_addr, 0, ETH_ALEN); | ||
1263 | memset(enic->pp.mac_addr, 0, ETH_ALEN); | ||
1264 | } | ||
1265 | |||
1266 | return err; | 1187 | return err; |
1267 | } | 1188 | } |
1268 | 1189 | ||
@@ -1270,34 +1191,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, | |||
1270 | struct sk_buff *skb) | 1191 | struct sk_buff *skb) |
1271 | { | 1192 | { |
1272 | struct enic *enic = netdev_priv(netdev); | 1193 | struct enic *enic = netdev_priv(netdev); |
1273 | int err, error, done; | ||
1274 | u16 response = PORT_PROFILE_RESPONSE_SUCCESS; | 1194 | u16 response = PORT_PROFILE_RESPONSE_SUCCESS; |
1195 | int err; | ||
1275 | 1196 | ||
1276 | if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED)) | 1197 | if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED)) |
1277 | return -ENODATA; | 1198 | return -ENODATA; |
1278 | 1199 | ||
1279 | err = enic_dev_init_done(enic, &done, &error); | 1200 | err = enic_process_get_pp_request(enic, enic->pp.request, &response); |
1280 | if (err) | 1201 | if (err) |
1281 | error = err; | 1202 | return err; |
1282 | |||
1283 | switch (error) { | ||
1284 | case ERR_SUCCESS: | ||
1285 | if (!done) | ||
1286 | response = PORT_PROFILE_RESPONSE_INPROGRESS; | ||
1287 | break; | ||
1288 | case ERR_EINVAL: | ||
1289 | response = PORT_PROFILE_RESPONSE_INVALID; | ||
1290 | break; | ||
1291 | case ERR_EBADSTATE: | ||
1292 | response = PORT_PROFILE_RESPONSE_BADSTATE; | ||
1293 | break; | ||
1294 | case ERR_ENOMEM: | ||
1295 | response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; | ||
1296 | break; | ||
1297 | default: | ||
1298 | response = PORT_PROFILE_RESPONSE_ERROR; | ||
1299 | break; | ||
1300 | } | ||
1301 | 1203 | ||
1302 | NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); | 1204 | NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); |
1303 | NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); | 1205 | NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); |
diff --git a/drivers/net/enic/enic_pp.c b/drivers/net/enic/enic_pp.c new file mode 100644 index 000000000000..ffaa75dd1ded --- /dev/null +++ b/drivers/net/enic/enic_pp.c | |||
@@ -0,0 +1,264 @@ | |||
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 | |||
33 | static int enic_set_port_profile(struct enic *enic) | ||
34 | { | ||
35 | struct net_device *netdev = enic->netdev; | ||
36 | struct vic_provinfo *vp; | ||
37 | const u8 oui[3] = VIC_PROVINFO_CISCO_OUI; | ||
38 | const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX); | ||
39 | char uuid_str[38]; | ||
40 | char client_mac_str[18]; | ||
41 | u8 *client_mac; | ||
42 | int err; | ||
43 | |||
44 | if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) | ||
45 | return -EINVAL; | ||
46 | |||
47 | vp = vic_provinfo_alloc(GFP_KERNEL, oui, | ||
48 | VIC_PROVINFO_GENERIC_TYPE); | ||
49 | if (!vp) | ||
50 | return -ENOMEM; | ||
51 | |||
52 | VIC_PROVINFO_ADD_TLV(vp, | ||
53 | VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, | ||
54 | strlen(enic->pp.name) + 1, enic->pp.name); | ||
55 | |||
56 | if (!is_zero_ether_addr(enic->pp.mac_addr)) | ||
57 | client_mac = enic->pp.mac_addr; | ||
58 | else | ||
59 | client_mac = netdev->dev_addr; | ||
60 | |||
61 | VIC_PROVINFO_ADD_TLV(vp, | ||
62 | VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, | ||
63 | ETH_ALEN, client_mac); | ||
64 | |||
65 | snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac); | ||
66 | VIC_PROVINFO_ADD_TLV(vp, | ||
67 | VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, | ||
68 | sizeof(client_mac_str), client_mac_str); | ||
69 | |||
70 | if (enic->pp.set & ENIC_SET_INSTANCE) { | ||
71 | sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); | ||
72 | VIC_PROVINFO_ADD_TLV(vp, | ||
73 | VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, | ||
74 | sizeof(uuid_str), uuid_str); | ||
75 | } | ||
76 | |||
77 | if (enic->pp.set & ENIC_SET_HOST) { | ||
78 | sprintf(uuid_str, "%pUB", enic->pp.host_uuid); | ||
79 | VIC_PROVINFO_ADD_TLV(vp, | ||
80 | VIC_GENERIC_PROV_TLV_HOST_UUID_STR, | ||
81 | sizeof(uuid_str), uuid_str); | ||
82 | } | ||
83 | |||
84 | VIC_PROVINFO_ADD_TLV(vp, | ||
85 | VIC_GENERIC_PROV_TLV_OS_TYPE, | ||
86 | sizeof(os_type), &os_type); | ||
87 | |||
88 | err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp)); | ||
89 | |||
90 | add_tlv_failure: | ||
91 | vic_provinfo_free(vp); | ||
92 | |||
93 | return err; | ||
94 | } | ||
95 | |||
96 | static int enic_unset_port_profile(struct enic *enic) | ||
97 | { | ||
98 | int err; | ||
99 | |||
100 | err = enic_vnic_dev_deinit(enic); | ||
101 | if (err) | ||
102 | return enic_dev_status_to_errno(err); | ||
103 | |||
104 | enic_reset_addr_lists(enic); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int enic_are_pp_different(struct enic_port_profile *pp1, | ||
110 | struct enic_port_profile *pp2) | ||
111 | { | ||
112 | return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid, | ||
113 | pp2->instance_uuid, PORT_UUID_MAX) | | ||
114 | !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) | | ||
115 | !!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN); | ||
116 | } | ||
117 | |||
118 | static int enic_pp_preassociate(struct enic *enic, | ||
119 | struct enic_port_profile *prev_pp, int *restore_pp); | ||
120 | static int enic_pp_disassociate(struct enic *enic, | ||
121 | struct enic_port_profile *prev_pp, int *restore_pp); | ||
122 | static int enic_pp_preassociate_rr(struct enic *enic, | ||
123 | struct enic_port_profile *prev_pp, int *restore_pp); | ||
124 | static int enic_pp_associate(struct enic *enic, | ||
125 | struct enic_port_profile *prev_pp, int *restore_pp); | ||
126 | |||
127 | static int (*enic_pp_handlers[])(struct enic *enic, | ||
128 | struct enic_port_profile *prev_state, int *restore_pp) = { | ||
129 | [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate, | ||
130 | [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr, | ||
131 | [PORT_REQUEST_ASSOCIATE] = enic_pp_associate, | ||
132 | [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate, | ||
133 | }; | ||
134 | |||
135 | static const int enic_pp_handlers_count = | ||
136 | sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers); | ||
137 | |||
138 | static int enic_pp_preassociate(struct enic *enic, | ||
139 | struct enic_port_profile *prev_pp, int *restore_pp) | ||
140 | { | ||
141 | return -EOPNOTSUPP; | ||
142 | } | ||
143 | |||
144 | static int enic_pp_disassociate(struct enic *enic, | ||
145 | struct enic_port_profile *prev_pp, int *restore_pp) | ||
146 | { | ||
147 | return enic_unset_port_profile(enic); | ||
148 | } | ||
149 | |||
150 | static int enic_pp_preassociate_rr(struct enic *enic, | ||
151 | struct enic_port_profile *prev_pp, int *restore_pp) | ||
152 | { | ||
153 | int err; | ||
154 | int active = 0; | ||
155 | |||
156 | if (enic->pp.request != PORT_REQUEST_ASSOCIATE) { | ||
157 | /* If pre-associate is not part of an associate. | ||
158 | We always disassociate first */ | ||
159 | err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, | ||
160 | prev_pp, restore_pp); | ||
161 | if (err) | ||
162 | return err; | ||
163 | |||
164 | *restore_pp = 0; | ||
165 | } | ||
166 | |||
167 | *restore_pp = 0; | ||
168 | |||
169 | err = enic_set_port_profile(enic); | ||
170 | if (err) | ||
171 | return err; | ||
172 | |||
173 | /* If pre-associate is not part of an associate. */ | ||
174 | if (enic->pp.request != PORT_REQUEST_ASSOCIATE) | ||
175 | err = enic_dev_status_to_errno(enic_dev_enable2(enic, active)); | ||
176 | |||
177 | return err; | ||
178 | } | ||
179 | |||
180 | static int enic_pp_associate(struct enic *enic, | ||
181 | struct enic_port_profile *prev_pp, int *restore_pp) | ||
182 | { | ||
183 | int err; | ||
184 | int active = 1; | ||
185 | |||
186 | /* Check if a pre-associate was called before */ | ||
187 | if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR || | ||
188 | (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR && | ||
189 | enic_are_pp_different(prev_pp, &enic->pp))) { | ||
190 | err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE]( | ||
191 | enic, prev_pp, restore_pp); | ||
192 | if (err) | ||
193 | return err; | ||
194 | |||
195 | *restore_pp = 0; | ||
196 | } | ||
197 | |||
198 | err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR]( | ||
199 | enic, prev_pp, restore_pp); | ||
200 | if (err) | ||
201 | return err; | ||
202 | |||
203 | *restore_pp = 0; | ||
204 | |||
205 | return enic_dev_status_to_errno(enic_dev_enable2(enic, active)); | ||
206 | } | ||
207 | |||
208 | int enic_process_set_pp_request(struct enic *enic, | ||
209 | struct enic_port_profile *prev_pp, int *restore_pp) | ||
210 | { | ||
211 | if (enic->pp.request < enic_pp_handlers_count | ||
212 | && enic_pp_handlers[enic->pp.request]) | ||
213 | return enic_pp_handlers[enic->pp.request](enic, | ||
214 | prev_pp, restore_pp); | ||
215 | else | ||
216 | return -EOPNOTSUPP; | ||
217 | } | ||
218 | |||
219 | int enic_process_get_pp_request(struct enic *enic, int request, | ||
220 | u16 *response) | ||
221 | { | ||
222 | int err, status = ERR_SUCCESS; | ||
223 | |||
224 | switch (request) { | ||
225 | |||
226 | case PORT_REQUEST_PREASSOCIATE_RR: | ||
227 | case PORT_REQUEST_ASSOCIATE: | ||
228 | err = enic_dev_enable2_done(enic, &status); | ||
229 | break; | ||
230 | |||
231 | case PORT_REQUEST_DISASSOCIATE: | ||
232 | err = enic_dev_deinit_done(enic, &status); | ||
233 | break; | ||
234 | |||
235 | default: | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | if (err) | ||
240 | status = err; | ||
241 | |||
242 | switch (status) { | ||
243 | case ERR_SUCCESS: | ||
244 | *response = PORT_PROFILE_RESPONSE_SUCCESS; | ||
245 | break; | ||
246 | case ERR_EINVAL: | ||
247 | *response = PORT_PROFILE_RESPONSE_INVALID; | ||
248 | break; | ||
249 | case ERR_EBADSTATE: | ||
250 | *response = PORT_PROFILE_RESPONSE_BADSTATE; | ||
251 | break; | ||
252 | case ERR_ENOMEM: | ||
253 | *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; | ||
254 | break; | ||
255 | case ERR_EINPROGRESS: | ||
256 | *response = PORT_PROFILE_RESPONSE_INPROGRESS; | ||
257 | break; | ||
258 | default: | ||
259 | *response = PORT_PROFILE_RESPONSE_ERROR; | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
diff --git a/drivers/net/enic/enic_pp.h b/drivers/net/enic/enic_pp.h new file mode 100644 index 000000000000..699e365a944d --- /dev/null +++ b/drivers/net/enic/enic_pp.h | |||
@@ -0,0 +1,27 @@ | |||
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 | #ifndef _ENIC_PP_H_ | ||
20 | #define _ENIC_PP_H_ | ||
21 | |||
22 | int enic_process_set_pp_request(struct enic *enic, | ||
23 | struct enic_port_profile *prev_pp, int *restore_pp); | ||
24 | int enic_process_get_pp_request(struct enic *enic, int request, | ||
25 | u16 *response); | ||
26 | |||
27 | #endif /* _ENIC_PP_H_ */ | ||