Commit 3e34c1fc authored by James Bottomley's avatar James Bottomley

[SCSI] Merge tag 'fcoe-02-19-13' into for-linus

FCoE Updates for 3.9
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parents c157750a 1f953b0d
What: /sys/bus/fcoe/ctlr_X What: /sys/bus/fcoe/
Date: August 2012
KernelVersion: TBD
Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org
Description: The FCoE bus. Attributes in this directory are control interfaces.
Attributes:
ctlr_create: 'FCoE Controller' instance creation interface. Writing an
<ifname> to this file will allocate and populate sysfs with a
fcoe_ctlr_device (ctlr_X). The user can then configure any
per-port settings and finally write to the fcoe_ctlr_device's
'start' attribute to begin the kernel's discovery and login
process.
ctlr_destroy: 'FCoE Controller' instance removal interface. Writing a
fcoe_ctlr_device's sysfs name to this file will log the
fcoe_ctlr_device out of the fabric or otherwise connected
FCoE devices. It will also free all kernel memory allocated
for this fcoe_ctlr_device and any structures associated
with it, this includes the scsi_host.
What: /sys/bus/fcoe/devices/ctlr_X
Date: March 2012 Date: March 2012
KernelVersion: TBD KernelVersion: TBD
Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org
Description: 'FCoE Controller' instances on the fcoe bus Description: 'FCoE Controller' instances on the fcoe bus.
The FCoE Controller now has a three stage creation process.
1) Write interface name to ctlr_create 2) Configure the FCoE
Controller (ctlr_X) 3) Enable the FCoE Controller to begin
discovery and login. The FCoE Controller is destroyed by
writing it's name, i.e. ctlr_X to the ctlr_delete file.
Attributes: Attributes:
fcf_dev_loss_tmo: Device loss timeout peroid (see below). Changing fcf_dev_loss_tmo: Device loss timeout peroid (see below). Changing
this value will change the dev_loss_tmo for all this value will change the dev_loss_tmo for all
FCFs discovered by this controller. FCFs discovered by this controller.
mode: Display or change the FCoE Controller's mode. Possible
modes are 'Fabric' and 'VN2VN'. If a FCoE Controller
is started in 'Fabric' mode then FIP FCF discovery is
initiated and ultimately a fabric login is attempted.
If a FCoE Controller is started in 'VN2VN' mode then
FIP VN2VN discovery and login is performed. A FCoE
Controller only supports one mode at a time.
enabled: Whether an FCoE controller is enabled or disabled.
0 if disabled, 1 if enabled. Writing either 0 or 1
to this file will enable or disable the FCoE controller.
lesb/link_fail: Link Error Status Block (LESB) link failure count. lesb/link_fail: Link Error Status Block (LESB) link failure count.
lesb/vlink_fail: Link Error Status Block (LESB) virtual link lesb/vlink_fail: Link Error Status Block (LESB) virtual link
...@@ -26,7 +65,7 @@ Attributes: ...@@ -26,7 +65,7 @@ Attributes:
Notes: ctlr_X (global increment starting at 0) Notes: ctlr_X (global increment starting at 0)
What: /sys/bus/fcoe/fcf_X What: /sys/bus/fcoe/devices/fcf_X
Date: March 2012 Date: March 2012
KernelVersion: TBD KernelVersion: TBD
Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org
......
This diff is collapsed.
This diff is collapsed.
...@@ -55,11 +55,11 @@ do { \ ...@@ -55,11 +55,11 @@ do { \
#define FCOE_DBG(fmt, args...) \ #define FCOE_DBG(fmt, args...) \
FCOE_CHECK_LOGGING(FCOE_LOGGING, \ FCOE_CHECK_LOGGING(FCOE_LOGGING, \
printk(KERN_INFO "fcoe: " fmt, ##args);) pr_info("fcoe: " fmt, ##args);)
#define FCOE_NETDEV_DBG(netdev, fmt, args...) \ #define FCOE_NETDEV_DBG(netdev, fmt, args...) \
FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \ FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \
printk(KERN_INFO "fcoe: %s: " fmt, \ pr_info("fcoe: %s: " fmt, \
netdev->name, ##args);) netdev->name, ##args);)
/** /**
......
...@@ -1291,8 +1291,16 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, ...@@ -1291,8 +1291,16 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
if (!fcf || !lport->port_id) if (!fcf || !lport->port_id) {
/*
* We are yet to select best FCF, but we got CVL in the
* meantime. reset the ctlr and let it rediscover the FCF
*/
mutex_lock(&fip->ctlr_mutex);
fcoe_ctlr_reset(fip);
mutex_unlock(&fip->ctlr_mutex);
return; return;
}
/* /*
* mask of required descriptors. Validating each one clears its bit. * mask of required descriptors. Validating each one clears its bit.
...@@ -1551,15 +1559,6 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip) ...@@ -1551,15 +1559,6 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
fcf->fabric_name, fcf->vfid, fcf->fcf_mac, fcf->fabric_name, fcf->vfid, fcf->fcf_mac,
fcf->fc_map, fcoe_ctlr_mtu_valid(fcf), fcf->fc_map, fcoe_ctlr_mtu_valid(fcf),
fcf->flogi_sent, fcf->pri); fcf->flogi_sent, fcf->pri);
if (fcf->fabric_name != first->fabric_name ||
fcf->vfid != first->vfid ||
fcf->fc_map != first->fc_map) {
LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
"or FC-MAP\n");
return NULL;
}
if (fcf->flogi_sent)
continue;
if (!fcoe_ctlr_fcf_usable(fcf)) { if (!fcoe_ctlr_fcf_usable(fcf)) {
LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx " LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
"map %x %svalid %savailable\n", "map %x %svalid %savailable\n",
...@@ -1569,6 +1568,15 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip) ...@@ -1569,6 +1568,15 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
"" : "un"); "" : "un");
continue; continue;
} }
if (fcf->fabric_name != first->fabric_name ||
fcf->vfid != first->vfid ||
fcf->fc_map != first->fc_map) {
LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
"or FC-MAP\n");
return NULL;
}
if (fcf->flogi_sent)
continue;
if (!best || fcf->pri < best->pri || best->flogi_sent) if (!best || fcf->pri < best->pri || best->flogi_sent)
best = fcf; best = fcf;
} }
...@@ -2864,22 +2872,21 @@ void fcoe_fcf_get_selected(struct fcoe_fcf_device *fcf_dev) ...@@ -2864,22 +2872,21 @@ void fcoe_fcf_get_selected(struct fcoe_fcf_device *fcf_dev)
} }
EXPORT_SYMBOL(fcoe_fcf_get_selected); EXPORT_SYMBOL(fcoe_fcf_get_selected);
void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *ctlr_dev) void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
{ {
struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
mutex_lock(&ctlr->ctlr_mutex); mutex_lock(&ctlr->ctlr_mutex);
switch (ctlr->mode) { switch (ctlr_dev->mode) {
case FIP_MODE_FABRIC: case FIP_CONN_TYPE_VN2VN:
ctlr_dev->mode = FIP_CONN_TYPE_FABRIC; ctlr->mode = FIP_MODE_VN2VN;
break;
case FIP_MODE_VN2VN:
ctlr_dev->mode = FIP_CONN_TYPE_VN2VN;
break; break;
case FIP_CONN_TYPE_FABRIC:
default: default:
ctlr_dev->mode = FIP_CONN_TYPE_UNKNOWN; ctlr->mode = FIP_MODE_FABRIC;
break; break;
} }
mutex_unlock(&ctlr->ctlr_mutex); mutex_unlock(&ctlr->ctlr_mutex);
} }
EXPORT_SYMBOL(fcoe_ctlr_get_fip_mode); EXPORT_SYMBOL(fcoe_ctlr_set_fip_mode);
...@@ -21,8 +21,17 @@ ...@@ -21,8 +21,17 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ctype.h>
#include <scsi/fcoe_sysfs.h> #include <scsi/fcoe_sysfs.h>
#include <scsi/libfcoe.h>
/*
* OK to include local libfcoe.h for debug_logging, but cannot include
* <scsi/libfcoe.h> otherwise non-netdev based fcoe solutions would have
* have to include more than fcoe_sysfs.h.
*/
#include "libfcoe.h"
static atomic_t ctlr_num; static atomic_t ctlr_num;
static atomic_t fcf_num; static atomic_t fcf_num;
...@@ -71,6 +80,8 @@ MODULE_PARM_DESC(fcf_dev_loss_tmo, ...@@ -71,6 +80,8 @@ MODULE_PARM_DESC(fcf_dev_loss_tmo,
((x)->lesb.lesb_err_block) ((x)->lesb.lesb_err_block)
#define fcoe_ctlr_fcs_error(x) \ #define fcoe_ctlr_fcs_error(x) \
((x)->lesb.lesb_fcs_error) ((x)->lesb.lesb_fcs_error)
#define fcoe_ctlr_enabled(x) \
((x)->enabled)
#define fcoe_fcf_state(x) \ #define fcoe_fcf_state(x) \
((x)->state) ((x)->state)
#define fcoe_fcf_fabric_name(x) \ #define fcoe_fcf_fabric_name(x) \
...@@ -210,25 +221,34 @@ static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \ ...@@ -210,25 +221,34 @@ static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \
#define fcoe_enum_name_search(title, table_type, table) \ #define fcoe_enum_name_search(title, table_type, table) \
static const char *get_fcoe_##title##_name(enum table_type table_key) \ static const char *get_fcoe_##title##_name(enum table_type table_key) \
{ \ { \
int i; \ if (table_key < 0 || table_key >= ARRAY_SIZE(table)) \
char *name = NULL; \ return NULL; \
\ return table[table_key]; \
for (i = 0; i < ARRAY_SIZE(table); i++) { \
if (table[i].value == table_key) { \
name = table[i].name; \
break; \
} \
} \
return name; \
} }
static struct { static char *fip_conn_type_names[] = {
enum fcf_state value; [ FIP_CONN_TYPE_UNKNOWN ] = "Unknown",
char *name; [ FIP_CONN_TYPE_FABRIC ] = "Fabric",
} fcf_state_names[] = { [ FIP_CONN_TYPE_VN2VN ] = "VN2VN",
{ FCOE_FCF_STATE_UNKNOWN, "Unknown" }, };
{ FCOE_FCF_STATE_DISCONNECTED, "Disconnected" }, fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)
{ FCOE_FCF_STATE_CONNECTED, "Connected" },
static enum fip_conn_type fcoe_parse_mode(const char *buf)
{
int i;
for (i = 0; i < ARRAY_SIZE(fip_conn_type_names); i++) {
if (strcasecmp(buf, fip_conn_type_names[i]) == 0)
return i;
}
return FIP_CONN_TYPE_UNKNOWN;
}
static char *fcf_state_names[] = {
[ FCOE_FCF_STATE_UNKNOWN ] = "Unknown",
[ FCOE_FCF_STATE_DISCONNECTED ] = "Disconnected",
[ FCOE_FCF_STATE_CONNECTED ] = "Connected",
}; };
fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names) fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names)
#define FCOE_FCF_STATE_MAX_NAMELEN 50 #define FCOE_FCF_STATE_MAX_NAMELEN 50
...@@ -246,17 +266,7 @@ static ssize_t show_fcf_state(struct device *dev, ...@@ -246,17 +266,7 @@ static ssize_t show_fcf_state(struct device *dev,
} }
static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL); static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL);
static struct { #define FCOE_MAX_MODENAME_LEN 20
enum fip_conn_type value;
char *name;
} fip_conn_type_names[] = {
{ FIP_CONN_TYPE_UNKNOWN, "Unknown" },
{ FIP_CONN_TYPE_FABRIC, "Fabric" },
{ FIP_CONN_TYPE_VN2VN, "VN2VN" },
};
fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)
#define FCOE_CTLR_MODE_MAX_NAMELEN 50
static ssize_t show_ctlr_mode(struct device *dev, static ssize_t show_ctlr_mode(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
...@@ -264,17 +274,116 @@ static ssize_t show_ctlr_mode(struct device *dev, ...@@ -264,17 +274,116 @@ static ssize_t show_ctlr_mode(struct device *dev,
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
const char *name; const char *name;
if (ctlr->f->get_fcoe_ctlr_mode)
ctlr->f->get_fcoe_ctlr_mode(ctlr);
name = get_fcoe_ctlr_mode_name(ctlr->mode); name = get_fcoe_ctlr_mode_name(ctlr->mode);
if (!name) if (!name)
return -EINVAL; return -EINVAL;
return snprintf(buf, FCOE_CTLR_MODE_MAX_NAMELEN, return snprintf(buf, FCOE_MAX_MODENAME_LEN,
"%s\n", name); "%s\n", name);
} }
static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO,
show_ctlr_mode, NULL); static ssize_t store_ctlr_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
char mode[FCOE_MAX_MODENAME_LEN + 1];
if (count > FCOE_MAX_MODENAME_LEN)
return -EINVAL;
strncpy(mode, buf, count);
if (mode[count - 1] == '\n')
mode[count - 1] = '\0';
else
mode[count] = '\0';
switch (ctlr->enabled) {
case FCOE_CTLR_ENABLED:
LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled.");
return -EBUSY;
case FCOE_CTLR_DISABLED:
if (!ctlr->f->set_fcoe_ctlr_mode) {
LIBFCOE_SYSFS_DBG(ctlr,
"Mode change not supported by LLD.");
return -ENOTSUPP;
}
ctlr->mode = fcoe_parse_mode(mode);
if (ctlr->mode == FIP_CONN_TYPE_UNKNOWN) {
LIBFCOE_SYSFS_DBG(ctlr,
"Unknown mode %s provided.", buf);
return -EINVAL;
}
ctlr->f->set_fcoe_ctlr_mode(ctlr);
LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.", buf);
return count;
case FCOE_CTLR_UNUSED:
default:
LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.");
return -ENOTSUPP;
};
}
static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO | S_IWUSR,
show_ctlr_mode, store_ctlr_mode);
static ssize_t store_ctlr_enabled(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
int rc;
switch (ctlr->enabled) {
case FCOE_CTLR_ENABLED:
if (*buf == '1')
return count;
ctlr->enabled = FCOE_CTLR_DISABLED;
break;
case FCOE_CTLR_DISABLED:
if (*buf == '0')
return count;
ctlr->enabled = FCOE_CTLR_ENABLED;
break;
case FCOE_CTLR_UNUSED:
return -ENOTSUPP;
};
rc = ctlr->f->set_fcoe_ctlr_enabled(ctlr);
if (rc)
return rc;
return count;
}
static char *ctlr_enabled_state_names[] = {
[ FCOE_CTLR_ENABLED ] = "1",
[ FCOE_CTLR_DISABLED ] = "0",
};
fcoe_enum_name_search(ctlr_enabled_state, ctlr_enabled_state,
ctlr_enabled_state_names)
#define FCOE_CTLR_ENABLED_MAX_NAMELEN 50
static ssize_t show_ctlr_enabled_state(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
const char *name;
name = get_fcoe_ctlr_enabled_state_name(ctlr->enabled);
if (!name)
return -EINVAL;
return snprintf(buf, FCOE_CTLR_ENABLED_MAX_NAMELEN,
"%s\n", name);
}
static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR,
show_ctlr_enabled_state,
store_ctlr_enabled);
static ssize_t static ssize_t
store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev, store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev,
...@@ -359,6 +468,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = { ...@@ -359,6 +468,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = {
static struct attribute *fcoe_ctlr_attrs[] = { static struct attribute *fcoe_ctlr_attrs[] = {
&device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr, &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr,
&device_attr_fcoe_ctlr_enabled.attr,
&device_attr_fcoe_ctlr_mode.attr, &device_attr_fcoe_ctlr_mode.attr,
NULL, NULL,
}; };
...@@ -443,9 +553,16 @@ struct device_type fcoe_fcf_device_type = { ...@@ -443,9 +553,16 @@ struct device_type fcoe_fcf_device_type = {
.release = fcoe_fcf_device_release, .release = fcoe_fcf_device_release,
}; };
struct bus_attribute fcoe_bus_attr_group[] = {
__ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store),
__ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store),
__ATTR_NULL
};
struct bus_type fcoe_bus_type = { struct bus_type fcoe_bus_type = {
.name = "fcoe", .name = "fcoe",
.match = &fcoe_bus_match, .match = &fcoe_bus_match,
.bus_attrs = fcoe_bus_attr_group,
}; };
/** /**
...@@ -566,6 +683,7 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, ...@@ -566,6 +683,7 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent,
ctlr->id = atomic_inc_return(&ctlr_num) - 1; ctlr->id = atomic_inc_return(&ctlr_num) - 1;
ctlr->f = f; ctlr->f = f;
ctlr->mode = FIP_CONN_TYPE_FABRIC;
INIT_LIST_HEAD(&ctlr->fcfs); INIT_LIST_HEAD(&ctlr->fcfs);
mutex_init(&ctlr->lock); mutex_init(&ctlr->lock);
ctlr->dev.parent = parent; ctlr->dev.parent = parent;
......
...@@ -83,6 +83,50 @@ static struct notifier_block libfcoe_notifier = { ...@@ -83,6 +83,50 @@ static struct notifier_block libfcoe_notifier = {
.notifier_call = libfcoe_device_notification, .notifier_call = libfcoe_device_notification,
}; };
/**
* fcoe_link_speed_update() - Update the supported and actual link speeds
* @lport: The local port to update speeds for
*
* Returns: 0 if the ethtool query was successful
* -1 if the ethtool query failed
*/
int fcoe_link_speed_update(struct fc_lport *lport)
{
struct net_device *netdev = fcoe_get_netdev(lport);
struct ethtool_cmd ecmd;
if (!__ethtool_get_settings(netdev, &ecmd)) {
lport->link_supported_speeds &=
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full))
lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
if (ecmd.supported & SUPPORTED_10000baseT_Full)
lport->link_supported_speeds |=
FC_PORTSPEED_10GBIT;
switch (ethtool_cmd_speed(&ecmd)) {
case SPEED_1000:
lport->link_speed = FC_PORTSPEED_1GBIT;
break;
case SPEED_10000:
lport->link_speed = FC_PORTSPEED_10GBIT;
break;
}
return 0;
}
return -1;
}
EXPORT_SYMBOL_GPL(fcoe_link_speed_update);
/**
* __fcoe_get_lesb() - Get the Link Error Status Block (LESB) for a given lport
* @lport: The local port to update speeds for
* @fc_lesb: Pointer to the LESB to be filled up
* @netdev: Pointer to the netdev that is associated with the lport
*
* Note, the Link Error Status Block (LESB) for FCoE is defined in FC-BB-6
* Clause 7.11 in v1.04.
*/
void __fcoe_get_lesb(struct fc_lport *lport, void __fcoe_get_lesb(struct fc_lport *lport,
struct fc_els_lesb *fc_lesb, struct fc_els_lesb *fc_lesb,
struct net_device *netdev) struct net_device *netdev)
...@@ -112,6 +156,51 @@ void __fcoe_get_lesb(struct fc_lport *lport, ...@@ -112,6 +156,51 @@ void __fcoe_get_lesb(struct fc_lport *lport,
} }
EXPORT_SYMBOL_GPL(__fcoe_get_lesb); EXPORT_SYMBOL_GPL(__fcoe_get_lesb);
/**
* fcoe_get_lesb() - Fill the FCoE Link Error Status Block
* @lport: the local port
* @fc_lesb: the link error status block
*/
void fcoe_get_lesb(struct fc_lport *lport,
struct fc_els_lesb *fc_lesb)
{
struct net_device *netdev = fcoe_get_netdev(lport);
__fcoe_get_lesb(lport, fc_lesb, netdev);
}
EXPORT_SYMBOL_GPL(fcoe_get_lesb);
/**
* fcoe_ctlr_get_lesb() - Get the Link Error Status Block (LESB) for a given
* fcoe controller device
* @ctlr_dev: The given fcoe controller device
*
*/
void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
{
struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
struct net_device *netdev = fcoe_get_netdev(fip->lp);
struct fcoe_fc_els_lesb *fcoe_lesb;
struct fc_els_lesb fc_lesb;
__fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
ctlr_dev->lesb.lesb_link_fail =
ntohl(fcoe_lesb->lesb_link_fail);
ctlr_dev->lesb.lesb_vlink_fail =
ntohl(fcoe_lesb->lesb_vlink_fail);
ctlr_dev->lesb.lesb_miss_fka =
ntohl(fcoe_lesb->lesb_miss_fka);
ctlr_dev->lesb.lesb_symb_err =
ntohl(fcoe_lesb->lesb_symb_err);
ctlr_dev->lesb.lesb_err_block =
ntohl(fcoe_lesb->lesb_err_block);
ctlr_dev->lesb.lesb_fcs_error =
ntohl(fcoe_lesb->lesb_fcs_error);
}
EXPORT_SYMBOL_GPL(fcoe_ctlr_get_lesb);
void fcoe_wwn_to_str(u64 wwn, char *buf, int len) void fcoe_wwn_to_str(u64 wwn, char *buf, int len)
{ {
u8 wwpn[8]; u8 wwpn[8];
...@@ -627,6 +716,110 @@ static int libfcoe_device_notification(struct notifier_block *notifier, ...@@ -627,6 +716,110 @@ static int libfcoe_device_notification(struct notifier_block *notifier,
return NOTIFY_OK; return NOTIFY_OK;
} }
ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
const char *buf, size_t count)
{
struct net_device *netdev = NULL;
struct fcoe_transport *ft = NULL;
struct fcoe_ctlr_device *ctlr_dev = NULL;
int rc = 0;
int err;
mutex_lock(&ft_mutex);
netdev = fcoe_if_to_netdev(buf);
if (!netdev) {
LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buf);
rc = -ENODEV;
goto out_nodev;
}
ft = fcoe_netdev_map_lookup(netdev);
if (ft) {
LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
"FCoE instance on %s.\n",
ft->name, netdev->name);
rc = -EEXIST;
goto out_putdev;
}
ft = fcoe_transport_lookup(netdev);
if (!ft) {
LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
netdev->name);
rc = -ENODEV;
goto out_putdev;
}
/* pass to transport create */
err = ft->alloc ? ft->alloc(netdev) : -ENODEV;
if (err) {
fcoe_del_netdev_mapping(netdev);
rc = -ENOMEM;
goto out_putdev;
}
err = fcoe_add_netdev_mapping(netdev, ft);
if (err) {
LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
"for FCoE transport %s for %s.\n",
ft->name, netdev->name);
rc = -ENODEV;
goto out_putdev;
}
LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
ft->name, (ctlr_dev) ? "succeeded" : "failed",
netdev->name);
out_putdev:
dev_put(netdev);
out_nodev:
mutex_unlock(&ft_mutex);
if (rc)
return rc;
return count;
}
ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus,
const char *buf, size_t count)
{
int rc = -ENODEV;
struct net_device *netdev = NULL;
struct fcoe_transport *ft = NULL;
mutex_lock(&ft_mutex);
netdev = fcoe_if_to_netdev(buf);
if (!netdev) {
LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buf);
goto out_nodev;
}
ft = fcoe_netdev_map_lookup(netdev);
if (!ft) {
LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
netdev->name);
goto out_putdev;
}
/* pass to transport destroy */
rc = ft->destroy(netdev);
if (rc)
goto out_putdev;
fcoe_del_netdev_mapping(netdev);
LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
ft->name, (rc) ? "failed" : "succeeded",
netdev->name);
rc = count; /* required for successful return */
out_putdev:
dev_put(netdev);
out_nodev:
mutex_unlock(&ft_mutex);
return rc;
}
EXPORT_SYMBOL(fcoe_ctlr_destroy_store);
/** /**
* fcoe_transport_create() - Create a fcoe interface * fcoe_transport_create() - Create a fcoe interface
...@@ -769,10 +962,6 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) ...@@ -769,10 +962,6 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
dev_put(netdev); dev_put(netdev);
out_nodev: out_nodev:
mutex_unlock(&ft_mutex); mutex_unlock(&ft_mutex);
if (rc == -ERESTARTSYS)
return restart_syscall();
else
return rc; return rc;
} }
......
...@@ -5,6 +5,7 @@ extern unsigned int libfcoe_debug_logging; ...@@ -5,6 +5,7 @@ extern unsigned int libfcoe_debug_logging;
#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */ #define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */ #define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
#define LIBFCOE_TRANSPORT_LOGGING 0x04 /* FCoE transport logging */ #define LIBFCOE_TRANSPORT_LOGGING 0x04 /* FCoE transport logging */
#define LIBFCOE_SYSFS_LOGGING 0x08 /* fcoe_sysfs logging */
#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \ #define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
do { \ do { \
...@@ -16,16 +17,19 @@ do { \ ...@@ -16,16 +17,19 @@ do { \
#define LIBFCOE_DBG(fmt, args...) \ #define LIBFCOE_DBG(fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \ LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
printk(KERN_INFO "libfcoe: " fmt, ##args);) pr_info("libfcoe: " fmt, ##args);)
#define LIBFCOE_FIP_DBG(fip, fmt, args...) \ #define LIBFCOE_FIP_DBG(fip, fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \ LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \
printk(KERN_INFO "host%d: fip: " fmt, \ pr_info("host%d: fip: " fmt, \
(fip)->lp->host->host_no, ##args);) (fip)->lp->host->host_no, ##args);)
#define LIBFCOE_TRANSPORT_DBG(fmt, args...) \ #define LIBFCOE_TRANSPORT_DBG(fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_TRANSPORT_LOGGING, \ LIBFCOE_CHECK_LOGGING(LIBFCOE_TRANSPORT_LOGGING, \
printk(KERN_INFO "%s: " fmt, \ pr_info("%s: " fmt, __func__, ##args);)
__func__, ##args);)
#define LIBFCOE_SYSFS_DBG(cdev, fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_SYSFS_LOGGING, \
pr_info("ctlr_%d: " fmt, cdev->id, ##args);)
#endif /* _FCOE_LIBFCOE_H_ */ #endif /* _FCOE_LIBFCOE_H_ */
...@@ -1381,10 +1381,10 @@ static void fc_fcp_timeout(unsigned long data) ...@@ -1381,10 +1381,10 @@ static void fc_fcp_timeout(unsigned long data)
fsp->state |= FC_SRB_FCP_PROCESSING_TMO; fsp->state |= FC_SRB_FCP_PROCESSING_TMO;
if (fsp->state & FC_SRB_RCV_STATUS) if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
fc_fcp_complete_locked(fsp);
else if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
fc_fcp_rec(fsp); fc_fcp_rec(fsp);
else if (fsp->state & FC_SRB_RCV_STATUS)
fc_fcp_complete_locked(fsp);
else else
fc_fcp_recovery(fsp, FC_TIMED_OUT); fc_fcp_recovery(fsp, FC_TIMED_OUT);
fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;
......
...@@ -41,23 +41,23 @@ extern unsigned int fc_debug_logging; ...@@ -41,23 +41,23 @@ extern unsigned int fc_debug_logging;
#define FC_LIBFC_DBG(fmt, args...) \ #define FC_LIBFC_DBG(fmt, args...) \
FC_CHECK_LOGGING(FC_LIBFC_LOGGING, \ FC_CHECK_LOGGING(FC_LIBFC_LOGGING, \
printk(KERN_INFO "libfc: " fmt, ##args)) pr_info("libfc: " fmt, ##args))
#define FC_LPORT_DBG(lport, fmt, args...) \ #define FC_LPORT_DBG(lport, fmt, args...) \
FC_CHECK_LOGGING(FC_LPORT_LOGGING, \ FC_CHECK_LOGGING(FC_LPORT_LOGGING, \
printk(KERN_INFO "host%u: lport %6.6x: " fmt, \ pr_info("host%u: lport %6.6x: " fmt, \
(lport)->host->host_no, \ (lport)->host->host_no, \
(lport)->port_id, ##args)) (lport)->port_id, ##args))
#define FC_DISC_DBG(disc, fmt, args...) \ #define FC_DISC_DBG(disc, fmt, args...) \
FC_CHECK_LOGGING(FC_DISC_LOGGING, \ FC_CHECK_LOGGING(FC_DISC_LOGGING, \
printk(KERN_INFO "host%u: disc: " fmt, \ pr_info("host%u: disc: " fmt, \
fc_disc_lport(disc)->host->host_no, \ fc_disc_lport(disc)->host->host_no, \
##args)) ##args))
#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \ #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \
FC_CHECK_LOGGING(FC_RPORT_LOGGING, \ FC_CHECK_LOGGING(FC_RPORT_LOGGING, \
printk(KERN_INFO "host%u: rport %6.6x: " fmt, \ pr_info("host%u: rport %6.6x: " fmt, \
(lport)->host->host_no, \ (lport)->host->host_no, \
(port_id), ##args)) (port_id), ##args))
...@@ -70,13 +70,13 @@ extern unsigned int fc_debug_logging; ...@@ -70,13 +70,13 @@ extern unsigned int fc_debug_logging;
if ((pkt)->seq_ptr) { \ if ((pkt)->seq_ptr) { \
struct fc_exch *_ep = NULL; \ struct fc_exch *_ep = NULL; \
_ep = fc_seq_exch((pkt)->seq_ptr); \ _ep = fc_seq_exch((pkt)->seq_ptr); \
printk(KERN_INFO "host%u: fcp: %6.6x: " \ pr_info("host%u: fcp: %6.6x: " \
"xid %04x-%04x: " fmt, \ "xid %04x-%04x: " fmt, \
(pkt)->lp->host->host_no, \ (pkt)->lp->host->host_no, \
(pkt)->rport->port_id, \ (pkt)->rport->port_id, \
(_ep)->oxid, (_ep)->rxid, ##args); \ (_ep)->oxid, (_ep)->rxid, ##args); \
} else { \ } else { \
printk(KERN_INFO "host%u: fcp: %6.6x: " fmt, \ pr_info("host%u: fcp: %6.6x: " fmt, \
(pkt)->lp->host->host_no, \ (pkt)->lp->host->host_no, \
(pkt)->rport->port_id, ##args); \ (pkt)->rport->port_id, ##args); \
} \ } \
...@@ -84,13 +84,13 @@ extern unsigned int fc_debug_logging; ...@@ -84,13 +84,13 @@ extern unsigned int fc_debug_logging;
#define FC_EXCH_DBG(exch, fmt, args...) \ #define FC_EXCH_DBG(exch, fmt, args...) \
FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \
printk(KERN_INFO "host%u: xid %4x: " fmt, \ pr_info("host%u: xid %4x: " fmt, \
(exch)->lp->host->host_no, \ (exch)->lp->host->host_no, \
exch->xid, ##args)) exch->xid, ##args))
#define FC_SCSI_DBG(lport, fmt, args...) \ #define FC_SCSI_DBG(lport, fmt, args...) \
FC_CHECK_LOGGING(FC_SCSI_LOGGING, \ FC_CHECK_LOGGING(FC_SCSI_LOGGING, \
printk(KERN_INFO "host%u: scsi: " fmt, \ pr_info("host%u: scsi: " fmt, \
(lport)->host->host_no, ##args)) (lport)->host->host_no, ##args))
/* /*
......
...@@ -582,7 +582,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) ...@@ -582,7 +582,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
static void fc_rport_error_retry(struct fc_rport_priv *rdata, static void fc_rport_error_retry(struct fc_rport_priv *rdata,
struct fc_frame *fp) struct fc_frame *fp)
{ {
unsigned long delay = FC_DEF_E_D_TOV; unsigned long delay = msecs_to_jiffies(FC_DEF_E_D_TOV);
/* make sure this isn't an FC_EX_CLOSED error, never retry those */ /* make sure this isn't an FC_EX_CLOSED error, never retry those */
if (PTR_ERR(fp) == -FC_EX_CLOSED) if (PTR_ERR(fp) == -FC_EX_CLOSED)
......
header-y += fc_els.h
header-y += fc_fs.h
header-y += fc_gs.h
header-y += fc_ns.h
...@@ -34,7 +34,8 @@ struct fcoe_sysfs_function_template { ...@@ -34,7 +34,8 @@ struct fcoe_sysfs_function_template {
void (*get_fcoe_ctlr_symb_err)(struct fcoe_ctlr_device *); void (*get_fcoe_ctlr_symb_err)(struct fcoe_ctlr_device *);
void (*get_fcoe_ctlr_err_block)(struct fcoe_ctlr_device *); void (*get_fcoe_ctlr_err_block)(struct fcoe_ctlr_device *);
void (*get_fcoe_ctlr_fcs_error)(struct fcoe_ctlr_device *); void (*get_fcoe_ctlr_fcs_error)(struct fcoe_ctlr_device *);
void (*get_fcoe_ctlr_mode)(struct fcoe_ctlr_device *); void (*set_fcoe_ctlr_mode)(struct fcoe_ctlr_device *);
int (*set_fcoe_ctlr_enabled)(struct fcoe_ctlr_device *);
void (*get_fcoe_fcf_selected)(struct fcoe_fcf_device *); void (*get_fcoe_fcf_selected)(struct fcoe_fcf_device *);
void (*get_fcoe_fcf_vlan_id)(struct fcoe_fcf_device *); void (*get_fcoe_fcf_vlan_id)(struct fcoe_fcf_device *);
}; };
...@@ -48,6 +49,12 @@ enum fip_conn_type { ...@@ -48,6 +49,12 @@ enum fip_conn_type {
FIP_CONN_TYPE_VN2VN, FIP_CONN_TYPE_VN2VN,
}; };
enum ctlr_enabled_state {
FCOE_CTLR_ENABLED,
FCOE_CTLR_DISABLED,
FCOE_CTLR_UNUSED,
};
struct fcoe_ctlr_device { struct fcoe_ctlr_device {
u32 id; u32 id;
...@@ -64,6 +71,8 @@ struct fcoe_ctlr_device { ...@@ -64,6 +71,8 @@ struct fcoe_ctlr_device {
int fcf_dev_loss_tmo; int fcf_dev_loss_tmo;
enum fip_conn_type mode; enum fip_conn_type mode;
enum ctlr_enabled_state enabled;
/* expected in host order for displaying */ /* expected in host order for displaying */
struct fcoe_fc_els_lesb lesb; struct fcoe_fc_els_lesb lesb;
}; };
......
...@@ -260,6 +260,9 @@ void __fcoe_get_lesb(struct fc_lport *lport, struct fc_els_lesb *fc_lesb, ...@@ -260,6 +260,9 @@ void __fcoe_get_lesb(struct fc_lport *lport, struct fc_els_lesb *fc_lesb,
struct net_device *netdev); struct net_device *netdev);
void fcoe_wwn_to_str(u64 wwn, char *buf, int len); void fcoe_wwn_to_str(u64 wwn, char *buf, int len);
int fcoe_validate_vport_create(struct fc_vport *vport); int fcoe_validate_vport_create(struct fc_vport *vport);
int fcoe_link_speed_update(struct fc_lport *);
void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev);
/** /**
* is_fip_mode() - returns true if FIP mode selected. * is_fip_mode() - returns true if FIP mode selected.
...@@ -289,8 +292,11 @@ static inline bool is_fip_mode(struct fcoe_ctlr *fip) ...@@ -289,8 +292,11 @@ static inline bool is_fip_mode(struct fcoe_ctlr *fip)
* @attached: whether this transport is already attached * @attached: whether this transport is already attached
* @list: list linkage to all attached transports * @list: list linkage to all attached transports
* @match: handler to allow the transport driver to match up a given netdev * @match: handler to allow the transport driver to match up a given netdev
* @alloc: handler to allocate per-instance FCoE structures
* (no discovery or login)
* @create: handler to sysfs entry of create for FCoE instances * @create: handler to sysfs entry of create for FCoE instances
* @destroy: handler to sysfs entry of destroy for FCoE instances * @destroy: handler to delete per-instance FCoE structures
* (frees all memory)
* @enable: handler to sysfs entry of enable for FCoE instances * @enable: handler to sysfs entry of enable for FCoE instances
* @disable: handler to sysfs entry of disable for FCoE instances * @disable: handler to sysfs entry of disable for FCoE instances
*/ */
...@@ -299,6 +305,7 @@ struct fcoe_transport { ...@@ -299,6 +305,7 @@ struct fcoe_transport {
bool attached; bool attached;
struct list_head list; struct list_head list;
bool (*match) (struct net_device *device); bool (*match) (struct net_device *device);
int (*alloc) (struct net_device *device);
int (*create) (struct net_device *device, enum fip_state fip_mode); int (*create) (struct net_device *device, enum fip_state fip_mode);
int (*destroy) (struct net_device *device); int (*destroy) (struct net_device *device);
int (*enable) (struct net_device *device); int (*enable) (struct net_device *device);
...@@ -347,7 +354,20 @@ struct fcoe_port { ...@@ -347,7 +354,20 @@ struct fcoe_port {
struct timer_list timer; struct timer_list timer;
struct work_struct destroy_work; struct work_struct destroy_work;
u8 data_src_addr[ETH_ALEN]; u8 data_src_addr[ETH_ALEN];
struct net_device * (*get_netdev)(const struct fc_lport *lport);
}; };
/**
* fcoe_get_netdev() - Return the net device associated with a local port
* @lport: The local port to get the net device from
*/
static inline struct net_device *fcoe_get_netdev(const struct fc_lport *lport)
{
struct fcoe_port *port = ((struct fcoe_port *)lport_priv(lport));
return (port->get_netdev) ? port->get_netdev(lport) : NULL;
}
void fcoe_clean_pending_queue(struct fc_lport *); void fcoe_clean_pending_queue(struct fc_lport *);
void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb); void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb);
void fcoe_queue_timer(ulong lport); void fcoe_queue_timer(ulong lport);
...@@ -356,7 +376,7 @@ int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, ...@@ -356,7 +376,7 @@ int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
/* FCoE Sysfs helpers */ /* FCoE Sysfs helpers */
void fcoe_fcf_get_selected(struct fcoe_fcf_device *); void fcoe_fcf_get_selected(struct fcoe_fcf_device *);
void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *); void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *);
/** /**
* struct netdev_list * struct netdev_list
...@@ -372,4 +392,12 @@ struct fcoe_netdev_mapping { ...@@ -372,4 +392,12 @@ struct fcoe_netdev_mapping {
int fcoe_transport_attach(struct fcoe_transport *ft); int fcoe_transport_attach(struct fcoe_transport *ft);
int fcoe_transport_detach(struct fcoe_transport *ft); int fcoe_transport_detach(struct fcoe_transport *ft);
/* sysfs store handler for ctrl_control interface */
ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
const char *buf, size_t count);
ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus,
const char *buf, size_t count);
#endif /* _LIBFCOE_H */ #endif /* _LIBFCOE_H */
# UAPI Header export list # UAPI Header export list
header-y += fc_els.h
header-y += fc_fs.h
header-y += fc_gs.h
header-y += fc_ns.h
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment