19b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev/*
297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Copyright (c) 2008-2009 Cisco Systems, Inc.  All rights reserved.
397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Copyright (c) 2009 Intel Corporation.  All rights reserved.
49b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev *
59b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * This program is free software; you can redistribute it and/or modify it
69b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * under the terms and conditions of the GNU General Public License,
79b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * version 2, as published by the Free Software Foundation.
89b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev *
99b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * This program is distributed in the hope it will be useful, but WITHOUT
109b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
119b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
129b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * more details.
139b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev *
149b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * You should have received a copy of the GNU General Public License along with
159b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * this program; if not, write to the Free Software Foundation, Inc.,
169b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
179b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev *
189b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev * Maintained at www.Open-FCoE.org
199b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev */
209b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev
2197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/types.h>
229b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev#include <linux/module.h>
2397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/kernel.h>
2497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/list.h>
2597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/spinlock.h>
2697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/timer.h>
275e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev#include <linux/netdevice.h>
2897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/etherdevice.h>
2997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/ethtool.h>
3097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/if_ether.h>
3197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/if_vlan.h>
3297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/errno.h>
3397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <linux/bitops.h>
345a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
3597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <net/rtnetlink.h>
3697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
3797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <scsi/fc/fc_els.h>
3897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <scsi/fc/fc_fs.h>
3997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <scsi/fc/fc_fip.h>
4097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <scsi/fc/fc_encaps.h>
4197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <scsi/fc/fc_fcoe.h>
42e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt#include <scsi/fc/fc_fcp.h>
435e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev
445e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev#include <scsi/libfc.h>
4597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#include <scsi/libfcoe.h>
469b34ecffd59d6ed66fdd6906e8a092a33e7c8564Vasu Dev
4721b7b2f557f4b105a4b7d739671d1ce6b867d3e6Yi Zou#include "libfcoe.h"
4821b7b2f557f4b105a4b7d739671d1ce6b867d3e6Yi Zou
4997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#define	FCOE_CTLR_MIN_FKA	500		/* min keep alive (mS) */
5097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt#define	FCOE_CTLR_DEF_FKA	FIP_DEF_FKA	/* default keep alive (mS) */
5197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
5297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_timeout(unsigned long);
534291365784c9622c9d643cf23421f9c7b9662d71Joe Eykholtstatic void fcoe_ctlr_timer_work(struct work_struct *);
5497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_recv_work(struct work_struct *);
55794d98e77f5901ceded697f1633463e88f078038Joe Eykholtstatic int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *);
5697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
57e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_start(struct fcoe_ctlr *);
58e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
59e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *);
60e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *);
61e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
6297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
63e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
64e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS;
65e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic u8 fcoe_all_p2p[ETH_ALEN] = FIP_ALL_P2P_MACS;
6697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
670095a9213324a4466c10de98837a27ab1b7e72beYi Zoustatic const char * const fcoe_ctlr_states[] = {
689b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	[FIP_ST_DISABLED] =	"DISABLED",
699b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	[FIP_ST_LINK_WAIT] =	"LINK_WAIT",
709b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	[FIP_ST_AUTO] =		"AUTO",
719b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	[FIP_ST_NON_FIP] =	"NON_FIP",
729b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	[FIP_ST_ENABLED] =	"ENABLED",
73e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	[FIP_ST_VNMP_START] =	"VNMP_START",
74e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	[FIP_ST_VNMP_PROBE1] =	"VNMP_PROBE1",
75e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	[FIP_ST_VNMP_PROBE2] =	"VNMP_PROBE2",
76e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	[FIP_ST_VNMP_CLAIM] =	"VNMP_CLAIM",
77e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	[FIP_ST_VNMP_UP] =	"VNMP_UP",
789b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt};
799b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt
809b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholtstatic const char *fcoe_ctlr_state(enum fip_state state)
819b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt{
829b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	const char *cp = "unknown";
839b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt
849b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	if (state < ARRAY_SIZE(fcoe_ctlr_states))
859b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt		cp = fcoe_ctlr_states[state];
869b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	if (!cp)
879b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt		cp = "unknown";
889b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	return cp;
899b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt}
909b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt
919b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt/**
929b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt * fcoe_ctlr_set_state() - Set and do debug printing for the new FIP state.
939b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt * @fip: The FCoE controller
949b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt * @state: The new state
959b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt */
969b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholtstatic void fcoe_ctlr_set_state(struct fcoe_ctlr *fip, enum fip_state state)
979b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt{
989b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	if (state == fip->state)
999b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt		return;
1009b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	if (fip->lp)
1019b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt		LIBFCOE_FIP_DBG(fip, "state %s -> %s\n",
1029b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt			fcoe_ctlr_state(fip->state), fcoe_ctlr_state(state));
1039b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	fip->state = state;
1049b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt}
1059b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt
10670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love/**
10770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid
10870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fcf: The FCF to check
10970b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love *
11097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Return non-zero if FCF fcoe_size has been validated.
11197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
11297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf)
11397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
11497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return (fcf->flags & FIP_FL_SOL) != 0;
11597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
11697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
11770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love/**
11870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_fcf_usable() - Check if a FCF is usable
11970b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fcf: The FCF to check
12070b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love *
12197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Return non-zero if the FCF is usable.
12297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
12397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
12497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
12597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u16 flags = FIP_FL_SOL | FIP_FL_AVAIL;
12697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
12797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return (fcf->flags & flags) == flags;
12897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
12997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
13097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
131cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt * fcoe_ctlr_map_dest() - Set flag and OUI for mapping destination addresses
132cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt * @fip: The FCoE controller
133cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt */
134cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholtstatic void fcoe_ctlr_map_dest(struct fcoe_ctlr *fip)
135cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt{
136cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt	if (fip->mode == FIP_MODE_VN2VN)
137cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt		hton24(fip->dest_addr, FIP_VN_FC_MAP);
138cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt	else
139cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt		hton24(fip->dest_addr, FIP_DEF_FC_MAP);
140cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt	hton24(fip->dest_addr + 3, 0);
141cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt	fip->map_dest = 1;
142cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt}
143cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt
144cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt/**
14570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_init() - Initialize the FCoE Controller instance
14670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller to initialize
14797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
1483d902ac09a2812b359edf633425d1327a18399e9Joe Eykholtvoid fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
14997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
1509b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
1513d902ac09a2812b359edf633425d1327a18399e9Joe Eykholt	fip->mode = mode;
15297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	INIT_LIST_HEAD(&fip->fcfs);
153fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_init(&fip->ctlr_mutex);
154794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	spin_lock_init(&fip->ctlr_lock);
15597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->flogi_oxid = FC_XID_UNKNOWN;
15697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
1574291365784c9622c9d643cf23421f9c7b9662d71Joe Eykholt	INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
15897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
15997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_queue_head_init(&fip->fip_recv_list);
16097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
16197c8389d54b9665c38105ea72a428a44b97ff2f6Joe EykholtEXPORT_SYMBOL(fcoe_ctlr_init);
16297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
16397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
16470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller
16570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller whose FCFs are to be reset
16697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
16797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Called with &fcoe_ctlr lock held.
16897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
16997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
17097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
17197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf;
17297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *next;
17397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
17497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->sel_fcf = NULL;
17597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
17697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		list_del(&fcf->list);
17797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		kfree(fcf);
17897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
17997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->fcf_count = 0;
18097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->sel_time = 0;
18197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
18297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
18397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
18470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_destroy() - Disable and tear down a FCoE controller
18570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller to tear down
18697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
18797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * This is called by FCoE drivers before freeing the &fcoe_ctlr.
18897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
18997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The receive handler will have been deleted before this to guarantee
19097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * that no more recv_work will be scheduled.
19197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
19297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The timer routine will simply return once we set FIP_ST_DISABLED.
19397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * This guarantees that no further timeouts or work will be scheduled.
19497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
19597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtvoid fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
19697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
197a4b7cfaee487caef913be978dce60896fe741268Chris Leech	cancel_work_sync(&fip->recv_work);
1981f4aed818d26eb9ed54520fbeb85d5ee691baa94Joe Eykholt	skb_queue_purge(&fip->fip_recv_list);
199a4b7cfaee487caef913be978dce60896fe741268Chris Leech
200fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
2019b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	fcoe_ctlr_set_state(fip, FIP_ST_DISABLED);
20297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcoe_ctlr_reset_fcfs(fip);
203fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_unlock(&fip->ctlr_mutex);
20497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	del_timer_sync(&fip->timer);
2054291365784c9622c9d643cf23421f9c7b9662d71Joe Eykholt	cancel_work_sync(&fip->timer_work);
20697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
20797c8389d54b9665c38105ea72a428a44b97ff2f6Joe EykholtEXPORT_SYMBOL(fcoe_ctlr_destroy);
20897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
20997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
210794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * fcoe_ctlr_announce() - announce new FCF selection
21169316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt * @fip: The FCoE controller
21269316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt *
21369316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt * Also sets the destination MAC for FCoE and control packets
214794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
215794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * Called with neither ctlr_mutex nor ctlr_lock held.
21669316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt */
21769316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholtstatic void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
21869316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt{
219794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct fcoe_fcf *sel;
220794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct fcoe_fcf *fcf;
221794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
222794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
223794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	spin_lock_bh(&fip->ctlr_lock);
224794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
225794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	kfree_skb(fip->flogi_req);
226794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	fip->flogi_req = NULL;
227794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	list_for_each_entry(fcf, &fip->fcfs, list)
228794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fcf->flogi_sent = 0;
229794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
230794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	spin_unlock_bh(&fip->ctlr_lock);
231794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	sel = fip->sel_fcf;
23269316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt
23369316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt	if (sel && !compare_ether_addr(sel->fcf_mac, fip->dest_addr))
234794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		goto unlock;
23569316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt	if (!is_zero_ether_addr(fip->dest_addr)) {
23669316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		printk(KERN_NOTICE "libfcoe: host%d: "
23769316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		       "FIP Fibre-Channel Forwarder MAC %pM deselected\n",
23869316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		       fip->lp->host->host_no, fip->dest_addr);
23969316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		memset(fip->dest_addr, 0, ETH_ALEN);
24069316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt	}
24169316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt	if (sel) {
24269316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		printk(KERN_INFO "libfcoe: host%d: FIP selected "
24369316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		       "Fibre-Channel Forwarder MAC %pM\n",
24469316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		       fip->lp->host->host_no, sel->fcf_mac);
24581c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi		memcpy(fip->dest_addr, sel->fcoe_mac, ETH_ALEN);
24669316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt		fip->map_dest = 0;
24769316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt	}
248794d98e77f5901ceded697f1633463e88f078038Joe Eykholtunlock:
249794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	mutex_unlock(&fip->ctlr_mutex);
25069316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt}
25169316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt
25269316ee2e375c5af0cf1f8d2d30f9aa277f0b454Joe Eykholt/**
25370b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port
25470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller to get the maximum FCoE size from
25597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
25697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Returns the maximum packet size including the FCoE header and trailer,
25797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * but not including any Ethernet or VLAN headers.
25897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
25997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic inline u32 fcoe_ctlr_fcoe_size(struct fcoe_ctlr *fip)
26097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
26197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	/*
26297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * Determine the max FCoE frame size allowed, including
26397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * FCoE header and trailer.
26497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * Note:  lp->mfs is currently the payload size, not the frame size.
26597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 */
26697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return fip->lp->mfs + sizeof(struct fc_frame_header) +
26797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof);
26897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
26997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
27097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
27170b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_solicit() - Send a FIP solicitation
27270b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller to send the solicitation on
27370b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fcf: The destination FCF (if NULL, a multicast solicitation is sent)
27497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
27597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
27697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
27797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct sk_buff *skb;
27897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_sol {
27997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct ethhdr eth;
28097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct fip_header fip;
28197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct {
28297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			struct fip_mac_desc mac;
28397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			struct fip_wwn_desc wwnn;
28497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			struct fip_size_desc size;
2850095a9213324a4466c10de98837a27ab1b7e72beYi Zou		} __packed desc;
2860095a9213324a4466c10de98837a27ab1b7e72beYi Zou	}  __packed * sol;
28797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u32 fcoe_size;
28897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
28997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb = dev_alloc_skb(sizeof(*sol));
29097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (!skb)
29197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return;
29297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
29397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol = (struct fip_sol *)skb->data;
29497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
29597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memset(sol, 0, sizeof(*sol));
29697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memcpy(sol->eth.h_dest, fcf ? fcf->fcf_mac : fcoe_all_fcfs, ETH_ALEN);
29797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memcpy(sol->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
29897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->eth.h_proto = htons(ETH_P_FIP);
29997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
30097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
30197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->fip.fip_op = htons(FIP_OP_DISC);
30297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->fip.fip_subcode = FIP_SC_SOL;
30397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW);
30497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->fip.fip_flags = htons(FIP_FL_FPMA);
305184dd3459bb334d9061b58faed3610d08d6c7ff8Vasu Dev	if (fip->spma)
306184dd3459bb334d9061b58faed3610d08d6c7ff8Vasu Dev		sol->fip.fip_flags |= htons(FIP_FL_SPMA);
30797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
30897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC;
30997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW;
31097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memcpy(sol->desc.mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
31197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
31297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->desc.wwnn.fd_desc.fip_dtype = FIP_DT_NAME;
31397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->desc.wwnn.fd_desc.fip_dlen = sizeof(sol->desc.wwnn) / FIP_BPW;
31497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	put_unaligned_be64(fip->lp->wwnn, &sol->desc.wwnn.fd_wwn);
31597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
31697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcoe_size = fcoe_ctlr_fcoe_size(fip);
31797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->desc.size.fd_desc.fip_dtype = FIP_DT_FCOE_SIZE;
31897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->desc.size.fd_desc.fip_dlen = sizeof(sol->desc.size) / FIP_BPW;
31997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sol->desc.size.fd_size = htons(fcoe_size);
32097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
32197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_put(skb, sizeof(*sol));
3220f4915398a4233cdbfc4e9bf4436323546945b3fChris Leech	skb->protocol = htons(ETH_P_FIP);
3236f6c2aa33b915c574543f176dee89d7aefc115c1john fastabend	skb->priority = fip->priority;
32497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_reset_mac_header(skb);
32597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_reset_network_header(skb);
32697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->send(fip, skb);
32797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
32897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (!fcf)
32997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fip->sol_time = jiffies;
33097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
33197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
33297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
33370b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_link_up() - Start FCoE controller
33470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller to start
33597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
33697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Called from the LLD when the network link is ready.
33797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
33897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtvoid fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
33997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
340fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
34197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
342fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt		mutex_unlock(&fip->ctlr_mutex);
34397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fc_linkup(fip->lp);
34497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	} else if (fip->state == FIP_ST_LINK_WAIT) {
3459b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt		fcoe_ctlr_set_state(fip, fip->mode);
346e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		switch (fip->mode) {
347e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		default:
348e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			LIBFCOE_FIP_DBG(fip, "invalid mode %d\n", fip->mode);
349e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			/* fall-through */
350e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_MODE_AUTO:
3510f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt			LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
352e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			/* fall-through */
353e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_MODE_FABRIC:
354e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_MODE_NON_FIP:
355e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			mutex_unlock(&fip->ctlr_mutex);
356e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fc_linkup(fip->lp);
357e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_solicit(fip, NULL);
358e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
359e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_MODE_VN2VN:
360e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_vn_start(fip);
361e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			mutex_unlock(&fip->ctlr_mutex);
362e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fc_linkup(fip->lp);
363e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
364e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
36597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	} else
366fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt		mutex_unlock(&fip->ctlr_mutex);
36797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
36897c8389d54b9665c38105ea72a428a44b97ff2f6Joe EykholtEXPORT_SYMBOL(fcoe_ctlr_link_up);
36997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
37097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
37170b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_reset() - Reset a FCoE controller
37270b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip:       The FCoE controller to reset
37397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
374dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholtstatic void fcoe_ctlr_reset(struct fcoe_ctlr *fip)
37597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
37697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcoe_ctlr_reset_fcfs(fip);
37797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	del_timer(&fip->timer);
37897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->ctlr_ka_time = 0;
37997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->port_ka_time = 0;
38097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->sol_time = 0;
38197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->flogi_oxid = FC_XID_UNKNOWN;
382cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt	fcoe_ctlr_map_dest(fip);
38397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
38497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
38597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
38670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_link_down() - Stop a FCoE controller
38770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller to be stopped
38897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
38997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Returns non-zero if the link was up and now isn't.
39097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
39197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Called from the LLD when the network link is not ready.
39297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * There may be multiple calls while the link is down.
39397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
39497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtint fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
39597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
396dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt	int link_dropped;
397dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt
398dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt	LIBFCOE_FIP_DBG(fip, "link down.\n");
399fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
400dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt	fcoe_ctlr_reset(fip);
4014291365784c9622c9d643cf23421f9c7b9662d71Joe Eykholt	link_dropped = fip->state != FIP_ST_LINK_WAIT;
4029b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt	fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
403fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_unlock(&fip->ctlr_mutex);
404dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt
405dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt	if (link_dropped)
406dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt		fc_linkdown(fip->lp);
407dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt	return link_dropped;
40897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
40997c8389d54b9665c38105ea72a428a44b97ff2f6Joe EykholtEXPORT_SYMBOL(fcoe_ctlr_link_down);
41097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
41197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
41270b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_send_keep_alive() - Send a keep-alive to the selected FCF
41370b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip:   The FCoE controller to send the FKA on
41470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @lport: libfc fc_lport to send from
41570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @ports: 0 for controller keep-alive, 1 for port keep-alive
41670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @sa:	   The source MAC address
41797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
41897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * A controller keep-alive is sent every fka_period (typically 8 seconds).
41997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The source MAC is the native MAC address.
42097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
42197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * A port keep-alive is sent every 90 seconds while logged in.
42297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The source MAC is the assigned mapped source address.
42397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The destination is the FCF's F-port.
42497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
42511b561886643d4e23d0fd58c205d830a448dd0a2Chris Leechstatic void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
42611b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech				      struct fc_lport *lport,
42711b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech				      int ports, u8 *sa)
42897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
42997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct sk_buff *skb;
43097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_kal {
43197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct ethhdr eth;
43297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct fip_header fip;
43397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct fip_mac_desc mac;
4340095a9213324a4466c10de98837a27ab1b7e72beYi Zou	} __packed * kal;
43597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_vn_desc *vn;
43697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u32 len;
43797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fc_lport *lp;
43897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf;
43997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
44097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcf = fip->sel_fcf;
44197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	lp = fip->lp;
442281ae642a6475ede25ff86ec124214e346c25e22Joe Eykholt	if (!fcf || (ports && !lp->port_id))
44397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return;
44497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
445be276cbe1bd680ab1f6c297017dd658e5a6b10d2Yi Zou	len = sizeof(*kal) + ports * sizeof(*vn);
44697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb = dev_alloc_skb(len);
44797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (!skb)
44897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return;
44997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
45097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal = (struct fip_kal *)skb->data;
45197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memset(kal, 0, len);
45297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memcpy(kal->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
45397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memcpy(kal->eth.h_source, sa, ETH_ALEN);
45497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->eth.h_proto = htons(ETH_P_FIP);
45597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
45697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
45797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->fip.fip_op = htons(FIP_OP_CTRL);
45897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->fip.fip_subcode = FIP_SC_KEEP_ALIVE;
45997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->fip.fip_dl_len = htons((sizeof(kal->mac) +
46070b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love				     ports * sizeof(*vn)) / FIP_BPW);
46197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->fip.fip_flags = htons(FIP_FL_FPMA);
462184dd3459bb334d9061b58faed3610d08d6c7ff8Vasu Dev	if (fip->spma)
463184dd3459bb334d9061b58faed3610d08d6c7ff8Vasu Dev		kal->fip.fip_flags |= htons(FIP_FL_SPMA);
46497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
46597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->mac.fd_desc.fip_dtype = FIP_DT_MAC;
46697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW;
46797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memcpy(kal->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
46897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (ports) {
46997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		vn = (struct fip_vn_desc *)(kal + 1);
47097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		vn->fd_desc.fip_dtype = FIP_DT_VN_ID;
47197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;
47211b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
473fb83153d7308e1344f1d4a2e287b6aaab2f6d14cKaladhar Musunuru		hton24(vn->fd_fc_id, lport->port_id);
474fb83153d7308e1344f1d4a2e287b6aaab2f6d14cKaladhar Musunuru		put_unaligned_be64(lport->wwpn, &vn->fd_wwpn);
47597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
47697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_put(skb, len);
4770f4915398a4233cdbfc4e9bf4436323546945b3fChris Leech	skb->protocol = htons(ETH_P_FIP);
4786f6c2aa33b915c574543f176dee89d7aefc115c1john fastabend	skb->priority = fip->priority;
47997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_reset_mac_header(skb);
48097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_reset_network_header(skb);
48197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->send(fip, skb);
48297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
48397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
48497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
48570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it
48670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip:   The FCoE controller for the ELS frame
48770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @dtype: The FIP descriptor type for the frame
48870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @skb:   The FCoE ELS frame including FC header but no FCoE headers
489e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @d_id:  The destination port ID.
49097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
49197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Returns non-zero error code on failure.
49297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
49397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The caller must check that the length is a multiple of 4.
49497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
49597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The @skb must have enough headroom (28 bytes) and tailroom (8 bytes).
49697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Headroom includes the FIP encapsulation description, FIP header, and
49797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Ethernet header.  The tailroom is for the FIP MAC descriptor.
49897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
49911b561886643d4e23d0fd58c205d830a448dd0a2Chris Leechstatic int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
500e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			    u8 dtype, struct sk_buff *skb, u32 d_id)
50197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
50297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_encaps_head {
50397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct ethhdr eth;
50497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct fip_header fip;
50597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		struct fip_encaps encaps;
5060095a9213324a4466c10de98837a27ab1b7e72beYi Zou	} __packed * cap;
5075554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	struct fc_frame_header *fh;
50897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_mac_desc *mac;
50997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf;
51097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t dlen;
5115a84baeaf7b8bb4188219140cb326a3e859b2312Yi Zou	u16 fip_flags;
5125554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	u8 op;
51397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
5145554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	fh = (struct fc_frame_header *)skb->data;
5155554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	op = *(u8 *)(fh + 1);
51697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	dlen = sizeof(struct fip_encaps) + skb->len;	/* len before push */
51797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap));
51897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memset(cap, 0, sizeof(*cap));
519e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
520e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (lport->point_to_multipoint) {
521e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest))
522e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			return -ENODEV;
5235554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		fip_flags = 0;
524e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	} else {
525e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcf = fip->sel_fcf;
526e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (!fcf)
527e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			return -ENODEV;
528e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fip_flags = fcf->flags;
529e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA :
530e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					 FIP_FL_FPMA;
531e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (!fip_flags)
532e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			return -ENODEV;
533e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN);
534e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
53597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
53697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	cap->eth.h_proto = htons(ETH_P_FIP);
53797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
53897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
53997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	cap->fip.fip_op = htons(FIP_OP_LS);
5405554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	if (op == ELS_LS_ACC || op == ELS_LS_RJT)
5415554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		cap->fip.fip_subcode = FIP_SC_REP;
5425554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	else
5435554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		cap->fip.fip_subcode = FIP_SC_REQ;
5445a84baeaf7b8bb4188219140cb326a3e859b2312Yi Zou	cap->fip.fip_flags = htons(fip_flags);
54597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
54697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	cap->encaps.fd_desc.fip_dtype = dtype;
54797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
54897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
5495554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	if (op != ELS_LS_RJT) {
5505554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		dlen += sizeof(*mac);
5515554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
5525554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		memset(mac, 0, sizeof(*mac));
5535554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		mac->fd_desc.fip_dtype = FIP_DT_MAC;
5545554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
5555554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
5565554345bc5275afed760631277fdab0a5a19472eJoe Eykholt			memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
5575554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		} else if (fip->mode == FIP_MODE_VN2VN) {
5585554345bc5275afed760631277fdab0a5a19472eJoe Eykholt			hton24(mac->fd_mac, FIP_VN_FC_MAP);
5595554345bc5275afed760631277fdab0a5a19472eJoe Eykholt			hton24(mac->fd_mac + 3, fip->port_id);
5605554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		} else if (fip_flags & FIP_FL_SPMA) {
5615554345bc5275afed760631277fdab0a5a19472eJoe Eykholt			LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
5625554345bc5275afed760631277fdab0a5a19472eJoe Eykholt			memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
5635554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		} else {
5645554345bc5275afed760631277fdab0a5a19472eJoe Eykholt			LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
5655554345bc5275afed760631277fdab0a5a19472eJoe Eykholt			/* FPMA only FLOGI.  Must leave the MAC desc zeroed. */
5665554345bc5275afed760631277fdab0a5a19472eJoe Eykholt		}
567593abc0720d5639ba21834b082adf83762af39beRobert Love	}
5685554345bc5275afed760631277fdab0a5a19472eJoe Eykholt	cap->fip.fip_dl_len = htons(dlen / FIP_BPW);
56997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
5700f4915398a4233cdbfc4e9bf4436323546945b3fChris Leech	skb->protocol = htons(ETH_P_FIP);
5716f6c2aa33b915c574543f176dee89d7aefc115c1john fastabend	skb->priority = fip->priority;
57297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_reset_mac_header(skb);
57397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_reset_network_header(skb);
57497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return 0;
57597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
57697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
57797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
57897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * fcoe_ctlr_els_send() - Send an ELS frame encapsulated by FIP if appropriate.
57997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * @fip:	FCoE controller.
58011b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech * @lport:	libfc fc_lport to send from
58197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * @skb:	FCoE ELS frame including FC header but no FCoE headers.
58297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
58397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Returns a non-zero error code if the frame should not be sent.
58497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Returns zero if the caller should send the frame with FCoE encapsulation.
58597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
58697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The caller must check that the length is a multiple of 4.
58797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
588e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * The the skb must also be an fc_frame.
589794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
590794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * This is called from the lower-level driver with spinlocks held,
591794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * so we must not take a mutex here.
59297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
59311b561886643d4e23d0fd58c205d830a448dd0a2Chris Leechint fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
59411b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		       struct sk_buff *skb)
59597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
596e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_frame *fp;
59797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fc_frame_header *fh;
59897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u16 old_xid;
59997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u8 op;
60011b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech	u8 mac[ETH_ALEN];
60197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
602e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fp = container_of(skb, struct fc_frame, skb);
60397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fh = (struct fc_frame_header *)skb->data;
60497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	op = *(u8 *)(fh + 1);
60597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
606e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (op == ELS_FLOGI && fip->mode != FIP_MODE_VN2VN) {
60797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		old_xid = fip->flogi_oxid;
60897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fip->flogi_oxid = ntohs(fh->fh_ox_id);
60997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (fip->state == FIP_ST_AUTO) {
61097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (old_xid == FC_XID_UNKNOWN)
61197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				fip->flogi_count = 0;
61297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fip->flogi_count++;
61397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (fip->flogi_count < 3)
61497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto drop;
615cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt			fcoe_ctlr_map_dest(fip);
61697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			return 0;
61797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
6185f48f70ecef25df93e122985272ff647f5653836Joe Eykholt		if (fip->state == FIP_ST_NON_FIP)
619cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt			fcoe_ctlr_map_dest(fip);
6205f48f70ecef25df93e122985272ff647f5653836Joe Eykholt	}
6215f48f70ecef25df93e122985272ff647f5653836Joe Eykholt
6225f48f70ecef25df93e122985272ff647f5653836Joe Eykholt	if (fip->state == FIP_ST_NON_FIP)
6235f48f70ecef25df93e122985272ff647f5653836Joe Eykholt		return 0;
624e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (!fip->sel_fcf && fip->mode != FIP_MODE_VN2VN)
625f31f2a1c3215e96fbff2152486d0fb590f72634eJoe Eykholt		goto drop;
6265f48f70ecef25df93e122985272ff647f5653836Joe Eykholt	switch (op) {
6275f48f70ecef25df93e122985272ff647f5653836Joe Eykholt	case ELS_FLOGI:
62897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		op = FIP_DT_FLOGI;
629794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		if (fip->mode == FIP_MODE_VN2VN)
630794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			break;
631794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		spin_lock_bh(&fip->ctlr_lock);
632794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		kfree_skb(fip->flogi_req);
633794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fip->flogi_req = skb;
634794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fip->flogi_req_send = 1;
635794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		spin_unlock_bh(&fip->ctlr_lock);
636794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		schedule_work(&fip->timer_work);
637794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		return -EINPROGRESS;
63897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	case ELS_FDISC:
63997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (ntoh24(fh->fh_s_id))
64097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			return 0;
64197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		op = FIP_DT_FDISC;
64297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		break;
64397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	case ELS_LOGO:
644e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (fip->mode == FIP_MODE_VN2VN) {
645e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (fip->state != FIP_ST_VNMP_UP)
646e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return -EINVAL;
647e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI)
648e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return -EINVAL;
649e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		} else {
650e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (fip->state != FIP_ST_ENABLED)
651e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return 0;
652e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
653e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return 0;
654e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
65597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		op = FIP_DT_LOGO;
65697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		break;
65797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	case ELS_LS_ACC:
65897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		/*
659e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * If non-FIP, we may have gotten an SID by accepting an FLOGI
66097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * from a point-to-point connection.  Switch to using
66197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * the source mac based on the SID.  The destination
66225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		 * MAC in this case would have been set by receiving the
66397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * FLOGI.
66497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 */
665e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (fip->state == FIP_ST_NON_FIP) {
666e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (fip->flogi_oxid == FC_XID_UNKNOWN)
667e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return 0;
668e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fip->flogi_oxid = FC_XID_UNKNOWN;
669e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fc_fcoe_set_mac(mac, fh->fh_d_id);
670e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fip->update_mac(lport, mac);
671e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
672e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		/* fall through */
673e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case ELS_LS_RJT:
674e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		op = fr_encaps(fp);
675e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (op)
676e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
67797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return 0;
67897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	default:
679e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (fip->state != FIP_ST_ENABLED &&
680e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		    fip->state != FIP_ST_VNMP_UP)
68197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			goto drop;
68297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return 0;
68397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
684e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	LIBFCOE_FIP_DBG(fip, "els_send op %u d_id %x\n",
685e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			op, ntoh24(fh->fh_d_id));
686e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fcoe_ctlr_encaps(fip, lport, op, skb, ntoh24(fh->fh_d_id)))
68797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
68897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->send(fip, skb);
68997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return -EINPROGRESS;
69097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtdrop:
69197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kfree_skb(skb);
69297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return -EINVAL;
69397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
69497c8389d54b9665c38105ea72a428a44b97ff2f6Joe EykholtEXPORT_SYMBOL(fcoe_ctlr_els_send);
69597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
69670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love/**
69770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller
69870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller to free FCFs on
69997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
700f018b73af6db4f330ad5da9ac53997a699c30c42Joe Eykholt * Called with lock held and preemption disabled.
70197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
7028690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt * An FCF is considered old if we have missed two advertisements.
7038690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt * That is, there have been no valid advertisement from it for 2.5
7048690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt * times its keep-alive period.
70597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
70697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * In addition, determine the time when an FCF selection can occur.
707f3da80e76142d63a6849556461906fbe118d1442Yi Zou *
708f3da80e76142d63a6849556461906fbe118d1442Yi Zou * Also, increment the MissDiscAdvCount when no advertisement is received
709f3da80e76142d63a6849556461906fbe118d1442Yi Zou * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
7108690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt *
7118690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt * Returns the time in jiffies for the next call.
71297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
7138690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholtstatic unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
71497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
71597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf;
71697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *next;
7178690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt	unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
7188690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt	unsigned long deadline;
71997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	unsigned long sel_time = 0;
720f018b73af6db4f330ad5da9ac53997a699c30c42Joe Eykholt	struct fcoe_dev_stats *stats;
72197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
722fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
723fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt
72497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
7258690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt		deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
7268690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt		if (fip->sel_fcf == fcf) {
7278690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt			if (time_after(jiffies, deadline)) {
7288690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				stats->MissDiscAdvCount++;
7298690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				printk(KERN_INFO "libfcoe: host%d: "
7308690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				       "Missing Discovery Advertisement "
7318690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				       "for fab %16.16llx count %lld\n",
7328690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				       fip->lp->host->host_no, fcf->fabric_name,
7338690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				       stats->MissDiscAdvCount);
7348690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt			} else if (time_after(next_timer, deadline))
7358690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				next_timer = deadline;
736f3da80e76142d63a6849556461906fbe118d1442Yi Zou		}
7378690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt
7388690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt		deadline += fcf->fka_period;
739d99ee45b7cb89803b79745dc3014ba64bfd02b7dJoe Eykholt		if (time_after_eq(jiffies, deadline)) {
74097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (fip->sel_fcf == fcf)
74197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				fip->sel_fcf = NULL;
74297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			list_del(&fcf->list);
74397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			WARN_ON(!fip->fcf_count);
74497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fip->fcf_count--;
74597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			kfree(fcf);
746f018b73af6db4f330ad5da9ac53997a699c30c42Joe Eykholt			stats->VLinkFailureCount++;
7478690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt		} else {
7488690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt			if (time_after(next_timer, deadline))
7498690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				next_timer = deadline;
7508690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt			if (fcoe_ctlr_mtu_valid(fcf) &&
7518690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt			    (!sel_time || time_before(sel_time, fcf->time)))
7528690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt				sel_time = fcf->time;
75397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
75497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
755fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	put_cpu();
756d99ee45b7cb89803b79745dc3014ba64bfd02b7dJoe Eykholt	if (sel_time && !fip->sel_fcf && !fip->sel_time) {
75797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
75897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fip->sel_time = sel_time;
75997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
760d99ee45b7cb89803b79745dc3014ba64bfd02b7dJoe Eykholt
7618690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt	return next_timer;
76297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
76397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
76497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
76570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry
7660f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt * @fip: The FCoE controller receiving the advertisement
76770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @skb: The received FIP advertisement frame
76870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fcf: The resulting FCF entry
76997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
77097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Returns zero on a valid parsed advertisement,
77197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * otherwise returns non zero value.
77297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
7730f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholtstatic int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
7740f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt			       struct sk_buff *skb, struct fcoe_fcf *fcf)
77597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
77697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_header *fiph;
77797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_desc *desc = NULL;
77897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_wwn_desc *wwn;
77997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_fab_desc *fab;
78097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_fka_desc *fka;
78197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	unsigned long t;
78297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t rlen;
78397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t dlen;
7840a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi	u32 desc_mask;
78597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
78697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	memset(fcf, 0, sizeof(*fcf));
78797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
78897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
78997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fiph = (struct fip_header *)skb->data;
79097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcf->flags = ntohs(fiph->fip_flags);
79197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
7920a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi	/*
7930a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi	 * mask of required descriptors. validating each one clears its bit.
7940a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi	 */
7950a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi	desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
7960a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA);
7970a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi
79897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	rlen = ntohs(fiph->fip_dl_len) * 4;
79997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (rlen + sizeof(*fiph) > skb->len)
80097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return -EINVAL;
80197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
80297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	desc = (struct fip_desc *)(fiph + 1);
80397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	while (rlen > 0) {
80497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		dlen = desc->fip_dlen * FIP_BPW;
80597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (dlen < sizeof(*desc) || dlen > rlen)
80697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			return -EINVAL;
8070a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		/* Drop Adv if there are duplicate critical descriptors */
8080a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		if ((desc->fip_dtype < 32) &&
8090a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		    !(desc_mask & 1U << desc->fip_dtype)) {
8100a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
8110a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi					"Descriptors in FIP adv\n");
8120a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			return -EINVAL;
8130a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		}
81497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		switch (desc->fip_dtype) {
81597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_PRI:
81697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen != sizeof(struct fip_pri_desc))
81797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto len_err;
81897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
8190a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			desc_mask &= ~BIT(FIP_DT_PRI);
82097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
82197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_MAC:
82297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen != sizeof(struct fip_mac_desc))
82397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto len_err;
82497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			memcpy(fcf->fcf_mac,
82597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			       ((struct fip_mac_desc *)desc)->fd_mac,
82697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			       ETH_ALEN);
82781c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			memcpy(fcf->fcoe_mac, fcf->fcf_mac, ETH_ALEN);
82897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (!is_valid_ether_addr(fcf->fcf_mac)) {
829e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				LIBFCOE_FIP_DBG(fip,
830e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					"Invalid MAC addr %pM in FIP adv\n",
831e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					fcf->fcf_mac);
83297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				return -EINVAL;
83397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			}
8340a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			desc_mask &= ~BIT(FIP_DT_MAC);
83597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
83697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_NAME:
83797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen != sizeof(struct fip_wwn_desc))
83897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto len_err;
83997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			wwn = (struct fip_wwn_desc *)desc;
84097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
8410a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			desc_mask &= ~BIT(FIP_DT_NAME);
84297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
84397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_FAB:
84497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen != sizeof(struct fip_fab_desc))
84597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto len_err;
84697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fab = (struct fip_fab_desc *)desc;
84797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
84897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fcf->vfid = ntohs(fab->fd_vfid);
84997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fcf->fc_map = ntoh24(fab->fd_map);
8500a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			desc_mask &= ~BIT(FIP_DT_FAB);
85197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
85297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_FKA:
85397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen != sizeof(struct fip_fka_desc))
85497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto len_err;
85597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fka = (struct fip_fka_desc *)desc;
8568cdffdccd948ea4872b7b65280bc04f2fa93fc96Yi Zou			if (fka->fd_flags & FIP_FKA_ADV_D)
8578cdffdccd948ea4872b7b65280bc04f2fa93fc96Yi Zou				fcf->fd_flags = 1;
85897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			t = ntohl(fka->fd_fka_period);
85997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (t >= FCOE_CTLR_MIN_FKA)
86097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				fcf->fka_period = msecs_to_jiffies(t);
8610a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			desc_mask &= ~BIT(FIP_DT_FKA);
86297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
86397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_MAP_OUI:
86497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_FCOE_SIZE:
86597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_FLOGI:
86697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_FDISC:
86797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_LOGO:
86897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_ELP:
86997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		default:
8700f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt			LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
871650bd12b9e31ec51d7ad0df3c4f94d863b827976Robert Love					"in FIP adv\n", desc->fip_dtype);
87297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			/* standard says ignore unknown descriptors >= 128 */
87397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
87497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				return -EINVAL;
8751508f3ecd991ecbf272e08f5ee70d2618f49159eBhanu Prakash Gollapudi			break;
87697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
87797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		desc = (struct fip_desc *)((char *)desc + dlen);
87897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		rlen -= dlen;
87997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
88097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (!fcf->fc_map || (fcf->fc_map & 0x10000))
88197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return -EINVAL;
882240778e821f596a6954116107c5cc3456df84f81Vasu Dev	if (!fcf->switch_name)
88397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return -EINVAL;
8840a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi	if (desc_mask) {
8850a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",
8860a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi				desc_mask);
8870a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		return -EINVAL;
8880a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi	}
88997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return 0;
89097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
89197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtlen_err:
8920f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt	LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
893650bd12b9e31ec51d7ad0df3c4f94d863b827976Robert Love			desc->fip_dtype, dlen);
89497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return -EINVAL;
89597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
89697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
89797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
89870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_recv_adv() - Handle an incoming advertisement
89970b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller receiving the advertisement
90070b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @skb: The received FIP packet
90197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
90297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
90397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
90497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf;
90597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf new;
90697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *found;
90797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV);
90897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	int first = 0;
90997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	int mtu_valid;
91097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
9110f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt	if (fcoe_ctlr_parse_adv(fip, skb, &new))
91297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return;
91397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
914fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
91597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	first = list_empty(&fip->fcfs);
91697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	found = NULL;
91797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	list_for_each_entry(fcf, &fip->fcfs, list) {
91897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (fcf->switch_name == new.switch_name &&
91997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		    fcf->fabric_name == new.fabric_name &&
92097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		    fcf->fc_map == new.fc_map &&
92197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		    compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) {
92297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			found = fcf;
92397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
92497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
92597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
92697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (!found) {
92797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT)
92897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			goto out;
92997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
93097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcf = kmalloc(sizeof(*fcf), GFP_ATOMIC);
93197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (!fcf)
93297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			goto out;
93397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
93497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fip->fcf_count++;
93597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		memcpy(fcf, &new, sizeof(new));
93697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		list_add(&fcf->list, &fip->fcfs);
93797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	} else {
93897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		/*
939c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt		 * Update the FCF's keep-alive descriptor flags.
940c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt		 * Other flag changes from new advertisements are
941c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt		 * ignored after a solicited advertisement is
942c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt		 * received and the FCF is selectable (usable).
94397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 */
944c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt		fcf->fd_flags = new.fd_flags;
945c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt		if (!fcoe_ctlr_fcf_usable(fcf))
946c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt			fcf->flags = new.flags;
947c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt
948d99ee45b7cb89803b79745dc3014ba64bfd02b7dJoe Eykholt		if (fcf == fip->sel_fcf && !fcf->fd_flags) {
94997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fip->ctlr_ka_time -= fcf->fka_period;
95097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fip->ctlr_ka_time += new.fka_period;
95197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (time_before(fip->ctlr_ka_time, fip->timer.expires))
95297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				mod_timer(&fip->timer, fip->ctlr_ka_time);
953c600fea2d813e8734748202970722c3b6a76b9a1Joe Eykholt		}
95497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcf->fka_period = new.fka_period;
95597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
95697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
95797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	mtu_valid = fcoe_ctlr_mtu_valid(fcf);
95897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcf->time = jiffies;
9599069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt	if (!found)
9609069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt		LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n",
9619069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt				fcf->fabric_name, fcf->fcf_mac);
96297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
96397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	/*
96497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * If this advertisement is not solicited and our max receive size
96597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * hasn't been verified, send a solicited advertisement.
96697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 */
96797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (!mtu_valid)
96897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcoe_ctlr_solicit(fip, fcf);
96997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
97097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	/*
97197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * If its been a while since we did a solicit, and this is
97297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * the first advertisement we've received, do a multicast
97397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * solicitation to gather as many advertisements as we can
97497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * before selection occurs.
97597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 */
97697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (first && time_after(jiffies, fip->sol_time + sol_tov))
97797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcoe_ctlr_solicit(fip, NULL);
97897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
97997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	/*
980981c1154b240ee77133a478fcd3853ac18111672Joe Eykholt	 * Put this FCF at the head of the list for priority among equals.
981981c1154b240ee77133a478fcd3853ac18111672Joe Eykholt	 * This helps in the case of an NPV switch which insists we use
982981c1154b240ee77133a478fcd3853ac18111672Joe Eykholt	 * the FCF that answers multicast solicitations, not the others that
983981c1154b240ee77133a478fcd3853ac18111672Joe Eykholt	 * are sending periodic multicast advertisements.
984981c1154b240ee77133a478fcd3853ac18111672Joe Eykholt	 */
98563ce2499947683dcc026373e24a4cb5a9d086e7dKirill A. Shutemov	if (mtu_valid)
98663ce2499947683dcc026373e24a4cb5a9d086e7dKirill A. Shutemov		list_move(&fcf->list, &fip->fcfs);
987981c1154b240ee77133a478fcd3853ac18111672Joe Eykholt
988981c1154b240ee77133a478fcd3853ac18111672Joe Eykholt	/*
98997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * If this is the first validated FCF, note the time and
99097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * set a timer to trigger selection.
99197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 */
992d99ee45b7cb89803b79745dc3014ba64bfd02b7dJoe Eykholt	if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) {
99397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fip->sel_time = jiffies +
99470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love			msecs_to_jiffies(FCOE_CTLR_START_DELAY);
99597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (!timer_pending(&fip->timer) ||
99697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		    time_before(fip->sel_time, fip->timer.expires))
99797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			mod_timer(&fip->timer, fip->sel_time);
99897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
99997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtout:
1000fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_unlock(&fip->ctlr_mutex);
100197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
100297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
100397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
100470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_recv_els() - Handle an incoming FIP encapsulated ELS frame
100570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller which received the packet
100670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @skb: The received FIP packet
100797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
100897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
100997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
101070b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	struct fc_lport *lport = fip->lp;
101197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_header *fiph;
101211b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech	struct fc_frame *fp = (struct fc_frame *)skb;
101397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fc_frame_header *fh = NULL;
101497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_desc *desc;
101597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_encaps *els;
101697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_dev_stats *stats;
101781c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi	struct fcoe_fcf *sel;
101897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	enum fip_desc_type els_dtype = 0;
101997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u8 els_op;
102097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u8 sub;
102197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u8 granted_mac[ETH_ALEN] = { 0 };
102297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t els_len = 0;
102397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t rlen;
102497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t dlen;
1025be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi	u32 desc_mask = 0;
1026be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi	u32 desc_cnt = 0;
102797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
102897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fiph = (struct fip_header *)skb->data;
102997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sub = fiph->fip_subcode;
103097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (sub != FIP_SC_REQ && sub != FIP_SC_REP)
103197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
103297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
103397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	rlen = ntohs(fiph->fip_dl_len) * 4;
103497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (rlen + sizeof(*fiph) > skb->len)
103597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
103697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
103797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	desc = (struct fip_desc *)(fiph + 1);
103897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	while (rlen > 0) {
1039be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi		desc_cnt++;
104097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		dlen = desc->fip_dlen * FIP_BPW;
104197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (dlen < sizeof(*desc) || dlen > rlen)
104297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			goto drop;
10430a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		/* Drop ELS if there are duplicate critical descriptors */
10440a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		if (desc->fip_dtype < 32) {
104581c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			if ((desc->fip_dtype != FIP_DT_MAC) &&
104681c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			    (desc_mask & 1U << desc->fip_dtype)) {
10470a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi				LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
10480a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi						"Descriptors in FIP ELS\n");
10490a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi				goto drop;
10500a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			}
1051be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi			desc_mask |= (1 << desc->fip_dtype);
10520a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		}
105397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		switch (desc->fip_dtype) {
105497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_MAC:
105581c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			sel = fip->sel_fcf;
1056be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi			if (desc_cnt == 1) {
1057be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi				LIBFCOE_FIP_DBG(fip, "FIP descriptors "
1058be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi						"received out of order\n");
1059be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi				goto drop;
1060be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi			}
106181c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			/*
106281c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			 * Some switch implementations send two MAC descriptors,
106381c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			 * with first MAC(granted_mac) being the FPMA, and the
106481c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			 * second one(fcoe_mac) is used as destination address
106581c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			 * for sending/receiving FCoE packets. FIP traffic is
106681c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			 * sent using fip_mac. For regular switches, both
106781c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			 * fip_mac and fcoe_mac would be the same.
106881c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			 */
106981c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			if (desc_cnt == 2)
107081c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi				memcpy(granted_mac,
107181c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi				       ((struct fip_mac_desc *)desc)->fd_mac,
107281c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi				       ETH_ALEN);
1073be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi
107497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen != sizeof(struct fip_mac_desc))
107597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto len_err;
107681c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi
107781c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi			if ((desc_cnt == 3) && (sel))
107881c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi				memcpy(sel->fcoe_mac,
107981c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi				       ((struct fip_mac_desc *)desc)->fd_mac,
108081c11dd2ed154b351eb6ee3443e07094a1d53ce1Bhanu Prakash Gollapudi				       ETH_ALEN);
108197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
108297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_FLOGI:
108397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_FDISC:
108497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_LOGO:
108597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_ELP:
1086be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi			if (desc_cnt != 1) {
1087be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi				LIBFCOE_FIP_DBG(fip, "FIP descriptors "
1088be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi						"received out of order\n");
1089be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi				goto drop;
1090be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi			}
109197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (fh)
109297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto drop;
109397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen < sizeof(*els) + sizeof(*fh) + 1)
109497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto len_err;
109597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			els_len = dlen - sizeof(*els);
109697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			els = (struct fip_encaps *)desc;
109797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fh = (struct fc_frame_header *)(els + 1);
109897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			els_dtype = desc->fip_dtype;
109997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
110097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		default:
11010f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt			LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
1102650bd12b9e31ec51d7ad0df3c4f94d863b827976Robert Love					"in FIP adv\n", desc->fip_dtype);
110397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			/* standard says ignore unknown descriptors >= 128 */
110497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
110597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt				goto drop;
1106be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi			if (desc_cnt <= 2) {
1107be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi				LIBFCOE_FIP_DBG(fip, "FIP descriptors "
1108be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi						"received out of order\n");
1109be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi				goto drop;
1110be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi			}
11111508f3ecd991ecbf272e08f5ee70d2618f49159eBhanu Prakash Gollapudi			break;
111297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
111397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		desc = (struct fip_desc *)((char *)desc + dlen);
111497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		rlen -= dlen;
111597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
111697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
111797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (!fh)
111897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
111997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	els_op = *(u8 *)(fh + 1);
112097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1121e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
1122794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	    sub == FIP_SC_REP && fip->mode != FIP_MODE_VN2VN) {
1123794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		if (els_op == ELS_LS_ACC) {
1124794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			if (!is_valid_ether_addr(granted_mac)) {
1125794d98e77f5901ceded697f1633463e88f078038Joe Eykholt				LIBFCOE_FIP_DBG(fip,
1126794d98e77f5901ceded697f1633463e88f078038Joe Eykholt					"Invalid MAC address %pM in FIP ELS\n",
1127794d98e77f5901ceded697f1633463e88f078038Joe Eykholt					granted_mac);
1128794d98e77f5901ceded697f1633463e88f078038Joe Eykholt				goto drop;
1129794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			}
1130794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
1131e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1132794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			if (fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
1133794d98e77f5901ceded697f1633463e88f078038Joe Eykholt				fip->flogi_oxid = FC_XID_UNKNOWN;
1134794d98e77f5901ceded697f1633463e88f078038Joe Eykholt				if (els_dtype == FIP_DT_FLOGI)
1135794d98e77f5901ceded697f1633463e88f078038Joe Eykholt					fcoe_ctlr_announce(fip);
1136794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			}
1137794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		} else if (els_dtype == FIP_DT_FLOGI &&
1138794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			   !fcoe_ctlr_flogi_retry(fip))
1139794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			goto drop;	/* retrying FLOGI so drop reject */
1140e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
114197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1142be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi	if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
1143be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi	    (!(1U << FIP_DT_MAC & desc_mask)))) {
1144be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi		LIBFCOE_FIP_DBG(fip, "Missing critical descriptors "
1145be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi				"in FIP ELS\n");
1146be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi		goto drop;
1147be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi	}
1148be61331d902e63011138723da3f737d34506f797Bhanu Prakash Gollapudi
114997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	/*
115097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * Convert skb into an fc_frame containing only the ELS.
115197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 */
115297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_pull(skb, (u8 *)fh - skb->data);
115397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	skb_trim(skb, els_len);
115497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fp = (struct fc_frame *)skb;
115597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fc_frame_init(fp);
115697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fr_sof(fp) = FC_SOF_I3;
115797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fr_eof(fp) = FC_EOF_T;
115870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	fr_dev(fp) = lport;
1159e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fr_encaps(fp) = els_dtype;
116097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1161f018b73af6db4f330ad5da9ac53997a699c30c42Joe Eykholt	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
116297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	stats->RxFrames++;
116397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	stats->RxWords += skb->len / FIP_BPW;
1164f018b73af6db4f330ad5da9ac53997a699c30c42Joe Eykholt	put_cpu();
116597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
116670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	fc_exch_recv(lport, fp);
116797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return;
116897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
116997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtlen_err:
11700f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt	LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
1171650bd12b9e31ec51d7ad0df3c4f94d863b827976Robert Love			desc->fip_dtype, dlen);
117297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtdrop:
117397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kfree_skb(skb);
117497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
117597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
117697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
117770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_recv_els() - Handle an incoming link reset frame
117870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller that received the frame
117970b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fh:	 The received FIP header
118097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
118197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * There may be multiple VN_Port descriptors.
118297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The overall length has already been checked.
118397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
118497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
118570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love				     struct fip_header *fh)
118697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
118797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_desc *desc;
118897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_mac_desc *mp;
118997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_wwn_desc *wp;
119097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_vn_desc *vp;
119197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t rlen;
119297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	size_t dlen;
119397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf = fip->sel_fcf;
119470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	struct fc_lport *lport = fip->lp;
11955550fda73d8bd3bed454e28c46f5a4e5288769bbBhanu Prakash Gollapudi	struct fc_lport *vn_port = NULL;
11965550fda73d8bd3bed454e28c46f5a4e5288769bbBhanu Prakash Gollapudi	u32 desc_mask;
1197c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	int num_vlink_desc;
1198c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	int reset_phys_port = 0;
1199c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	struct fip_vn_desc **vlink_desc_arr = NULL;
120097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
12010f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt	LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
1202d29510a2968f87eaf455c606cd8802b6f8a0774bRobert Love
12037b2787ec15b9d1c2f716da61b0eec21a3f5e6520Robert Love	if (!fcf || !lport->port_id)
120497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return;
120597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
120697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	/*
120797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * mask of required descriptors.  Validating each one clears its bit.
120897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 */
1209c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME);
121097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
121197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	rlen = ntohs(fh->fip_dl_len) * FIP_BPW;
121297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	desc = (struct fip_desc *)(fh + 1);
1213c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi
1214c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	/*
1215c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	 * Actually need to subtract 'sizeof(*mp) - sizeof(*wp)' from 'rlen'
1216c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	 * before determining max Vx_Port descriptor but a buggy FCF could have
1217c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	 * omited either or both MAC Address and Name Identifier descriptors
1218c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	 */
1219c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	num_vlink_desc = rlen / sizeof(*vp);
1220c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	if (num_vlink_desc)
1221c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		vlink_desc_arr = kmalloc(sizeof(vp) * num_vlink_desc,
1222c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi					 GFP_ATOMIC);
1223c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	if (!vlink_desc_arr)
1224c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		return;
1225c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	num_vlink_desc = 0;
1226c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi
122797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	while (rlen >= sizeof(*desc)) {
122897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		dlen = desc->fip_dlen * FIP_BPW;
122997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (dlen > rlen)
1230c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			goto err;
12310a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		/* Drop CVL if there are duplicate critical descriptors */
12320a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		if ((desc->fip_dtype < 32) &&
1233c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		    (desc->fip_dtype != FIP_DT_VN_ID) &&
12340a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		    !(desc_mask & 1U << desc->fip_dtype)) {
12350a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi			LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
12360a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi					"Descriptors in FIP CVL\n");
1237c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			goto err;
12380a9c5d344dbd983af59865f9880621e5cbbda899Bhanu Prakash Gollapudi		}
123997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		switch (desc->fip_dtype) {
124097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_MAC:
124197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			mp = (struct fip_mac_desc *)desc;
124297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen < sizeof(*mp))
1243c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				goto err;
124497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac))
1245c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				goto err;
124697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			desc_mask &= ~BIT(FIP_DT_MAC);
124797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
124897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_NAME:
124997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			wp = (struct fip_wwn_desc *)desc;
125097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen < sizeof(*wp))
1251c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				goto err;
125297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name)
1253c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				goto err;
125497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			desc_mask &= ~BIT(FIP_DT_NAME);
125597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
125697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		case FIP_DT_VN_ID:
125797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			vp = (struct fip_vn_desc *)desc;
125897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (dlen < sizeof(*vp))
1259c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				goto err;
1260c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			vlink_desc_arr[num_vlink_desc++] = vp;
1261c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			vn_port = fc_vport_id_lookup(lport,
1262c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi						      ntoh24(vp->fd_fc_id));
1263c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			if (vn_port && (vn_port == lport)) {
1264c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				mutex_lock(&fip->ctlr_mutex);
1265c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				per_cpu_ptr(lport->dev_stats,
1266c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi					    get_cpu())->VLinkFailureCount++;
1267c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				put_cpu();
1268c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				fcoe_ctlr_reset(fip);
1269c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				mutex_unlock(&fip->ctlr_mutex);
12705550fda73d8bd3bed454e28c46f5a4e5288769bbBhanu Prakash Gollapudi			}
127197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
127297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		default:
127397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			/* standard says ignore unknown descriptors >= 128 */
127497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
1275c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				goto err;
127697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			break;
127797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
127897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		desc = (struct fip_desc *)((char *)desc + dlen);
127997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		rlen -= dlen;
128097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
128197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
128297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	/*
128397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 * reset only if all required descriptors were present and valid.
128497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	 */
1285c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	if (desc_mask)
12860f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt		LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n",
12870f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt				desc_mask);
1288c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	else if (!num_vlink_desc) {
1289c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		LIBFCOE_FIP_DBG(fip, "CVL: no Vx_Port descriptor found\n");
1290c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		/*
1291c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		 * No Vx_Port description. Clear all NPIV ports,
1292c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		 * followed by physical port
1293c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		 */
1294c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		mutex_lock(&fip->ctlr_mutex);
1295c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		per_cpu_ptr(lport->dev_stats,
1296c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			    get_cpu())->VLinkFailureCount++;
1297c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		put_cpu();
1298c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		fcoe_ctlr_reset(fip);
1299c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		mutex_unlock(&fip->ctlr_mutex);
1300c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi
130114619ea689cc0b257cf998469005d0515133d7bcBhanu Prakash Gollapudi		mutex_lock(&lport->lp_mutex);
130214619ea689cc0b257cf998469005d0515133d7bcBhanu Prakash Gollapudi		list_for_each_entry(vn_port, &lport->vports, list)
130314619ea689cc0b257cf998469005d0515133d7bcBhanu Prakash Gollapudi			fc_lport_reset(vn_port);
130414619ea689cc0b257cf998469005d0515133d7bcBhanu Prakash Gollapudi		mutex_unlock(&lport->lp_mutex);
130514619ea689cc0b257cf998469005d0515133d7bcBhanu Prakash Gollapudi
1306c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		fc_lport_reset(fip->lp);
1307c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		fcoe_ctlr_solicit(fip, NULL);
130897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	} else {
1309c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		int i;
1310dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt
1311c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
1312c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		for (i = 0; i < num_vlink_desc; i++) {
1313c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			vp = vlink_desc_arr[i];
1314c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			vn_port = fc_vport_id_lookup(lport,
1315c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi						     ntoh24(vp->fd_fc_id));
1316c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			if (!vn_port)
1317c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				continue;
1318c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi
1319c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			/*
1320c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			 * 'port_id' is already validated, check MAC address and
1321c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			 * wwpn
1322c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			 */
1323c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			if (compare_ether_addr(fip->get_src_addr(vn_port),
1324c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi						vp->fd_mac) != 0 ||
1325c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				get_unaligned_be64(&vp->fd_wwpn) !=
1326c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi							vn_port->wwpn)
1327c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				continue;
1328c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi
1329c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			if (vn_port == lport)
1330c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				/*
1331c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				 * Physical port, defer processing till all
1332c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				 * listed NPIV ports are cleared
1333c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				 */
1334c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				reset_phys_port = 1;
1335c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi			else    /* NPIV port */
1336c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi				fc_lport_reset(vn_port);
1337c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		}
13385550fda73d8bd3bed454e28c46f5a4e5288769bbBhanu Prakash Gollapudi
1339c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi		if (reset_phys_port) {
13405550fda73d8bd3bed454e28c46f5a4e5288769bbBhanu Prakash Gollapudi			fc_lport_reset(fip->lp);
13415550fda73d8bd3bed454e28c46f5a4e5288769bbBhanu Prakash Gollapudi			fcoe_ctlr_solicit(fip, NULL);
13425550fda73d8bd3bed454e28c46f5a4e5288769bbBhanu Prakash Gollapudi		}
134397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
1344c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi
1345c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudierr:
1346c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59Bhanu Prakash Gollapudi	kfree(vlink_desc_arr);
134797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
134897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
134997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
135070b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_recv() - Receive a FIP packet
135170b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller that received the packet
135270b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @skb: The received FIP packet
135397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
13541f4aed818d26eb9ed54520fbeb85d5ee691baa94Joe Eykholt * This may be called from either NET_RX_SOFTIRQ or IRQ.
135597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
135697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtvoid fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
135797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
13581f4aed818d26eb9ed54520fbeb85d5ee691baa94Joe Eykholt	skb_queue_tail(&fip->fip_recv_list, skb);
135997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	schedule_work(&fip->recv_work);
136097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
136197c8389d54b9665c38105ea72a428a44b97ff2f6Joe EykholtEXPORT_SYMBOL(fcoe_ctlr_recv);
136297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
136397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
136470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_recv_handler() - Receive a FIP frame
136570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller that received the frame
136670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @skb: The received FIP frame
136797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
136897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Returns non-zero if the frame is dropped.
136997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
137097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
137197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
137297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fip_header *fiph;
137397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct ethhdr *eh;
137497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	enum fip_state state;
137597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u16 op;
137697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u8 sub;
137797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
137897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (skb_linearize(skb))
137997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
138097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (skb->len < sizeof(*fiph))
138197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
138297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	eh = eth_hdr(skb);
1383e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->mode == FIP_MODE_VN2VN) {
1384e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
1385e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		    compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) &&
1386e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		    compare_ether_addr(eh->h_dest, fcoe_all_p2p))
1387e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			goto drop;
1388e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	} else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) &&
1389e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		   compare_ether_addr(eh->h_dest, fcoe_all_enode))
139097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
139197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fiph = (struct fip_header *)skb->data;
139297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	op = ntohs(fiph->fip_op);
139397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sub = fiph->fip_subcode;
139497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
139597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (FIP_VER_DECAPS(fiph->fip_ver) != FIP_VER)
139697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
139797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len)
139897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
139997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1400fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
140197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	state = fip->state;
140297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (state == FIP_ST_AUTO) {
140397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fip->map_dest = 0;
14049b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt		fcoe_ctlr_set_state(fip, FIP_ST_ENABLED);
140597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		state = FIP_ST_ENABLED;
14060f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt		LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
140797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
1408fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_unlock(&fip->ctlr_mutex);
1409e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1410e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN)
1411e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return fcoe_ctlr_vn_recv(fip, skb);
1412e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1413e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP &&
1414e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	    state != FIP_ST_VNMP_CLAIM)
141597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		goto drop;
141697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
141797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (op == FIP_OP_LS) {
141897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcoe_ctlr_recv_els(fip, skb);	/* consumes skb */
141997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return 0;
142097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
1421e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1422e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (state != FIP_ST_ENABLED)
1423e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		goto drop;
1424e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
142597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (op == FIP_OP_DISC && sub == FIP_SC_ADV)
142697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcoe_ctlr_recv_adv(fip, skb);
142797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK)
142897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcoe_ctlr_recv_clr_vlink(fip, fiph);
142997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kfree_skb(skb);
143097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return 0;
143197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtdrop:
143297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	kfree_skb(skb);
143397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return -1;
143497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
143597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
143697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
143770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_select() - Select the best FCF (if possible)
143870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller
143997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
1440ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholt * Returns the selected FCF, or NULL if none are usable.
1441ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholt *
144297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * If there are conflicting advertisements, no FCF can be chosen.
144397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
1444794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * If there is already a selected FCF, this will choose a better one or
1445794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * an equivalent one that hasn't already been sent a FLOGI.
1446794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
144797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Called with lock held.
144897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
1449ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholtstatic struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
145097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
145197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf;
1452794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct fcoe_fcf *best = fip->sel_fcf;
1453b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt	struct fcoe_fcf *first;
1454b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt
1455b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt	first = list_first_entry(&fip->fcfs, struct fcoe_fcf, list);
145697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
145797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	list_for_each_entry(fcf, &fip->fcfs, list) {
14589069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt		LIBFCOE_FIP_DBG(fip, "consider FCF fab %16.16llx "
14599069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt				"VFID %d mac %pM map %x val %d "
14609069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt				"sent %u pri %u\n",
14619069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt				fcf->fabric_name, fcf->vfid, fcf->fcf_mac,
14629069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt				fcf->fc_map, fcoe_ctlr_mtu_valid(fcf),
14639069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt				fcf->flogi_sent, fcf->pri);
1464b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt		if (fcf->fabric_name != first->fabric_name ||
1465b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt		    fcf->vfid != first->vfid ||
1466b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt		    fcf->fc_map != first->fc_map) {
1467b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt			LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
1468b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt					"or FC-MAP\n");
1469b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt			return NULL;
1470b69ae0ae3f322d9a6bc4e209049b5b6e193ad652Joe Eykholt		}
1471794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		if (fcf->flogi_sent)
1472794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			continue;
147397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (!fcoe_ctlr_fcf_usable(fcf)) {
14749f8f3aa640ae5da220eea95215317f19ace91481Chris Leech			LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
14759f8f3aa640ae5da220eea95215317f19ace91481Chris Leech					"map %x %svalid %savailable\n",
14769f8f3aa640ae5da220eea95215317f19ace91481Chris Leech					fcf->fabric_name, fcf->fc_map,
14779f8f3aa640ae5da220eea95215317f19ace91481Chris Leech					(fcf->flags & FIP_FL_SOL) ? "" : "in",
14789f8f3aa640ae5da220eea95215317f19ace91481Chris Leech					(fcf->flags & FIP_FL_AVAIL) ?
14799f8f3aa640ae5da220eea95215317f19ace91481Chris Leech					"" : "un");
148097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			continue;
148197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
1482794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		if (!best || fcf->pri < best->pri || best->flogi_sent)
148397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			best = fcf;
148497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
148597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip->sel_fcf = best;
1486c47036a7cd378533495d8cc06a7cf8a881072a9dJoe Eykholt	if (best) {
14879069f5c433e402be5707f37f3d0dfb376659c1e4Joe Eykholt		LIBFCOE_FIP_DBG(fip, "using FCF mac %pM\n", best->fcf_mac);
1488c47036a7cd378533495d8cc06a7cf8a881072a9dJoe Eykholt		fip->port_ka_time = jiffies +
1489c47036a7cd378533495d8cc06a7cf8a881072a9dJoe Eykholt			msecs_to_jiffies(FIP_VN_KA_PERIOD);
1490c47036a7cd378533495d8cc06a7cf8a881072a9dJoe Eykholt		fip->ctlr_ka_time = jiffies + best->fka_period;
1491c47036a7cd378533495d8cc06a7cf8a881072a9dJoe Eykholt		if (time_before(fip->ctlr_ka_time, fip->timer.expires))
1492c47036a7cd378533495d8cc06a7cf8a881072a9dJoe Eykholt			mod_timer(&fip->timer, fip->ctlr_ka_time);
1493c47036a7cd378533495d8cc06a7cf8a881072a9dJoe Eykholt	}
1494ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholt	return best;
149597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
149697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
149797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
1498794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * fcoe_ctlr_flogi_send_locked() - send FIP-encapsulated FLOGI to current FCF
1499794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * @fip: The FCoE controller
1500794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
1501794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * Returns non-zero error if it could not be sent.
1502794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
1503794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * Called with ctlr_mutex and ctlr_lock held.
1504794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * Caller must verify that fip->sel_fcf is not NULL.
1505794d98e77f5901ceded697f1633463e88f078038Joe Eykholt */
1506794d98e77f5901ceded697f1633463e88f078038Joe Eykholtstatic int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip)
1507794d98e77f5901ceded697f1633463e88f078038Joe Eykholt{
1508794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct sk_buff *skb;
1509794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct sk_buff *skb_orig;
1510794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct fc_frame_header *fh;
1511794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	int error;
1512794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1513794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	skb_orig = fip->flogi_req;
1514794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (!skb_orig)
1515794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		return -EINVAL;
1516794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1517794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	/*
1518794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	 * Clone and send the FLOGI request.  If clone fails, use original.
1519794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	 */
1520794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	skb = skb_clone(skb_orig, GFP_ATOMIC);
1521794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (!skb) {
1522794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		skb = skb_orig;
1523794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fip->flogi_req = NULL;
1524794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	}
1525794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	fh = (struct fc_frame_header *)skb->data;
1526794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	error = fcoe_ctlr_encaps(fip, fip->lp, FIP_DT_FLOGI, skb,
1527794d98e77f5901ceded697f1633463e88f078038Joe Eykholt				 ntoh24(fh->fh_d_id));
1528794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (error) {
1529794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		kfree_skb(skb);
1530794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		return error;
1531794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	}
1532794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	fip->send(fip, skb);
1533794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	fip->sel_fcf->flogi_sent = 1;
1534794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	return 0;
1535794d98e77f5901ceded697f1633463e88f078038Joe Eykholt}
1536794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1537794d98e77f5901ceded697f1633463e88f078038Joe Eykholt/**
1538794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * fcoe_ctlr_flogi_retry() - resend FLOGI request to a new FCF if possible
1539794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * @fip: The FCoE controller
1540794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
1541794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * Returns non-zero error code if there's no FLOGI request to retry or
1542794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * no alternate FCF available.
1543794d98e77f5901ceded697f1633463e88f078038Joe Eykholt */
1544794d98e77f5901ceded697f1633463e88f078038Joe Eykholtstatic int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
1545794d98e77f5901ceded697f1633463e88f078038Joe Eykholt{
1546794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct fcoe_fcf *fcf;
1547794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	int error;
1548794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1549794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
1550794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	spin_lock_bh(&fip->ctlr_lock);
1551794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n");
1552ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholt	fcf = fcoe_ctlr_select(fip);
1553794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (!fcf || fcf->flogi_sent) {
1554794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		kfree_skb(fip->flogi_req);
1555794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fip->flogi_req = NULL;
1556794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		error = -ENOENT;
1557794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	} else {
1558794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fcoe_ctlr_solicit(fip, NULL);
1559794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		error = fcoe_ctlr_flogi_send_locked(fip);
1560794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	}
1561794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	spin_unlock_bh(&fip->ctlr_lock);
1562794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	mutex_unlock(&fip->ctlr_mutex);
1563794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	return error;
1564794d98e77f5901ceded697f1633463e88f078038Joe Eykholt}
1565794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1566794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1567794d98e77f5901ceded697f1633463e88f078038Joe Eykholt/**
1568794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * fcoe_ctlr_flogi_send() - Handle sending of FIP FLOGI.
1569794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * @fip: The FCoE controller that timed out
1570794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
1571794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * Done here because fcoe_ctlr_els_send() can't get mutex.
1572794d98e77f5901ceded697f1633463e88f078038Joe Eykholt *
1573794d98e77f5901ceded697f1633463e88f078038Joe Eykholt * Called with ctlr_mutex held.  The caller must not hold ctlr_lock.
1574794d98e77f5901ceded697f1633463e88f078038Joe Eykholt */
1575794d98e77f5901ceded697f1633463e88f078038Joe Eykholtstatic void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
1576794d98e77f5901ceded697f1633463e88f078038Joe Eykholt{
1577794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	struct fcoe_fcf *fcf;
1578794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1579794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	spin_lock_bh(&fip->ctlr_lock);
1580794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	fcf = fip->sel_fcf;
1581794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (!fcf || !fip->flogi_req_send)
1582794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		goto unlock;
1583794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1584794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	LIBFCOE_FIP_DBG(fip, "sending FLOGI\n");
1585794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1586794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	/*
1587794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	 * If this FLOGI is being sent due to a timeout retry
1588794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	 * to the same FCF as before, select a different FCF if possible.
1589794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	 */
1590794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (fcf->flogi_sent) {
1591794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		LIBFCOE_FIP_DBG(fip, "sending FLOGI - reselect\n");
1592ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholt		fcf = fcoe_ctlr_select(fip);
1593794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		if (!fcf || fcf->flogi_sent) {
1594794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			LIBFCOE_FIP_DBG(fip, "sending FLOGI - clearing\n");
1595794d98e77f5901ceded697f1633463e88f078038Joe Eykholt			list_for_each_entry(fcf, &fip->fcfs, list)
1596794d98e77f5901ceded697f1633463e88f078038Joe Eykholt				fcf->flogi_sent = 0;
1597ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholt			fcf = fcoe_ctlr_select(fip);
1598794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		}
1599794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	}
1600794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (fcf) {
1601794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fcoe_ctlr_flogi_send_locked(fip);
1602794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fip->flogi_req_send = 0;
1603794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	} else /* XXX */
1604794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n");
1605794d98e77f5901ceded697f1633463e88f078038Joe Eykholtunlock:
1606794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	spin_unlock_bh(&fip->ctlr_lock);
1607794d98e77f5901ceded697f1633463e88f078038Joe Eykholt}
1608794d98e77f5901ceded697f1633463e88f078038Joe Eykholt
1609794d98e77f5901ceded697f1633463e88f078038Joe Eykholt/**
161070b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_timeout() - FIP timeout handler
161170b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @arg: The FCoE controller that timed out
161297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
161397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_timeout(unsigned long arg)
161497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
161597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
1616fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt
1617fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	schedule_work(&fip->timer_work);
1618fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt}
1619fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt
1620fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt/**
1621fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt * fcoe_ctlr_timer_work() - Worker thread function for timer work
1622fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt * @work: Handle to a FCoE controller
1623fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt *
1624fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt * Ages FCFs.  Triggers FCF selection if possible.
1625fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt * Sends keep-alives and resets.
1626fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt */
1627fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholtstatic void fcoe_ctlr_timer_work(struct work_struct *work)
1628fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt{
1629fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	struct fcoe_ctlr *fip;
1630fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	struct fc_lport *vport;
1631fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	u8 *mac;
1632fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	u8 reset = 0;
1633fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	u8 send_ctlr_ka = 0;
1634fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	u8 send_port_ka = 0;
163597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *sel;
163697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_fcf *fcf;
16378690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt	unsigned long next_timer;
163897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1639fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	fip = container_of(work, struct fcoe_ctlr, timer_work);
1640e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->mode == FIP_MODE_VN2VN)
1641e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return fcoe_ctlr_vn_timeout(fip);
1642fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_lock(&fip->ctlr_mutex);
164397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (fip->state == FIP_ST_DISABLED) {
1644fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt		mutex_unlock(&fip->ctlr_mutex);
164597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return;
164697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
164797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
164897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fcf = fip->sel_fcf;
16498690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt	next_timer = fcoe_ctlr_age_fcfs(fip);
165097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
165197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	sel = fip->sel_fcf;
16528690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt	if (!sel && fip->sel_time) {
16538690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt		if (time_after_eq(jiffies, fip->sel_time)) {
1654ba9cd5d095b42271588c20ccd6ddd561d0e4cc1eJoe Eykholt			sel = fcoe_ctlr_select(fip);
16558690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt			fip->sel_time = 0;
16568690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt		} else if (time_after(next_timer, fip->sel_time))
16578690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt			next_timer = fip->sel_time;
165897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
165997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1660794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	if (sel && fip->flogi_req_send)
1661794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		fcoe_ctlr_flogi_send(fip);
1662794d98e77f5901ceded697f1633463e88f078038Joe Eykholt	else if (!sel && fcf)
1663794d98e77f5901ceded697f1633463e88f078038Joe Eykholt		reset = 1;
166497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
16658cdffdccd948ea4872b7b65280bc04f2fa93fc96Yi Zou	if (sel && !sel->fd_flags) {
166697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
166797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fip->ctlr_ka_time = jiffies + sel->fka_period;
1668fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt			send_ctlr_ka = 1;
166997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
167097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (time_after(next_timer, fip->ctlr_ka_time))
167197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			next_timer = fip->ctlr_ka_time;
167297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
167397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (time_after_eq(jiffies, fip->port_ka_time)) {
1674f47dd855d9e64a5d499a93e858a82bc5e7b21345Bhanu Prakash Gollapudi			fip->port_ka_time = jiffies +
167570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love				msecs_to_jiffies(FIP_VN_KA_PERIOD);
1676fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt			send_port_ka = 1;
167797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
167897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (time_after(next_timer, fip->port_ka_time))
167997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			next_timer = fip->port_ka_time;
168097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
16818690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt	if (!list_empty(&fip->fcfs))
16828690cb8359d8e9f8d7ca12791ef7ea32b709df8bJoe Eykholt		mod_timer(&fip->timer, next_timer);
1683fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	mutex_unlock(&fip->ctlr_mutex);
168497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1685516a648631c912e84e0035590f98eef1d716f4eaBhanu Prakash Gollapudi	if (reset) {
1686dd42dac4ecd1799077c132aab35d3c36b26d4d8cJoe Eykholt		fc_lport_reset(fip->lp);
1687516a648631c912e84e0035590f98eef1d716f4eaBhanu Prakash Gollapudi		/* restart things with a solicitation */
1688516a648631c912e84e0035590f98eef1d716f4eaBhanu Prakash Gollapudi		fcoe_ctlr_solicit(fip, NULL);
1689516a648631c912e84e0035590f98eef1d716f4eaBhanu Prakash Gollapudi	}
169011b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech
1691fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	if (send_ctlr_ka)
169211b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr);
1693fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt
1694fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt	if (send_port_ka) {
169511b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		mutex_lock(&fip->lp->lp_mutex);
169611b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		mac = fip->get_src_addr(fip->lp);
169711b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac);
169811b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		list_for_each_entry(vport, &fip->lp->vports, list) {
169911b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech			mac = fip->get_src_addr(vport);
170011b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech			fcoe_ctlr_send_keep_alive(fip, vport, 1, mac);
170111b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		}
170211b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech		mutex_unlock(&fip->lp->lp_mutex);
170311b561886643d4e23d0fd58c205d830a448dd0a2Chris Leech	}
170497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
170597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
170697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
170770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_ctlr_recv_work() - Worker thread function for receiving FIP frames
170870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @recv_work: Handle to a FCoE controller
170997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
171097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholtstatic void fcoe_ctlr_recv_work(struct work_struct *recv_work)
171197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
171297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fcoe_ctlr *fip;
171397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct sk_buff *skb;
171497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
171597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fip = container_of(recv_work, struct fcoe_ctlr, recv_work);
17161f4aed818d26eb9ed54520fbeb85d5ee691baa94Joe Eykholt	while ((skb = skb_dequeue(&fip->fip_recv_list)))
171797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fcoe_ctlr_recv_handler(fip, skb);
171897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
171997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
172097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt/**
1721386309ce927a308d7742a6fb24a536d3383fbd49Joe Eykholt * fcoe_ctlr_recv_flogi() - Snoop pre-FIP receipt of FLOGI response
172270b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fip: The FCoE controller
172370b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @fp:	 The FC frame to snoop
172497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
172597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Snoop potential response to FLOGI or even incoming FLOGI.
172697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
172797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The caller has checked that we are waiting for login as indicated
172897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * by fip->flogi_oxid != FC_XID_UNKNOWN.
172997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
173097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * The caller is responsible for freeing the frame.
1731386309ce927a308d7742a6fb24a536d3383fbd49Joe Eykholt * Fill in the granted_mac address.
173297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt *
173397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt * Return non-zero if the frame should not be delivered to libfc.
173497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt */
173511b561886643d4e23d0fd58c205d830a448dd0a2Chris Leechint fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
1736386309ce927a308d7742a6fb24a536d3383fbd49Joe Eykholt			 struct fc_frame *fp)
173797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt{
173897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	struct fc_frame_header *fh;
173997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	u8 op;
1740386309ce927a308d7742a6fb24a536d3383fbd49Joe Eykholt	u8 *sa;
174197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1742386309ce927a308d7742a6fb24a536d3383fbd49Joe Eykholt	sa = eth_hdr(&fp->skb)->h_source;
174397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	fh = fc_frame_header_get(fp);
174497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (fh->fh_type != FC_TYPE_ELS)
174597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		return 0;
174697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
174797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	op = fc_frame_payload_op(fp);
174897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP &&
174997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	    fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
175097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
1751fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt		mutex_lock(&fip->ctlr_mutex);
175297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) {
1753fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt			mutex_unlock(&fip->ctlr_mutex);
175497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			return -EINVAL;
175597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
17569b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt		fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
17570f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt		LIBFCOE_FIP_DBG(fip,
17580f51c2e54c0bfdb6b02c53f6d7dd9b35f91821b6Joe Eykholt				"received FLOGI LS_ACC using non-FIP mode\n");
175997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
176097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		/*
176197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * FLOGI accepted.
176297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * If the src mac addr is FC_OUI-based, then we mark the
176397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * address_mode flag to use FC_OUI-based Ethernet DA.
176497c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * Otherwise we use the FCoE gateway addr
176597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 */
176697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) {
1767cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt			fcoe_ctlr_map_dest(fip);
176897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		} else {
176997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			memcpy(fip->dest_addr, sa, ETH_ALEN);
177097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fip->map_dest = 0;
177197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
177297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		fip->flogi_oxid = FC_XID_UNKNOWN;
1773fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt		mutex_unlock(&fip->ctlr_mutex);
1774386309ce927a308d7742a6fb24a536d3383fbd49Joe Eykholt		fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id);
177597c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	} else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
177697c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		/*
177797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 * Save source MAC for point-to-point responses.
177897c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		 */
1779fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt		mutex_lock(&fip->ctlr_mutex);
178097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
178197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			memcpy(fip->dest_addr, sa, ETH_ALEN);
178297c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt			fip->map_dest = 0;
1783e49bf6145f50da2d95f9fab605ce74f8fb44cb16Joe Eykholt			if (fip->state == FIP_ST_AUTO)
1784e49bf6145f50da2d95f9fab605ce74f8fb44cb16Joe Eykholt				LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
1785e49bf6145f50da2d95f9fab605ce74f8fb44cb16Joe Eykholt						"Setting non-FIP mode\n");
17869b651da900ccfe5581befb46eb06ef781a1d7e74Joe Eykholt			fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
178797c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt		}
1788fdb068c6cd6e30d43664f856d3530715a5742713Joe Eykholt		mutex_unlock(&fip->ctlr_mutex);
178997c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	}
179097c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt	return 0;
179197c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt}
179297c8389d54b9665c38105ea72a428a44b97ff2f6Joe EykholtEXPORT_SYMBOL(fcoe_ctlr_recv_flogi);
179397c8389d54b9665c38105ea72a428a44b97ff2f6Joe Eykholt
17945e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev/**
179570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_wwn_from_mac() - Converts a 48-bit IEEE MAC address to a 64-bit FC WWN
179670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @mac:    The MAC address to convert
179770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @scheme: The scheme to use when converting
179870b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @port:   The port indicator for converting
17995e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev *
18005e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev * Returns: u64 fc world wide name
18015e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev */
18025e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Devu64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN],
18035e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		      unsigned int scheme, unsigned int port)
18045e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev{
18055e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	u64 wwn;
18065e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	u64 host_mac;
18075e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev
18085e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	/* The MAC is in NO, so flip only the low 48 bits */
18095e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	host_mac = ((u64) mac[0] << 40) |
18105e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		((u64) mac[1] << 32) |
18115e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		((u64) mac[2] << 24) |
18125e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		((u64) mac[3] << 16) |
18135e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		((u64) mac[4] << 8) |
18145e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		(u64) mac[5];
18155e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev
18165e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	WARN_ON(host_mac >= (1ULL << 48));
18175e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	wwn = host_mac | ((u64) scheme << 60);
18185e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	switch (scheme) {
18195e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	case 1:
18205e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		WARN_ON(port != 0);
18215e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		break;
18225e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	case 2:
18235e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		WARN_ON(port >= 0xfff);
18245e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		wwn |= (u64) port << 48;
18255e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		break;
18265e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	default:
18275e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		WARN_ON(1);
18285e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		break;
18295e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	}
18305e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev
18315e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	return wwn;
18325e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev}
18335e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu DevEXPORT_SYMBOL_GPL(fcoe_wwn_from_mac);
18345e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev
18355e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev/**
1836e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_rport() - return the fcoe_rport for a given fc_rport_priv
1837e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @rdata: libfc remote port
1838e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
1839e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata)
1840e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
1841e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	return (struct fcoe_rport *)(rdata + 1);
1842e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
1843e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1844e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
1845e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_send() - Send a FIP VN2VN Probe Request or Reply.
1846e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
1847e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @sub: sub-opcode for probe request, reply, or advertisement.
1848e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @dest: The destination Ethernet MAC address
1849e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @min_len: minimum size of the Ethernet payload to be sent
1850e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
1851e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
1852e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			      enum fip_vn2vn_subcode sub,
1853e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			      const u8 *dest, size_t min_len)
1854e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
1855e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct sk_buff *skb;
1856e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_frame {
1857e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		struct ethhdr eth;
1858e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		struct fip_header fip;
1859e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		struct fip_mac_desc mac;
1860e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		struct fip_wwn_desc wwnn;
1861e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		struct fip_vn_desc vn;
18620095a9213324a4466c10de98837a27ab1b7e72beYi Zou	} __packed * frame;
1863e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_fc4_feat *ff;
1864e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_size_desc *size;
1865e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u32 fcp_feat;
1866e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	size_t len;
1867e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	size_t dlen;
1868e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1869e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	len = sizeof(*frame);
1870e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	dlen = 0;
1871e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
1872e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		dlen = sizeof(struct fip_fc4_feat) +
1873e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		       sizeof(struct fip_size_desc);
1874e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		len += dlen;
1875e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
1876e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	dlen += sizeof(frame->mac) + sizeof(frame->wwnn) + sizeof(frame->vn);
1877e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	len = max(len, min_len + sizeof(struct ethhdr));
1878e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1879e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	skb = dev_alloc_skb(len);
1880e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (!skb)
1881e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
1882e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1883e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame = (struct fip_frame *)skb->data;
1884e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	memset(frame, 0, len);
1885e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	memcpy(frame->eth.h_dest, dest, ETH_ALEN);
1886e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
1887e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->eth.h_proto = htons(ETH_P_FIP);
1888e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1889e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
1890e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->fip.fip_op = htons(FIP_OP_VN2VN);
1891e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->fip.fip_subcode = sub;
1892e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->fip.fip_dl_len = htons(dlen / FIP_BPW);
1893e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1894e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->mac.fd_desc.fip_dtype = FIP_DT_MAC;
1895e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW;
1896e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
1897e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1898e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->wwnn.fd_desc.fip_dtype = FIP_DT_NAME;
1899e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->wwnn.fd_desc.fip_dlen = sizeof(frame->wwnn) / FIP_BPW;
1900e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	put_unaligned_be64(fip->lp->wwnn, &frame->wwnn.fd_wwn);
1901e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1902e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->vn.fd_desc.fip_dtype = FIP_DT_VN_ID;
1903e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frame->vn.fd_desc.fip_dlen = sizeof(frame->vn) / FIP_BPW;
1904e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	hton24(frame->vn.fd_mac, FIP_VN_FC_MAP);
1905e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	hton24(frame->vn.fd_mac + 3, fip->port_id);
1906e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	hton24(frame->vn.fd_fc_id, fip->port_id);
1907e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	put_unaligned_be64(fip->lp->wwpn, &frame->vn.fd_wwpn);
1908e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1909e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	/*
1910e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * For claims, add FC-4 features.
1911e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * TBD: Add interface to get fc-4 types and features from libfc.
1912e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 */
1913e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) {
1914e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		ff = (struct fip_fc4_feat *)(frame + 1);
1915e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		ff->fd_desc.fip_dtype = FIP_DT_FC4F;
1916e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		ff->fd_desc.fip_dlen = sizeof(*ff) / FIP_BPW;
1917e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		ff->fd_fts = fip->lp->fcts;
1918e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1919e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcp_feat = 0;
1920e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (fip->lp->service_params & FCP_SPPF_INIT_FCN)
1921e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcp_feat |= FCP_FEAT_INIT;
1922e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (fip->lp->service_params & FCP_SPPF_TARG_FCN)
1923e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcp_feat |= FCP_FEAT_TARG;
1924e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcp_feat <<= (FC_TYPE_FCP * 4) % 32;
1925e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		ff->fd_ff.fd_feat[FC_TYPE_FCP * 4 / 32] = htonl(fcp_feat);
1926e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1927e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		size = (struct fip_size_desc *)(ff + 1);
1928e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		size->fd_desc.fip_dtype = FIP_DT_FCOE_SIZE;
1929e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		size->fd_desc.fip_dlen = sizeof(*size) / FIP_BPW;
1930e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		size->fd_size = htons(fcoe_ctlr_fcoe_size(fip));
1931e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
1932e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1933e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	skb_put(skb, len);
1934e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	skb->protocol = htons(ETH_P_FIP);
19356f6c2aa33b915c574543f176dee89d7aefc115c1john fastabend	skb->priority = fip->priority;
1936e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	skb_reset_mac_header(skb);
1937e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	skb_reset_network_header(skb);
1938e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1939e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fip->send(fip, skb);
1940e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
1941e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1942e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
1943e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_rport_callback - Event handler for rport events.
1944e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @lport: The lport which is receiving the event
1945e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @rdata: remote port private data
194625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * @event: The event that occurred
1947e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
1948e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Locking Note:  The rport lock must not be held when calling this function.
1949e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
1950e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_rport_callback(struct fc_lport *lport,
1951e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					struct fc_rport_priv *rdata,
1952e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					enum fc_rport_event event)
1953e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
1954e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_ctlr *fip = lport->disc.priv;
1955e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
1956e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1957e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	LIBFCOE_FIP_DBG(fip, "vn_rport_callback %x event %d\n",
1958e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			rdata->ids.port_id, event);
1959e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1960e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&fip->ctlr_mutex);
1961e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	switch (event) {
1962e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case RPORT_EV_READY:
1963e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		frport->login_count = 0;
1964e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
1965e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case RPORT_EV_LOGO:
1966e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case RPORT_EV_FAILED:
1967e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case RPORT_EV_STOP:
1968e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		frport->login_count++;
1969e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (frport->login_count > FCOE_CTLR_VN2VN_LOGIN_LIMIT) {
1970e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			LIBFCOE_FIP_DBG(fip,
1971e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					"rport FLOGI limited port_id %6.6x\n",
1972e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					rdata->ids.port_id);
1973e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			lport->tt.rport_logoff(rdata);
1974e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
1975e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
1976e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	default:
1977e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
1978e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
1979e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&fip->ctlr_mutex);
1980e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
1981e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1982e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic struct fc_rport_operations fcoe_ctlr_vn_rport_ops = {
1983e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	.event_callback = fcoe_ctlr_vn_rport_callback,
1984e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt};
1985e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1986e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
1987e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_disc_stop_locked() - stop discovery in VN2VN mode
1988e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
1989e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
1990e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
1991e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
1992e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport)
1993e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
1994e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&lport->disc.disc_mutex);
1995e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	lport->disc.disc_callback = NULL;
1996e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&lport->disc.disc_mutex);
1997e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
1998e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
1999e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2000e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_disc_stop() - stop discovery in VN2VN mode
2001e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2002e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2003e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called through the local port template for discovery.
2004e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called without the ctlr_mutex held.
2005e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2006e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_disc_stop(struct fc_lport *lport)
2007e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2008e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_ctlr *fip = lport->disc.priv;
2009e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2010e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&fip->ctlr_mutex);
2011e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fcoe_ctlr_disc_stop_locked(lport);
2012e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&fip->ctlr_mutex);
2013e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2014e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2015e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2016e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_disc_stop_final() - stop discovery for shutdown in VN2VN mode
2017e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2018e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2019e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called through the local port template for discovery.
2020e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called without the ctlr_mutex held.
2021e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2022e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_disc_stop_final(struct fc_lport *lport)
2023e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2024e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fcoe_ctlr_disc_stop(lport);
2025e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	lport->tt.rport_flush_queue();
2026e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	synchronize_rcu();
2027e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2028e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2029e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2030e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_restart() - VN2VN probe restart with new port_id
2031e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2032e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2033e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with fcoe_ctlr lock held.
2034e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2035e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip)
2036e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2037e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	unsigned long wait;
2038e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u32 port_id;
2039e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2040e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fcoe_ctlr_disc_stop_locked(fip->lp);
2041e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2042e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	/*
2043e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * Get proposed port ID.
2044e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * If this is the first try after link up, use any previous port_id.
2045e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * If there was none, use the low bits of the port_name.
2046e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * On subsequent tries, get the next random one.
2047e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * Don't use reserved IDs, use another non-zero value, just as random.
2048e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 */
2049e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	port_id = fip->port_id;
2050e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->probe_tries)
2051e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		port_id = prandom32(&fip->rnd_state) & 0xffff;
2052e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	else if (!port_id)
2053e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		port_id = fip->lp->wwpn & 0xffff;
2054e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (!port_id || port_id == 0xffff)
2055e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		port_id = 1;
2056e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fip->port_id = port_id;
2057e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2058e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->probe_tries < FIP_VN_RLIM_COUNT) {
2059e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fip->probe_tries++;
2060e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		wait = random32() % FIP_VN_PROBE_WAIT;
2061e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	} else
2062e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		wait = FIP_VN_RLIM_INT;
2063e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait));
2064e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fcoe_ctlr_set_state(fip, FIP_ST_VNMP_START);
2065e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2066e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2067e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2068e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_start() - Start in VN2VN mode
2069e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2070e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2071e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with fcoe_ctlr lock held.
2072e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2073e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip)
2074e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2075e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fip->probe_tries = 0;
2076e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	prandom32_seed(&fip->rnd_state, fip->lp->wwpn);
2077e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fcoe_ctlr_vn_restart(fip);
2078e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2079e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2080e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2081e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_parse - parse probe request or response
2082e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2083e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @skb: incoming packet
2084e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @rdata: buffer for resulting parsed VN entry plus fcoe_rport
2085e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2086e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Returns non-zero error number on error.
2087e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Does not consume the packet.
2088e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2089e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
2090e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			      struct sk_buff *skb,
2091e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			      struct fc_rport_priv *rdata)
2092e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2093e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_header *fiph;
2094e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_desc *desc = NULL;
2095e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_mac_desc *macd = NULL;
2096e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_wwn_desc *wwn = NULL;
2097e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_vn_desc *vn = NULL;
2098e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_size_desc *size = NULL;
2099e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport;
2100e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	size_t rlen;
2101e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	size_t dlen;
2102e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u32 desc_mask = 0;
2103e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u32 dtype;
2104e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u8 sub;
2105e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2106e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
2107e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frport = fcoe_ctlr_rport(rdata);
2108e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2109e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fiph = (struct fip_header *)skb->data;
2110e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frport->flags = ntohs(fiph->fip_flags);
2111e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2112e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	sub = fiph->fip_subcode;
2113e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	switch (sub) {
2114e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_PROBE_REQ:
2115e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_PROBE_REP:
2116e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_BEACON:
2117e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
2118e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			    BIT(FIP_DT_VN_ID);
2119e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2120e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_CLAIM_NOTIFY:
2121e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_CLAIM_REP:
2122e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
2123e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			    BIT(FIP_DT_VN_ID) | BIT(FIP_DT_FC4F) |
2124e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			    BIT(FIP_DT_FCOE_SIZE);
2125e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2126e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	default:
2127e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub);
2128e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return -EINVAL;
2129e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2130e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2131e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rlen = ntohs(fiph->fip_dl_len) * 4;
2132e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (rlen + sizeof(*fiph) > skb->len)
2133e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return -EINVAL;
2134e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2135e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	desc = (struct fip_desc *)(fiph + 1);
2136e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	while (rlen > 0) {
2137e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		dlen = desc->fip_dlen * FIP_BPW;
2138e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (dlen < sizeof(*desc) || dlen > rlen)
2139e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			return -EINVAL;
2140e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2141e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		dtype = desc->fip_dtype;
2142e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (dtype < 32) {
2143e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (!(desc_mask & BIT(dtype))) {
2144e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				LIBFCOE_FIP_DBG(fip,
2145e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt						"unexpected or duplicated desc "
2146e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt						"desc type %u in "
2147e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt						"FIP VN2VN subtype %u\n",
2148e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt						dtype, sub);
2149e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return -EINVAL;
2150e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			}
2151e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			desc_mask &= ~BIT(dtype);
2152e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
2153e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2154e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		switch (dtype) {
2155e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_DT_MAC:
2156e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (dlen != sizeof(struct fip_mac_desc))
2157e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				goto len_err;
2158e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			macd = (struct fip_mac_desc *)desc;
2159e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (!is_valid_ether_addr(macd->fd_mac)) {
2160e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				LIBFCOE_FIP_DBG(fip,
2161e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					"Invalid MAC addr %pM in FIP VN2VN\n",
2162e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					 macd->fd_mac);
2163e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return -EINVAL;
2164e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			}
2165e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN);
2166e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2167e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_DT_NAME:
2168e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (dlen != sizeof(struct fip_wwn_desc))
2169e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				goto len_err;
2170e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			wwn = (struct fip_wwn_desc *)desc;
2171e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
2172e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2173e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_DT_VN_ID:
2174e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (dlen != sizeof(struct fip_vn_desc))
2175e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				goto len_err;
2176e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			vn = (struct fip_vn_desc *)desc;
2177e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN);
2178e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			rdata->ids.port_id = ntoh24(vn->fd_fc_id);
2179e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn);
2180e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2181e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_DT_FC4F:
2182e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (dlen != sizeof(struct fip_fc4_feat))
2183e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				goto len_err;
2184e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2185e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		case FIP_DT_FCOE_SIZE:
2186e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (dlen != sizeof(struct fip_size_desc))
2187e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				goto len_err;
2188e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			size = (struct fip_size_desc *)desc;
2189e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			frport->fcoe_len = ntohs(size->fd_size);
2190e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2191e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		default:
2192e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
2193e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					"in FIP probe\n", dtype);
2194e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			/* standard says ignore unknown descriptors >= 128 */
2195e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (dtype < FIP_DT_VENDOR_BASE)
2196e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				return -EINVAL;
2197e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2198e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
2199e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		desc = (struct fip_desc *)((char *)desc + dlen);
2200e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		rlen -= dlen;
2201e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2202e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	return 0;
2203e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2204e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtlen_err:
2205e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
2206e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			dtype, dlen);
2207e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	return -EINVAL;
2208e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2209e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2210e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2211e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_send_claim() - send multicast FIP VN2VN Claim Notification.
2212e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2213e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2214e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2215e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2216e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_send_claim(struct fcoe_ctlr *fip)
2217e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2218e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_NOTIFY, fcoe_all_vn2vn, 0);
2219e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fip->sol_time = jiffies;
2220e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2221e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2222e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2223e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_probe_req() - handle incoming VN2VN probe request.
2224e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2225e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @rdata: parsed remote port with frport from the probe request
2226e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2227e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2228e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2229e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip,
2230e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				   struct fc_rport_priv *rdata)
2231e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2232e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
2233e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2234e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (rdata->ids.port_id != fip->port_id)
2235e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2236e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2237e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	switch (fip->state) {
2238e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_CLAIM:
2239e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_UP:
2240e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
2241e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				  frport->enode_mac, 0);
2242e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2243e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE1:
2244e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE2:
2245e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		/*
2246e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * Decide whether to reply to the Probe.
2247e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * Our selected address is never a "recorded" one, so
2248e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * only reply if our WWPN is greater and the
2249e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * Probe's REC bit is not set.
2250e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * If we don't reply, we will change our address.
2251e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 */
2252e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (fip->lp->wwpn > rdata->ids.port_name &&
2253e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		    !(frport->flags & FIP_FL_REC_OR_P2P)) {
2254e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP,
2255e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					  frport->enode_mac, 0);
2256e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2257e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
2258e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		/* fall through */
2259e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_START:
2260e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_restart(fip);
2261e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2262e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	default:
2263e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2264e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2265e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2266e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2267e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2268e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_probe_reply() - handle incoming VN2VN probe reply.
2269e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2270e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @rdata: parsed remote port with frport from the probe request
2271e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2272e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2273e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2274e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip,
2275e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				   struct fc_rport_priv *rdata)
2276e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2277e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (rdata->ids.port_id != fip->port_id)
2278e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2279e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	switch (fip->state) {
2280e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_START:
2281e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE1:
2282e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE2:
2283e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_CLAIM:
2284e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_restart(fip);
2285e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2286e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_UP:
2287e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send_claim(fip);
2288e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2289e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	default:
2290e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2291e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2292e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2293e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2294e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2295e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_add() - Add a VN2VN entry to the list, based on a claim reply.
2296e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2297e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @new: newly-parsed remote port with frport as a template for new rdata
2298e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2299e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2300e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2301e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new)
2302e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2303e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_lport *lport = fip->lp;
2304e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_rport_priv *rdata;
2305e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_rport_identifiers *ids;
2306e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport;
2307e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u32 port_id;
2308e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2309e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	port_id = new->ids.port_id;
2310e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (port_id == fip->port_id)
2311e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2312e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2313e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&lport->disc.disc_mutex);
2314e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rdata = lport->tt.rport_create(lport, port_id);
2315e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (!rdata) {
2316e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		mutex_unlock(&lport->disc.disc_mutex);
2317e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2318e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2319e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2320e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rdata->ops = &fcoe_ctlr_vn_rport_ops;
2321e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rdata->disc_id = lport->disc.disc_id;
2322e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2323e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	ids = &rdata->ids;
2324e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) ||
2325e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	    (ids->node_name != -1 && ids->node_name != new->ids.node_name))
2326e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->tt.rport_logoff(rdata);
2327e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	ids->port_name = new->ids.port_name;
2328e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	ids->node_name = new->ids.node_name;
2329e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&lport->disc.disc_mutex);
2330e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2331e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frport = fcoe_ctlr_rport(rdata);
2332e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n",
2333e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			port_id, frport->fcoe_len ? "old" : "new");
2334e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	*frport = *fcoe_ctlr_rport(new);
2335e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frport->time = 0;
2336e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2337e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2338e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2339e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_lookup() - Find VN remote port's MAC address
2340e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2341e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @port_id:  The port_id of the remote VN_node
2342e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @mac: buffer which will hold the VN_NODE destination MAC address, if found.
2343e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2344e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Returns non-zero error if no remote port found.
2345e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2346e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac)
2347e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2348e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_lport *lport = fip->lp;
2349e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_rport_priv *rdata;
2350e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport;
2351e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	int ret = -1;
2352e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2353e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rcu_read_lock();
2354e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rdata = lport->tt.rport_lookup(lport, port_id);
2355e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (rdata) {
2356e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		frport = fcoe_ctlr_rport(rdata);
2357e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		memcpy(mac, frport->enode_mac, ETH_ALEN);
2358e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		ret = 0;
2359e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2360e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rcu_read_unlock();
2361e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	return ret;
2362e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2363e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2364e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2365e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_claim_notify() - handle received FIP VN2VN Claim Notification
2366e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2367e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @new: newly-parsed remote port with frport as a template for new rdata
2368e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2369e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2370e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2371e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip,
2372e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				      struct fc_rport_priv *new)
2373e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2374e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport = fcoe_ctlr_rport(new);
2375e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2376e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (frport->flags & FIP_FL_REC_OR_P2P) {
2377e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2378e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2379e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2380e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	switch (fip->state) {
2381e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_START:
2382e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE1:
2383e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE2:
2384e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (new->ids.port_id == fip->port_id)
2385e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_vn_restart(fip);
2386e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2387e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_CLAIM:
2388e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_UP:
2389e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (new->ids.port_id == fip->port_id) {
2390e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (new->ids.port_name > fip->lp->wwpn) {
2391e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				fcoe_ctlr_vn_restart(fip);
2392e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				break;
2393e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			}
2394e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_vn_send_claim(fip);
2395e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			break;
2396e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
2397e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac,
2398e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				  min((u32)frport->fcoe_len,
2399e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				      fcoe_ctlr_fcoe_size(fip)));
2400e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_add(fip, new);
2401e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2402e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	default:
2403e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2404e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2405e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2406e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2407e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2408e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_claim_resp() - handle received Claim Response
2409e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller that received the frame
2410e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @new: newly-parsed remote port with frport from the Claim Response
2411e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2412e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2413e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2414e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip,
2415e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				    struct fc_rport_priv *new)
2416e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2417e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	LIBFCOE_FIP_DBG(fip, "claim resp from from rport %x - state %s\n",
2418e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			new->ids.port_id, fcoe_ctlr_state(fip->state));
2419e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->state == FIP_ST_VNMP_UP || fip->state == FIP_ST_VNMP_CLAIM)
2420e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_add(fip, new);
2421e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2422e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2423e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2424e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_beacon() - handle received beacon.
2425e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller that received the frame
2426e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @new: newly-parsed remote port with frport from the Beacon
2427e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2428e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2429e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2430e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip,
2431e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				struct fc_rport_priv *new)
2432e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2433e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_lport *lport = fip->lp;
2434e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_rport_priv *rdata;
2435e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport;
2436e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2437e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	frport = fcoe_ctlr_rport(new);
2438e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (frport->flags & FIP_FL_REC_OR_P2P) {
2439e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2440e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2441e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2442e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&lport->disc.disc_mutex);
2443e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rdata = lport->tt.rport_lookup(lport, new->ids.port_id);
2444e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (rdata)
2445e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		kref_get(&rdata->kref);
2446e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&lport->disc.disc_mutex);
2447e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (rdata) {
2448e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (rdata->ids.node_name == new->ids.node_name &&
2449e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		    rdata->ids.port_name == new->ids.port_name) {
2450e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			frport = fcoe_ctlr_rport(rdata);
2451e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			if (!frport->time && fip->state == FIP_ST_VNMP_UP)
2452e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				lport->tt.rport_login(rdata);
2453e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			frport->time = jiffies;
2454e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
2455e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		kref_put(&rdata->kref, lport->tt.rport_destroy);
2456e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2457e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2458e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->state != FIP_ST_VNMP_UP)
2459e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		return;
2460e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2461e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	/*
2462e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * Beacon from a new neighbor.
2463e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * Send a claim notify if one hasn't been sent recently.
2464e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 * Don't add the neighbor yet.
2465e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	 */
2466e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	LIBFCOE_FIP_DBG(fip, "beacon from new rport %x. sending claim notify\n",
2467e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			new->ids.port_id);
2468e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (time_after(jiffies,
2469e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		       fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT)))
2470e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send_claim(fip);
2471e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2472e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2473e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2474e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_age() - Check for VN_ports without recent beacons
2475e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2476e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2477e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called with ctlr_mutex held.
2478e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Called only in state FIP_ST_VNMP_UP.
2479e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Returns the soonest time for next age-out or a time far in the future.
2480e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2481e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip)
2482e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2483e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_lport *lport = fip->lp;
2484e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_rport_priv *rdata;
2485e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport;
2486e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	unsigned long next_time;
2487e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	unsigned long deadline;
2488e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2489e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10);
2490e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&lport->disc.disc_mutex);
2491e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) {
2492e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		frport = fcoe_ctlr_rport(rdata);
2493e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (!frport->time)
2494e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			continue;
2495e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		deadline = frport->time +
2496e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			   msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10);
2497e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (time_after_eq(jiffies, deadline)) {
2498e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			frport->time = 0;
2499e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			LIBFCOE_FIP_DBG(fip,
2500e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				"port %16.16llx fc_id %6.6x beacon expired\n",
2501e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				rdata->ids.port_name, rdata->ids.port_id);
2502e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			lport->tt.rport_logoff(rdata);
2503e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		} else if (time_before(deadline, next_time))
2504e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			next_time = deadline;
2505e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2506e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&lport->disc.disc_mutex);
2507e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	return next_time;
2508e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2509e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2510e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2511e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_recv() - Receive a FIP frame
2512e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller that received the frame
2513e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @skb: The received FIP frame
2514e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2515e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Returns non-zero if the frame is dropped.
2516e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Always consumes the frame.
2517e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2518e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
2519e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2520e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fip_header *fiph;
2521e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	enum fip_vn2vn_subcode sub;
25222dc02ee52f32aac6d8dd1172f104dc30ae1051bbKiran Patil	struct {
2523e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		struct fc_rport_priv rdata;
2524e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		struct fcoe_rport frport;
2525e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	} buf;
2526e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	int rc;
2527e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2528e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fiph = (struct fip_header *)skb->data;
2529e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	sub = fiph->fip_subcode;
2530e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2531e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata);
2532e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (rc) {
2533e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc);
2534e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		goto drop;
2535e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2536e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2537e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&fip->ctlr_mutex);
2538e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	switch (sub) {
2539e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_PROBE_REQ:
2540e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_probe_req(fip, &buf.rdata);
2541e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2542e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_PROBE_REP:
2543e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_probe_reply(fip, &buf.rdata);
2544e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2545e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_CLAIM_NOTIFY:
2546e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_claim_notify(fip, &buf.rdata);
2547e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2548e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_CLAIM_REP:
2549e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_claim_resp(fip, &buf.rdata);
2550e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2551e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_SC_VN_BEACON:
2552e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_beacon(fip, &buf.rdata);
2553e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2554e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	default:
2555e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub);
2556e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		rc = -1;
2557e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2558e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2559e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&fip->ctlr_mutex);
2560e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtdrop:
2561e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	kfree_skb(skb);
2562e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	return rc;
2563e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2564e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2565e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2566e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode.
2567922611569572d3c1aa0ed6491d21583fb3fcca22Joe Eykholt * @lport: The local port
2568922611569572d3c1aa0ed6491d21583fb3fcca22Joe Eykholt * @fp: The received frame
2569e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2570e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * This should never be called since we don't see RSCNs or other
2571e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fabric-generated ELSes.
2572e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2573922611569572d3c1aa0ed6491d21583fb3fcca22Joe Eykholtstatic void fcoe_ctlr_disc_recv(struct fc_lport *lport, struct fc_frame *fp)
2574e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2575e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_seq_els_data rjt_data;
2576e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2577e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rjt_data.reason = ELS_RJT_UNSUP;
2578e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	rjt_data.explan = ELS_EXPL_NONE;
2579922611569572d3c1aa0ed6491d21583fb3fcca22Joe Eykholt	lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
2580e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	fc_frame_free(fp);
2581e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2582e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2583e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2584e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_disc_recv - start discovery for VN2VN mode.
2585e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2586e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2587e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * This sets a flag indicating that remote ports should be created
2588e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * and started for the peers we discover.  We use the disc_callback
2589e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * pointer as that flag.  Peers already discovered are created here.
2590e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2591e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * The lport lock is held during this call. The callback must be done
2592e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * later, without holding either the lport or discovery locks.
2593e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * The fcoe_ctlr lock may also be held during this call.
2594e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2595e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_disc_start(void (*callback)(struct fc_lport *,
2596e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt						  enum fc_disc_event),
2597e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				 struct fc_lport *lport)
2598e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2599e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_disc *disc = &lport->disc;
2600e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_ctlr *fip = disc->priv;
2601e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2602e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&disc->disc_mutex);
2603e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	disc->disc_callback = callback;
2604e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	disc->disc_id = (disc->disc_id + 2) | 1;
2605e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	disc->pending = 1;
2606e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	schedule_work(&fip->timer_work);
2607e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&disc->disc_mutex);
2608e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2609e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2610e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2611e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_disc() - report FIP VN_port discovery results after claim state.
2612e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2613e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt *
2614e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Starts the FLOGI and PLOGI login process to each discovered rport for which
2615e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * we've received at least one beacon.
2616e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * Performs the discovery complete callback.
2617e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2618e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip)
2619e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2620e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_lport *lport = fip->lp;
2621e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_disc *disc = &lport->disc;
2622e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fc_rport_priv *rdata;
2623e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	struct fcoe_rport *frport;
2624e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	void (*callback)(struct fc_lport *, enum fc_disc_event);
2625e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2626e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&disc->disc_mutex);
2627e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	callback = disc->pending ? disc->disc_callback : NULL;
2628e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	disc->pending = 0;
2629e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	list_for_each_entry_rcu(rdata, &disc->rports, peers) {
2630e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		frport = fcoe_ctlr_rport(rdata);
2631e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (frport->time)
2632e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			lport->tt.rport_login(rdata);
2633e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2634e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&disc->disc_mutex);
2635e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (callback)
2636e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		callback(lport, DISC_EV_SUCCESS);
2637e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2638e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2639e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
2640e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * fcoe_ctlr_vn_timeout - timer work function for VN2VN mode.
2641e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller
2642e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt */
2643e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtstatic void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
2644e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt{
2645e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	unsigned long next_time;
2646e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u8 mac[ETH_ALEN];
2647e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	u32 new_port_id = 0;
2648e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2649e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_lock(&fip->ctlr_mutex);
2650e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	switch (fip->state) {
2651e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_START:
2652e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE1);
2653e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2654e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		next_time = jiffies + msecs_to_jiffies(FIP_VN_PROBE_WAIT);
2655e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2656e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE1:
2657e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE2);
2658e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
2659e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2660e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2661e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_PROBE2:
2662e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_set_state(fip, FIP_ST_VNMP_CLAIM);
2663e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		new_port_id = fip->port_id;
2664e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		hton24(mac, FIP_VN_FC_MAP);
2665e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		hton24(mac + 3, new_port_id);
2666cd229e42eb8cdfdcbe15dfeec39c3641f62de43aJoe Eykholt		fcoe_ctlr_map_dest(fip);
2667e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fip->update_mac(fip->lp, mac);
2668e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_send_claim(fip);
2669e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2670e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2671e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_CLAIM:
2672e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		/*
2673e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * This may be invoked either by starting discovery so don't
2674e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 * go to the next state unless it's been long enough.
2675e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		 */
2676e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		next_time = fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2677e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (time_after_eq(jiffies, next_time)) {
2678e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_set_state(fip, FIP_ST_VNMP_UP);
2679e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
2680e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					  fcoe_all_vn2vn, 0);
2681e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
2682e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fip->port_ka_time = next_time;
2683e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
2684e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fcoe_ctlr_vn_disc(fip);
2685e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2686e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_VNMP_UP:
2687e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		next_time = fcoe_ctlr_vn_age(fip);
2688e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (time_after_eq(jiffies, fip->port_ka_time)) {
2689e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON,
2690e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					  fcoe_all_vn2vn, 0);
2691e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			fip->port_ka_time = jiffies +
2692e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt				 msecs_to_jiffies(FIP_VN_BEACON_INT +
2693e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt					(random32() % FIP_VN_BEACON_FUZZ));
2694e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		}
2695e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		if (time_before(fip->port_ka_time, next_time))
2696e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt			next_time = fip->port_ka_time;
2697e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		break;
2698e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	case FIP_ST_LINK_WAIT:
2699e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		goto unlock;
2700e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	default:
270111aa99001afdbe5fe152e833aa1fea82b85dbedaJoe Perches		WARN(1, "unexpected state %d\n", fip->state);
2702e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		goto unlock;
2703e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
2704e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mod_timer(&fip->timer, next_time);
2705e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtunlock:
2706e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	mutex_unlock(&fip->ctlr_mutex);
2707e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2708e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	/* If port ID is new, notify local port after dropping ctlr_mutex */
2709e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (new_port_id)
2710e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fc_lport_set_local_id(fip->lp, new_port_id);
2711e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt}
2712e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt
2713e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt/**
271470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * fcoe_libfc_config() - Sets up libfc related properties for local port
271570b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @lp: The local port to configure libfc for
2716e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @fip: The FCoE controller in use by the local port
271770b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love * @tt: The libfc function template
2718e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt * @init_fcp: If non-zero, the FCP portion of libfc should be initialized
27195e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev *
27205e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev * Returns : 0 for success
27215e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev */
2722e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholtint fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
2723e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		      const struct libfc_function_template *tt, int init_fcp)
27245e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev{
27255e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	/* Set the function pointers set by the LLDD */
272670b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	memcpy(&lport->tt, tt, sizeof(*tt));
2727e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (init_fcp && fc_fcp_init(lport))
27285e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev		return -ENOMEM;
272970b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	fc_exch_init(lport);
273070b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	fc_elsct_init(lport);
273170b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	fc_lport_init(lport);
2732e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->mode == FIP_MODE_VN2VN)
2733e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->rport_priv_size = sizeof(struct fcoe_rport);
273470b51aabf3b03fbf8d61c14847ccce4c69fb0cddRobert Love	fc_rport_init(lport);
2735e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	if (fip->mode == FIP_MODE_VN2VN) {
2736e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->point_to_multipoint = 1;
2737e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
2738e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->tt.disc_start = fcoe_ctlr_disc_start;
2739e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->tt.disc_stop = fcoe_ctlr_disc_stop;
2740e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
2741e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		mutex_init(&lport->disc.disc_mutex);
2742e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		INIT_LIST_HEAD(&lport->disc.rports);
2743e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		lport->disc.priv = fip;
2744e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	} else {
2745e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt		fc_disc_init(lport);
2746e10f8c667b874a57512c936089092a3d1ef7ab8aJoe Eykholt	}
27475e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev	return 0;
27485e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu Dev}
27495e80f7f7c87990ffe7856a0d35a94ea52b8f4c59Vasu DevEXPORT_SYMBOL_GPL(fcoe_libfc_config);
2750