Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a891b07 authored by Robert Love's avatar Robert Love
Browse files

libfcoe, fcoe, bnx2fc: Add new fcoe control interface



This patch does a few things.

1) Makes /sys/bus/fcoe/ctlr_{create,destroy} interfaces.
   These interfaces take an <ifname> and will either
   create an FCoE Controller or destroy an FCoE
   Controller depending on which file is written to.

   The new FCoE Controller will start in a DISABLED
   state and will not do discovery or login until it
   is ENABLED. This pause will allow us to configure
   the FCoE Controller before enabling it.

2) Makes the 'mode' attribute of a fcoe_ctlr_device
   writale. This allows the user to configure the mode
   in which the FCoE Controller will start in when it
   is ENABLED.

   Possible modes are 'Fabric', or 'VN2VN'.

   The default mode for a fcoe_ctlr{,_device} is 'Fabric'.
   Drivers must implement the set_fcoe_ctlr_mode routine
   to support this feature.

   libfcoe offers an exported routine to set a FCoE
   Controller's mode. The mode can only be changed
   when the FCoE Controller is DISABLED.

   This patch also removes the get_fcoe_ctlr_mode pointer
   in the fcoe_sysfs function template, the code in
   fcoe_ctlr.c to get the mode and the assignment of
   the fcoe_sysfs function pointer to the fcoe_ctlr.c
   implementation (in fcoe and bnx2fc). fcoe_sysfs can
   return that value for the mode without consulting the
   LLD.

3) Make a 'enabled' attribute of a fcoe_ctlr_device. On a
   read, fcoe_sysfs will return the attribute's value. On
   a write, fcoe_sysfs will call the LLD (if there is a
   callback) to notifiy that the enalbed state has changed.

This patch maintains the old FCoE control interfaces as
module parameters, but it adds comments pointing out that
the old interfaces are deprecated.

Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
parent 3993de61
Loading
Loading
Loading
Loading
+40 −1
Original line number Diff line number Diff line
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
KernelVersion:	TBD
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:

	fcf_dev_loss_tmo: Device loss timeout peroid (see below). Changing
			  this value will change the dev_loss_tmo for all
			  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/vlink_fail:  Link Error Status Block (LESB) virtual link
+0 −1
Original line number Diff line number Diff line
@@ -2555,7 +2555,6 @@ module_init(bnx2fc_mod_init);
module_exit(bnx2fc_mod_exit);

static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = {
	.get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode,
	.get_fcoe_ctlr_link_fail = bnx2fc_ctlr_get_lesb,
	.get_fcoe_ctlr_vlink_fail = bnx2fc_ctlr_get_lesb,
	.get_fcoe_ctlr_miss_fka = bnx2fc_ctlr_get_lesb,
+0 −1
Original line number Diff line number Diff line
@@ -155,7 +155,6 @@ static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *);
static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *);

static struct fcoe_sysfs_function_template fcoe_sysfs_templ = {
	.get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode,
	.get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb,
	.get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb,
	.get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb,
+130 −7
Original line number Diff line number Diff line
@@ -21,8 +21,10 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/ctype.h>

#include <scsi/fcoe_sysfs.h>
#include <scsi/libfcoe.h>

/*
 * OK to include local libfcoe.h for debug_logging, but cannot include
@@ -78,6 +80,8 @@ MODULE_PARM_DESC(fcf_dev_loss_tmo,
	((x)->lesb.lesb_err_block)
#define fcoe_ctlr_fcs_error(x)			\
	((x)->lesb.lesb_fcs_error)
#define fcoe_ctlr_enabled(x)			\
	((x)->enabled)
#define fcoe_fcf_state(x)			\
	((x)->state)
#define fcoe_fcf_fabric_name(x)			\
@@ -228,7 +232,18 @@ static char *fip_conn_type_names[] = {
	[ 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 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",
@@ -259,17 +274,116 @@ static ssize_t show_ctlr_mode(struct device *dev,
	struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
	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);
	if (!name)
		return -EINVAL;
	return snprintf(buf, FCOE_CTLR_MODE_MAX_NAMELEN,
	return snprintf(buf, FCOE_MAX_MODENAME_LEN,
			"%s\n", name);
}

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, mode, S_IRUGO,
			show_ctlr_mode, NULL);

static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR,
			show_ctlr_enabled_state,
			store_ctlr_enabled);

static ssize_t
store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev,
@@ -354,6 +468,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = {

static struct attribute *fcoe_ctlr_attrs[] = {
	&device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr,
	&device_attr_fcoe_ctlr_enabled.attr,
	&device_attr_fcoe_ctlr_mode.attr,
	NULL,
};
@@ -438,9 +553,16 @@ struct device_type fcoe_fcf_device_type = {
	.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 = {
	.name = "fcoe",
	.match = &fcoe_bus_match,
	.bus_attrs = fcoe_bus_attr_group,
};

/**
@@ -561,6 +683,7 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent,

	ctlr->id = atomic_inc_return(&ctlr_num) - 1;
	ctlr->f = f;
	ctlr->mode = FIP_CONN_TYPE_FABRIC;
	INIT_LIST_HEAD(&ctlr->fcfs);
	mutex_init(&ctlr->lock);
	ctlr->dev.parent = parent;
+104 −0
Original line number Diff line number Diff line
@@ -627,6 +627,110 @@ static int libfcoe_device_notification(struct notifier_block *notifier,
	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
Loading