Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / net / enic / enic_pp.c
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 }