/*
* Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Maintained at www.Open-FCoE.org
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/errno.h>
#include <linux/bitops.h>
#include <net/rtnetlink.h>
#include <scsi/fc/fc_els.h>
#include <scsi/fc/fc_fs.h>
#include <scsi/fc/fc_fip.h>
#include <scsi/fc/fc_encaps.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/libfc.h>
#include <scsi/libfcoe.h>
MODULE_AUTHOR("Open-FCoE.org");
MODULE_DESCRIPTION("FIP discovery protocol support for FCoE HBAs");
MODULE_LICENSE("GPL v2");
#define FCOE_CTLR_MIN_FKA 500 /* min keep alive (mS) */
#define FCOE_CTLR_DEF_FKA FIP_DEF_FKA /* default keep alive (mS) */
static void fcoe_ctlr_timeout(unsigned long);
static void fcoe_ctlr_link_work(struct work_struct *);
static void fcoe_ctlr_recv_work(struct work_struct *);
static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
unsigned int libfcoe_debug_logging;
module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
do { \
if (unlikely(libfcoe_debug_logging & LEVEL)) \
do { \
CMD; \
} while (0); \
} while (0)
#define LIBFCOE_DBG(fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
printk(KERN_INFO "libfcoe: " fmt, ##args);)
#define LIBFCOE_FIP_DBG(fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \
printk(KERN_INFO "fip: " fmt, ##args);)
/*
* Return non-zero if FCF fcoe_size has been validated.
*/
static inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf)
{
return (fcf->flags & FIP_FL_SOL) != 0;
}
/*
* Return non-zero if the FCF is usable.
*/
static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
{
u16 flags = FIP_FL_SOL | FIP_FL_AVAIL;
return (fcf->flags & flags) == flags;
}
/**
* fcoe_ctlr_init() - Initialize the FCoE Controller instance.
* @fip: FCoE controller.
*/
void fcoe_ctlr_init(struct fcoe_ctlr *fip)
{
fip->state = FIP_ST_LINK_WAIT;
INIT_LIST_HEAD(&fip->fcfs);
spin_lock_init(&fip->lock);
fip->flogi_oxid = FC_XID_UNKNOWN;
setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
INIT_WORK(&fip->link_work, fcoe_ctlr_link_work);
INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
skb_queue_head_init(&fip->fip_recv_list);
}
EXPORT_SYMBOL(fcoe_ctlr_init);
/**
* fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller.
* @fip: FCoE controller.
*
* Called with &fcoe_ctlr lock held.
*/
static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
struct fcoe_fcf *next;
fip->sel_fcf = NULL;
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
list_del(&fcf->list);
kfree(fcf);
}
fip->fcf_count = 0;
fip->sel_time = 0;
}
/**
* fcoe_ctlr_destroy() - Disable and tear-down the FCoE controller.
* @fip: FCoE controller.
*
* This is called by FCoE drivers before freeing the &fcoe_ctlr.
*
* The receive handler will have been deleted before this to guarantee
* that no more recv_work will be scheduled.
*
* The timer routine will simply return once we set FIP_ST_DISABLED.
* This guarantees that no further timeouts or work will be scheduled.
*/
void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
{
cancel_work_sync(&fip->recv_work);
spin_lock_bh(&fip->fip_recv_list.lock);
__skb_queue_purge(&fip->fip_recv_list);
spin_unlock_bh(&fip->fip_recv_list.lock);
spin_lock_bh(&fip->lock);
fip->state = FIP_ST_DISABLED;
fcoe_ctlr_reset_fcfs(
|