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.\n");
 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.\n");
 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, "Unknown mode %s provided.\n",
 315                                          buf);
 316                        return -EINVAL;
 317                }
 318
 319                ctlr->f->set_fcoe_ctlr_mode(ctlr);
 320                LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.\n", buf);
 321
 322                return count;
 323        case FCOE_CTLR_UNUSED:
 324        default:
 325                LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.\n");
 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
 556static BUS_ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store);
 557static BUS_ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store);
 558
 559static struct attribute *fcoe_bus_attrs[] = {
 560        &bus_attr_ctlr_create.attr,
 561        &bus_attr_ctlr_destroy.attr,
 562        NULL,
 563};
 564ATTRIBUTE_GROUPS(fcoe_bus);
 565
 566struct bus_type fcoe_bus_type = {
 567        .name = "fcoe",
 568        .match = &fcoe_bus_match,
 569        .bus_groups = fcoe_bus_groups,
 570};
 571
 572/**
 573 * fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue
 574 * @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed
 575 */
 576void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
 577{
 578        if (!fcoe_ctlr_work_q(ctlr)) {
 579                printk(KERN_ERR
 580                       "ERROR: FIP Ctlr '%d' attempted to flush work, "
 581                       "when no workqueue created.\n", ctlr->id);
 582                dump_stack();
 583                return;
 584        }
 585
 586        flush_workqueue(fcoe_ctlr_work_q(ctlr));
 587}
 588
 589/**
 590 * fcoe_ctlr_device_queue_work() - Schedule work for a FIP ctlr's workqueue
 591 * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue
 592 * @work:   Work to queue for execution
 593 *
 594 * Return value:
 595 *      1 on success / 0 already queued / < 0 for error
 596 */
 597int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr,
 598                               struct work_struct *work)
 599{
 600        if (unlikely(!fcoe_ctlr_work_q(ctlr))) {
 601                printk(KERN_ERR
 602                       "ERROR: FIP Ctlr '%d' attempted to queue work, "
 603                       "when no workqueue created.\n", ctlr->id);
 604                dump_stack();
 605
 606                return -EINVAL;
 607        }
 608
 609        return queue_work(fcoe_ctlr_work_q(ctlr), work);
 610}
 611
 612/**
 613 * fcoe_ctlr_device_flush_devloss() - Flush a FIP ctlr's devloss workqueue
 614 * @ctlr: Pointer to FIP ctlr whose workqueue is to be flushed
 615 */
 616void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr)
 617{
 618        if (!fcoe_ctlr_devloss_work_q(ctlr)) {
 619                printk(KERN_ERR
 620                       "ERROR: FIP Ctlr '%d' attempted to flush work, "
 621                       "when no workqueue created.\n", ctlr->id);
 622                dump_stack();
 623                return;
 624        }
 625
 626        flush_workqueue(fcoe_ctlr_devloss_work_q(ctlr));
 627}
 628
 629/**
 630 * fcoe_ctlr_device_queue_devloss_work() - Schedule work for a FIP ctlr's devloss workqueue
 631 * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue
 632 * @work:   Work to queue for execution
 633 * @delay:  jiffies to delay the work queuing
 634 *
 635 * Return value:
 636 *      1 on success / 0 already queued / < 0 for error
 637 */
 638int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr,
 639                                       struct delayed_work *work,
 640                                       unsigned long delay)
 641{
 642        if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) {
 643                printk(KERN_ERR
 644                       "ERROR: FIP Ctlr '%d' attempted to queue work, "
 645                       "when no workqueue created.\n", ctlr->id);
 646                dump_stack();
 647
 648                return -EINVAL;
 649        }
 650
 651        return queue_delayed_work(fcoe_ctlr_devloss_work_q(ctlr), work, delay);
 652}
 653
 654static int fcoe_fcf_device_match(struct fcoe_fcf_device *new,
 655                                 struct fcoe_fcf_device *old)
 656{
 657        if (new->switch_name == old->switch_name &&
 658            new->fabric_name == old->fabric_name &&
 659            new->fc_map == old->fc_map &&
 660            ether_addr_equal(new->mac, old->mac))
 661                return 1;
 662        return 0;
 663}
 664
 665/**
 666 * fcoe_ctlr_device_add() - Add a FIP ctlr to sysfs
 667 * @parent:    The parent device to which the fcoe_ctlr instance
 668 *             should be attached
 669 * @f:         The LLD's FCoE sysfs function template pointer
 670 * @priv_size: Size to be allocated with the fcoe_ctlr_device for the LLD
 671 *
 672 * This routine allocates a FIP ctlr object with some additional memory
 673 * for the LLD. The FIP ctlr is initialized, added to sysfs and then
 674 * attributes are added to it.
 675 */
 676struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent,
 677                                    struct fcoe_sysfs_function_template *f,
 678                                    int priv_size)
 679{
 680        struct fcoe_ctlr_device *ctlr;
 681        int error = 0;
 682
 683        ctlr = kzalloc(sizeof(struct fcoe_ctlr_device) + priv_size,
 684                       GFP_KERNEL);
 685        if (!ctlr)
 686                goto out;
 687
 688        ctlr->id = atomic_inc_return(&ctlr_num) - 1;
 689        ctlr->f = f;
 690        ctlr->mode = FIP_CONN_TYPE_FABRIC;
 691        INIT_LIST_HEAD(&ctlr->fcfs);
 692        mutex_init(&ctlr->lock);
 693        ctlr->dev.parent = parent;
 694        ctlr->dev.bus = &fcoe_bus_type;
 695        ctlr->dev.type = &fcoe_ctlr_device_type;
 696
 697        ctlr->fcf_dev_loss_tmo = fcoe_fcf_dev_loss_tmo;
 698
 699        snprintf(ctlr->work_q_name, sizeof(ctlr->work_q_name),
 700                 "ctlr_wq_%d", ctlr->id);
 701        ctlr->work_q = create_singlethread_workqueue(
 702                ctlr->work_q_name);
 703        if (!ctlr->work_q)
 704                goto out_del;
 705
 706        snprintf(ctlr->devloss_work_q_name,
 707                 sizeof(ctlr->devloss_work_q_name),
 708                 "ctlr_dl_wq_%d", ctlr->id);
 709        ctlr->devloss_work_q = create_singlethread_workqueue(
 710                ctlr->devloss_work_q_name);
 711        if (!ctlr->devloss_work_q)
 712                goto out_del_q;
 713
 714        dev_set_name(&ctlr->dev, "ctlr_%d", ctlr->id);
 715        error = device_register(&ctlr->dev);
 716        if (error)
 717                goto out_del_q2;
 718
 719        return ctlr;
 720
 721out_del_q2:
 722        destroy_workqueue(ctlr->devloss_work_q);
 723        ctlr->devloss_work_q = NULL;
 724out_del_q:
 725        destroy_workqueue(ctlr->work_q);
 726        ctlr->work_q = NULL;
 727out_del:
 728        kfree(ctlr);
 729out:
 730        return NULL;
 731}
 732EXPORT_SYMBOL_GPL(fcoe_ctlr_device_add);
 733
 734/**
 735 * fcoe_ctlr_device_delete() - Delete a FIP ctlr and its subtree from sysfs
 736 * @ctlr: A pointer to the ctlr to be deleted
 737 *
 738 * Deletes a FIP ctlr and any fcfs attached
 739 * to it. Deleting fcfs will cause their childen
 740 * to be deleted as well.
 741 *
 742 * The ctlr is detached from sysfs and it's resources
 743 * are freed (work q), but the memory is not freed
 744 * until its last reference is released.
 745 *
 746 * This routine expects no locks to be held before
 747 * calling.
 748 *
 749 * TODO: Currently there are no callbacks to clean up LLD data
 750 * for a fcoe_fcf_device. LLDs must keep this in mind as they need
 751 * to clean up each of their LLD data for all fcoe_fcf_device before
 752 * calling fcoe_ctlr_device_delete.
 753 */
 754void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *ctlr)
 755{
 756        struct fcoe_fcf_device *fcf, *next;
 757        /* Remove any attached fcfs */
 758        mutex_lock(&ctlr->lock);
 759        list_for_each_entry_safe(fcf, next,
 760                                 &ctlr->fcfs, peers) {
 761                list_del(&fcf->peers);
 762                fcf->state = FCOE_FCF_STATE_DELETED;
 763                fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work);
 764        }
 765        mutex_unlock(&ctlr->lock);
 766
 767        fcoe_ctlr_device_flush_work(ctlr);
 768
 769        destroy_workqueue(ctlr->devloss_work_q);
 770        ctlr->devloss_work_q = NULL;
 771        destroy_workqueue(ctlr->work_q);
 772        ctlr->work_q = NULL;
 773
 774        device_unregister(&ctlr->dev);
 775}
 776EXPORT_SYMBOL_GPL(fcoe_ctlr_device_delete);
 777
 778/**
 779 * fcoe_fcf_device_final_delete() - Final delete routine
 780 * @work: The FIP fcf's embedded work struct
 781 *
 782 * It is expected that the fcf has been removed from
 783 * the FIP ctlr's list before calling this routine.
 784 */
 785static void fcoe_fcf_device_final_delete(struct work_struct *work)
 786{
 787        struct fcoe_fcf_device *fcf =
 788                container_of(work, struct fcoe_fcf_device, delete_work);
 789        struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
 790
 791        /*
 792         * Cancel any outstanding timers. These should really exist
 793         * only when rmmod'ing the LLDD and we're asking for
 794         * immediate termination of the rports
 795         */
 796        if (!cancel_delayed_work(&fcf->dev_loss_work))
 797                fcoe_ctlr_device_flush_devloss(ctlr);
 798
 799        device_unregister(&fcf->dev);
 800}
 801
 802/**
 803 * fip_timeout_deleted_fcf() - Delete a fcf when the devloss timer fires
 804 * @work: The FIP fcf's embedded work struct
 805 *
 806 * Removes the fcf from the FIP ctlr's list of fcfs and
 807 * queues the final deletion.
 808 */
 809static void fip_timeout_deleted_fcf(struct work_struct *work)
 810{
 811        struct fcoe_fcf_device *fcf =
 812                container_of(work, struct fcoe_fcf_device, dev_loss_work.work);
 813        struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
 814
 815        mutex_lock(&ctlr->lock);
 816
 817        /*
 818         * If the fcf is deleted or reconnected before the timer
 819         * fires the devloss queue will be flushed, but the state will
 820         * either be CONNECTED or DELETED. If that is the case we
 821         * cancel deleting the fcf.
 822         */
 823        if (fcf->state != FCOE_FCF_STATE_DISCONNECTED)
 824                goto out;
 825
 826        dev_printk(KERN_ERR, &fcf->dev,
 827                   "FIP fcf connection time out: removing fcf\n");
 828
 829        list_del(&fcf->peers);
 830        fcf->state = FCOE_FCF_STATE_DELETED;
 831        fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work);
 832
 833out:
 834        mutex_unlock(&ctlr->lock);
 835}
 836
 837/**
 838 * fcoe_fcf_device_delete() - Delete a FIP fcf
 839 * @fcf: Pointer to the fcf which is to be deleted
 840 *
 841 * Queues the FIP fcf on the devloss workqueue
 842 *
 843 * Expects the ctlr_attrs mutex to be held for fcf
 844 * state change.
 845 */
 846void fcoe_fcf_device_delete(struct fcoe_fcf_device *fcf)
 847{
 848        struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
 849        int timeout = fcf->dev_loss_tmo;
 850
 851        if (fcf->state != FCOE_FCF_STATE_CONNECTED)
 852                return;
 853
 854        fcf->state = FCOE_FCF_STATE_DISCONNECTED;
 855
 856        /*
 857         * FCF will only be re-connected by the LLD calling
 858         * fcoe_fcf_device_add, and it should be setting up
 859         * priv then.
 860         */
 861        fcf->priv = NULL;
 862
 863        fcoe_ctlr_device_queue_devloss_work(ctlr, &fcf->dev_loss_work,
 864                                           timeout * HZ);
 865}
 866EXPORT_SYMBOL_GPL(fcoe_fcf_device_delete);
 867
 868/**
 869 * fcoe_fcf_device_add() - Add a FCoE sysfs fcoe_fcf_device to the system
 870 * @ctlr:    The fcoe_ctlr_device that will be the fcoe_fcf_device parent
 871 * @new_fcf: A temporary FCF used for lookups on the current list of fcfs
 872 *
 873 * Expects to be called with the ctlr->lock held
 874 */
 875struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr,
 876                                            struct fcoe_fcf_device *new_fcf)
 877{
 878        struct fcoe_fcf_device *fcf;
 879        int error = 0;
 880
 881        list_for_each_entry(fcf, &ctlr->fcfs, peers) {
 882                if (fcoe_fcf_device_match(new_fcf, fcf)) {
 883                        if (fcf->state == FCOE_FCF_STATE_CONNECTED)
 884                                return fcf;
 885
 886                        fcf->state = FCOE_FCF_STATE_CONNECTED;
 887
 888                        if (!cancel_delayed_work(&fcf->dev_loss_work))
 889                                fcoe_ctlr_device_flush_devloss(ctlr);
 890
 891                        return fcf;
 892                }
 893        }
 894
 895        fcf = kzalloc(sizeof(struct fcoe_fcf_device), GFP_ATOMIC);
 896        if (unlikely(!fcf))
 897                goto out;
 898
 899        INIT_WORK(&fcf->delete_work, fcoe_fcf_device_final_delete);
 900        INIT_DELAYED_WORK(&fcf->dev_loss_work, fip_timeout_deleted_fcf);
 901
 902        fcf->dev.parent = &ctlr->dev;
 903        fcf->dev.bus = &fcoe_bus_type;
 904        fcf->dev.type = &fcoe_fcf_device_type;
 905        fcf->id = atomic_inc_return(&fcf_num) - 1;
 906        fcf->state = FCOE_FCF_STATE_UNKNOWN;
 907
 908        fcf->dev_loss_tmo = ctlr->fcf_dev_loss_tmo;
 909
 910        dev_set_name(&fcf->dev, "fcf_%d", fcf->id);
 911
 912        fcf->fabric_name = new_fcf->fabric_name;
 913        fcf->switch_name = new_fcf->switch_name;
 914        fcf->fc_map = new_fcf->fc_map;
 915        fcf->vfid = new_fcf->vfid;
 916        memcpy(fcf->mac, new_fcf->mac, ETH_ALEN);
 917        fcf->priority = new_fcf->priority;
 918        fcf->fka_period = new_fcf->fka_period;
 919        fcf->selected = new_fcf->selected;
 920
 921        error = device_register(&fcf->dev);
 922        if (error)
 923                goto out_del;
 924
 925        fcf->state = FCOE_FCF_STATE_CONNECTED;
 926        list_add_tail(&fcf->peers, &ctlr->fcfs);
 927
 928        return fcf;
 929
 930out_del:
 931        kfree(fcf);
 932out:
 933        return NULL;
 934}
 935EXPORT_SYMBOL_GPL(fcoe_fcf_device_add);
 936
 937int __init fcoe_sysfs_setup(void)
 938{
 939        int error;
 940
 941        atomic_set(&ctlr_num, 0);
 942        atomic_set(&fcf_num, 0);
 943
 944        error = bus_register(&fcoe_bus_type);
 945        if (error)
 946                return error;
 947
 948        return 0;
 949}
 950
 951void __exit fcoe_sysfs_teardown(void)
 952{
 953        bus_unregister(&fcoe_bus_type);
 954}
 955