blob: 4865e8181172dbb9ccf7971b44a249f4480a16c5 [file] [log] [blame]
Vasu Dev9b34ecf2009-03-17 11:42:13 -07001/*
Joe Eykholt97c83892009-03-17 11:42:40 -07002 * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
3 * Copyright (c) 2009 Intel Corporation. All rights reserved.
Vasu Dev9b34ecf2009-03-17 11:42:13 -07004 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Maintained at www.Open-FCoE.org
19 */
20
Joe Eykholt97c83892009-03-17 11:42:40 -070021#include <linux/types.h>
Vasu Dev9b34ecf2009-03-17 11:42:13 -070022#include <linux/module.h>
Joe Eykholt97c83892009-03-17 11:42:40 -070023#include <linux/kernel.h>
24#include <linux/list.h>
25#include <linux/spinlock.h>
26#include <linux/timer.h>
Vasu Dev5e80f7f2009-03-17 11:42:18 -070027#include <linux/netdevice.h>
Joe Eykholt97c83892009-03-17 11:42:40 -070028#include <linux/etherdevice.h>
29#include <linux/ethtool.h>
30#include <linux/if_ether.h>
31#include <linux/if_vlan.h>
Joe Eykholt97c83892009-03-17 11:42:40 -070032#include <linux/errno.h>
33#include <linux/bitops.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Joe Eykholt97c83892009-03-17 11:42:40 -070035#include <net/rtnetlink.h>
36
37#include <scsi/fc/fc_els.h>
38#include <scsi/fc/fc_fs.h>
39#include <scsi/fc/fc_fip.h>
40#include <scsi/fc/fc_encaps.h>
41#include <scsi/fc/fc_fcoe.h>
Joe Eykholte10f8c62010-07-20 15:20:30 -070042#include <scsi/fc/fc_fcp.h>
Vasu Dev5e80f7f2009-03-17 11:42:18 -070043
44#include <scsi/libfc.h>
Joe Eykholt97c83892009-03-17 11:42:40 -070045#include <scsi/libfcoe.h>
Vasu Dev9b34ecf2009-03-17 11:42:13 -070046
47MODULE_AUTHOR("Open-FCoE.org");
Joe Eykholt97c83892009-03-17 11:42:40 -070048MODULE_DESCRIPTION("FIP discovery protocol support for FCoE HBAs");
Vasu Dev9b34ecf2009-03-17 11:42:13 -070049MODULE_LICENSE("GPL v2");
Vasu Dev5e80f7f2009-03-17 11:42:18 -070050
Joe Eykholt97c83892009-03-17 11:42:40 -070051#define FCOE_CTLR_MIN_FKA 500 /* min keep alive (mS) */
52#define FCOE_CTLR_DEF_FKA FIP_DEF_FKA /* default keep alive (mS) */
53
54static void fcoe_ctlr_timeout(unsigned long);
Joe Eykholt42913652010-03-12 16:08:23 -080055static void fcoe_ctlr_timer_work(struct work_struct *);
Joe Eykholt97c83892009-03-17 11:42:40 -070056static void fcoe_ctlr_recv_work(struct work_struct *);
57
Joe Eykholte10f8c62010-07-20 15:20:30 -070058static void fcoe_ctlr_vn_start(struct fcoe_ctlr *);
59static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
60static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *);
61static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *);
62
Joe Eykholt97c83892009-03-17 11:42:40 -070063static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
Joe Eykholte10f8c62010-07-20 15:20:30 -070064static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
65static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS;
66static u8 fcoe_all_p2p[ETH_ALEN] = FIP_ALL_P2P_MACS;
Joe Eykholt97c83892009-03-17 11:42:40 -070067
Robert Love650bd122009-06-10 15:31:05 -070068unsigned int libfcoe_debug_logging;
69module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
70MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
Joe Eykholt97c83892009-03-17 11:42:40 -070071
Robert Love70b51aa2009-11-03 11:47:45 -080072#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
Robert Love650bd122009-06-10 15:31:05 -070073#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
74
Robert Love70b51aa2009-11-03 11:47:45 -080075#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
76do { \
77 if (unlikely(libfcoe_debug_logging & LEVEL)) \
78 do { \
79 CMD; \
80 } while (0); \
Joe Eykholta69b06b2009-08-25 13:58:42 -070081} while (0)
Joe Eykholt97c83892009-03-17 11:42:40 -070082
Robert Love650bd122009-06-10 15:31:05 -070083#define LIBFCOE_DBG(fmt, args...) \
84 LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
85 printk(KERN_INFO "libfcoe: " fmt, ##args);)
86
Joe Eykholt0f51c2e2009-11-03 11:48:16 -080087#define LIBFCOE_FIP_DBG(fip, fmt, args...) \
Robert Love650bd122009-06-10 15:31:05 -070088 LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \
Joe Eykholt0f51c2e2009-11-03 11:48:16 -080089 printk(KERN_INFO "host%d: fip: " fmt, \
90 (fip)->lp->host->host_no, ##args);)
Joe Eykholt97c83892009-03-17 11:42:40 -070091
Joe Eykholt9b651da2010-07-20 15:20:24 -070092static const char *fcoe_ctlr_states[] = {
93 [FIP_ST_DISABLED] = "DISABLED",
94 [FIP_ST_LINK_WAIT] = "LINK_WAIT",
95 [FIP_ST_AUTO] = "AUTO",
96 [FIP_ST_NON_FIP] = "NON_FIP",
97 [FIP_ST_ENABLED] = "ENABLED",
Joe Eykholte10f8c62010-07-20 15:20:30 -070098 [FIP_ST_VNMP_START] = "VNMP_START",
99 [FIP_ST_VNMP_PROBE1] = "VNMP_PROBE1",
100 [FIP_ST_VNMP_PROBE2] = "VNMP_PROBE2",
101 [FIP_ST_VNMP_CLAIM] = "VNMP_CLAIM",
102 [FIP_ST_VNMP_UP] = "VNMP_UP",
Joe Eykholt9b651da2010-07-20 15:20:24 -0700103};
104
105static const char *fcoe_ctlr_state(enum fip_state state)
106{
107 const char *cp = "unknown";
108
109 if (state < ARRAY_SIZE(fcoe_ctlr_states))
110 cp = fcoe_ctlr_states[state];
111 if (!cp)
112 cp = "unknown";
113 return cp;
114}
115
116/**
117 * fcoe_ctlr_set_state() - Set and do debug printing for the new FIP state.
118 * @fip: The FCoE controller
119 * @state: The new state
120 */
121static void fcoe_ctlr_set_state(struct fcoe_ctlr *fip, enum fip_state state)
122{
123 if (state == fip->state)
124 return;
125 if (fip->lp)
126 LIBFCOE_FIP_DBG(fip, "state %s -> %s\n",
127 fcoe_ctlr_state(fip->state), fcoe_ctlr_state(state));
128 fip->state = state;
129}
130
Robert Love70b51aa2009-11-03 11:47:45 -0800131/**
132 * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid
133 * @fcf: The FCF to check
134 *
Joe Eykholt97c83892009-03-17 11:42:40 -0700135 * Return non-zero if FCF fcoe_size has been validated.
136 */
137static inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf)
138{
139 return (fcf->flags & FIP_FL_SOL) != 0;
140}
141
Robert Love70b51aa2009-11-03 11:47:45 -0800142/**
143 * fcoe_ctlr_fcf_usable() - Check if a FCF is usable
144 * @fcf: The FCF to check
145 *
Joe Eykholt97c83892009-03-17 11:42:40 -0700146 * Return non-zero if the FCF is usable.
147 */
148static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
149{
150 u16 flags = FIP_FL_SOL | FIP_FL_AVAIL;
151
152 return (fcf->flags & flags) == flags;
153}
154
155/**
Robert Love70b51aa2009-11-03 11:47:45 -0800156 * fcoe_ctlr_init() - Initialize the FCoE Controller instance
157 * @fip: The FCoE controller to initialize
Joe Eykholt97c83892009-03-17 11:42:40 -0700158 */
Joe Eykholt3d902ac2010-07-20 15:19:58 -0700159void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
Joe Eykholt97c83892009-03-17 11:42:40 -0700160{
Joe Eykholt9b651da2010-07-20 15:20:24 -0700161 fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
Joe Eykholt3d902ac2010-07-20 15:19:58 -0700162 fip->mode = mode;
Joe Eykholt97c83892009-03-17 11:42:40 -0700163 INIT_LIST_HEAD(&fip->fcfs);
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700164 mutex_init(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -0700165 fip->flogi_oxid = FC_XID_UNKNOWN;
166 setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
Joe Eykholt42913652010-03-12 16:08:23 -0800167 INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
Joe Eykholt97c83892009-03-17 11:42:40 -0700168 INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
169 skb_queue_head_init(&fip->fip_recv_list);
170}
171EXPORT_SYMBOL(fcoe_ctlr_init);
172
173/**
Robert Love70b51aa2009-11-03 11:47:45 -0800174 * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller
175 * @fip: The FCoE controller whose FCFs are to be reset
Joe Eykholt97c83892009-03-17 11:42:40 -0700176 *
177 * Called with &fcoe_ctlr lock held.
178 */
179static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
180{
181 struct fcoe_fcf *fcf;
182 struct fcoe_fcf *next;
183
184 fip->sel_fcf = NULL;
185 list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
186 list_del(&fcf->list);
187 kfree(fcf);
188 }
189 fip->fcf_count = 0;
190 fip->sel_time = 0;
191}
192
193/**
Robert Love70b51aa2009-11-03 11:47:45 -0800194 * fcoe_ctlr_destroy() - Disable and tear down a FCoE controller
195 * @fip: The FCoE controller to tear down
Joe Eykholt97c83892009-03-17 11:42:40 -0700196 *
197 * This is called by FCoE drivers before freeing the &fcoe_ctlr.
198 *
199 * The receive handler will have been deleted before this to guarantee
200 * that no more recv_work will be scheduled.
201 *
202 * The timer routine will simply return once we set FIP_ST_DISABLED.
203 * This guarantees that no further timeouts or work will be scheduled.
204 */
205void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
206{
Chris Leecha4b7cfa2009-08-25 13:59:08 -0700207 cancel_work_sync(&fip->recv_work);
Joe Eykholt1f4aed82009-11-03 11:48:22 -0800208 skb_queue_purge(&fip->fip_recv_list);
Chris Leecha4b7cfa2009-08-25 13:59:08 -0700209
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700210 mutex_lock(&fip->ctlr_mutex);
Joe Eykholt9b651da2010-07-20 15:20:24 -0700211 fcoe_ctlr_set_state(fip, FIP_ST_DISABLED);
Joe Eykholt97c83892009-03-17 11:42:40 -0700212 fcoe_ctlr_reset_fcfs(fip);
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700213 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -0700214 del_timer_sync(&fip->timer);
Joe Eykholt42913652010-03-12 16:08:23 -0800215 cancel_work_sync(&fip->timer_work);
Joe Eykholt97c83892009-03-17 11:42:40 -0700216}
217EXPORT_SYMBOL(fcoe_ctlr_destroy);
218
219/**
Robert Love70b51aa2009-11-03 11:47:45 -0800220 * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port
221 * @fip: The FCoE controller to get the maximum FCoE size from
Joe Eykholt97c83892009-03-17 11:42:40 -0700222 *
223 * Returns the maximum packet size including the FCoE header and trailer,
224 * but not including any Ethernet or VLAN headers.
225 */
226static inline u32 fcoe_ctlr_fcoe_size(struct fcoe_ctlr *fip)
227{
228 /*
229 * Determine the max FCoE frame size allowed, including
230 * FCoE header and trailer.
231 * Note: lp->mfs is currently the payload size, not the frame size.
232 */
233 return fip->lp->mfs + sizeof(struct fc_frame_header) +
234 sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof);
235}
236
237/**
Robert Love70b51aa2009-11-03 11:47:45 -0800238 * fcoe_ctlr_solicit() - Send a FIP solicitation
239 * @fip: The FCoE controller to send the solicitation on
240 * @fcf: The destination FCF (if NULL, a multicast solicitation is sent)
Joe Eykholt97c83892009-03-17 11:42:40 -0700241 */
242static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
243{
244 struct sk_buff *skb;
245 struct fip_sol {
246 struct ethhdr eth;
247 struct fip_header fip;
248 struct {
249 struct fip_mac_desc mac;
250 struct fip_wwn_desc wwnn;
251 struct fip_size_desc size;
252 } __attribute__((packed)) desc;
253 } __attribute__((packed)) *sol;
254 u32 fcoe_size;
255
256 skb = dev_alloc_skb(sizeof(*sol));
257 if (!skb)
258 return;
259
260 sol = (struct fip_sol *)skb->data;
261
262 memset(sol, 0, sizeof(*sol));
263 memcpy(sol->eth.h_dest, fcf ? fcf->fcf_mac : fcoe_all_fcfs, ETH_ALEN);
264 memcpy(sol->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
265 sol->eth.h_proto = htons(ETH_P_FIP);
266
267 sol->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
268 sol->fip.fip_op = htons(FIP_OP_DISC);
269 sol->fip.fip_subcode = FIP_SC_SOL;
270 sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW);
271 sol->fip.fip_flags = htons(FIP_FL_FPMA);
Vasu Dev184dd342009-05-17 12:33:28 +0000272 if (fip->spma)
273 sol->fip.fip_flags |= htons(FIP_FL_SPMA);
Joe Eykholt97c83892009-03-17 11:42:40 -0700274
275 sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC;
276 sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW;
277 memcpy(sol->desc.mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
278
279 sol->desc.wwnn.fd_desc.fip_dtype = FIP_DT_NAME;
280 sol->desc.wwnn.fd_desc.fip_dlen = sizeof(sol->desc.wwnn) / FIP_BPW;
281 put_unaligned_be64(fip->lp->wwnn, &sol->desc.wwnn.fd_wwn);
282
283 fcoe_size = fcoe_ctlr_fcoe_size(fip);
284 sol->desc.size.fd_desc.fip_dtype = FIP_DT_FCOE_SIZE;
285 sol->desc.size.fd_desc.fip_dlen = sizeof(sol->desc.size) / FIP_BPW;
286 sol->desc.size.fd_size = htons(fcoe_size);
287
288 skb_put(skb, sizeof(*sol));
Chris Leech0f491532009-05-06 10:52:18 -0700289 skb->protocol = htons(ETH_P_FIP);
Joe Eykholt97c83892009-03-17 11:42:40 -0700290 skb_reset_mac_header(skb);
291 skb_reset_network_header(skb);
292 fip->send(fip, skb);
293
294 if (!fcf)
295 fip->sol_time = jiffies;
296}
297
298/**
Robert Love70b51aa2009-11-03 11:47:45 -0800299 * fcoe_ctlr_link_up() - Start FCoE controller
300 * @fip: The FCoE controller to start
Joe Eykholt97c83892009-03-17 11:42:40 -0700301 *
302 * Called from the LLD when the network link is ready.
303 */
304void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
305{
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700306 mutex_lock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -0700307 if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700308 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -0700309 fc_linkup(fip->lp);
310 } else if (fip->state == FIP_ST_LINK_WAIT) {
Joe Eykholt9b651da2010-07-20 15:20:24 -0700311 fcoe_ctlr_set_state(fip, fip->mode);
Joe Eykholte10f8c62010-07-20 15:20:30 -0700312 switch (fip->mode) {
313 default:
314 LIBFCOE_FIP_DBG(fip, "invalid mode %d\n", fip->mode);
315 /* fall-through */
316 case FIP_MODE_AUTO:
Joe Eykholt0f51c2e2009-11-03 11:48:16 -0800317 LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
Joe Eykholte10f8c62010-07-20 15:20:30 -0700318 /* fall-through */
319 case FIP_MODE_FABRIC:
320 case FIP_MODE_NON_FIP:
321 mutex_unlock(&fip->ctlr_mutex);
322 fc_linkup(fip->lp);
323 fcoe_ctlr_solicit(fip, NULL);
324 break;
325 case FIP_MODE_VN2VN:
326 fcoe_ctlr_vn_start(fip);
327 mutex_unlock(&fip->ctlr_mutex);
328 fc_linkup(fip->lp);
329 break;
330 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700331 } else
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700332 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -0700333}
334EXPORT_SYMBOL(fcoe_ctlr_link_up);
335
336/**
Robert Love70b51aa2009-11-03 11:47:45 -0800337 * fcoe_ctlr_reset() - Reset a FCoE controller
338 * @fip: The FCoE controller to reset
Joe Eykholt97c83892009-03-17 11:42:40 -0700339 */
Joe Eykholtdd42dac2009-11-03 11:48:27 -0800340static void fcoe_ctlr_reset(struct fcoe_ctlr *fip)
Joe Eykholt97c83892009-03-17 11:42:40 -0700341{
Joe Eykholt97c83892009-03-17 11:42:40 -0700342 fcoe_ctlr_reset_fcfs(fip);
343 del_timer(&fip->timer);
Joe Eykholt97c83892009-03-17 11:42:40 -0700344 fip->ctlr_ka_time = 0;
345 fip->port_ka_time = 0;
346 fip->sol_time = 0;
347 fip->flogi_oxid = FC_XID_UNKNOWN;
348 fip->map_dest = 0;
Joe Eykholt97c83892009-03-17 11:42:40 -0700349}
350
351/**
Robert Love70b51aa2009-11-03 11:47:45 -0800352 * fcoe_ctlr_link_down() - Stop a FCoE controller
353 * @fip: The FCoE controller to be stopped
Joe Eykholt97c83892009-03-17 11:42:40 -0700354 *
355 * Returns non-zero if the link was up and now isn't.
356 *
357 * Called from the LLD when the network link is not ready.
358 * There may be multiple calls while the link is down.
359 */
360int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
361{
Joe Eykholtdd42dac2009-11-03 11:48:27 -0800362 int link_dropped;
363
364 LIBFCOE_FIP_DBG(fip, "link down.\n");
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700365 mutex_lock(&fip->ctlr_mutex);
Joe Eykholtdd42dac2009-11-03 11:48:27 -0800366 fcoe_ctlr_reset(fip);
Joe Eykholt42913652010-03-12 16:08:23 -0800367 link_dropped = fip->state != FIP_ST_LINK_WAIT;
Joe Eykholt9b651da2010-07-20 15:20:24 -0700368 fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700369 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholtdd42dac2009-11-03 11:48:27 -0800370
371 if (link_dropped)
372 fc_linkdown(fip->lp);
373 return link_dropped;
Joe Eykholt97c83892009-03-17 11:42:40 -0700374}
375EXPORT_SYMBOL(fcoe_ctlr_link_down);
376
377/**
Robert Love70b51aa2009-11-03 11:47:45 -0800378 * fcoe_ctlr_send_keep_alive() - Send a keep-alive to the selected FCF
379 * @fip: The FCoE controller to send the FKA on
380 * @lport: libfc fc_lport to send from
381 * @ports: 0 for controller keep-alive, 1 for port keep-alive
382 * @sa: The source MAC address
Joe Eykholt97c83892009-03-17 11:42:40 -0700383 *
384 * A controller keep-alive is sent every fka_period (typically 8 seconds).
385 * The source MAC is the native MAC address.
386 *
387 * A port keep-alive is sent every 90 seconds while logged in.
388 * The source MAC is the assigned mapped source address.
389 * The destination is the FCF's F-port.
390 */
Chris Leech11b56182009-11-03 11:46:29 -0800391static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
392 struct fc_lport *lport,
393 int ports, u8 *sa)
Joe Eykholt97c83892009-03-17 11:42:40 -0700394{
395 struct sk_buff *skb;
396 struct fip_kal {
397 struct ethhdr eth;
398 struct fip_header fip;
399 struct fip_mac_desc mac;
400 } __attribute__((packed)) *kal;
401 struct fip_vn_desc *vn;
402 u32 len;
403 struct fc_lport *lp;
404 struct fcoe_fcf *fcf;
405
406 fcf = fip->sel_fcf;
407 lp = fip->lp;
Joe Eykholt281ae642010-06-11 16:43:33 -0700408 if (!fcf || (ports && !lp->port_id))
Joe Eykholt97c83892009-03-17 11:42:40 -0700409 return;
410
Yi Zoube276cb2009-11-03 11:50:16 -0800411 len = sizeof(*kal) + ports * sizeof(*vn);
Joe Eykholt97c83892009-03-17 11:42:40 -0700412 skb = dev_alloc_skb(len);
413 if (!skb)
414 return;
415
416 kal = (struct fip_kal *)skb->data;
417 memset(kal, 0, len);
418 memcpy(kal->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
419 memcpy(kal->eth.h_source, sa, ETH_ALEN);
420 kal->eth.h_proto = htons(ETH_P_FIP);
421
422 kal->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
423 kal->fip.fip_op = htons(FIP_OP_CTRL);
424 kal->fip.fip_subcode = FIP_SC_KEEP_ALIVE;
425 kal->fip.fip_dl_len = htons((sizeof(kal->mac) +
Robert Love70b51aa2009-11-03 11:47:45 -0800426 ports * sizeof(*vn)) / FIP_BPW);
Joe Eykholt97c83892009-03-17 11:42:40 -0700427 kal->fip.fip_flags = htons(FIP_FL_FPMA);
Vasu Dev184dd342009-05-17 12:33:28 +0000428 if (fip->spma)
429 kal->fip.fip_flags |= htons(FIP_FL_SPMA);
Joe Eykholt97c83892009-03-17 11:42:40 -0700430
431 kal->mac.fd_desc.fip_dtype = FIP_DT_MAC;
432 kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW;
433 memcpy(kal->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
Joe Eykholt97c83892009-03-17 11:42:40 -0700434 if (ports) {
435 vn = (struct fip_vn_desc *)(kal + 1);
436 vn->fd_desc.fip_dtype = FIP_DT_VN_ID;
437 vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;
Chris Leech11b56182009-11-03 11:46:29 -0800438 memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
Kaladhar Musunurufb831532010-05-07 15:18:57 -0700439 hton24(vn->fd_fc_id, lport->port_id);
440 put_unaligned_be64(lport->wwpn, &vn->fd_wwpn);
Joe Eykholt97c83892009-03-17 11:42:40 -0700441 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700442 skb_put(skb, len);
Chris Leech0f491532009-05-06 10:52:18 -0700443 skb->protocol = htons(ETH_P_FIP);
Joe Eykholt97c83892009-03-17 11:42:40 -0700444 skb_reset_mac_header(skb);
445 skb_reset_network_header(skb);
446 fip->send(fip, skb);
447}
448
449/**
Robert Love70b51aa2009-11-03 11:47:45 -0800450 * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it
451 * @fip: The FCoE controller for the ELS frame
452 * @dtype: The FIP descriptor type for the frame
453 * @skb: The FCoE ELS frame including FC header but no FCoE headers
Joe Eykholte10f8c62010-07-20 15:20:30 -0700454 * @d_id: The destination port ID.
Joe Eykholt97c83892009-03-17 11:42:40 -0700455 *
456 * Returns non-zero error code on failure.
457 *
458 * The caller must check that the length is a multiple of 4.
459 *
460 * The @skb must have enough headroom (28 bytes) and tailroom (8 bytes).
461 * Headroom includes the FIP encapsulation description, FIP header, and
462 * Ethernet header. The tailroom is for the FIP MAC descriptor.
463 */
Chris Leech11b56182009-11-03 11:46:29 -0800464static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
Joe Eykholte10f8c62010-07-20 15:20:30 -0700465 u8 dtype, struct sk_buff *skb, u32 d_id)
Joe Eykholt97c83892009-03-17 11:42:40 -0700466{
467 struct fip_encaps_head {
468 struct ethhdr eth;
469 struct fip_header fip;
470 struct fip_encaps encaps;
471 } __attribute__((packed)) *cap;
Joe Eykholt55543452010-07-20 15:20:35 -0700472 struct fc_frame_header *fh;
Joe Eykholt97c83892009-03-17 11:42:40 -0700473 struct fip_mac_desc *mac;
474 struct fcoe_fcf *fcf;
475 size_t dlen;
Yi Zou5a84bae2009-07-29 17:03:55 -0700476 u16 fip_flags;
Joe Eykholt55543452010-07-20 15:20:35 -0700477 u8 op;
Joe Eykholt97c83892009-03-17 11:42:40 -0700478
Joe Eykholt55543452010-07-20 15:20:35 -0700479 fh = (struct fc_frame_header *)skb->data;
480 op = *(u8 *)(fh + 1);
Joe Eykholt97c83892009-03-17 11:42:40 -0700481 dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */
482 cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap));
Joe Eykholt97c83892009-03-17 11:42:40 -0700483 memset(cap, 0, sizeof(*cap));
Joe Eykholte10f8c62010-07-20 15:20:30 -0700484
485 if (lport->point_to_multipoint) {
486 if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest))
487 return -ENODEV;
Joe Eykholt55543452010-07-20 15:20:35 -0700488 fip_flags = 0;
Joe Eykholte10f8c62010-07-20 15:20:30 -0700489 } else {
490 fcf = fip->sel_fcf;
491 if (!fcf)
492 return -ENODEV;
493 fip_flags = fcf->flags;
494 fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA :
495 FIP_FL_FPMA;
496 if (!fip_flags)
497 return -ENODEV;
498 memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
499 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700500 memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
501 cap->eth.h_proto = htons(ETH_P_FIP);
502
503 cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
504 cap->fip.fip_op = htons(FIP_OP_LS);
Joe Eykholt55543452010-07-20 15:20:35 -0700505 if (op == ELS_LS_ACC || op == ELS_LS_RJT)
506 cap->fip.fip_subcode = FIP_SC_REP;
507 else
508 cap->fip.fip_subcode = FIP_SC_REQ;
Yi Zou5a84bae2009-07-29 17:03:55 -0700509 cap->fip.fip_flags = htons(fip_flags);
Joe Eykholt97c83892009-03-17 11:42:40 -0700510
511 cap->encaps.fd_desc.fip_dtype = dtype;
512 cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
513
Joe Eykholt55543452010-07-20 15:20:35 -0700514 if (op != ELS_LS_RJT) {
515 dlen += sizeof(*mac);
516 mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
517 memset(mac, 0, sizeof(*mac));
518 mac->fd_desc.fip_dtype = FIP_DT_MAC;
519 mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
520 if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
521 memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
522 } else if (fip->mode == FIP_MODE_VN2VN) {
523 hton24(mac->fd_mac, FIP_VN_FC_MAP);
524 hton24(mac->fd_mac + 3, fip->port_id);
525 } else if (fip_flags & FIP_FL_SPMA) {
526 LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
527 memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
528 } else {
529 LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
530 /* FPMA only FLOGI. Must leave the MAC desc zeroed. */
531 }
Robert Love593abc02010-04-09 14:22:17 -0700532 }
Joe Eykholt55543452010-07-20 15:20:35 -0700533 cap->fip.fip_dl_len = htons(dlen / FIP_BPW);
Joe Eykholt97c83892009-03-17 11:42:40 -0700534
Chris Leech0f491532009-05-06 10:52:18 -0700535 skb->protocol = htons(ETH_P_FIP);
Joe Eykholt97c83892009-03-17 11:42:40 -0700536 skb_reset_mac_header(skb);
537 skb_reset_network_header(skb);
538 return 0;
539}
540
541/**
542 * fcoe_ctlr_els_send() - Send an ELS frame encapsulated by FIP if appropriate.
543 * @fip: FCoE controller.
Chris Leech11b56182009-11-03 11:46:29 -0800544 * @lport: libfc fc_lport to send from
Joe Eykholt97c83892009-03-17 11:42:40 -0700545 * @skb: FCoE ELS frame including FC header but no FCoE headers.
546 *
547 * Returns a non-zero error code if the frame should not be sent.
548 * Returns zero if the caller should send the frame with FCoE encapsulation.
549 *
550 * The caller must check that the length is a multiple of 4.
551 * The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
Joe Eykholte10f8c62010-07-20 15:20:30 -0700552 * The the skb must also be an fc_frame.
Joe Eykholt97c83892009-03-17 11:42:40 -0700553 */
Chris Leech11b56182009-11-03 11:46:29 -0800554int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
555 struct sk_buff *skb)
Joe Eykholt97c83892009-03-17 11:42:40 -0700556{
Joe Eykholte10f8c62010-07-20 15:20:30 -0700557 struct fc_frame *fp;
Joe Eykholt97c83892009-03-17 11:42:40 -0700558 struct fc_frame_header *fh;
559 u16 old_xid;
560 u8 op;
Chris Leech11b56182009-11-03 11:46:29 -0800561 u8 mac[ETH_ALEN];
Joe Eykholt97c83892009-03-17 11:42:40 -0700562
Joe Eykholte10f8c62010-07-20 15:20:30 -0700563 fp = container_of(skb, struct fc_frame, skb);
Joe Eykholt97c83892009-03-17 11:42:40 -0700564 fh = (struct fc_frame_header *)skb->data;
565 op = *(u8 *)(fh + 1);
566
Joe Eykholte10f8c62010-07-20 15:20:30 -0700567 if (op == ELS_FLOGI && fip->mode != FIP_MODE_VN2VN) {
Joe Eykholt97c83892009-03-17 11:42:40 -0700568 old_xid = fip->flogi_oxid;
569 fip->flogi_oxid = ntohs(fh->fh_ox_id);
570 if (fip->state == FIP_ST_AUTO) {
571 if (old_xid == FC_XID_UNKNOWN)
572 fip->flogi_count = 0;
573 fip->flogi_count++;
574 if (fip->flogi_count < 3)
575 goto drop;
576 fip->map_dest = 1;
577 return 0;
578 }
Joe Eykholt5f48f702009-05-06 10:52:12 -0700579 if (fip->state == FIP_ST_NON_FIP)
580 fip->map_dest = 1;
581 }
582
583 if (fip->state == FIP_ST_NON_FIP)
584 return 0;
Joe Eykholte10f8c62010-07-20 15:20:30 -0700585 if (!fip->sel_fcf && fip->mode != FIP_MODE_VN2VN)
Joe Eykholtf31f2a12009-11-03 11:48:32 -0800586 goto drop;
Joe Eykholt5f48f702009-05-06 10:52:12 -0700587 switch (op) {
588 case ELS_FLOGI:
Joe Eykholt97c83892009-03-17 11:42:40 -0700589 op = FIP_DT_FLOGI;
590 break;
591 case ELS_FDISC:
592 if (ntoh24(fh->fh_s_id))
593 return 0;
594 op = FIP_DT_FDISC;
595 break;
596 case ELS_LOGO:
Joe Eykholte10f8c62010-07-20 15:20:30 -0700597 if (fip->mode == FIP_MODE_VN2VN) {
598 if (fip->state != FIP_ST_VNMP_UP)
599 return -EINVAL;
600 if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI)
601 return -EINVAL;
602 } else {
603 if (fip->state != FIP_ST_ENABLED)
604 return 0;
605 if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
606 return 0;
607 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700608 op = FIP_DT_LOGO;
609 break;
610 case ELS_LS_ACC:
Joe Eykholt97c83892009-03-17 11:42:40 -0700611 /*
Joe Eykholte10f8c62010-07-20 15:20:30 -0700612 * If non-FIP, we may have gotten an SID by accepting an FLOGI
Joe Eykholt97c83892009-03-17 11:42:40 -0700613 * from a point-to-point connection. Switch to using
614 * the source mac based on the SID. The destination
615 * MAC in this case would have been set by receving the
616 * FLOGI.
617 */
Joe Eykholte10f8c62010-07-20 15:20:30 -0700618 if (fip->state == FIP_ST_NON_FIP) {
619 if (fip->flogi_oxid == FC_XID_UNKNOWN)
620 return 0;
621 fip->flogi_oxid = FC_XID_UNKNOWN;
622 fc_fcoe_set_mac(mac, fh->fh_d_id);
623 fip->update_mac(lport, mac);
624 }
625 /* fall through */
626 case ELS_LS_RJT:
627 op = fr_encaps(fp);
628 if (op)
629 break;
Joe Eykholt97c83892009-03-17 11:42:40 -0700630 return 0;
631 default:
Joe Eykholte10f8c62010-07-20 15:20:30 -0700632 if (fip->state != FIP_ST_ENABLED &&
633 fip->state != FIP_ST_VNMP_UP)
Joe Eykholt97c83892009-03-17 11:42:40 -0700634 goto drop;
635 return 0;
636 }
Joe Eykholte10f8c62010-07-20 15:20:30 -0700637 LIBFCOE_FIP_DBG(fip, "els_send op %u d_id %x\n",
638 op, ntoh24(fh->fh_d_id));
639 if (fcoe_ctlr_encaps(fip, lport, op, skb, ntoh24(fh->fh_d_id)))
Joe Eykholt97c83892009-03-17 11:42:40 -0700640 goto drop;
641 fip->send(fip, skb);
642 return -EINPROGRESS;
643drop:
644 kfree_skb(skb);
645 return -EINVAL;
646}
647EXPORT_SYMBOL(fcoe_ctlr_els_send);
648
Robert Love70b51aa2009-11-03 11:47:45 -0800649/**
650 * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller
651 * @fip: The FCoE controller to free FCFs on
Joe Eykholt97c83892009-03-17 11:42:40 -0700652 *
Joe Eykholtf018b732010-03-12 16:08:55 -0800653 * Called with lock held and preemption disabled.
Joe Eykholt97c83892009-03-17 11:42:40 -0700654 *
Joe Eykholt8690cb82010-06-11 16:44:10 -0700655 * An FCF is considered old if we have missed two advertisements.
656 * That is, there have been no valid advertisement from it for 2.5
657 * times its keep-alive period.
Joe Eykholt97c83892009-03-17 11:42:40 -0700658 *
659 * In addition, determine the time when an FCF selection can occur.
Yi Zouf3da80e2009-11-20 14:55:08 -0800660 *
661 * Also, increment the MissDiscAdvCount when no advertisement is received
662 * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
Joe Eykholt8690cb82010-06-11 16:44:10 -0700663 *
664 * Returns the time in jiffies for the next call.
Joe Eykholt97c83892009-03-17 11:42:40 -0700665 */
Joe Eykholt8690cb82010-06-11 16:44:10 -0700666static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
Joe Eykholt97c83892009-03-17 11:42:40 -0700667{
668 struct fcoe_fcf *fcf;
669 struct fcoe_fcf *next;
Joe Eykholt8690cb82010-06-11 16:44:10 -0700670 unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
671 unsigned long deadline;
Joe Eykholt97c83892009-03-17 11:42:40 -0700672 unsigned long sel_time = 0;
Joe Eykholtf018b732010-03-12 16:08:55 -0800673 struct fcoe_dev_stats *stats;
Joe Eykholt97c83892009-03-17 11:42:40 -0700674
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700675 stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
676
Joe Eykholt97c83892009-03-17 11:42:40 -0700677 list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
Joe Eykholt8690cb82010-06-11 16:44:10 -0700678 deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
679 if (fip->sel_fcf == fcf) {
680 if (time_after(jiffies, deadline)) {
Joe Eykholt8690cb82010-06-11 16:44:10 -0700681 stats->MissDiscAdvCount++;
682 printk(KERN_INFO "libfcoe: host%d: "
683 "Missing Discovery Advertisement "
684 "for fab %16.16llx count %lld\n",
685 fip->lp->host->host_no, fcf->fabric_name,
686 stats->MissDiscAdvCount);
687 } else if (time_after(next_timer, deadline))
688 next_timer = deadline;
Yi Zouf3da80e2009-11-20 14:55:08 -0800689 }
Joe Eykholt8690cb82010-06-11 16:44:10 -0700690
691 deadline += fcf->fka_period;
Joe Eykholtd99ee452010-06-11 16:44:15 -0700692 if (time_after_eq(jiffies, deadline)) {
Joe Eykholt97c83892009-03-17 11:42:40 -0700693 if (fip->sel_fcf == fcf)
694 fip->sel_fcf = NULL;
695 list_del(&fcf->list);
696 WARN_ON(!fip->fcf_count);
697 fip->fcf_count--;
698 kfree(fcf);
Joe Eykholtf018b732010-03-12 16:08:55 -0800699 stats->VLinkFailureCount++;
Joe Eykholt8690cb82010-06-11 16:44:10 -0700700 } else {
701 if (time_after(next_timer, deadline))
702 next_timer = deadline;
703 if (fcoe_ctlr_mtu_valid(fcf) &&
704 (!sel_time || time_before(sel_time, fcf->time)))
705 sel_time = fcf->time;
Joe Eykholt97c83892009-03-17 11:42:40 -0700706 }
707 }
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700708 put_cpu();
Joe Eykholtd99ee452010-06-11 16:44:15 -0700709 if (sel_time && !fip->sel_fcf && !fip->sel_time) {
Joe Eykholt97c83892009-03-17 11:42:40 -0700710 sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
711 fip->sel_time = sel_time;
Joe Eykholt97c83892009-03-17 11:42:40 -0700712 }
Joe Eykholtd99ee452010-06-11 16:44:15 -0700713
Joe Eykholt8690cb82010-06-11 16:44:10 -0700714 return next_timer;
Joe Eykholt97c83892009-03-17 11:42:40 -0700715}
716
717/**
Robert Love70b51aa2009-11-03 11:47:45 -0800718 * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry
Joe Eykholt0f51c2e2009-11-03 11:48:16 -0800719 * @fip: The FCoE controller receiving the advertisement
Robert Love70b51aa2009-11-03 11:47:45 -0800720 * @skb: The received FIP advertisement frame
721 * @fcf: The resulting FCF entry
Joe Eykholt97c83892009-03-17 11:42:40 -0700722 *
723 * Returns zero on a valid parsed advertisement,
724 * otherwise returns non zero value.
725 */
Joe Eykholt0f51c2e2009-11-03 11:48:16 -0800726static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
727 struct sk_buff *skb, struct fcoe_fcf *fcf)
Joe Eykholt97c83892009-03-17 11:42:40 -0700728{
729 struct fip_header *fiph;
730 struct fip_desc *desc = NULL;
731 struct fip_wwn_desc *wwn;
732 struct fip_fab_desc *fab;
733 struct fip_fka_desc *fka;
734 unsigned long t;
735 size_t rlen;
736 size_t dlen;
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700737 u32 desc_mask;
Joe Eykholt97c83892009-03-17 11:42:40 -0700738
739 memset(fcf, 0, sizeof(*fcf));
740 fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
741
742 fiph = (struct fip_header *)skb->data;
743 fcf->flags = ntohs(fiph->fip_flags);
744
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700745 /*
746 * mask of required descriptors. validating each one clears its bit.
747 */
748 desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
749 BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA);
750
Joe Eykholt97c83892009-03-17 11:42:40 -0700751 rlen = ntohs(fiph->fip_dl_len) * 4;
752 if (rlen + sizeof(*fiph) > skb->len)
753 return -EINVAL;
754
755 desc = (struct fip_desc *)(fiph + 1);
756 while (rlen > 0) {
757 dlen = desc->fip_dlen * FIP_BPW;
758 if (dlen < sizeof(*desc) || dlen > rlen)
759 return -EINVAL;
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700760 /* Drop Adv if there are duplicate critical descriptors */
761 if ((desc->fip_dtype < 32) &&
762 !(desc_mask & 1U << desc->fip_dtype)) {
763 LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
764 "Descriptors in FIP adv\n");
765 return -EINVAL;
766 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700767 switch (desc->fip_dtype) {
768 case FIP_DT_PRI:
769 if (dlen != sizeof(struct fip_pri_desc))
770 goto len_err;
771 fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700772 desc_mask &= ~BIT(FIP_DT_PRI);
Joe Eykholt97c83892009-03-17 11:42:40 -0700773 break;
774 case FIP_DT_MAC:
775 if (dlen != sizeof(struct fip_mac_desc))
776 goto len_err;
777 memcpy(fcf->fcf_mac,
778 ((struct fip_mac_desc *)desc)->fd_mac,
779 ETH_ALEN);
780 if (!is_valid_ether_addr(fcf->fcf_mac)) {
Joe Eykholte10f8c62010-07-20 15:20:30 -0700781 LIBFCOE_FIP_DBG(fip,
782 "Invalid MAC addr %pM in FIP adv\n",
783 fcf->fcf_mac);
Joe Eykholt97c83892009-03-17 11:42:40 -0700784 return -EINVAL;
785 }
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700786 desc_mask &= ~BIT(FIP_DT_MAC);
Joe Eykholt97c83892009-03-17 11:42:40 -0700787 break;
788 case FIP_DT_NAME:
789 if (dlen != sizeof(struct fip_wwn_desc))
790 goto len_err;
791 wwn = (struct fip_wwn_desc *)desc;
792 fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700793 desc_mask &= ~BIT(FIP_DT_NAME);
Joe Eykholt97c83892009-03-17 11:42:40 -0700794 break;
795 case FIP_DT_FAB:
796 if (dlen != sizeof(struct fip_fab_desc))
797 goto len_err;
798 fab = (struct fip_fab_desc *)desc;
799 fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
800 fcf->vfid = ntohs(fab->fd_vfid);
801 fcf->fc_map = ntoh24(fab->fd_map);
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700802 desc_mask &= ~BIT(FIP_DT_FAB);
Joe Eykholt97c83892009-03-17 11:42:40 -0700803 break;
804 case FIP_DT_FKA:
805 if (dlen != sizeof(struct fip_fka_desc))
806 goto len_err;
807 fka = (struct fip_fka_desc *)desc;
Yi Zou8cdffdc2009-11-20 14:54:57 -0800808 if (fka->fd_flags & FIP_FKA_ADV_D)
809 fcf->fd_flags = 1;
Joe Eykholt97c83892009-03-17 11:42:40 -0700810 t = ntohl(fka->fd_fka_period);
811 if (t >= FCOE_CTLR_MIN_FKA)
812 fcf->fka_period = msecs_to_jiffies(t);
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700813 desc_mask &= ~BIT(FIP_DT_FKA);
Joe Eykholt97c83892009-03-17 11:42:40 -0700814 break;
815 case FIP_DT_MAP_OUI:
816 case FIP_DT_FCOE_SIZE:
817 case FIP_DT_FLOGI:
818 case FIP_DT_FDISC:
819 case FIP_DT_LOGO:
820 case FIP_DT_ELP:
821 default:
Joe Eykholt0f51c2e2009-11-03 11:48:16 -0800822 LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
Robert Love650bd122009-06-10 15:31:05 -0700823 "in FIP adv\n", desc->fip_dtype);
Joe Eykholt97c83892009-03-17 11:42:40 -0700824 /* standard says ignore unknown descriptors >= 128 */
825 if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
826 return -EINVAL;
Bhanu Prakash Gollapudi1508f3ec2010-06-11 16:43:38 -0700827 break;
Joe Eykholt97c83892009-03-17 11:42:40 -0700828 }
829 desc = (struct fip_desc *)((char *)desc + dlen);
830 rlen -= dlen;
831 }
832 if (!fcf->fc_map || (fcf->fc_map & 0x10000))
833 return -EINVAL;
834 if (!fcf->switch_name || !fcf->fabric_name)
835 return -EINVAL;
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700836 if (desc_mask) {
837 LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",
838 desc_mask);
839 return -EINVAL;
840 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700841 return 0;
842
843len_err:
Joe Eykholt0f51c2e2009-11-03 11:48:16 -0800844 LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
Robert Love650bd122009-06-10 15:31:05 -0700845 desc->fip_dtype, dlen);
Joe Eykholt97c83892009-03-17 11:42:40 -0700846 return -EINVAL;
847}
848
849/**
Robert Love70b51aa2009-11-03 11:47:45 -0800850 * fcoe_ctlr_recv_adv() - Handle an incoming advertisement
851 * @fip: The FCoE controller receiving the advertisement
852 * @skb: The received FIP packet
Joe Eykholt97c83892009-03-17 11:42:40 -0700853 */
854static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
855{
856 struct fcoe_fcf *fcf;
857 struct fcoe_fcf new;
858 struct fcoe_fcf *found;
859 unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV);
860 int first = 0;
861 int mtu_valid;
862
Joe Eykholt0f51c2e2009-11-03 11:48:16 -0800863 if (fcoe_ctlr_parse_adv(fip, skb, &new))
Joe Eykholt97c83892009-03-17 11:42:40 -0700864 return;
865
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700866 mutex_lock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -0700867 first = list_empty(&fip->fcfs);
868 found = NULL;
869 list_for_each_entry(fcf, &fip->fcfs, list) {
870 if (fcf->switch_name == new.switch_name &&
871 fcf->fabric_name == new.fabric_name &&
872 fcf->fc_map == new.fc_map &&
873 compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) {
874 found = fcf;
875 break;
876 }
877 }
878 if (!found) {
879 if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT)
880 goto out;
881
882 fcf = kmalloc(sizeof(*fcf), GFP_ATOMIC);
883 if (!fcf)
884 goto out;
885
886 fip->fcf_count++;
887 memcpy(fcf, &new, sizeof(new));
888 list_add(&fcf->list, &fip->fcfs);
889 } else {
890 /*
Joe Eykholtc600fea2010-06-11 16:44:20 -0700891 * Update the FCF's keep-alive descriptor flags.
892 * Other flag changes from new advertisements are
893 * ignored after a solicited advertisement is
894 * received and the FCF is selectable (usable).
Joe Eykholt97c83892009-03-17 11:42:40 -0700895 */
Joe Eykholtc600fea2010-06-11 16:44:20 -0700896 fcf->fd_flags = new.fd_flags;
897 if (!fcoe_ctlr_fcf_usable(fcf))
898 fcf->flags = new.flags;
899
Joe Eykholtd99ee452010-06-11 16:44:15 -0700900 if (fcf == fip->sel_fcf && !fcf->fd_flags) {
Joe Eykholt97c83892009-03-17 11:42:40 -0700901 fip->ctlr_ka_time -= fcf->fka_period;
902 fip->ctlr_ka_time += new.fka_period;
903 if (time_before(fip->ctlr_ka_time, fip->timer.expires))
904 mod_timer(&fip->timer, fip->ctlr_ka_time);
Joe Eykholtc600fea2010-06-11 16:44:20 -0700905 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700906 fcf->fka_period = new.fka_period;
907 memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
908 }
909 mtu_valid = fcoe_ctlr_mtu_valid(fcf);
910 fcf->time = jiffies;
Robert Love650bd122009-06-10 15:31:05 -0700911 if (!found) {
Chris Leech9f8f3aa2010-04-09 14:23:16 -0700912 LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx "
913 "map %x val %d\n",
Robert Love650bd122009-06-10 15:31:05 -0700914 fcf->fabric_name, fcf->fc_map, mtu_valid);
915 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700916
917 /*
918 * If this advertisement is not solicited and our max receive size
919 * hasn't been verified, send a solicited advertisement.
920 */
921 if (!mtu_valid)
922 fcoe_ctlr_solicit(fip, fcf);
923
924 /*
925 * If its been a while since we did a solicit, and this is
926 * the first advertisement we've received, do a multicast
927 * solicitation to gather as many advertisements as we can
928 * before selection occurs.
929 */
930 if (first && time_after(jiffies, fip->sol_time + sol_tov))
931 fcoe_ctlr_solicit(fip, NULL);
932
933 /*
934 * If this is the first validated FCF, note the time and
935 * set a timer to trigger selection.
936 */
Joe Eykholtd99ee452010-06-11 16:44:15 -0700937 if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) {
Joe Eykholt97c83892009-03-17 11:42:40 -0700938 fip->sel_time = jiffies +
Robert Love70b51aa2009-11-03 11:47:45 -0800939 msecs_to_jiffies(FCOE_CTLR_START_DELAY);
Joe Eykholt97c83892009-03-17 11:42:40 -0700940 if (!timer_pending(&fip->timer) ||
941 time_before(fip->sel_time, fip->timer.expires))
942 mod_timer(&fip->timer, fip->sel_time);
943 }
944out:
Joe Eykholtfdb068c2010-07-20 15:19:47 -0700945 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -0700946}
947
948/**
Robert Love70b51aa2009-11-03 11:47:45 -0800949 * fcoe_ctlr_recv_els() - Handle an incoming FIP encapsulated ELS frame
950 * @fip: The FCoE controller which received the packet
951 * @skb: The received FIP packet
Joe Eykholt97c83892009-03-17 11:42:40 -0700952 */
953static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
954{
Robert Love70b51aa2009-11-03 11:47:45 -0800955 struct fc_lport *lport = fip->lp;
Joe Eykholt97c83892009-03-17 11:42:40 -0700956 struct fip_header *fiph;
Chris Leech11b56182009-11-03 11:46:29 -0800957 struct fc_frame *fp = (struct fc_frame *)skb;
Joe Eykholt97c83892009-03-17 11:42:40 -0700958 struct fc_frame_header *fh = NULL;
959 struct fip_desc *desc;
960 struct fip_encaps *els;
961 struct fcoe_dev_stats *stats;
962 enum fip_desc_type els_dtype = 0;
963 u8 els_op;
964 u8 sub;
965 u8 granted_mac[ETH_ALEN] = { 0 };
966 size_t els_len = 0;
967 size_t rlen;
968 size_t dlen;
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -0700969 u32 desc_mask = 0;
970 u32 desc_cnt = 0;
Joe Eykholt97c83892009-03-17 11:42:40 -0700971
972 fiph = (struct fip_header *)skb->data;
973 sub = fiph->fip_subcode;
974 if (sub != FIP_SC_REQ && sub != FIP_SC_REP)
975 goto drop;
976
977 rlen = ntohs(fiph->fip_dl_len) * 4;
978 if (rlen + sizeof(*fiph) > skb->len)
979 goto drop;
980
981 desc = (struct fip_desc *)(fiph + 1);
982 while (rlen > 0) {
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -0700983 desc_cnt++;
Joe Eykholt97c83892009-03-17 11:42:40 -0700984 dlen = desc->fip_dlen * FIP_BPW;
985 if (dlen < sizeof(*desc) || dlen > rlen)
986 goto drop;
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700987 /* Drop ELS if there are duplicate critical descriptors */
988 if (desc->fip_dtype < 32) {
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -0700989 if (desc_mask & 1U << desc->fip_dtype) {
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700990 LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
991 "Descriptors in FIP ELS\n");
992 goto drop;
993 }
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -0700994 desc_mask |= (1 << desc->fip_dtype);
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -0700995 }
Joe Eykholt97c83892009-03-17 11:42:40 -0700996 switch (desc->fip_dtype) {
997 case FIP_DT_MAC:
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -0700998 if (desc_cnt == 1) {
999 LIBFCOE_FIP_DBG(fip, "FIP descriptors "
1000 "received out of order\n");
1001 goto drop;
1002 }
1003
Joe Eykholt97c83892009-03-17 11:42:40 -07001004 if (dlen != sizeof(struct fip_mac_desc))
1005 goto len_err;
1006 memcpy(granted_mac,
1007 ((struct fip_mac_desc *)desc)->fd_mac,
1008 ETH_ALEN);
Joe Eykholt97c83892009-03-17 11:42:40 -07001009 break;
1010 case FIP_DT_FLOGI:
1011 case FIP_DT_FDISC:
1012 case FIP_DT_LOGO:
1013 case FIP_DT_ELP:
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -07001014 if (desc_cnt != 1) {
1015 LIBFCOE_FIP_DBG(fip, "FIP descriptors "
1016 "received out of order\n");
1017 goto drop;
1018 }
Joe Eykholt97c83892009-03-17 11:42:40 -07001019 if (fh)
1020 goto drop;
1021 if (dlen < sizeof(*els) + sizeof(*fh) + 1)
1022 goto len_err;
1023 els_len = dlen - sizeof(*els);
1024 els = (struct fip_encaps *)desc;
1025 fh = (struct fc_frame_header *)(els + 1);
1026 els_dtype = desc->fip_dtype;
1027 break;
1028 default:
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001029 LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
Robert Love650bd122009-06-10 15:31:05 -07001030 "in FIP adv\n", desc->fip_dtype);
Joe Eykholt97c83892009-03-17 11:42:40 -07001031 /* standard says ignore unknown descriptors >= 128 */
1032 if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
1033 goto drop;
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -07001034 if (desc_cnt <= 2) {
1035 LIBFCOE_FIP_DBG(fip, "FIP descriptors "
1036 "received out of order\n");
1037 goto drop;
1038 }
Bhanu Prakash Gollapudi1508f3ec2010-06-11 16:43:38 -07001039 break;
Joe Eykholt97c83892009-03-17 11:42:40 -07001040 }
1041 desc = (struct fip_desc *)((char *)desc + dlen);
1042 rlen -= dlen;
1043 }
1044
1045 if (!fh)
1046 goto drop;
1047 els_op = *(u8 *)(fh + 1);
1048
Joe Eykholte10f8c62010-07-20 15:20:30 -07001049 if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
1050 sub == FIP_SC_REP && els_op == ELS_LS_ACC &&
1051 fip->mode != FIP_MODE_VN2VN) {
1052 if (!is_valid_ether_addr(granted_mac)) {
1053 LIBFCOE_FIP_DBG(fip,
1054 "Invalid MAC address %pM in FIP ELS\n",
1055 granted_mac);
1056 goto drop;
1057 }
1058 memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
1059
1060 if (fip->flogi_oxid == ntohs(fh->fh_ox_id))
1061 fip->flogi_oxid = FC_XID_UNKNOWN;
1062 }
Joe Eykholt97c83892009-03-17 11:42:40 -07001063
Bhanu Prakash Gollapudibe613312010-06-11 16:44:36 -07001064 if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
1065 (!(1U << FIP_DT_MAC & desc_mask)))) {
1066 LIBFCOE_FIP_DBG(fip, "Missing critical descriptors "
1067 "in FIP ELS\n");
1068 goto drop;
1069 }
1070
Joe Eykholt97c83892009-03-17 11:42:40 -07001071 /*
1072 * Convert skb into an fc_frame containing only the ELS.
1073 */
1074 skb_pull(skb, (u8 *)fh - skb->data);
1075 skb_trim(skb, els_len);
1076 fp = (struct fc_frame *)skb;
1077 fc_frame_init(fp);
1078 fr_sof(fp) = FC_SOF_I3;
1079 fr_eof(fp) = FC_EOF_T;
Robert Love70b51aa2009-11-03 11:47:45 -08001080 fr_dev(fp) = lport;
Joe Eykholte10f8c62010-07-20 15:20:30 -07001081 fr_encaps(fp) = els_dtype;
Joe Eykholt97c83892009-03-17 11:42:40 -07001082
Joe Eykholtf018b732010-03-12 16:08:55 -08001083 stats = per_cpu_ptr(lport->dev_stats, get_cpu());
Joe Eykholt97c83892009-03-17 11:42:40 -07001084 stats->RxFrames++;
1085 stats->RxWords += skb->len / FIP_BPW;
Joe Eykholtf018b732010-03-12 16:08:55 -08001086 put_cpu();
Joe Eykholt97c83892009-03-17 11:42:40 -07001087
Robert Love70b51aa2009-11-03 11:47:45 -08001088 fc_exch_recv(lport, fp);
Joe Eykholt97c83892009-03-17 11:42:40 -07001089 return;
1090
1091len_err:
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001092 LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
Robert Love650bd122009-06-10 15:31:05 -07001093 desc->fip_dtype, dlen);
Joe Eykholt97c83892009-03-17 11:42:40 -07001094drop:
1095 kfree_skb(skb);
1096}
1097
1098/**
Robert Love70b51aa2009-11-03 11:47:45 -08001099 * fcoe_ctlr_recv_els() - Handle an incoming link reset frame
1100 * @fip: The FCoE controller that received the frame
1101 * @fh: The received FIP header
Joe Eykholt97c83892009-03-17 11:42:40 -07001102 *
1103 * There may be multiple VN_Port descriptors.
1104 * The overall length has already been checked.
1105 */
1106static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
Robert Love70b51aa2009-11-03 11:47:45 -08001107 struct fip_header *fh)
Joe Eykholt97c83892009-03-17 11:42:40 -07001108{
1109 struct fip_desc *desc;
1110 struct fip_mac_desc *mp;
1111 struct fip_wwn_desc *wp;
1112 struct fip_vn_desc *vp;
1113 size_t rlen;
1114 size_t dlen;
1115 struct fcoe_fcf *fcf = fip->sel_fcf;
Robert Love70b51aa2009-11-03 11:47:45 -08001116 struct fc_lport *lport = fip->lp;
Bhanu Prakash Gollapudi5550fda2010-06-11 16:44:31 -07001117 struct fc_lport *vn_port = NULL;
1118 u32 desc_mask;
1119 int is_vn_port = 0;
Joe Eykholt97c83892009-03-17 11:42:40 -07001120
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001121 LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
Robert Loved29510a2010-05-07 15:18:30 -07001122
Robert Love7b2787e2010-05-07 15:18:41 -07001123 if (!fcf || !lport->port_id)
Joe Eykholt97c83892009-03-17 11:42:40 -07001124 return;
1125
1126 /*
1127 * mask of required descriptors. Validating each one clears its bit.
1128 */
1129 desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | BIT(FIP_DT_VN_ID);
1130
1131 rlen = ntohs(fh->fip_dl_len) * FIP_BPW;
1132 desc = (struct fip_desc *)(fh + 1);
1133 while (rlen >= sizeof(*desc)) {
1134 dlen = desc->fip_dlen * FIP_BPW;
1135 if (dlen > rlen)
1136 return;
Bhanu Prakash Gollapudi0a9c5d32010-06-11 16:44:25 -07001137 /* Drop CVL if there are duplicate critical descriptors */
1138 if ((desc->fip_dtype < 32) &&
1139 !(desc_mask & 1U << desc->fip_dtype)) {
1140 LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
1141 "Descriptors in FIP CVL\n");
1142 return;
1143 }
Joe Eykholt97c83892009-03-17 11:42:40 -07001144 switch (desc->fip_dtype) {
1145 case FIP_DT_MAC:
1146 mp = (struct fip_mac_desc *)desc;
1147 if (dlen < sizeof(*mp))
1148 return;
1149 if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac))
1150 return;
1151 desc_mask &= ~BIT(FIP_DT_MAC);
1152 break;
1153 case FIP_DT_NAME:
1154 wp = (struct fip_wwn_desc *)desc;
1155 if (dlen < sizeof(*wp))
1156 return;
1157 if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name)
1158 return;
1159 desc_mask &= ~BIT(FIP_DT_NAME);
1160 break;
1161 case FIP_DT_VN_ID:
1162 vp = (struct fip_vn_desc *)desc;
1163 if (dlen < sizeof(*vp))
1164 return;
1165 if (compare_ether_addr(vp->fd_mac,
Robert Love70b51aa2009-11-03 11:47:45 -08001166 fip->get_src_addr(lport)) == 0 &&
1167 get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
Bhanu Prakash Gollapudi5550fda2010-06-11 16:44:31 -07001168 ntoh24(vp->fd_fc_id) == lport->port_id) {
Joe Eykholt97c83892009-03-17 11:42:40 -07001169 desc_mask &= ~BIT(FIP_DT_VN_ID);
Bhanu Prakash Gollapudi5550fda2010-06-11 16:44:31 -07001170 break;
1171 }
1172 /* check if clr_vlink is for NPIV port */
1173 mutex_lock(&lport->lp_mutex);
1174 list_for_each_entry(vn_port, &lport->vports, list) {
1175 if (compare_ether_addr(vp->fd_mac,
1176 fip->get_src_addr(vn_port)) == 0 &&
1177 (get_unaligned_be64(&vp->fd_wwpn)
1178 == vn_port->wwpn) &&
1179 (ntoh24(vp->fd_fc_id) ==
1180 fc_host_port_id(vn_port->host))) {
1181 desc_mask &= ~BIT(FIP_DT_VN_ID);
1182 is_vn_port = 1;
1183 break;
1184 }
1185 }
1186 mutex_unlock(&lport->lp_mutex);
1187
Joe Eykholt97c83892009-03-17 11:42:40 -07001188 break;
1189 default:
1190 /* standard says ignore unknown descriptors >= 128 */
1191 if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
1192 return;
1193 break;
1194 }
1195 desc = (struct fip_desc *)((char *)desc + dlen);
1196 rlen -= dlen;
1197 }
1198
1199 /*
1200 * reset only if all required descriptors were present and valid.
1201 */
1202 if (desc_mask) {
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001203 LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n",
1204 desc_mask);
Joe Eykholt97c83892009-03-17 11:42:40 -07001205 } else {
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001206 LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
Joe Eykholtdd42dac2009-11-03 11:48:27 -08001207
Bhanu Prakash Gollapudi5550fda2010-06-11 16:44:31 -07001208 if (is_vn_port)
1209 fc_lport_reset(vn_port);
1210 else {
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001211 mutex_lock(&fip->ctlr_mutex);
Bhanu Prakash Gollapudi5550fda2010-06-11 16:44:31 -07001212 per_cpu_ptr(lport->dev_stats,
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001213 get_cpu())->VLinkFailureCount++;
1214 put_cpu();
Bhanu Prakash Gollapudi5550fda2010-06-11 16:44:31 -07001215 fcoe_ctlr_reset(fip);
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001216 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholtdd42dac2009-11-03 11:48:27 -08001217
Bhanu Prakash Gollapudi5550fda2010-06-11 16:44:31 -07001218 fc_lport_reset(fip->lp);
1219 fcoe_ctlr_solicit(fip, NULL);
1220 }
Joe Eykholt97c83892009-03-17 11:42:40 -07001221 }
1222}
1223
1224/**
Robert Love70b51aa2009-11-03 11:47:45 -08001225 * fcoe_ctlr_recv() - Receive a FIP packet
1226 * @fip: The FCoE controller that received the packet
1227 * @skb: The received FIP packet
Joe Eykholt97c83892009-03-17 11:42:40 -07001228 *
Joe Eykholt1f4aed82009-11-03 11:48:22 -08001229 * This may be called from either NET_RX_SOFTIRQ or IRQ.
Joe Eykholt97c83892009-03-17 11:42:40 -07001230 */
1231void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
1232{
Joe Eykholt1f4aed82009-11-03 11:48:22 -08001233 skb_queue_tail(&fip->fip_recv_list, skb);
Joe Eykholt97c83892009-03-17 11:42:40 -07001234 schedule_work(&fip->recv_work);
1235}
1236EXPORT_SYMBOL(fcoe_ctlr_recv);
1237
1238/**
Robert Love70b51aa2009-11-03 11:47:45 -08001239 * fcoe_ctlr_recv_handler() - Receive a FIP frame
1240 * @fip: The FCoE controller that received the frame
1241 * @skb: The received FIP frame
Joe Eykholt97c83892009-03-17 11:42:40 -07001242 *
1243 * Returns non-zero if the frame is dropped.
1244 */
1245static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
1246{
1247 struct fip_header *fiph;
1248 struct ethhdr *eh;
1249 enum fip_state state;
1250 u16 op;
1251 u8 sub;
1252
1253 if (skb_linearize(skb))
1254 goto drop;
1255 if (skb->len < sizeof(*fiph))
1256 goto drop;
1257 eh = eth_hdr(skb);
Joe Eykholte10f8c62010-07-20 15:20:30 -07001258 if (fip->mode == FIP_MODE_VN2VN) {
1259 if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
1260 compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) &&
1261 compare_ether_addr(eh->h_dest, fcoe_all_p2p))
1262 goto drop;
1263 } else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
1264 compare_ether_addr(eh->h_dest, fcoe_all_enode))
Joe Eykholt97c83892009-03-17 11:42:40 -07001265 goto drop;
1266 fiph = (struct fip_header *)skb->data;
1267 op = ntohs(fiph->fip_op);
1268 sub = fiph->fip_subcode;
1269
Joe Eykholt97c83892009-03-17 11:42:40 -07001270 if (FIP_VER_DECAPS(fiph->fip_ver) != FIP_VER)
1271 goto drop;
1272 if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len)
1273 goto drop;
1274
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001275 mutex_lock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001276 state = fip->state;
1277 if (state == FIP_ST_AUTO) {
1278 fip->map_dest = 0;
Joe Eykholt9b651da2010-07-20 15:20:24 -07001279 fcoe_ctlr_set_state(fip, FIP_ST_ENABLED);
Joe Eykholt97c83892009-03-17 11:42:40 -07001280 state = FIP_ST_ENABLED;
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001281 LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
Joe Eykholt97c83892009-03-17 11:42:40 -07001282 }
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001283 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholte10f8c62010-07-20 15:20:30 -07001284
1285 if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN)
1286 return fcoe_ctlr_vn_recv(fip, skb);
1287
1288 if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP &&
1289 state != FIP_ST_VNMP_CLAIM)
Joe Eykholt97c83892009-03-17 11:42:40 -07001290 goto drop;
1291
1292 if (op == FIP_OP_LS) {
1293 fcoe_ctlr_recv_els(fip, skb); /* consumes skb */
1294 return 0;
1295 }
Joe Eykholte10f8c62010-07-20 15:20:30 -07001296
1297 if (state != FIP_ST_ENABLED)
1298 goto drop;
1299
Joe Eykholt97c83892009-03-17 11:42:40 -07001300 if (op == FIP_OP_DISC && sub == FIP_SC_ADV)
1301 fcoe_ctlr_recv_adv(fip, skb);
1302 else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK)
1303 fcoe_ctlr_recv_clr_vlink(fip, fiph);
1304 kfree_skb(skb);
1305 return 0;
1306drop:
1307 kfree_skb(skb);
1308 return -1;
1309}
1310
1311/**
Robert Love70b51aa2009-11-03 11:47:45 -08001312 * fcoe_ctlr_select() - Select the best FCF (if possible)
1313 * @fip: The FCoE controller
Joe Eykholt97c83892009-03-17 11:42:40 -07001314 *
1315 * If there are conflicting advertisements, no FCF can be chosen.
1316 *
1317 * Called with lock held.
1318 */
1319static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
1320{
1321 struct fcoe_fcf *fcf;
1322 struct fcoe_fcf *best = NULL;
1323
1324 list_for_each_entry(fcf, &fip->fcfs, list) {
Chris Leech9f8f3aa2010-04-09 14:23:16 -07001325 LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx "
1326 "VFID %d map %x val %d\n",
1327 fcf->fabric_name, fcf->vfid,
Robert Love650bd122009-06-10 15:31:05 -07001328 fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
Joe Eykholt97c83892009-03-17 11:42:40 -07001329 if (!fcoe_ctlr_fcf_usable(fcf)) {
Chris Leech9f8f3aa2010-04-09 14:23:16 -07001330 LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
1331 "map %x %svalid %savailable\n",
1332 fcf->fabric_name, fcf->fc_map,
1333 (fcf->flags & FIP_FL_SOL) ? "" : "in",
1334 (fcf->flags & FIP_FL_AVAIL) ?
1335 "" : "un");
Joe Eykholt97c83892009-03-17 11:42:40 -07001336 continue;
1337 }
1338 if (!best) {
1339 best = fcf;
1340 continue;
1341 }
1342 if (fcf->fabric_name != best->fabric_name ||
1343 fcf->vfid != best->vfid ||
1344 fcf->fc_map != best->fc_map) {
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001345 LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
Robert Love650bd122009-06-10 15:31:05 -07001346 "or FC-MAP\n");
Joe Eykholt97c83892009-03-17 11:42:40 -07001347 return;
1348 }
1349 if (fcf->pri < best->pri)
1350 best = fcf;
1351 }
1352 fip->sel_fcf = best;
1353}
1354
1355/**
Robert Love70b51aa2009-11-03 11:47:45 -08001356 * fcoe_ctlr_timeout() - FIP timeout handler
1357 * @arg: The FCoE controller that timed out
Joe Eykholt97c83892009-03-17 11:42:40 -07001358 */
1359static void fcoe_ctlr_timeout(unsigned long arg)
1360{
1361 struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001362
1363 schedule_work(&fip->timer_work);
1364}
1365
1366/**
1367 * fcoe_ctlr_timer_work() - Worker thread function for timer work
1368 * @work: Handle to a FCoE controller
1369 *
1370 * Ages FCFs. Triggers FCF selection if possible.
1371 * Sends keep-alives and resets.
1372 */
1373static void fcoe_ctlr_timer_work(struct work_struct *work)
1374{
1375 struct fcoe_ctlr *fip;
1376 struct fc_lport *vport;
1377 u8 *mac;
1378 u8 reset = 0;
1379 u8 send_ctlr_ka = 0;
1380 u8 send_port_ka = 0;
Joe Eykholt97c83892009-03-17 11:42:40 -07001381 struct fcoe_fcf *sel;
1382 struct fcoe_fcf *fcf;
Joe Eykholt8690cb82010-06-11 16:44:10 -07001383 unsigned long next_timer;
Joe Eykholt97c83892009-03-17 11:42:40 -07001384
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001385 fip = container_of(work, struct fcoe_ctlr, timer_work);
Joe Eykholte10f8c62010-07-20 15:20:30 -07001386 if (fip->mode == FIP_MODE_VN2VN)
1387 return fcoe_ctlr_vn_timeout(fip);
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001388 mutex_lock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001389 if (fip->state == FIP_ST_DISABLED) {
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001390 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001391 return;
1392 }
1393
1394 fcf = fip->sel_fcf;
Joe Eykholt8690cb82010-06-11 16:44:10 -07001395 next_timer = fcoe_ctlr_age_fcfs(fip);
Joe Eykholt97c83892009-03-17 11:42:40 -07001396
1397 sel = fip->sel_fcf;
Joe Eykholt8690cb82010-06-11 16:44:10 -07001398 if (!sel && fip->sel_time) {
1399 if (time_after_eq(jiffies, fip->sel_time)) {
1400 fcoe_ctlr_select(fip);
1401 sel = fip->sel_fcf;
1402 fip->sel_time = 0;
1403 } else if (time_after(next_timer, fip->sel_time))
1404 next_timer = fip->sel_time;
Joe Eykholt97c83892009-03-17 11:42:40 -07001405 }
1406
1407 if (sel != fcf) {
1408 fcf = sel; /* the old FCF may have been freed */
1409 if (sel) {
Robert Love650bd122009-06-10 15:31:05 -07001410 printk(KERN_INFO "libfcoe: host%d: FIP selected "
Johannes Berg66d6fae2009-07-15 17:21:14 +02001411 "Fibre-Channel Forwarder MAC %pM\n",
1412 fip->lp->host->host_no, sel->fcf_mac);
Joe Eykholt97c83892009-03-17 11:42:40 -07001413 memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
1414 fip->port_ka_time = jiffies +
Robert Love70b51aa2009-11-03 11:47:45 -08001415 msecs_to_jiffies(FIP_VN_KA_PERIOD);
Joe Eykholt97c83892009-03-17 11:42:40 -07001416 fip->ctlr_ka_time = jiffies + sel->fka_period;
Joe Eykholtd99ee452010-06-11 16:44:15 -07001417 if (time_after(next_timer, fip->ctlr_ka_time))
1418 next_timer = fip->ctlr_ka_time;
Joe Eykholt97c83892009-03-17 11:42:40 -07001419 } else {
Robert Love650bd122009-06-10 15:31:05 -07001420 printk(KERN_NOTICE "libfcoe: host%d: "
Robert Love70b51aa2009-11-03 11:47:45 -08001421 "FIP Fibre-Channel Forwarder timed out. "
Joe Eykholt97c83892009-03-17 11:42:40 -07001422 "Starting FCF discovery.\n",
1423 fip->lp->host->host_no);
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001424 reset = 1;
Joe Eykholt97c83892009-03-17 11:42:40 -07001425 }
Joe Eykholt97c83892009-03-17 11:42:40 -07001426 }
1427
Yi Zou8cdffdc2009-11-20 14:54:57 -08001428 if (sel && !sel->fd_flags) {
Joe Eykholt97c83892009-03-17 11:42:40 -07001429 if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
1430 fip->ctlr_ka_time = jiffies + sel->fka_period;
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001431 send_ctlr_ka = 1;
Joe Eykholt97c83892009-03-17 11:42:40 -07001432 }
1433 if (time_after(next_timer, fip->ctlr_ka_time))
1434 next_timer = fip->ctlr_ka_time;
1435
1436 if (time_after_eq(jiffies, fip->port_ka_time)) {
Bhanu Prakash Gollapudif47dd852010-01-21 10:16:00 -08001437 fip->port_ka_time = jiffies +
Robert Love70b51aa2009-11-03 11:47:45 -08001438 msecs_to_jiffies(FIP_VN_KA_PERIOD);
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001439 send_port_ka = 1;
Joe Eykholt97c83892009-03-17 11:42:40 -07001440 }
1441 if (time_after(next_timer, fip->port_ka_time))
1442 next_timer = fip->port_ka_time;
Joe Eykholt97c83892009-03-17 11:42:40 -07001443 }
Joe Eykholt8690cb82010-06-11 16:44:10 -07001444 if (!list_empty(&fip->fcfs))
1445 mod_timer(&fip->timer, next_timer);
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001446 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001447
Bhanu Prakash Gollapudi516a6482010-06-11 16:43:44 -07001448 if (reset) {
Joe Eykholtdd42dac2009-11-03 11:48:27 -08001449 fc_lport_reset(fip->lp);
Bhanu Prakash Gollapudi516a6482010-06-11 16:43:44 -07001450 /* restart things with a solicitation */
1451 fcoe_ctlr_solicit(fip, NULL);
1452 }
Chris Leech11b56182009-11-03 11:46:29 -08001453
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001454 if (send_ctlr_ka)
Chris Leech11b56182009-11-03 11:46:29 -08001455 fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr);
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001456
1457 if (send_port_ka) {
Chris Leech11b56182009-11-03 11:46:29 -08001458 mutex_lock(&fip->lp->lp_mutex);
1459 mac = fip->get_src_addr(fip->lp);
1460 fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac);
1461 list_for_each_entry(vport, &fip->lp->vports, list) {
1462 mac = fip->get_src_addr(vport);
1463 fcoe_ctlr_send_keep_alive(fip, vport, 1, mac);
1464 }
1465 mutex_unlock(&fip->lp->lp_mutex);
1466 }
Joe Eykholt97c83892009-03-17 11:42:40 -07001467}
1468
1469/**
Robert Love70b51aa2009-11-03 11:47:45 -08001470 * fcoe_ctlr_recv_work() - Worker thread function for receiving FIP frames
1471 * @recv_work: Handle to a FCoE controller
Joe Eykholt97c83892009-03-17 11:42:40 -07001472 */
1473static void fcoe_ctlr_recv_work(struct work_struct *recv_work)
1474{
1475 struct fcoe_ctlr *fip;
1476 struct sk_buff *skb;
1477
1478 fip = container_of(recv_work, struct fcoe_ctlr, recv_work);
Joe Eykholt1f4aed82009-11-03 11:48:22 -08001479 while ((skb = skb_dequeue(&fip->fip_recv_list)))
Joe Eykholt97c83892009-03-17 11:42:40 -07001480 fcoe_ctlr_recv_handler(fip, skb);
Joe Eykholt97c83892009-03-17 11:42:40 -07001481}
1482
1483/**
Joe Eykholt386309ce2009-11-03 11:49:16 -08001484 * fcoe_ctlr_recv_flogi() - Snoop pre-FIP receipt of FLOGI response
Robert Love70b51aa2009-11-03 11:47:45 -08001485 * @fip: The FCoE controller
1486 * @fp: The FC frame to snoop
Joe Eykholt97c83892009-03-17 11:42:40 -07001487 *
1488 * Snoop potential response to FLOGI or even incoming FLOGI.
1489 *
1490 * The caller has checked that we are waiting for login as indicated
1491 * by fip->flogi_oxid != FC_XID_UNKNOWN.
1492 *
1493 * The caller is responsible for freeing the frame.
Joe Eykholt386309ce2009-11-03 11:49:16 -08001494 * Fill in the granted_mac address.
Joe Eykholt97c83892009-03-17 11:42:40 -07001495 *
1496 * Return non-zero if the frame should not be delivered to libfc.
1497 */
Chris Leech11b56182009-11-03 11:46:29 -08001498int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
Joe Eykholt386309ce2009-11-03 11:49:16 -08001499 struct fc_frame *fp)
Joe Eykholt97c83892009-03-17 11:42:40 -07001500{
1501 struct fc_frame_header *fh;
1502 u8 op;
Joe Eykholt386309ce2009-11-03 11:49:16 -08001503 u8 *sa;
Joe Eykholt97c83892009-03-17 11:42:40 -07001504
Joe Eykholt386309ce2009-11-03 11:49:16 -08001505 sa = eth_hdr(&fp->skb)->h_source;
Joe Eykholt97c83892009-03-17 11:42:40 -07001506 fh = fc_frame_header_get(fp);
1507 if (fh->fh_type != FC_TYPE_ELS)
1508 return 0;
1509
1510 op = fc_frame_payload_op(fp);
1511 if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP &&
1512 fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
1513
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001514 mutex_lock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001515 if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) {
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001516 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001517 return -EINVAL;
1518 }
Joe Eykholt9b651da2010-07-20 15:20:24 -07001519 fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
Joe Eykholt0f51c2e2009-11-03 11:48:16 -08001520 LIBFCOE_FIP_DBG(fip,
1521 "received FLOGI LS_ACC using non-FIP mode\n");
Joe Eykholt97c83892009-03-17 11:42:40 -07001522
1523 /*
1524 * FLOGI accepted.
1525 * If the src mac addr is FC_OUI-based, then we mark the
1526 * address_mode flag to use FC_OUI-based Ethernet DA.
1527 * Otherwise we use the FCoE gateway addr
1528 */
1529 if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) {
1530 fip->map_dest = 1;
1531 } else {
1532 memcpy(fip->dest_addr, sa, ETH_ALEN);
1533 fip->map_dest = 0;
1534 }
1535 fip->flogi_oxid = FC_XID_UNKNOWN;
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001536 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt386309ce2009-11-03 11:49:16 -08001537 fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id);
Joe Eykholt97c83892009-03-17 11:42:40 -07001538 } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
1539 /*
1540 * Save source MAC for point-to-point responses.
1541 */
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001542 mutex_lock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001543 if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
1544 memcpy(fip->dest_addr, sa, ETH_ALEN);
1545 fip->map_dest = 0;
Joe Eykholte49bf612010-03-12 16:07:57 -08001546 if (fip->state == FIP_ST_AUTO)
1547 LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
1548 "Setting non-FIP mode\n");
Joe Eykholt9b651da2010-07-20 15:20:24 -07001549 fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
Joe Eykholt97c83892009-03-17 11:42:40 -07001550 }
Joe Eykholtfdb068c2010-07-20 15:19:47 -07001551 mutex_unlock(&fip->ctlr_mutex);
Joe Eykholt97c83892009-03-17 11:42:40 -07001552 }
1553 return 0;
1554}
1555EXPORT_SYMBOL(fcoe_ctlr_recv_flogi);
1556
Vasu Dev5e80f7f2009-03-17 11:42:18 -07001557/**
Robert Love70b51aa2009-11-03 11:47:45 -08001558 * fcoe_wwn_from_mac() - Converts a 48-bit IEEE MAC address to a 64-bit FC WWN
1559 * @mac: The MAC address to convert
1560 * @scheme: The scheme to use when converting
1561 * @port: The port indicator for converting
Vasu Dev5e80f7f2009-03-17 11:42:18 -07001562 *
1563 * Returns: u64 fc world wide name
1564 */
1565u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN],
1566 unsigned int scheme, unsigned int port)
1567{
1568 u64 wwn;
1569 u64 host_mac;
1570
1571 /* The MAC is in NO, so flip only the low 48 bits */
1572 host_mac = ((u64) mac[0] << 40) |
1573 ((u64) mac[1] << 32) |
1574 ((u64) mac[2] << 24) |
1575 ((u64) mac[3] << 16) |
1576 ((u64) mac[4] << 8) |
1577 (u64) mac[5];
1578
1579 WARN_ON(host_mac >= (1ULL << 48));
1580 wwn = host_mac | ((u64) scheme << 60);
1581 switch (scheme) {
1582 case 1:
1583 WARN_ON(port != 0);
1584 break;
1585 case 2:
1586 WARN_ON(port >= 0xfff);
1587 wwn |= (u64) port << 48;
1588 break;
1589 default:
1590 WARN_ON(1);
1591 break;
1592 }
1593
1594 return wwn;
1595}
1596EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac);
1597
1598/**
Joe Eykholte10f8c62010-07-20 15:20:30 -07001599 * fcoe_ctlr_rport() - return the fcoe_rport for a given fc_rport_priv
1600 * @rdata: libfc remote port
1601 */
1602static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata)
1603{
1604 return (struct fcoe_rport *)(rdata + 1);
1605}
1606
1607/**
1608 * fcoe_ctlr_vn_send() - Send a FIP VN2VN Probe Request or Reply.
1609 * @fip: The FCoE controller
1610 * @sub: sub-opcode for probe request, reply, or advertisement.
1611 * @dest: The destination Ethernet MAC address
1612 * @min_len: minimum size of the Ethernet payload to be sent
1613 */
1614static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
1615 enum fip_vn2vn_subcode sub,
1616 const u8 *dest, size_t min_len)
1617{
1618 struct sk_buff *skb;
1619 struct fip_frame {
1620 struct ethhdr eth;
1621 struct fip_header fip;
1622 struct fip_mac_desc mac;
1623 struct fip_wwn_desc wwnn;
1624 struct fip_vn_desc vn;
1625 } __attribute__((packed)) *frame;
1626 struct fip_fc4_feat *ff;
1627 struct fip_size_desc *size;
1628 u32 fcp_feat;
1629 size_t len;
1630 size_t dlen;
1631
1632 len = sizeof(*frame);
1633 dlen = 0;
1634 if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
1635 dlen = sizeof(struct fip_fc4_feat) +
1636 sizeof(struct fip_size_desc);
1637 len += dlen;
1638 }
1639 dlen += sizeof(frame->mac) + sizeof(frame->wwnn) + sizeof(frame->vn);
1640 len = max(len, min_len + sizeof(struct ethhdr));
1641
1642 skb = dev_alloc_skb(len);
1643 if (!skb)
1644 return;
1645
1646 frame = (struct fip_frame *)skb->data;
1647 memset(frame, 0, len);
1648 memcpy(frame->eth.h_dest, dest, ETH_ALEN);
1649 memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
1650 frame->eth.h_proto = htons(ETH_P_FIP);
1651
1652 frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
1653 frame->fip.fip_op = htons(FIP_OP_VN2VN);
1654 frame->fip.fip_subcode = sub;
1655 frame->fip.fip_dl_len = htons(dlen / FIP_BPW);
1656
1657 frame->mac.fd_desc.fip_dtype = FIP_DT_MAC;
1658 frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW;
1659 memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
1660
1661 frame->wwnn.fd_desc.fip_dtype = FIP_DT_NAME;
1662 frame->wwnn.fd_desc.fip_dlen = sizeof(frame->wwnn) / FIP_BPW;
1663 put_unaligned_be64(fip->lp->wwnn, &frame->wwnn.fd_wwn);
1664
1665 frame->vn.fd_desc.fip_dtype = FIP_DT_VN_ID;
1666 frame->vn.fd_desc.fip_dlen = sizeof(frame->vn) / FIP_BPW;
1667 hton24(frame->vn.fd_mac, FIP_VN_FC_MAP);
1668 hton24(frame->vn.fd_mac + 3, fip->port_id);
1669 hton24(frame->vn.fd_fc_id, fip->port_id);
1670 put_unaligned_be64(fip->lp->wwpn, &frame->vn.fd_wwpn);
1671
1672 /*
1673 * For claims, add FC-4 features.
1674 * TBD: Add interface to get fc-4 types and features from libfc.
1675 */
1676 if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
1677 ff = (struct fip_fc4_feat *)(frame + 1);
1678 ff->fd_desc.fip_dtype = FIP_DT_FC4F;
1679 ff->fd_desc.fip_dlen = sizeof(*ff) / FIP_BPW;
1680 ff->fd_fts = fip->lp->fcts;
1681
1682 fcp_feat = 0;
1683 if (fip->lp->service_params & FCP_SPPF_INIT_FCN)
1684 fcp_feat |= FCP_FEAT_INIT;
1685 if (fip->lp->service_params & FCP_SPPF_TARG_FCN)
1686 fcp_feat |= FCP_FEAT_TARG;
1687 fcp_feat <<= (FC_TYPE_FCP * 4) % 32;
1688 ff->fd_ff.fd_feat[FC_TYPE_FCP * 4 / 32] = htonl(fcp_feat);
1689
1690 size = (struct fip_size_desc *)(ff + 1);
1691 size->fd_desc.fip_dtype = FIP_DT_FCOE_SIZE;
1692 size->fd_desc.fip_dlen = sizeof(*size) / FIP_BPW;
1693 size->fd_size = htons(fcoe_ctlr_fcoe_size(fip));
1694 }
1695
1696 skb_put(skb, len);
1697 skb->protocol = htons(ETH_P_FIP);
1698 skb_reset_mac_header(skb);
1699 skb_reset_network_header(skb);
1700
1701 fip->send(fip, skb);
1702}
1703
1704/**
1705 * fcoe_ctlr_vn_rport_callback - Event handler for rport events.
1706 * @lport: The lport which is receiving the event
1707 * @rdata: remote port private data
1708 * @event: The event that occured
1709 *
1710 * Locking Note: The rport lock must not be held when calling this function.
1711 */
1712static void fcoe_ctlr_vn_rport_callback(struct fc_lport *lport,
1713 struct fc_rport_priv *rdata,
1714 enum fc_rport_event event)
1715{
1716 struct fcoe_ctlr *fip = lport->disc.priv;
1717 struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
1718
1719 LIBFCOE_FIP_DBG(fip, "vn_rport_callback %x event %d\n",
1720 rdata->ids.port_id, event);
1721
1722 mutex_lock(&fip->ctlr_mutex);
1723 switch (event) {
1724 case RPORT_EV_READY:
1725 frport->login_count = 0;
1726 break;
1727 case RPORT_EV_LOGO:
1728 case RPORT_EV_FAILED:
1729 case RPORT_EV_STOP:
1730 frport->login_count++;
1731 if (frport->login_count > FCOE_CTLR_VN2VN_LOGIN_LIMIT) {
1732 LIBFCOE_FIP_DBG(fip,
1733 "rport FLOGI limited port_id %6.6x\n",
1734 rdata->ids.port_id);
1735 lport->tt.rport_logoff(rdata);
1736 }
1737 break;
1738 default:
1739 break;
1740 }
1741 mutex_unlock(&fip->ctlr_mutex);
1742}
1743
1744static struct fc_rport_operations fcoe_ctlr_vn_rport_ops = {
1745 .event_callback = fcoe_ctlr_vn_rport_callback,
1746};
1747
1748/**
1749 * fcoe_ctlr_disc_stop_locked() - stop discovery in VN2VN mode
1750 * @fip: The FCoE controller
1751 *
1752 * Called with ctlr_mutex held.
1753 */
1754static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport)
1755{
1756 mutex_lock(&lport->disc.disc_mutex);
1757 lport->disc.disc_callback = NULL;
1758 mutex_unlock(&lport->disc.disc_mutex);
1759}
1760
1761/**
1762 * fcoe_ctlr_disc_stop() - stop discovery in VN2VN mode
1763 * @fip: The FCoE controller
1764 *
1765 * Called through the local port template for discovery.
1766 * Called without the ctlr_mutex held.
1767 */
1768static void fcoe_ctlr_disc_stop(struct fc_lport *lport)
1769{
1770 struct fcoe_ctlr *fip = lport->disc.priv;
1771
1772 mutex_lock(&fip->ctlr_mutex);
1773 fcoe_ctlr_disc_stop_locked(lport);
1774 mutex_unlock(&fip->ctlr_mutex);
1775}
1776
1777/**
1778 * fcoe_ctlr_disc_stop_final() - stop discovery for shutdown in VN2VN mode
1779 * @fip: The FCoE controller
1780 *
1781 * Called through the local port template for discovery.
1782 * Called without the ctlr_mutex held.
1783 */
1784static void fcoe_ctlr_disc_stop_final(struct fc_lport *lport)
1785{
1786 fcoe_ctlr_disc_stop(lport);
1787 lport->tt.rport_flush_queue();
1788 synchronize_rcu();
1789}
1790
1791/**
1792 * fcoe_ctlr_vn_restart() - VN2VN probe restart with new port_id
1793 * @fip: The FCoE controller
1794 *
1795 * Called with fcoe_ctlr lock held.
1796 */
1797static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip)
1798{
1799 unsigned long wait;
1800 u32 port_id;
1801
1802 fcoe_ctlr_disc_stop_locked(fip->lp);
1803
1804 /*
1805 * Get proposed port ID.
1806 * If this is the first try after link up, use any previous port_id.
1807 * If there was none, use the low bits of the port_name.
1808 * On subsequent tries, get the next random one.
1809 * Don't use reserved IDs, use another non-zero value, just as random.
1810 */
1811 port_id = fip->port_id;
1812 if (fip->probe_tries)
1813 port_id = prandom32(&fip->rnd_state) & 0xffff;
1814 else if (!port_id)
1815 port_id = fip->lp->wwpn & 0xffff;
1816 if (!port_id || port_id == 0xffff)
1817 port_id = 1;
1818 fip->port_id = port_id;
1819
1820 if (fip->probe_tries < FIP_VN_RLIM_COUNT) {
1821 fip->probe_tries++;
1822 wait = random32() % FIP_VN_PROBE_WAIT;
1823 } else
1824 wait = FIP_VN_RLIM_INT;
1825 mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait));
1826 fcoe_ctlr_set_state(fip, FIP_ST_VNMP_START);
1827}
1828
1829/**
1830 * fcoe_ctlr_vn_start() - Start in VN2VN mode
1831 * @fip: The FCoE controller
1832 *
1833 * Called with fcoe_ctlr lock held.
1834 */
1835static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip)
1836{
1837 fip->probe_tries = 0;
1838 prandom32_seed(&fip->rnd_state, fip->lp->wwpn);
1839 fcoe_ctlr_vn_restart(fip);
1840}
1841
1842/**
1843 * fcoe_ctlr_vn_parse - parse probe request or response
1844 * @fip: The FCoE controller
1845 * @skb: incoming packet
1846 * @rdata: buffer for resulting parsed VN entry plus fcoe_rport
1847 *
1848 * Returns non-zero error number on error.
1849 * Does not consume the packet.
1850 */
1851static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
1852 struct sk_buff *skb,
1853 struct fc_rport_priv *rdata)
1854{
1855 struct fip_header *fiph;
1856 struct fip_desc *desc = NULL;
1857 struct fip_mac_desc *macd = NULL;
1858 struct fip_wwn_desc *wwn = NULL;
1859 struct fip_vn_desc *vn = NULL;
1860 struct fip_size_desc *size = NULL;
1861 struct fcoe_rport *frport;
1862 size_t rlen;
1863 size_t dlen;
1864 u32 desc_mask = 0;
1865 u32 dtype;
1866 u8 sub;
1867
1868 memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
1869 frport = fcoe_ctlr_rport(rdata);
1870
1871 fiph = (struct fip_header *)skb->data;
1872 frport->flags = ntohs(fiph->fip_flags);
1873
1874 sub = fiph->fip_subcode;
1875 switch (sub) {
1876 case FIP_SC_VN_PROBE_REQ:
1877 case FIP_SC_VN_PROBE_REP:
1878 case FIP_SC_VN_BEACON:
1879 desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
1880 BIT(FIP_DT_VN_ID);
1881 break;
1882 case FIP_SC_VN_CLAIM_NOTIFY:
1883 case FIP_SC_VN_CLAIM_REP:
1884 desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
1885 BIT(FIP_DT_VN_ID) | BIT(FIP_DT_FC4F) |
1886 BIT(FIP_DT_FCOE_SIZE);
1887 break;
1888 default:
1889 LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub);
1890 return -EINVAL;
1891 }
1892
1893 rlen = ntohs(fiph->fip_dl_len) * 4;
1894 if (rlen + sizeof(*fiph) > skb->len)
1895 return -EINVAL;
1896
1897 desc = (struct fip_desc *)(fiph + 1);
1898 while (rlen > 0) {
1899 dlen = desc->fip_dlen * FIP_BPW;
1900 if (dlen < sizeof(*desc) || dlen > rlen)
1901 return -EINVAL;
1902
1903 dtype = desc->fip_dtype;
1904 if (dtype < 32) {
1905 if (!(desc_mask & BIT(dtype))) {
1906 LIBFCOE_FIP_DBG(fip,
1907 "unexpected or duplicated desc "
1908 "desc type %u in "
1909 "FIP VN2VN subtype %u\n",
1910 dtype, sub);
1911 return -EINVAL;
1912 }
1913 desc_mask &= ~BIT(dtype);
1914 }
1915
1916 switch (dtype) {
1917 case FIP_DT_MAC:
1918 if (dlen != sizeof(struct fip_mac_desc))
1919 goto len_err;
1920 macd = (struct fip_mac_desc *)desc;
1921 if (!is_valid_ether_addr(macd->fd_mac)) {
1922 LIBFCOE_FIP_DBG(fip,
1923 "Invalid MAC addr %pM in FIP VN2VN\n",
1924 macd->fd_mac);
1925 return -EINVAL;
1926 }
1927 memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN);
1928 break;
1929 case FIP_DT_NAME:
1930 if (dlen != sizeof(struct fip_wwn_desc))
1931 goto len_err;
1932 wwn = (struct fip_wwn_desc *)desc;
1933 rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
1934 break;
1935 case FIP_DT_VN_ID:
1936 if (dlen != sizeof(struct fip_vn_desc))
1937 goto len_err;
1938 vn = (struct fip_vn_desc *)desc;
1939 memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN);
1940 rdata->ids.port_id = ntoh24(vn->fd_fc_id);
1941 rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn);
1942 break;
1943 case FIP_DT_FC4F:
1944 if (dlen != sizeof(struct fip_fc4_feat))
1945 goto len_err;
1946 break;
1947 case FIP_DT_FCOE_SIZE:
1948 if (dlen != sizeof(struct fip_size_desc))
1949 goto len_err;
1950 size = (struct fip_size_desc *)desc;
1951 frport->fcoe_len = ntohs(size->fd_size);
1952 break;
1953 default:
1954 LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
1955 "in FIP probe\n", dtype);
1956 /* standard says ignore unknown descriptors >= 128 */
1957 if (dtype < FIP_DT_VENDOR_BASE)
1958 return -EINVAL;
1959 break;
1960 }
1961 desc = (struct fip_desc *)((char *)desc + dlen);
1962 rlen -= dlen;
1963 }
1964 return 0;
1965
1966len_err:
1967 LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
1968 dtype, dlen);
1969 return -EINVAL;
1970}
1971
1972/**
1973 * fcoe_ctlr_vn_send_claim() - send multicast FIP VN2VN Claim Notification.
1974 * @fip: The FCoE controller
1975 *
1976 * Called with ctlr_mutex held.
1977 */
1978static void fcoe_ctlr_vn_send_claim(struct fcoe_ctlr *fip)
1979{
1980 fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_NOTIFY, fcoe_all_vn2vn, 0);
1981 fip->sol_time = jiffies;
1982}
1983
1984/**
1985 * fcoe_ctlr_vn_probe_req() - handle incoming VN2VN probe request.
1986 * @fip: The FCoE controller
1987 * @rdata: parsed remote port with frport from the probe request
1988 *
1989 * Called with ctlr_mutex held.
1990 */
1991static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip,
1992 struct fc_rport_priv *rdata)
1993{
1994 struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
1995
1996 if (rdata->ids.port_id != fip->port_id)
1997 return;
1998
1999 switch (fip->state) {
2000 case FIP_ST_VNMP_CLAIM:
2001 case FIP_ST_VNMP_UP:
2002 fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
2003 frport->enode_mac, 0);
2004 break;
2005 case FIP_ST_VNMP_PROBE1:
2006 case FIP_ST_VNMP_PROBE2:
2007 /*
2008 * Decide whether to reply to the Probe.
2009 * Our selected address is never a "recorded" one, so
2010 * only reply if our WWPN is greater and the
2011 * Probe's REC bit is not set.
2012 * If we don't reply, we will change our address.
2013 */
2014 if (fip->lp->wwpn > rdata->ids.port_name &&
2015 !(frport->flags & FIP_FL_REC_OR_P2P)) {
2016 fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
2017 frport->enode_mac, 0);
2018 break;
2019 }
2020 /* fall through */
2021 case FIP_ST_VNMP_START:
2022 fcoe_ctlr_vn_restart(fip);
2023 break;
2024 default:
2025 break;
2026 }
2027}
2028
2029/**
2030 * fcoe_ctlr_vn_probe_reply() - handle incoming VN2VN probe reply.
2031 * @fip: The FCoE controller
2032 * @rdata: parsed remote port with frport from the probe request
2033 *
2034 * Called with ctlr_mutex held.
2035 */
2036static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip,
2037 struct fc_rport_priv *rdata)
2038{
2039 if (rdata->ids.port_id != fip->port_id)
2040 return;
2041 switch (fip->state) {
2042 case FIP_ST_VNMP_START:
2043 case FIP_ST_VNMP_PROBE1:
2044 case FIP_ST_VNMP_PROBE2:
2045 case FIP_ST_VNMP_CLAIM:
2046 fcoe_ctlr_vn_restart(fip);
2047 break;
2048 case FIP_ST_VNMP_UP:
2049 fcoe_ctlr_vn_send_claim(fip);
2050 break;
2051 default:
2052 break;
2053 }
2054}
2055
2056/**
2057 * fcoe_ctlr_vn_add() - Add a VN2VN entry to the list, based on a claim reply.
2058 * @fip: The FCoE controller
2059 * @new: newly-parsed remote port with frport as a template for new rdata
2060 *
2061 * Called with ctlr_mutex held.
2062 */
2063static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new)
2064{
2065 struct fc_lport *lport = fip->lp;
2066 struct fc_rport_priv *rdata;
2067 struct fc_rport_identifiers *ids;
2068 struct fcoe_rport *frport;
2069 u32 port_id;
2070
2071 port_id = new->ids.port_id;
2072 if (port_id == fip->port_id)
2073 return;
2074
2075 mutex_lock(&lport->disc.disc_mutex);
2076 rdata = lport->tt.rport_create(lport, port_id);
2077 if (!rdata) {
2078 mutex_unlock(&lport->disc.disc_mutex);
2079 return;
2080 }
2081
2082 rdata->ops = &fcoe_ctlr_vn_rport_ops;
2083 rdata->disc_id = lport->disc.disc_id;
2084
2085 ids = &rdata->ids;
2086 if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) ||
2087 (ids->node_name != -1 && ids->node_name != new->ids.node_name))
2088 lport->tt.rport_logoff(rdata);
2089 ids->port_name = new->ids.port_name;
2090 ids->node_name = new->ids.node_name;
2091 mutex_unlock(&lport->disc.disc_mutex);
2092
2093 frport = fcoe_ctlr_rport(rdata);
2094 LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n",
2095 port_id, frport->fcoe_len ? "old" : "new");
2096 *frport = *fcoe_ctlr_rport(new);
2097 frport->time = 0;
2098}
2099
2100/**
2101 * fcoe_ctlr_vn_lookup() - Find VN remote port's MAC address
2102 * @fip: The FCoE controller
2103 * @port_id: The port_id of the remote VN_node
2104 * @mac: buffer which will hold the VN_NODE destination MAC address, if found.
2105 *
2106 * Returns non-zero error if no remote port found.
2107 */
2108static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac)
2109{
2110 struct fc_lport *lport = fip->lp;
2111 struct fc_rport_priv *rdata;
2112 struct fcoe_rport *frport;
2113 int ret = -1;
2114
2115 rcu_read_lock();
2116 rdata = lport->tt.rport_lookup(lport, port_id);
2117 if (rdata) {
2118 frport = fcoe_ctlr_rport(rdata);
2119 memcpy(mac, frport->enode_mac, ETH_ALEN);
2120 ret = 0;
2121 }
2122 rcu_read_unlock();
2123 return ret;
2124}
2125
2126/**
2127 * fcoe_ctlr_vn_claim_notify() - handle received FIP VN2VN Claim Notification
2128 * @fip: The FCoE controller
2129 * @new: newly-parsed remote port with frport as a template for new rdata
2130 *
2131 * Called with ctlr_mutex held.
2132 */
2133static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip,
2134 struct fc_rport_priv *new)
2135{
2136 struct fcoe_rport *frport = fcoe_ctlr_rport(new);
2137
2138 if (frport->flags & FIP_FL_REC_OR_P2P) {
2139 fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2140 return;
2141 }
2142 switch (fip->state) {
2143 case FIP_ST_VNMP_START:
2144 case FIP_ST_VNMP_PROBE1:
2145 case FIP_ST_VNMP_PROBE2:
2146 if (new->ids.port_id == fip->port_id)
2147 fcoe_ctlr_vn_restart(fip);
2148 break;
2149 case FIP_ST_VNMP_CLAIM:
2150 case FIP_ST_VNMP_UP:
2151 if (new->ids.port_id == fip->port_id) {
2152 if (new->ids.port_name > fip->lp->wwpn) {
2153 fcoe_ctlr_vn_restart(fip);
2154 break;
2155 }
2156 fcoe_ctlr_vn_send_claim(fip);
2157 break;
2158 }
2159 fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac,
2160 min((u32)frport->fcoe_len,
2161 fcoe_ctlr_fcoe_size(fip)));
2162 fcoe_ctlr_vn_add(fip, new);
2163 break;
2164 default:
2165 break;
2166 }
2167}
2168
2169/**
2170 * fcoe_ctlr_vn_claim_resp() - handle received Claim Response
2171 * @fip: The FCoE controller that received the frame
2172 * @new: newly-parsed remote port with frport from the Claim Response
2173 *
2174 * Called with ctlr_mutex held.
2175 */
2176static void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip,
2177 struct fc_rport_priv *new)
2178{
2179 LIBFCOE_FIP_DBG(fip, "claim resp from from rport %x - state %s\n",
2180 new->ids.port_id, fcoe_ctlr_state(fip->state));
2181 if (fip->state == FIP_ST_VNMP_UP || fip->state == FIP_ST_VNMP_CLAIM)
2182 fcoe_ctlr_vn_add(fip, new);
2183}
2184
2185/**
2186 * fcoe_ctlr_vn_beacon() - handle received beacon.
2187 * @fip: The FCoE controller that received the frame
2188 * @new: newly-parsed remote port with frport from the Beacon
2189 *
2190 * Called with ctlr_mutex held.
2191 */
2192static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip,
2193 struct fc_rport_priv *new)
2194{
2195 struct fc_lport *lport = fip->lp;
2196 struct fc_rport_priv *rdata;
2197 struct fcoe_rport *frport;
2198
2199 frport = fcoe_ctlr_rport(new);
2200 if (frport->flags & FIP_FL_REC_OR_P2P) {
2201 fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2202 return;
2203 }
2204 mutex_lock(&lport->disc.disc_mutex);
2205 rdata = lport->tt.rport_lookup(lport, new->ids.port_id);
2206 if (rdata)
2207 kref_get(&rdata->kref);
2208 mutex_unlock(&lport->disc.disc_mutex);
2209 if (rdata) {
2210 if (rdata->ids.node_name == new->ids.node_name &&
2211 rdata->ids.port_name == new->ids.port_name) {
2212 frport = fcoe_ctlr_rport(rdata);
2213 if (!frport->time && fip->state == FIP_ST_VNMP_UP)
2214 lport->tt.rport_login(rdata);
2215 frport->time = jiffies;
2216 }
2217 kref_put(&rdata->kref, lport->tt.rport_destroy);
2218 return;
2219 }
2220 if (fip->state != FIP_ST_VNMP_UP)
2221 return;
2222
2223 /*
2224 * Beacon from a new neighbor.
2225 * Send a claim notify if one hasn't been sent recently.
2226 * Don't add the neighbor yet.
2227 */
2228 LIBFCOE_FIP_DBG(fip, "beacon from new rport %x. sending claim notify\n",
2229 new->ids.port_id);
2230 if (time_after(jiffies,
2231 fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT)))
2232 fcoe_ctlr_vn_send_claim(fip);
2233}
2234
2235/**
2236 * fcoe_ctlr_vn_age() - Check for VN_ports without recent beacons
2237 * @fip: The FCoE controller
2238 *
2239 * Called with ctlr_mutex held.
2240 * Called only in state FIP_ST_VNMP_UP.
2241 * Returns the soonest time for next age-out or a time far in the future.
2242 */
2243static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip)
2244{
2245 struct fc_lport *lport = fip->lp;
2246 struct fc_rport_priv *rdata;
2247 struct fcoe_rport *frport;
2248 unsigned long next_time;
2249 unsigned long deadline;
2250
2251 next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10);
2252 mutex_lock(&lport->disc.disc_mutex);
2253 list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
2254 frport = fcoe_ctlr_rport(rdata);
2255 if (!frport->time)
2256 continue;
2257 deadline = frport->time +
2258 msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10);
2259 if (time_after_eq(jiffies, deadline)) {
2260 frport->time = 0;
2261 LIBFCOE_FIP_DBG(fip,
2262 "port %16.16llx fc_id %6.6x beacon expired\n",
2263 rdata->ids.port_name, rdata->ids.port_id);
2264 lport->tt.rport_logoff(rdata);
2265 } else if (time_before(deadline, next_time))
2266 next_time = deadline;
2267 }
2268 mutex_unlock(&lport->disc.disc_mutex);
2269 return next_time;
2270}
2271
2272/**
2273 * fcoe_ctlr_vn_recv() - Receive a FIP frame
2274 * @fip: The FCoE controller that received the frame
2275 * @skb: The received FIP frame
2276 *
2277 * Returns non-zero if the frame is dropped.
2278 * Always consumes the frame.
2279 */
2280static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
2281{
2282 struct fip_header *fiph;
2283 enum fip_vn2vn_subcode sub;
2284 union {
2285 struct fc_rport_priv rdata;
2286 struct fcoe_rport frport;
2287 } buf;
2288 int rc;
2289
2290 fiph = (struct fip_header *)skb->data;
2291 sub = fiph->fip_subcode;
2292
2293 rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata);
2294 if (rc) {
2295 LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc);
2296 goto drop;
2297 }
2298
2299 mutex_lock(&fip->ctlr_mutex);
2300 switch (sub) {
2301 case FIP_SC_VN_PROBE_REQ:
2302 fcoe_ctlr_vn_probe_req(fip, &buf.rdata);
2303 break;
2304 case FIP_SC_VN_PROBE_REP:
2305 fcoe_ctlr_vn_probe_reply(fip, &buf.rdata);
2306 break;
2307 case FIP_SC_VN_CLAIM_NOTIFY:
2308 fcoe_ctlr_vn_claim_notify(fip, &buf.rdata);
2309 break;
2310 case FIP_SC_VN_CLAIM_REP:
2311 fcoe_ctlr_vn_claim_resp(fip, &buf.rdata);
2312 break;
2313 case FIP_SC_VN_BEACON:
2314 fcoe_ctlr_vn_beacon(fip, &buf.rdata);
2315 break;
2316 default:
2317 LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub);
2318 rc = -1;
2319 break;
2320 }
2321 mutex_unlock(&fip->ctlr_mutex);
2322drop:
2323 kfree_skb(skb);
2324 return rc;
2325}
2326
2327/**
2328 * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode.
2329 * @fip: The FCoE controller
2330 *
2331 * This should never be called since we don't see RSCNs or other
2332 * fabric-generated ELSes.
2333 */
2334static void fcoe_ctlr_disc_recv(struct fc_seq *seq, struct fc_frame *fp,
2335 struct fc_lport *lport)
2336{
2337 struct fc_seq_els_data rjt_data;
2338
2339 rjt_data.fp = NULL;
2340 rjt_data.reason = ELS_RJT_UNSUP;
2341 rjt_data.explan = ELS_EXPL_NONE;
2342 lport->tt.seq_els_rsp_send(seq, ELS_LS_RJT, &rjt_data);
2343 fc_frame_free(fp);
2344}
2345
2346/**
2347 * fcoe_ctlr_disc_recv - start discovery for VN2VN mode.
2348 * @fip: The FCoE controller
2349 *
2350 * This sets a flag indicating that remote ports should be created
2351 * and started for the peers we discover. We use the disc_callback
2352 * pointer as that flag. Peers already discovered are created here.
2353 *
2354 * The lport lock is held during this call. The callback must be done
2355 * later, without holding either the lport or discovery locks.
2356 * The fcoe_ctlr lock may also be held during this call.
2357 */
2358static void fcoe_ctlr_disc_start(void (*callback)(struct fc_lport *,
2359 enum fc_disc_event),
2360 struct fc_lport *lport)
2361{
2362 struct fc_disc *disc = &lport->disc;
2363 struct fcoe_ctlr *fip = disc->priv;
2364
2365 mutex_lock(&disc->disc_mutex);
2366 disc->disc_callback = callback;
2367 disc->disc_id = (disc->disc_id + 2) | 1;
2368 disc->pending = 1;
2369 schedule_work(&fip->timer_work);
2370 mutex_unlock(&disc->disc_mutex);
2371}
2372
2373/**
2374 * fcoe_ctlr_vn_disc() - report FIP VN_port discovery results after claim state.
2375 * @fip: The FCoE controller
2376 *
2377 * Starts the FLOGI and PLOGI login process to each discovered rport for which
2378 * we've received at least one beacon.
2379 * Performs the discovery complete callback.
2380 */
2381static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip)
2382{
2383 struct fc_lport *lport = fip->lp;
2384 struct fc_disc *disc = &lport->disc;
2385 struct fc_rport_priv *rdata;
2386 struct fcoe_rport *frport;
2387 void (*callback)(struct fc_lport *, enum fc_disc_event);
2388
2389 mutex_lock(&disc->disc_mutex);
2390 callback = disc->pending ? disc->disc_callback : NULL;
2391 disc->pending = 0;
2392 list_for_each_entry_rcu(rdata, &disc->rports, peers) {
2393 frport = fcoe_ctlr_rport(rdata);
2394 if (frport->time)
2395 lport->tt.rport_login(rdata);
2396 }
2397 mutex_unlock(&disc->disc_mutex);
2398 if (callback)
2399 callback(lport, DISC_EV_SUCCESS);
2400}
2401
2402/**
2403 * fcoe_ctlr_vn_timeout - timer work function for VN2VN mode.
2404 * @fip: The FCoE controller
2405 */
2406static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
2407{
2408 unsigned long next_time;
2409 u8 mac[ETH_ALEN];
2410 u32 new_port_id = 0;
2411
2412 mutex_lock(&fip->ctlr_mutex);
2413 switch (fip->state) {
2414 case FIP_ST_VNMP_START:
2415 fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE1);
2416 fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2417 next_time = jiffies + msecs_to_jiffies(FIP_VN_PROBE_WAIT);
2418 break;
2419 case FIP_ST_VNMP_PROBE1:
2420 fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE2);
2421 fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2422 next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2423 break;
2424 case FIP_ST_VNMP_PROBE2:
2425 fcoe_ctlr_set_state(fip, FIP_ST_VNMP_CLAIM);
2426 new_port_id = fip->port_id;
2427 hton24(mac, FIP_VN_FC_MAP);
2428 hton24(mac + 3, new_port_id);
2429 fip->update_mac(fip->lp, mac);
2430 fcoe_ctlr_vn_send_claim(fip);
2431 next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2432 break;
2433 case FIP_ST_VNMP_CLAIM:
2434 /*
2435 * This may be invoked either by starting discovery so don't
2436 * go to the next state unless it's been long enough.
2437 */
2438 next_time = fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2439 if (time_after_eq(jiffies, next_time)) {
2440 fcoe_ctlr_set_state(fip, FIP_ST_VNMP_UP);
2441 fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
2442 fcoe_all_vn2vn, 0);
2443 next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2444 fip->port_ka_time = next_time;
2445 }
2446 fcoe_ctlr_vn_disc(fip);
2447 break;
2448 case FIP_ST_VNMP_UP:
2449 next_time = fcoe_ctlr_vn_age(fip);
2450 if (time_after_eq(jiffies, fip->port_ka_time)) {
2451 fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
2452 fcoe_all_vn2vn, 0);
2453 fip->port_ka_time = jiffies +
2454 msecs_to_jiffies(FIP_VN_BEACON_INT +
2455 (random32() % FIP_VN_BEACON_FUZZ));
2456 }
2457 if (time_before(fip->port_ka_time, next_time))
2458 next_time = fip->port_ka_time;
2459 break;
2460 case FIP_ST_LINK_WAIT:
2461 goto unlock;
2462 default:
2463 WARN(1, "unexpected state %d", fip->state);
2464 goto unlock;
2465 }
2466 mod_timer(&fip->timer, next_time);
2467unlock:
2468 mutex_unlock(&fip->ctlr_mutex);
2469
2470 /* If port ID is new, notify local port after dropping ctlr_mutex */
2471 if (new_port_id)
2472 fc_lport_set_local_id(fip->lp, new_port_id);
2473}
2474
2475/**
Robert Love70b51aa2009-11-03 11:47:45 -08002476 * fcoe_libfc_config() - Sets up libfc related properties for local port
2477 * @lp: The local port to configure libfc for
Joe Eykholte10f8c62010-07-20 15:20:30 -07002478 * @fip: The FCoE controller in use by the local port
Robert Love70b51aa2009-11-03 11:47:45 -08002479 * @tt: The libfc function template
Joe Eykholte10f8c62010-07-20 15:20:30 -07002480 * @init_fcp: If non-zero, the FCP portion of libfc should be initialized
Vasu Dev5e80f7f2009-03-17 11:42:18 -07002481 *
2482 * Returns : 0 for success
2483 */
Joe Eykholte10f8c62010-07-20 15:20:30 -07002484int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
2485 const struct libfc_function_template *tt, int init_fcp)
Vasu Dev5e80f7f2009-03-17 11:42:18 -07002486{
2487 /* Set the function pointers set by the LLDD */
Robert Love70b51aa2009-11-03 11:47:45 -08002488 memcpy(&lport->tt, tt, sizeof(*tt));
Joe Eykholte10f8c62010-07-20 15:20:30 -07002489 if (init_fcp && fc_fcp_init(lport))
Vasu Dev5e80f7f2009-03-17 11:42:18 -07002490 return -ENOMEM;
Robert Love70b51aa2009-11-03 11:47:45 -08002491 fc_exch_init(lport);
2492 fc_elsct_init(lport);
2493 fc_lport_init(lport);
Joe Eykholte10f8c62010-07-20 15:20:30 -07002494 if (fip->mode == FIP_MODE_VN2VN)
2495 lport->rport_priv_size = sizeof(struct fcoe_rport);
Robert Love70b51aa2009-11-03 11:47:45 -08002496 fc_rport_init(lport);
Joe Eykholte10f8c62010-07-20 15:20:30 -07002497 if (fip->mode == FIP_MODE_VN2VN) {
2498 lport->point_to_multipoint = 1;
2499 lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
2500 lport->tt.disc_start = fcoe_ctlr_disc_start;
2501 lport->tt.disc_stop = fcoe_ctlr_disc_stop;
2502 lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
2503 mutex_init(&lport->disc.disc_mutex);
2504 INIT_LIST_HEAD(&lport->disc.rports);
2505 lport->disc.priv = fip;
2506 } else {
2507 fc_disc_init(lport);
2508 }
Vasu Dev5e80f7f2009-03-17 11:42:18 -07002509 return 0;
2510}
2511EXPORT_SYMBOL_GPL(fcoe_libfc_config);