linux/drivers/scsi/fcoe/fcoe_sysfs.c
<<
>>
Prefs
   1/*
   2 * Copyright(c) 2011 - 2012 Intel Corporation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms and conditions of the GNU General Public License,
   6 * version 2, as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope it will be useful, but WITHOUT
   9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  11 * more details.
  12 *
  13 * You should have received a copy of the GNU General Public License along with
  14 * this program; if not, write to the Free Software Foundation, Inc.,
  15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  16 *
  17 * Maintained at www.Open-FCoE.org
  18 */
  19
  20#include <linux/module.h>
  21#include <linux/types.h>
  22#include <linux/kernel.h>
  23#include <linux/etherdevice.h>
  24#include <linux/ctype.h>
  25
  26#include <scsi/fcoe_sysfs.h>
  27#include <scsi/libfcoe.h>
  28
  29/*
  30 * OK to include local libfcoe.h for debug_logging, but cannot include
  31 * <scsi/libfcoe.h> otherwise non-netdev based fcoe solutions would have
  32 * have to include more than fcoe_sysfs.h.
  33 */
  34#include "libfcoe.h"
  35
  36static atomic_t ctlr_num;
  37static atomic_t fcf_num;
  38
  39/*
  40 * fcoe_fcf_dev_loss_tmo: the default number of seconds that fcoe sysfs
  41 * should insulate the loss of a fcf.
  42 */
  43static unsigned int fcoe_fcf_dev_loss_tmo = 1800;  /* seconds */
  44
  45module_param_named(fcf_dev_loss_tmo, fcoe_fcf_dev_loss_tmo,
  46                   uint, S_IRUGO|S_IWUSR);
  47MODULE_PARM_DESC(fcf_dev_loss_tmo,
  48                 "Maximum number of seconds that libfcoe should"
  49                 " insulate the loss of a fcf. Once this value is"
  50                 " exceeded, the fcf is removed.");
  51
  52/*
  53 * These are used by the fcoe_*_show_function routines, they
  54 * are intentionally placed in the .c file as they're not intended
  55 * for use throughout the code.
  56 */
  57#define fcoe_ctlr_id(x)                         \
  58        ((x)->id)
  59#define fcoe_ctlr_work_q_name(x)                \
  60        ((x)->work_q_name)
  61#define fcoe_ctlr_work_q(x)                     \
  62        ((x)->work_q)
  63#define fcoe_ctlr_devloss_work_q_name(x)        \
  64        ((x)->devloss_work_q_name)
  65#define fcoe_ctlr_devloss_work_q(x)             \
  66        ((x)->devloss_work_q)
  67#define fcoe_ctlr_mode(x)                       \
  68        ((x)->mode)
  69#define fcoe_ctlr_fcf_dev_loss_tmo(x)           \
  70        ((x)->fcf_dev_loss_tmo)
  71#define fcoe_ctlr_link_fail(x)                  \
  72        ((x)->lesb.lesb_link_fail)
  73#define fcoe_ctlr_vlink_fail(x)                 \
  74        ((x)->lesb.lesb_vlink_fail)
  75#define fcoe_ctlr_miss_fka(x)                   \
  76        ((x)->lesb.lesb_miss_fka)
  77#define fcoe_ctlr_symb_err(x)                   \
  78        ((x)->lesb.lesb_symb_err)
  79#define fcoe_ctlr_err_block(x)                  \
  80        ((x)->lesb.lesb_err_block)
  81#define fcoe_ctlr_fcs_error(x)                  \
  82        ((x)->lesb.lesb_fcs_error)
  83#define fcoe_ctlr_enabled(x)                    \
  84        ((x)->enabled)
  85#define fcoe_fcf_state(x)                       \
  86        ((x)->state)
  87#define fcoe_fcf_fabric_name(x)                 \
  88        ((x)->fabric_name)
  89#define fcoe_fcf_switch_name(x)                 \
  90        ((x)->switch_name)
  91#define fcoe_fcf_fc_map(x)                      \
  92        ((x)->fc_map)
  93#define fcoe_fcf_vfid(x)                        \
  94        ((x)->vfid)
  95#define fcoe_fcf_mac(x)                         \
  96        ((x)->mac)
  97#define fcoe_fcf_priority(x)                    \
  98        ((x)->priority)
  99#define fcoe_fcf_fka_period(x)                  \
 100        ((x)->fka_period)
 101#define fcoe_fcf_dev_loss_tmo(x)                \
 102        ((x)->dev_loss_tmo)
 103#define fcoe_fcf_selected(x)                    \
 104        ((x)->selected)
 105#define fcoe_fcf_vlan_id(x)                     \
 106        ((x)->vlan_id)
 107
 108/*
 109 * dev_loss_tmo attribute
 110 */
 111static int fcoe_str_to_dev_loss(const char *buf, unsigned long *val)
 112{
 113        int ret;
 114
 115        ret = kstrtoul(buf, 0, val);
 116        if (ret)
 117                return -EINVAL;
 118        /*
 119         * Check for overflow; dev_loss_tmo is u32
 120         */
 121        if (*val > UINT_MAX)
 122                return -EINVAL;
 123
 124        return 0;
 125}
 126
 127static int fcoe_fcf_set_dev_loss_tmo(struct fcoe_fcf_device *fcf,
 128                                     unsigned long val)
 129{
 130        if ((fcf->state == FCOE_FCF_STATE_UNKNOWN) ||
 131            (fcf->state == FCOE_FCF_STATE_DISCONNECTED) ||
 132            (fcf->state == FCOE_FCF_STATE_DELETED))
 133                return -EBUSY;
 134        /*
 135         * Check for overflow; dev_loss_tmo is u32
 136         */
 137        if (val > UINT_MAX)
 138                return -EINVAL;
 139
 140        fcoe_fcf_dev_loss_tmo(fcf) = val;
 141        return 0;
 142}
 143
 144#define FCOE_DEVICE_ATTR(_prefix, _name, _mode, _show, _store)  \
 145struct device_attribute device_attr_fcoe_##_prefix##_##_name =  \
 146        __ATTR(_name, _mode, _show, _store)
 147
 148#define fcoe_ctlr_show_function(field, format_string, sz, cast) \
 149static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \
 150                                            struct device_attribute *attr, \
 151                                            char *buf)                  \
 152{                                                                       \
 153        struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);               \
 154        if (ctlr->f->get_fcoe_ctlr_##field)                             \
 155                ctlr->f->get_fcoe_ctlr_##field(ctlr);                   \
 156        return snprintf(buf, sz, format_string,                         \
 157                        cast fcoe_ctlr_##field(ctlr));                  \
 158}
 159
 160#define fcoe_fcf_show_function(field, format_string, sz, cast)  \
 161static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \
 162                                           struct device_attribute *attr, \
 163                                           char *buf)                   \
 164{                                                                       \
 165        struct fcoe_fcf_device *fcf = dev_to_fcf(dev);                  \
 166        struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);  \
 167        if (ctlr->f->get_fcoe_fcf_##field)                              \
 168                ctlr->f->get_fcoe_fcf_##field(fcf);                     \
 169        return snprintf(buf, sz, format_string,                         \
 170                        cast fcoe_fcf_##field(fcf));                    \
 171}
 172
 173#define fcoe_ctlr_private_show_function(field, format_string, sz, cast) \
 174static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \
 175                                            struct device_attribute *attr, \
 176                                            char *buf)                  \
 177{                                                                       \
 178        struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);               \
 179        return snprintf(buf, sz, format_string, cast fcoe_ctlr_##field(ctlr)); \
 180}
 181
 182#define fcoe_fcf_private_show_function(field, format_string, sz, cast)  \
 183static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \
 184                                           struct device_attribute *attr, \
 185                                           char *buf)                   \
 186{                                                               \
 187        struct fcoe_fcf_device *fcf = dev_to_fcf(dev);                  \
 188        return snprintf(buf, sz, format_string, cast fcoe_fcf_##field(fcf)); \
 189}
 190
 191#define fcoe_ctlr_private_rd_attr(field, format_string, sz)             \
 192        fcoe_ctlr_private_show_function(field, format_string, sz, )     \
 193        static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO,                   \
 194                                show_fcoe_ctlr_device_##field, NULL)
 195
 196#define fcoe_ctlr_rd_attr(field, format_string, sz)                     \
 197        fcoe_ctlr_show_function(field, format_string, sz, )             \
 198        static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO,                   \
 199                                show_fcoe_ctlr_device_##field, NULL)
 200
 201#define fcoe_fcf_rd_attr(field, format_string, sz)                      \
 202        fcoe_fcf_show_function(field, format_string, sz, )              \
 203        static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO,                    \
 204                                show_fcoe_fcf_device_##field, NULL)
 205
 206#define fcoe_fcf_private_rd_attr(field, format_string, sz)              \
 207        fcoe_fcf_private_show_function(field, format_string, sz, )      \
 208        static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO,                    \
 209                                show_fcoe_fcf_device_##field, NULL)
 210
 211#define fcoe_ctlr_private_rd_attr_cast(field, format_string, sz, cast)  \
 212        fcoe_ctlr_private_show_function(field, format_string, sz, (cast)) \
 213        static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO,                   \
 214                                show_fcoe_ctlr_device_##field, NULL)
 215
 216#define fcoe_fcf_private_rd_attr_cast(field, format_string, sz, cast)   \
 217        fcoe_fcf_private_show_function(field, format_string, sz, (cast)) \
 218        static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO,                    \
 219                                show_fcoe_fcf_device_##field, NULL)
 220
 221#define fcoe_enum_name_search(title, table_type, table)                 \
 222static const char *get_fcoe_##title##_name(enum table_type table_key)   \
 223{                                                                       \
 224        if (table_key < 0 || table_key >= ARRAY_SIZE(table))            \
 225                return NULL;                                            \
 226        return table[table_key];                                        \
 227}
 228
 229static char *fip_conn_type_names[] = {
 230        [ FIP_CONN_TYPE_UNKNOWN ] = "Unknown",
 231        [ FIP_CONN_TYPE_FABRIC ]  = "Fabric",
 232        [ FIP_CONN_TYPE_VN2VN ]   = "VN2VN",
 233};
 234fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)
 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}
 247
 248static char *fcf_state_names[] = {
 249        [ FCOE_FCF_STATE_UNKNOWN ]      = "Unknown",
 250        [ FCOE_FCF_STATE_DISCONNECTED ] = "Disconnected",
 251        [ FCOE_FCF_STATE_CONNECTED ]    = "Connected",
 252};
 253fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names)
 254#define FCOE_FCF_STATE_MAX_NAMELEN 50
 255
 256static ssize_t show_fcf_state(struct device *dev,
 257                              struct device_attribute *attr,
 258                              char *buf)
 259{
 260        struct fcoe_fcf_device *fcf = dev_to_fcf(dev);
 261        const char *name;
 262        name = get_fcoe_fcf_state_name(fcf->state);
 263        if (!name)
 264                return -EINVAL;
 265        return snprintf(buf, FCOE_FCF_STATE_MAX_NAMELEN, "%s\n", name);
 266}
 267static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL);
 268
 269#define FCOE_MAX_MODENAME_LEN 20
 270static ssize_t show_ctlr_mode(struct device *dev,
 271                              struct device_attribute *attr,
 272                              char *buf)
 273{
 274        struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
 275        const char *name;
 276
 277        name = get_fcoe_ctlr_mode_name(ctlr->mode);
 278        if (!name)
 279                return -EINVAL;
 280        return snprintf(buf, FCOE_MAX_MODENAME_LEN,
 281                        "%s\n", name);
 282}
 283
 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);
 387
 388static ssize_t
 389store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev,
 390                                         struct device_attribute *attr,
 391                                         const char *buf, size_t count)
 392{
 393        struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
 394        struct fcoe_fcf_device *fcf;
 395        unsigned long val;
 396        int rc;
 397
 398        rc = fcoe_str_to_dev_loss(buf, &val);
 399        if (rc)
 400                return rc;
 401
 402        fcoe_ctlr_fcf_dev_loss_tmo(ctlr) = val;
 403        mutex_lock(&ctlr->lock);
 404        list_for_each_entry(fcf, &ctlr->fcfs, peers)
 405                fcoe_fcf_set_dev_loss_tmo(fcf, val);
 406        mutex_unlock(&ctlr->lock);
 407        return count;
 408}
 409fcoe_ctlr_private_show_function(fcf_dev_loss_tmo, "%d\n", 20, );
 410static FCOE_DEVICE_ATTR(ctlr, fcf_dev_loss_tmo, S_IRUGO | S_IWUSR,
 411                        show_fcoe_ctlr_device_fcf_dev_loss_tmo,
 412                        store_private_fcoe_ctlr_fcf_dev_loss_tmo);
 413
 414/* Link Error Status Block (LESB) */
 415fcoe_ctlr_rd_attr(link_fail, "%u\n", 20);
 416fcoe_ctlr_rd_attr(vlink_fail, "%u\n", 20);
 417fcoe_ctlr_rd_attr(miss_fka, "%u\n", 20);
 418fcoe_ctlr_rd_attr(symb_err, "%u\n", 20);
 419fcoe_ctlr_rd_attr(err_block, "%u\n", 20);
 420fcoe_ctlr_rd_attr(fcs_error, "%u\n", 20);
 421
 422fcoe_fcf_private_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);
 423fcoe_fcf_private_rd_attr_cast(switch_name, "0x%llx\n", 20, unsigned long long);
 424fcoe_fcf_private_rd_attr(priority, "%u\n", 20);
 425fcoe_fcf_private_rd_attr(fc_map, "0x%x\n", 20);
 426fcoe_fcf_private_rd_attr(vfid, "%u\n", 20);
 427fcoe_fcf_private_rd_attr(mac, "%pM\n", 20);
 428fcoe_fcf_private_rd_attr(fka_period, "%u\n", 20);
 429fcoe_fcf_rd_attr(selected, "%u\n", 20);
 430fcoe_fcf_rd_attr(vlan_id, "%u\n", 20);
 431
 432fcoe_fcf_private_show_function(dev_loss_tmo, "%d\n", 20, )
 433static ssize_t
 434store_fcoe_fcf_dev_loss_tmo(struct device *dev, struct device_attribute *attr,
 435                            const char *buf, size_t count)
 436{
 437        struct fcoe_fcf_device *fcf = dev_to_fcf(dev);
 438        unsigned long val;
 439        int rc;
 440
 441        rc = fcoe_str_to_dev_loss(buf, &val);
 442        if (rc)
 443                return rc;
 444
 445        rc = fcoe_fcf_set_dev_loss_tmo(fcf, val);
 446        if (rc)
 447                return rc;
 448        return count;
 449}
 450static FCOE_DEVICE_ATTR(fcf, dev_loss_tmo, S_IRUGO | S_IWUSR,
 451                        show_fcoe_fcf_device_dev_loss_tmo,
 452                        store_fcoe_fcf_dev_loss_tmo);
 453
 454static struct attribute *fcoe_ctlr_lesb_attrs[] = {
 455        &device_attr_fcoe_ctlr_link_fail.attr,
 456        &device_attr_fcoe_ctlr_vlink_fail.attr,
 457        &device_attr_fcoe_ctlr_miss_fka.attr,
 458        &device_attr_fcoe_ctlr_symb_err.attr,
 459        &device_attr_fcoe_ctlr_err_block.attr,
 460        &device_attr_fcoe_ctlr_fcs_error.attr,
 461        NULL,
 462};
 463
 464static struct attribute_group fcoe_ctlr_lesb_attr_group = {
 465        .name = "lesb",
 466        .attrs = fcoe_ctlr_lesb_attrs,
 467};
 468
 469static struct attribute *fcoe_ctlr_attrs[] = {
 470        &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr,
 471        &device_attr_fcoe_ctlr_enabled.attr,
 472        &device_attr_fcoe_ctlr_mode.attr,
 473        NULL,
 474};
 475
 476static struct attribute_group fcoe_ctlr_attr_group = {
 477        .attrs = fcoe_ctlr_attrs,
 478};
 479
 480static const struct attribute_group *fcoe_ctlr_attr_groups[] = {
 481        &fcoe_ctlr_attr_group,
 482        &fcoe_ctlr_lesb_attr_group,
 483        NULL,
 484};
 485
 486static struct attribute *fcoe_fcf_attrs[] = {
 487        &device_attr_fcoe_fcf_fabric_name.attr,
 488        &device_attr_fcoe_fcf_switch_name.attr,
 489        &device_attr_fcoe_fcf_dev_loss_tmo.attr,
 490        &device_attr_fcoe_fcf_fc_map.attr,
 491        &device_attr_fcoe_fcf_vfid.attr,
 492        &device_attr_fcoe_fcf_mac.attr,
 493        &device_attr_fcoe_fcf_priority.attr,
 494        &device_attr_fcoe_fcf_fka_period.attr,
 495        &device_attr_fcoe_fcf_state.attr,
 496        &device_attr_fcoe_fcf_selected.attr,
 497        &device_attr_fcoe_fcf_vlan_id.attr,
 498        NULL
 499};
 500
 501static struct attribute_group fcoe_fcf_attr_group = {
 502        .attrs = fcoe_fcf_attrs,
 503};
 504
 505static const struct attribute_group *fcoe_fcf_attr_groups[] = {
 506        &fcoe_fcf_attr_group,
 507        NULL,
 508};
 509
 510struct bus_type fcoe_bus_type;
 511
 512static int fcoe_bus_match(struct device *dev,
 513                          struct device_driver *drv)
 514{
 515        if (dev->bus == &fcoe_bus_type)
 516                return 1;
 517        return 0;
 518}
 519
 520/**
 521 * fcoe_ctlr_device_release() - Release the FIP ctlr memory
 522 * @dev: Pointer to the FIP ctlr's embedded device
 523 *
 524 * Called when the last FIP ctlr reference is released.
 525 */
 526static void fcoe_ctlr_device_release(struct device *dev)
 527{
 528        struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
 529        kfree(ctlr);
 530}
 531
 532/**
 533 * fcoe_fcf_device_release() - Release the FIP fcf memory
 534 * @dev: Pointer to the fcf's embedded device
 535 *
 536 * Called when the last FIP fcf reference is released.
 537 */
 538static void fcoe_fcf_device_release(struct device *dev)
 539{
 540        struct fcoe_fcf_device *fcf = dev_to_fcf(dev);
 541        kfree(fcf);
 542}
 543
 544struct device_type fcoe_ctlr_device_type = {
 545        .name = "fcoe_ctlr",
 546        .groups = fcoe_ctlr_attr_groups,
 547        .release = fcoe_ctlr_device_release,
 548};
 549
 550struct device_type fcoe_fcf_device_type = {
 551        .name = "fcoe_fcf",
 552        .groups = fcoe_fcf_attr_groups,
 553        .release = fcoe_fcf_device_release,
 554};
 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
 562struct bus_type fcoe_bus_type = {
 563        .name = "fcoe",
 564        .match = &fcoe_bus_match,
 565        .bus_attrs = fcoe_bus_attr_group,
 566};
 567
 568/**
 569 * fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue
 570 * @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed
 571 */
 572void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
 573{
 574        if (!fcoe_ctlr_work_q(ctlr)) {
 575                printk(KERN_ERR
 576                       "ERROR: FIP Ctlr '%d' attempted to flush work, "
 577                       "when no workqueue created.\n", ctlr->id);
 578                dump_stack();
 579                return;
 580        }
 581
 582        flush_workqueue(fcoe_ctlr_work_q(ctlr));
 583}
 584
 585/**
 586 * fcoe_ctlr_device_queue_work() - Schedule work for a FIP ctlr's workqueue
 587 * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue
 588 * @work:   Work to queue for execution
 589 *
 590 * Return value:
 591 *      1 on success / 0 already queued / < 0 for error
 592 */
 593int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
 594                               struct work_struct *work)
 595{
 596        if (unlikely(!fcoe_ctlr_work_q(ctlr))) {
 597                printk(KERN_ERR
 598                       "ERROR: FIP Ctlr '%d' attempted to queue work, "
 599                       "when no workqueue created.\n", ctlr->id);
 600                dump_stack();
 601
 602                return -EINVAL;
 603        }
 604
 605        return queue_work(fcoe_ctlr_work_q(ctlr), work);
 606}
 607
 608/**
 609 * fcoe_ctlr_device_flush_devloss() - Flush a FIP ctlr's devloss workqueue
 610 * @ctlr: Pointer to FIP ctlr whose workqueue is to be flushed
 611 */
 612void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
 613{
 614        if (!fcoe_ctlr_devloss_work_q(ctlr)) {
 615                printk(KERN_ERR
 616                       "ERROR: FIP Ctlr '%d' attempted to flush work, "
 617                       "when no workqueue created.\n", ctlr->id);
 618                dump_stack();
 619                return;
 620        }
 621
 622        flush_workqueue(fcoe_ctlr_devloss_work_q(ctlr));
 623}
 624
 625/**
 626 * fcoe_ctlr_device_queue_devloss_work() - Schedule work for a FIP ctlr's devloss workqueue
 627 * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue
 628 * @work:   Work to queue for execution
 629 * @delay:  jiffies to delay the work queuing
 630 *
 631 * Return value:
 632 *      1 on success / 0 already queued / < 0 for error
 633 */
 634int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr,
 635                                       struct delayed_work *work,
 636                                       unsigned long delay)
 637{
 638        if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) {
 639                printk(KERN_ERR
 640                       "ERROR: FIP Ctlr '%d' attempted to queue work, "
 641                       "when no workqueue created.\n", ctlr->id);
 642                dump_stack();
 643
 644                return -EINVAL;
 645        }
 646
 647        return queue_delayed_work(fcoe_ctlr_devloss_work_q(ctlr), work, delay);
 648}
 649
 650static int fcoe_fcf_device_match(struct fcoe_fcf_device *new,
 651                                 struct fcoe_fcf_device *old)
 652{
 653        if (new->switch_name == old->switch_name &&
 654            new->fabric_name == old->fabric_name &&
 655            new->fc_map == old->fc_map &&
 656            compare_ether_addr(new->mac, old->mac) == 0)
 657                return 1;
 658        return 0;
 659}
 660
 661/**
 662 * fcoe_ctlr_device_add() - Add a FIP ctlr to sysfs
 663 * @parent:    The parent device to which the fcoe_ctlr instance
 664 *             should be attached
 665 * @f:         The LLD's FCoE sysfs function template pointer
 666 * @priv_size: Size to be allocated with the fcoe_ctlr_device for the LLD
 667 *
 668 * This routine allocates a FIP ctlr object with some additional memory
 669 * for the LLD. The FIP ctlr is initialized, added to sysfs and then
 670 * attributes are added to it.
 671 */
 672struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent,
 673                                    struct fcoe_sysfs_function_template *f,
 674                                    int priv_size)
 675{
 676        struct fcoe_ctlr_device *ctlr;
 677        int error = 0;
 678
 679        ctlr = kzalloc(sizeof(struct fcoe_ctlr_device) + priv_size,
 680                       GFP_KERNEL);
 681        if (!ctlr)
 682                goto out;
 683
 684        ctlr->id = atomic_inc_return(&ctlr_num) - 1;
 685        ctlr->f = f;
 686        ctlr->mode = FIP_CONN_TYPE_FABRIC;
 687        INIT_LIST_HEAD(&ctlr->fcfs);
 688        mutex_init(&ctlr->lock);
 689        ctlr->dev.parent = parent;
 690        ctlr->dev.bus = &fcoe_bus_type;
 691        ctlr->dev.type = &fcoe_ctlr_device_type;
 692
 693        ctlr->fcf_dev_loss_tmo = fcoe_fcf_dev_loss_tmo;
 694
 695        snprintf(ctlr->work_q_name, sizeof(ctlr->work_q_name),
 696                 "ctlr_wq_%d", ctlr->id);
 697        ctlr->work_q = create_singlethread_workqueue(
 698                ctlr->work_q_name);
 699        if (!ctlr->work_q)
 700                goto out_del;
 701
 702        snprintf(ctlr->devloss_work_q_name,
 703                 sizeof(ctlr->devloss_work_q_name),
 704                 "ctlr_dl_wq_%d", ctlr->id);
 705        ctlr->devloss_work_q = create_singlethread_workqueue(
 706                ctlr->devloss_work_q_name);
 707        if (!ctlr->devloss_work_q)
 708                goto out_del_q;
 709
 710        dev_set_name(&ctlr->dev, "ctlr_%d", ctlr->id);
 711        error = device_register(&ctlr->dev);
 712        if (error)
 713                goto out_del_q2;
 714
 715        return ctlr;
 716
 717out_del_q2:
 718        destroy_workqueue(ctlr->devloss_work_q);
 719        ctlr->devloss_work_q = NULL;
 720out_del_q:
 721        destroy_workqueue(ctlr->work_q);
 722        ctlr->work_q = NULL;
 723out_del:
 724        kfree(ctlr);
 725out:
 726        return NULL;
 727}
 728EXPORT_SYMBOL_GPL(fcoe_ctlr_device_add);
 729
 730/**
 731 * fcoe_ctlr_device_delete() - Delete a FIP ctlr and its subtree from sysfs
 732 * @ctlr: A pointer to the ctlr to be deleted
 733 *
 734 * Deletes a FIP ctlr and any fcfs attached
 735 * to it. Deleting fcfs will cause their childen
 736 * to be deleted as well.
 737 *
 738 * The ctlr is detached from sysfs and it's resources
 739 * are freed (work q), but the memory is not freed
 740 * until its last reference is released.
 741 *
 742 * This routine expects no locks to be held before
 743 * calling.
 744 *
 745 * TODO: Currently there are no callbacks to clean up LLD data
 746 * for a fcoe_fcf_device. LLDs must keep this in mind as they need
 747 * to clean up each of their LLD data for all fcoe_fcf_device before
 748 * calling fcoe_ctlr_device_delete.
 749 */
 750void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *ctlr)
 751{
 752        struct fcoe_fcf_device *fcf, *next;
 753        /* Remove any attached fcfs */
 754        mutex_lock(&ctlr->lock);
 755        list_for_each_entry_safe(fcf, next,
 756                                 &ctlr->fcfs, peers) {
 757                list_del(&fcf->peers);
 758                fcf->state = FCOE_FCF_STATE_DELETED;
 759                fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work);
 760        }
 761        mutex_unlock(&ctlr->lock);
 762
 763        fcoe_ctlr_device_flush_work(ctlr);
 764
 765        destroy_workqueue(ctlr->devloss_work_q);
 766        ctlr->devloss_work_q = NULL;
 767        destroy_workqueue(ctlr->work_q);
 768        ctlr->work_q = NULL;
 769
 770        device_unregister(&ctlr->dev);
 771}
 772EXPORT_SYMBOL_GPL(fcoe_ctlr_device_delete);
 773
 774/**
 775 * fcoe_fcf_device_final_delete() - Final delete routine
 776 * @work: The FIP fcf's embedded work struct
 777 *
 778 * It is expected that the fcf has been removed from
 779 * the FIP ctlr's list before calling this routine.
 780 */
 781static void fcoe_fcf_device_final_delete(struct work_struct *work)
 782{
 783        struct fcoe_fcf_device *fcf =
 784                container_of(work, struct fcoe_fcf_device, delete_work);
 785        struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
 786
 787        /*
 788         * Cancel any outstanding timers. These should really exist
 789         * only when rmmod'ing the LLDD and we're asking for
 790         * immediate termination of the rports
 791         */
 792        if (!cancel_delayed_work(&fcf->dev_loss_work))
 793                fcoe_ctlr_device_flush_devloss(ctlr);
 794
 795        device_unregister(&fcf->dev);
 796}
 797
 798/**
 799 * fip_timeout_deleted_fcf() - Delete a fcf when the devloss timer fires
 800 * @work: The FIP fcf's embedded work struct
 801 *
 802 * Removes the fcf from the FIP ctlr's list of fcfs and
 803 * queues the final deletion.
 804 */
 805static void fip_timeout_deleted_fcf(struct work_struct *work)
 806{
 807        struct fcoe_fcf_device *fcf =
 808                container_of(work, struct fcoe_fcf_device, dev_loss_work.work);
 809        struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
 810
 811        mutex_lock(&ctlr->lock);
 812
 813        /*
 814         * If the fcf is deleted or reconnected before the timer
 815         * fires the devloss queue will be flushed, but the state will
 816         * either be CONNECTED or DELETED. If that is the case we
 817         * cancel deleting the fcf.
 818         */
 819        if (fcf->state != FCOE_FCF_STATE_DISCONNECTED)
 820                goto out;
 821
 822        dev_printk(KERN_ERR, &fcf->dev,
 823                   "FIP fcf connection time out: removing fcf\n");
 824
 825        list_del(&fcf->peers);
 826        fcf->state = FCOE_FCF_STATE_DELETED;
 827        fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work);
 828
 829out:
 830        mutex_unlock(&ctlr->lock);
 831}
 832
 833/**
 834 * fcoe_fcf_device_delete() - Delete a FIP fcf
 835 * @fcf: Pointer to the fcf which is to be deleted
 836 *
 837 * Queues the FIP fcf on the devloss workqueue
 838 *
 839 * Expects the ctlr_attrs mutex to be held for fcf
 840 * state change.
 841 */
 842void fcoe_fcf_device_delete(struct fcoe_fcf_device *fcf)
 843{
 844        struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
 845        int timeout = fcf->dev_loss_tmo;
 846
 847        if (fcf->state != FCOE_FCF_STATE_CONNECTED)
 848                return;
 849
 850        fcf->state = FCOE_FCF_STATE_DISCONNECTED;
 851
 852        /*
 853         * FCF will only be re-connected by the LLD calling
 854         * fcoe_fcf_device_add, and it should be setting up
 855         * priv then.
 856         */
 857        fcf->priv = NULL;
 858
 859        fcoe_ctlr_device_queue_devloss_work(ctlr, &fcf->dev_loss_work,
 860                                           timeout * HZ);
 861}
 862EXPORT_SYMBOL_GPL(fcoe_fcf_device_delete);
 863
 864/**
 865 * fcoe_fcf_device_add() - Add a FCoE sysfs fcoe_fcf_device to the system
 866 * @ctlr:    The fcoe_ctlr_device that will be the fcoe_fcf_device parent
 867 * @new_fcf: A temporary FCF used for lookups on the current list of fcfs
 868 *
 869 * Expects to be called with the ctlr->lock held
 870 */
 871struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr,
 872                                            struct fcoe_fcf_device *new_fcf)
 873{
 874        struct fcoe_fcf_device *fcf;
 875        int error = 0;
 876
 877        list_for_each_entry(fcf, &ctlr->fcfs, peers) {
 878                if (fcoe_fcf_device_match(new_fcf, fcf)) {
 879                        if (fcf->state == FCOE_FCF_STATE_CONNECTED)
 880                                return fcf;
 881
 882                        fcf->state = FCOE_FCF_STATE_CONNECTED;
 883
 884                        if (!cancel_delayed_work(&fcf->dev_loss_work))
 885                                fcoe_ctlr_device_flush_devloss(ctlr);
 886
 887                        return fcf;
 888                }
 889        }
 890
 891        fcf = kzalloc(sizeof(struct fcoe_fcf_device), GFP_ATOMIC);
 892        if (unlikely(!fcf))
 893                goto out;
 894
 895        INIT_WORK(&fcf->delete_work, fcoe_fcf_device_final_delete);
 896        INIT_DELAYED_WORK(&fcf->dev_loss_work, fip_timeout_deleted_fcf);
 897
 898        fcf->dev.parent = &ctlr->dev;
 899        fcf->dev.bus = &fcoe_bus_type;
 900        fcf->dev.type = &fcoe_fcf_device_type;
 901        fcf->id = atomic_inc_return(&fcf_num) - 1;
 902        fcf->state = FCOE_FCF_STATE_UNKNOWN;
 903
 904        fcf->dev_loss_tmo = ctlr->fcf_dev_loss_tmo;
 905
 906        dev_set_name(&fcf->dev, "fcf_%d", fcf->id);
 907
 908        fcf->fabric_name = new_fcf->fabric_name;
 909        fcf->switch_name = new_fcf->switch_name;
 910        fcf->fc_map = new_fcf->fc_map;
 911        fcf->vfid = new_fcf->vfid;
 912        memcpy(fcf->mac, new_fcf->mac, ETH_ALEN);
 913        fcf->priority = new_fcf->priority;
 914        fcf->fka_period = new_fcf->fka_period;
 915        fcf->selected = new_fcf->selected;
 916
 917        error = device_register(&fcf->dev);
 918        if (error)
 919                goto out_del;
 920
 921        fcf->state = FCOE_FCF_STATE_CONNECTED;
 922        list_add_tail(&fcf->peers, &ctlr->fcfs);
 923
 924        return fcf;
 925
 926out_del:
 927        kfree(fcf);
 928out:
 929        return NULL;
 930}
 931EXPORT_SYMBOL_GPL(fcoe_fcf_device_add);
 932
 933int __init fcoe_sysfs_setup(void)
 934{
 935        int error;
 936
 937        atomic_set(&ctlr_num, 0);
 938        atomic_set(&fcf_num, 0);
 939
 940        error = bus_register(&fcoe_bus_type);
 941        if (error)
 942                return error;
 943
 944        return 0;
 945}
 946
 947void __exit fcoe_sysfs_teardown(void)
 948{
 949        bus_unregister(&fcoe_bus_type);
 950}
 951