aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/fcoe
diff options
context:
space:
mode:
authorRobert Love <robert.w.love@intel.com>2012-11-27 01:53:30 -0500
committerRobert Love <robert.w.love@intel.com>2012-12-14 13:38:54 -0500
commit6a891b071b640e1de44c4a5117fa2c974dcfa84a (patch)
treecd40772ab35844d21ae44ad4a16fec4246b5f21f /drivers/scsi/fcoe
parent3993de6183885a099163b9562a2ea9c07b994a0e (diff)
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: Robert Love <robert.w.love@intel.com> Acked-by: Neil Horman <nhorman@tuxdriver.com>
Diffstat (limited to 'drivers/scsi/fcoe')
-rw-r--r--drivers/scsi/fcoe/fcoe.c1
-rw-r--r--drivers/scsi/fcoe/fcoe_sysfs.c137
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c104
3 files changed, 234 insertions, 8 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 666b7ac4475f..9bd982d2c07f 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -155,7 +155,6 @@ static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *);
155static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *); 155static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *);
156 156
157static struct fcoe_sysfs_function_template fcoe_sysfs_templ = { 157static struct fcoe_sysfs_function_template fcoe_sysfs_templ = {
158 .get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode,
159 .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, 158 .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb,
160 .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, 159 .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb,
161 .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb, 160 .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb,
diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c
index 9c74374b53cd..8c05ae017f5b 100644
--- a/drivers/scsi/fcoe/fcoe_sysfs.c
+++ b/drivers/scsi/fcoe/fcoe_sysfs.c
@@ -21,8 +21,10 @@
21#include <linux/types.h> 21#include <linux/types.h>
22#include <linux/kernel.h> 22#include <linux/kernel.h>
23#include <linux/etherdevice.h> 23#include <linux/etherdevice.h>
24#include <linux/ctype.h>
24 25
25#include <scsi/fcoe_sysfs.h> 26#include <scsi/fcoe_sysfs.h>
27#include <scsi/libfcoe.h>
26 28
27/* 29/*
28 * OK to include local libfcoe.h for debug_logging, but cannot include 30 * OK to include local libfcoe.h for debug_logging, but cannot include
@@ -78,6 +80,8 @@ MODULE_PARM_DESC(fcf_dev_loss_tmo,
78 ((x)->lesb.lesb_err_block) 80 ((x)->lesb.lesb_err_block)
79#define fcoe_ctlr_fcs_error(x) \ 81#define fcoe_ctlr_fcs_error(x) \
80 ((x)->lesb.lesb_fcs_error) 82 ((x)->lesb.lesb_fcs_error)
83#define fcoe_ctlr_enabled(x) \
84 ((x)->enabled)
81#define fcoe_fcf_state(x) \ 85#define fcoe_fcf_state(x) \
82 ((x)->state) 86 ((x)->state)
83#define fcoe_fcf_fabric_name(x) \ 87#define fcoe_fcf_fabric_name(x) \
@@ -228,7 +232,18 @@ static char *fip_conn_type_names[] = {
228 [ FIP_CONN_TYPE_VN2VN ] = "VN2VN", 232 [ FIP_CONN_TYPE_VN2VN ] = "VN2VN",
229}; 233};
230fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names) 234fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)
231#define FCOE_CTLR_MODE_MAX_NAMELEN 50 235
236static enum fip_conn_type fcoe_parse_mode(const char *buf)
237{
238 int i;
239
240 for (i = 0; i < ARRAY_SIZE(fip_conn_type_names); i++) {
241 if (strcasecmp(buf, fip_conn_type_names[i]) == 0)
242 return i;
243 }
244
245 return FIP_CONN_TYPE_UNKNOWN;
246}
232 247
233static char *fcf_state_names[] = { 248static char *fcf_state_names[] = {
234 [ FCOE_FCF_STATE_UNKNOWN ] = "Unknown", 249 [ FCOE_FCF_STATE_UNKNOWN ] = "Unknown",
@@ -259,17 +274,116 @@ static ssize_t show_ctlr_mode(struct device *dev,
259 struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); 274 struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
260 const char *name; 275 const char *name;
261 276
262 if (ctlr->f->get_fcoe_ctlr_mode)
263 ctlr->f->get_fcoe_ctlr_mode(ctlr);
264
265 name = get_fcoe_ctlr_mode_name(ctlr->mode); 277 name = get_fcoe_ctlr_mode_name(ctlr->mode);
266 if (!name) 278 if (!name)
267 return -EINVAL; 279 return -EINVAL;
268 return snprintf(buf, FCOE_CTLR_MODE_MAX_NAMELEN, 280 return snprintf(buf, FCOE_MAX_MODENAME_LEN,
269 "%s\n", name); 281 "%s\n", name);
270} 282}
271static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO, 283
272 show_ctlr_mode, NULL); 284static ssize_t store_ctlr_mode(struct device *dev,
285 struct device_attribute *attr,
286 const char *buf, size_t count)
287{
288 struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
289 char mode[FCOE_MAX_MODENAME_LEN + 1];
290
291 if (count > FCOE_MAX_MODENAME_LEN)
292 return -EINVAL;
293
294 strncpy(mode, buf, count);
295
296 if (mode[count - 1] == '\n')
297 mode[count - 1] = '\0';
298 else
299 mode[count] = '\0';
300
301 switch (ctlr->enabled) {
302 case FCOE_CTLR_ENABLED:
303 LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled.");
304 return -EBUSY;
305 case FCOE_CTLR_DISABLED:
306 if (!ctlr->f->set_fcoe_ctlr_mode) {
307 LIBFCOE_SYSFS_DBG(ctlr,
308 "Mode change not supported by LLD.");
309 return -ENOTSUPP;
310 }
311
312 ctlr->mode = fcoe_parse_mode(mode);
313 if (ctlr->mode == FIP_CONN_TYPE_UNKNOWN) {
314 LIBFCOE_SYSFS_DBG(ctlr,
315 "Unknown mode %s provided.", buf);
316 return -EINVAL;
317 }
318
319 ctlr->f->set_fcoe_ctlr_mode(ctlr);
320 LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.", buf);
321
322 return count;
323 case FCOE_CTLR_UNUSED:
324 default:
325 LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.");
326 return -ENOTSUPP;
327 };
328}
329
330static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO | S_IWUSR,
331 show_ctlr_mode, store_ctlr_mode);
332
333static ssize_t store_ctlr_enabled(struct device *dev,
334 struct device_attribute *attr,
335 const char *buf, size_t count)
336{
337 struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
338 int rc;
339
340 switch (ctlr->enabled) {
341 case FCOE_CTLR_ENABLED:
342 if (*buf == '1')
343 return count;
344 ctlr->enabled = FCOE_CTLR_DISABLED;
345 break;
346 case FCOE_CTLR_DISABLED:
347 if (*buf == '0')
348 return count;
349 ctlr->enabled = FCOE_CTLR_ENABLED;
350 break;
351 case FCOE_CTLR_UNUSED:
352 return -ENOTSUPP;
353 };
354
355 rc = ctlr->f->set_fcoe_ctlr_enabled(ctlr);
356 if (rc)
357 return rc;
358
359 return count;
360}
361
362static char *ctlr_enabled_state_names[] = {
363 [ FCOE_CTLR_ENABLED ] = "1",
364 [ FCOE_CTLR_DISABLED ] = "0",
365};
366fcoe_enum_name_search(ctlr_enabled_state, ctlr_enabled_state,
367 ctlr_enabled_state_names)
368#define FCOE_CTLR_ENABLED_MAX_NAMELEN 50
369
370static ssize_t show_ctlr_enabled_state(struct device *dev,
371 struct device_attribute *attr,
372 char *buf)
373{
374 struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
375 const char *name;
376
377 name = get_fcoe_ctlr_enabled_state_name(ctlr->enabled);
378 if (!name)
379 return -EINVAL;
380 return snprintf(buf, FCOE_CTLR_ENABLED_MAX_NAMELEN,
381 "%s\n", name);
382}
383
384static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR,
385 show_ctlr_enabled_state,
386 store_ctlr_enabled);
273 387
274static ssize_t 388static ssize_t
275store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev, 389store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev,
@@ -354,6 +468,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = {
354 468
355static struct attribute *fcoe_ctlr_attrs[] = { 469static struct attribute *fcoe_ctlr_attrs[] = {
356 &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr, 470 &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr,
471 &device_attr_fcoe_ctlr_enabled.attr,
357 &device_attr_fcoe_ctlr_mode.attr, 472 &device_attr_fcoe_ctlr_mode.attr,
358 NULL, 473 NULL,
359}; 474};
@@ -438,9 +553,16 @@ struct device_type fcoe_fcf_device_type = {
438 .release = fcoe_fcf_device_release, 553 .release = fcoe_fcf_device_release,
439}; 554};
440 555
556struct bus_attribute fcoe_bus_attr_group[] = {
557 __ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store),
558 __ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store),
559 __ATTR_NULL
560};
561
441struct bus_type fcoe_bus_type = { 562struct bus_type fcoe_bus_type = {
442 .name = "fcoe", 563 .name = "fcoe",
443 .match = &fcoe_bus_match, 564 .match = &fcoe_bus_match,
565 .bus_attrs = fcoe_bus_attr_group,
444}; 566};
445 567
446/** 568/**
@@ -561,6 +683,7 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent,
561 683
562 ctlr->id = atomic_inc_return(&ctlr_num) - 1; 684 ctlr->id = atomic_inc_return(&ctlr_num) - 1;
563 ctlr->f = f; 685 ctlr->f = f;
686 ctlr->mode = FIP_CONN_TYPE_FABRIC;
564 INIT_LIST_HEAD(&ctlr->fcfs); 687 INIT_LIST_HEAD(&ctlr->fcfs);
565 mutex_init(&ctlr->lock); 688 mutex_init(&ctlr->lock);
566 ctlr->dev.parent = parent; 689 ctlr->dev.parent = parent;
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index ac76d8a042d7..83e78f922054 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -627,6 +627,110 @@ static int libfcoe_device_notification(struct notifier_block *notifier,
627 return NOTIFY_OK; 627 return NOTIFY_OK;
628} 628}
629 629
630ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
631 const char *buf, size_t count)
632{
633 struct net_device *netdev = NULL;
634 struct fcoe_transport *ft = NULL;
635 struct fcoe_ctlr_device *ctlr_dev = NULL;
636 int rc = 0;
637 int err;
638
639 mutex_lock(&ft_mutex);
640
641 netdev = fcoe_if_to_netdev(buf);
642 if (!netdev) {
643 LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buf);
644 rc = -ENODEV;
645 goto out_nodev;
646 }
647
648 ft = fcoe_netdev_map_lookup(netdev);
649 if (ft) {
650 LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
651 "FCoE instance on %s.\n",
652 ft->name, netdev->name);
653 rc = -EEXIST;
654 goto out_putdev;
655 }
656
657 ft = fcoe_transport_lookup(netdev);
658 if (!ft) {
659 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
660 netdev->name);
661 rc = -ENODEV;
662 goto out_putdev;
663 }
664
665 /* pass to transport create */
666 err = ft->alloc ? ft->alloc(netdev) : -ENODEV;
667 if (err) {
668 fcoe_del_netdev_mapping(netdev);
669 rc = -ENOMEM;
670 goto out_putdev;
671 }
672
673 err = fcoe_add_netdev_mapping(netdev, ft);
674 if (err) {
675 LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
676 "for FCoE transport %s for %s.\n",
677 ft->name, netdev->name);
678 rc = -ENODEV;
679 goto out_putdev;
680 }
681
682 LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
683 ft->name, (ctlr_dev) ? "succeeded" : "failed",
684 netdev->name);
685
686out_putdev:
687 dev_put(netdev);
688out_nodev:
689 mutex_unlock(&ft_mutex);
690 if (rc)
691 return rc;
692 return count;
693}
694
695ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus,
696 const char *buf, size_t count)
697{
698 int rc = -ENODEV;
699 struct net_device *netdev = NULL;
700 struct fcoe_transport *ft = NULL;
701
702 mutex_lock(&ft_mutex);
703
704 netdev = fcoe_if_to_netdev(buf);
705 if (!netdev) {
706 LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buf);
707 goto out_nodev;
708 }
709
710 ft = fcoe_netdev_map_lookup(netdev);
711 if (!ft) {
712 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
713 netdev->name);
714 goto out_putdev;
715 }
716
717 /* pass to transport destroy */
718 rc = ft->destroy(netdev);
719 if (rc)
720 goto out_putdev;
721
722 fcoe_del_netdev_mapping(netdev);
723 LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
724 ft->name, (rc) ? "failed" : "succeeded",
725 netdev->name);
726 rc = count; /* required for successful return */
727out_putdev:
728 dev_put(netdev);
729out_nodev:
730 mutex_unlock(&ft_mutex);
731 return rc;
732}
733EXPORT_SYMBOL(fcoe_ctlr_destroy_store);
630 734
631/** 735/**
632 * fcoe_transport_create() - Create a fcoe interface 736 * fcoe_transport_create() - Create a fcoe interface