Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] libfcoe: Add fcoe_sysfs

This patch adds a 'fcoe bus' infrastructure to the kernel
that is driven by changes to libfcoe which allow LLDs to
present FIP (FCoE Initialization Protocol) discovered
entities and their attributes to user space via sysfs.

This patch adds the following APIs-

fcoe_ctlr_device_add
fcoe_ctlr_device_delete
fcoe_fcf_device_add
fcoe_fcf_device_delete

They allow the LLD to expose the FCoE ENode Controller
and any discovered FCFs (Fibre Channel Forwarders, e.g.
FCoE switches) to the user. Each of these new devices
has their own bus_type so that they are grouped together
for easy lookup from a user space application. Each
new class has an attribute_group to expose attributes
for any created instances. The attributes are-

fcoe_ctlr_device
* fcf_dev_loss_tmo
* lesb_link_fail
* lesb_vlink_fail
* lesb_miss_fka
* lesb_symb_err
* lesb_err_block
* lesb_fcs_error

fcoe_fcf_device
* fabric_name
* switch_name
* priority
* selected
* fc_map
* vfid
* mac
* fka_peroid
* fabric_state
* dev_loss_tmo

A device loss infrastructre similar to the FC Transport's
is also added by this patch. It is nice to have so that a
link flapping adapter doesn't continually advance the count
used to identify the discovered FCF. FCFs will exist in a
"Disconnected" state until either the timer expires or the
FCF is rediscovered and becomes "Connected."

This patch generates a few checkpatch.pl WARNINGS that
I'm not sure what to do about. They're macros modeled
around the FC Transport attribute building macros, which
have the same 'feature' where the caller can ommit a cast
in the argument list and no cast occurs in the code. I'm
not sure how to keep the code condensed while keeping the
macros. Any advice would be appreciated.

Signed-off-by: Robert Love <robert.w.love@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

authored by

Robert Love and committed by
James Bottomley
9a74e884 fd8f8902

+1046 -3
+77
Documentation/ABI/testing/sysfs-bus-fcoe
··· 1 + What: /sys/bus/fcoe/ctlr_X 2 + Date: March 2012 3 + KernelVersion: TBD 4 + Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org 5 + Description: 'FCoE Controller' instances on the fcoe bus 6 + Attributes: 7 + 8 + fcf_dev_loss_tmo: Device loss timeout peroid (see below). Changing 9 + this value will change the dev_loss_tmo for all 10 + FCFs discovered by this controller. 11 + 12 + lesb_link_fail: Link Error Status Block (LESB) link failure count. 13 + 14 + lesb_vlink_fail: Link Error Status Block (LESB) virtual link 15 + failure count. 16 + 17 + lesb_miss_fka: Link Error Status Block (LESB) missed FCoE 18 + Initialization Protocol (FIP) Keep-Alives (FKA). 19 + 20 + lesb_symb_err: Link Error Status Block (LESB) symbolic error count. 21 + 22 + lesb_err_block: Link Error Status Block (LESB) block error count. 23 + 24 + lesb_fcs_error: Link Error Status Block (LESB) Fibre Channel 25 + Serivces error count. 26 + 27 + Notes: ctlr_X (global increment starting at 0) 28 + 29 + What: /sys/bus/fcoe/fcf_X 30 + Date: March 2012 31 + KernelVersion: TBD 32 + Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org 33 + Description: 'FCoE FCF' instances on the fcoe bus. A FCF is a Fibre Channel 34 + Forwarder, which is a FCoE switch that can accept FCoE 35 + (Ethernet) packets, unpack them, and forward the embedded 36 + Fibre Channel frames into a FC fabric. It can also take 37 + outbound FC frames and pack them in Ethernet packets to 38 + be sent to their destination on the Ethernet segment. 39 + Attributes: 40 + 41 + fabric_name: Identifies the fabric that the FCF services. 42 + 43 + switch_name: Identifies the FCF. 44 + 45 + priority: The switch's priority amongst other FCFs on the same 46 + fabric. 47 + 48 + selected: 1 indicates that the switch has been selected for use; 49 + 0 indicates that the swich will not be used. 50 + 51 + fc_map: The Fibre Channel MAP 52 + 53 + vfid: The Virtual Fabric ID 54 + 55 + mac: The FCF's MAC address 56 + 57 + fka_peroid: The FIP Keep-Alive peroid 58 + 59 + fabric_state: The internal kernel state 60 + "Unknown" - Initialization value 61 + "Disconnected" - No link to the FCF/fabric 62 + "Connected" - Host is connected to the FCF 63 + "Deleted" - FCF is being removed from the system 64 + 65 + dev_loss_tmo: The device loss timeout peroid for this FCF. 66 + 67 + Notes: A device loss infrastructre similar to the FC Transport's 68 + is present in fcoe_sysfs. It is nice to have so that a 69 + link flapping adapter doesn't continually advance the count 70 + used to identify the discovered FCF. FCFs will exist in a 71 + "Disconnected" state until either the timer expires and the 72 + FCF becomes "Deleted" or the FCF is rediscovered and becomes 73 + "Connected." 74 + 75 + 76 + Users: The first user of this interface will be the fcoeadm application, 77 + which is commonly packaged in the fcoe-utils package.
+1 -1
drivers/scsi/fcoe/Makefile
··· 1 1 obj-$(CONFIG_FCOE) += fcoe.o 2 2 obj-$(CONFIG_LIBFCOE) += libfcoe.o 3 3 4 - libfcoe-objs := fcoe_ctlr.o fcoe_transport.o 4 + libfcoe-objs := fcoe_ctlr.o fcoe_transport.o fcoe_sysfs.o
+832
drivers/scsi/fcoe/fcoe_sysfs.c
··· 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 + 25 + #include <scsi/fcoe_sysfs.h> 26 + 27 + static atomic_t ctlr_num; 28 + static atomic_t fcf_num; 29 + 30 + /* 31 + * fcoe_fcf_dev_loss_tmo: the default number of seconds that fcoe sysfs 32 + * should insulate the loss of a fcf. 33 + */ 34 + static unsigned int fcoe_fcf_dev_loss_tmo = 1800; /* seconds */ 35 + 36 + module_param_named(fcf_dev_loss_tmo, fcoe_fcf_dev_loss_tmo, 37 + uint, S_IRUGO|S_IWUSR); 38 + MODULE_PARM_DESC(fcf_dev_loss_tmo, 39 + "Maximum number of seconds that libfcoe should" 40 + " insulate the loss of a fcf. Once this value is" 41 + " exceeded, the fcf is removed."); 42 + 43 + /* 44 + * These are used by the fcoe_*_show_function routines, they 45 + * are intentionally placed in the .c file as they're not intended 46 + * for use throughout the code. 47 + */ 48 + #define fcoe_ctlr_id(x) \ 49 + ((x)->id) 50 + #define fcoe_ctlr_work_q_name(x) \ 51 + ((x)->work_q_name) 52 + #define fcoe_ctlr_work_q(x) \ 53 + ((x)->work_q) 54 + #define fcoe_ctlr_devloss_work_q_name(x) \ 55 + ((x)->devloss_work_q_name) 56 + #define fcoe_ctlr_devloss_work_q(x) \ 57 + ((x)->devloss_work_q) 58 + #define fcoe_ctlr_mode(x) \ 59 + ((x)->mode) 60 + #define fcoe_ctlr_fcf_dev_loss_tmo(x) \ 61 + ((x)->fcf_dev_loss_tmo) 62 + #define fcoe_ctlr_link_fail(x) \ 63 + ((x)->lesb.lesb_link_fail) 64 + #define fcoe_ctlr_vlink_fail(x) \ 65 + ((x)->lesb.lesb_vlink_fail) 66 + #define fcoe_ctlr_miss_fka(x) \ 67 + ((x)->lesb.lesb_miss_fka) 68 + #define fcoe_ctlr_symb_err(x) \ 69 + ((x)->lesb.lesb_symb_err) 70 + #define fcoe_ctlr_err_block(x) \ 71 + ((x)->lesb.lesb_err_block) 72 + #define fcoe_ctlr_fcs_error(x) \ 73 + ((x)->lesb.lesb_fcs_error) 74 + #define fcoe_fcf_state(x) \ 75 + ((x)->state) 76 + #define fcoe_fcf_fabric_name(x) \ 77 + ((x)->fabric_name) 78 + #define fcoe_fcf_switch_name(x) \ 79 + ((x)->switch_name) 80 + #define fcoe_fcf_fc_map(x) \ 81 + ((x)->fc_map) 82 + #define fcoe_fcf_vfid(x) \ 83 + ((x)->vfid) 84 + #define fcoe_fcf_mac(x) \ 85 + ((x)->mac) 86 + #define fcoe_fcf_priority(x) \ 87 + ((x)->priority) 88 + #define fcoe_fcf_fka_period(x) \ 89 + ((x)->fka_period) 90 + #define fcoe_fcf_dev_loss_tmo(x) \ 91 + ((x)->dev_loss_tmo) 92 + #define fcoe_fcf_selected(x) \ 93 + ((x)->selected) 94 + #define fcoe_fcf_vlan_id(x) \ 95 + ((x)->vlan_id) 96 + 97 + /* 98 + * dev_loss_tmo attribute 99 + */ 100 + static int fcoe_str_to_dev_loss(const char *buf, unsigned long *val) 101 + { 102 + int ret; 103 + 104 + ret = kstrtoul(buf, 0, val); 105 + if (ret || *val < 0) 106 + return -EINVAL; 107 + /* 108 + * Check for overflow; dev_loss_tmo is u32 109 + */ 110 + if (*val > UINT_MAX) 111 + return -EINVAL; 112 + 113 + return 0; 114 + } 115 + 116 + static int fcoe_fcf_set_dev_loss_tmo(struct fcoe_fcf_device *fcf, 117 + unsigned long val) 118 + { 119 + if ((fcf->state == FCOE_FCF_STATE_UNKNOWN) || 120 + (fcf->state == FCOE_FCF_STATE_DISCONNECTED) || 121 + (fcf->state == FCOE_FCF_STATE_DELETED)) 122 + return -EBUSY; 123 + /* 124 + * Check for overflow; dev_loss_tmo is u32 125 + */ 126 + if (val > UINT_MAX) 127 + return -EINVAL; 128 + 129 + fcoe_fcf_dev_loss_tmo(fcf) = val; 130 + return 0; 131 + } 132 + 133 + #define FCOE_DEVICE_ATTR(_prefix, _name, _mode, _show, _store) \ 134 + struct device_attribute device_attr_fcoe_##_prefix##_##_name = \ 135 + __ATTR(_name, _mode, _show, _store) 136 + 137 + #define fcoe_ctlr_show_function(field, format_string, sz, cast) \ 138 + static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \ 139 + struct device_attribute *attr, \ 140 + char *buf) \ 141 + { \ 142 + struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); \ 143 + if (ctlr->f->get_fcoe_ctlr_##field) \ 144 + ctlr->f->get_fcoe_ctlr_##field(ctlr); \ 145 + return snprintf(buf, sz, format_string, \ 146 + cast fcoe_ctlr_##field(ctlr)); \ 147 + } 148 + 149 + #define fcoe_fcf_show_function(field, format_string, sz, cast) \ 150 + static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \ 151 + struct device_attribute *attr, \ 152 + char *buf) \ 153 + { \ 154 + struct fcoe_fcf_device *fcf = dev_to_fcf(dev); \ 155 + struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); \ 156 + if (ctlr->f->get_fcoe_fcf_##field) \ 157 + ctlr->f->get_fcoe_fcf_##field(fcf); \ 158 + return snprintf(buf, sz, format_string, \ 159 + cast fcoe_fcf_##field(fcf)); \ 160 + } 161 + 162 + #define fcoe_ctlr_private_show_function(field, format_string, sz, cast) \ 163 + static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \ 164 + struct device_attribute *attr, \ 165 + char *buf) \ 166 + { \ 167 + struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); \ 168 + return snprintf(buf, sz, format_string, cast fcoe_ctlr_##field(ctlr)); \ 169 + } 170 + 171 + #define fcoe_fcf_private_show_function(field, format_string, sz, cast) \ 172 + static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \ 173 + struct device_attribute *attr, \ 174 + char *buf) \ 175 + { \ 176 + struct fcoe_fcf_device *fcf = dev_to_fcf(dev); \ 177 + return snprintf(buf, sz, format_string, cast fcoe_fcf_##field(fcf)); \ 178 + } 179 + 180 + #define fcoe_ctlr_private_rd_attr(field, format_string, sz) \ 181 + fcoe_ctlr_private_show_function(field, format_string, sz, ) \ 182 + static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO, \ 183 + show_fcoe_ctlr_device_##field, NULL) 184 + 185 + #define fcoe_ctlr_rd_attr(field, format_string, sz) \ 186 + fcoe_ctlr_show_function(field, format_string, sz, ) \ 187 + static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO, \ 188 + show_fcoe_ctlr_device_##field, NULL) 189 + 190 + #define fcoe_fcf_rd_attr(field, format_string, sz) \ 191 + fcoe_fcf_show_function(field, format_string, sz, ) \ 192 + static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO, \ 193 + show_fcoe_fcf_device_##field, NULL) 194 + 195 + #define fcoe_fcf_private_rd_attr(field, format_string, sz) \ 196 + fcoe_fcf_private_show_function(field, format_string, sz, ) \ 197 + static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO, \ 198 + show_fcoe_fcf_device_##field, NULL) 199 + 200 + #define fcoe_ctlr_private_rd_attr_cast(field, format_string, sz, cast) \ 201 + fcoe_ctlr_private_show_function(field, format_string, sz, (cast)) \ 202 + static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO, \ 203 + show_fcoe_ctlr_device_##field, NULL) 204 + 205 + #define fcoe_fcf_private_rd_attr_cast(field, format_string, sz, cast) \ 206 + fcoe_fcf_private_show_function(field, format_string, sz, (cast)) \ 207 + static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO, \ 208 + show_fcoe_fcf_device_##field, NULL) 209 + 210 + #define fcoe_enum_name_search(title, table_type, table) \ 211 + static const char *get_fcoe_##title##_name(enum table_type table_key) \ 212 + { \ 213 + int i; \ 214 + char *name = NULL; \ 215 + \ 216 + for (i = 0; i < ARRAY_SIZE(table); i++) { \ 217 + if (table[i].value == table_key) { \ 218 + name = table[i].name; \ 219 + break; \ 220 + } \ 221 + } \ 222 + return name; \ 223 + } 224 + 225 + static struct { 226 + enum fcf_state value; 227 + char *name; 228 + } fcf_state_names[] = { 229 + { FCOE_FCF_STATE_UNKNOWN, "Unknown" }, 230 + { FCOE_FCF_STATE_DISCONNECTED, "Disconnected" }, 231 + { FCOE_FCF_STATE_CONNECTED, "Connected" }, 232 + }; 233 + fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names) 234 + #define FCOE_FCF_STATE_MAX_NAMELEN 50 235 + 236 + static ssize_t show_fcf_state(struct device *dev, 237 + struct device_attribute *attr, 238 + char *buf) 239 + { 240 + struct fcoe_fcf_device *fcf = dev_to_fcf(dev); 241 + const char *name; 242 + name = get_fcoe_fcf_state_name(fcf->state); 243 + if (!name) 244 + return -EINVAL; 245 + return snprintf(buf, FCOE_FCF_STATE_MAX_NAMELEN, "%s\n", name); 246 + } 247 + static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL); 248 + 249 + static struct { 250 + enum fip_conn_type value; 251 + char *name; 252 + } fip_conn_type_names[] = { 253 + { FIP_CONN_TYPE_UNKNOWN, "Unknown" }, 254 + { FIP_CONN_TYPE_FABRIC, "Fabric" }, 255 + { FIP_CONN_TYPE_VN2VN, "VN2VN" }, 256 + }; 257 + fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names) 258 + #define FCOE_CTLR_MODE_MAX_NAMELEN 50 259 + 260 + static ssize_t show_ctlr_mode(struct device *dev, 261 + struct device_attribute *attr, 262 + char *buf) 263 + { 264 + struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); 265 + const char *name; 266 + 267 + if (ctlr->f->get_fcoe_ctlr_mode) 268 + ctlr->f->get_fcoe_ctlr_mode(ctlr); 269 + 270 + name = get_fcoe_ctlr_mode_name(ctlr->mode); 271 + if (!name) 272 + return -EINVAL; 273 + return snprintf(buf, FCOE_CTLR_MODE_MAX_NAMELEN, 274 + "%s\n", name); 275 + } 276 + static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO, 277 + show_ctlr_mode, NULL); 278 + 279 + static ssize_t 280 + store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev, 281 + struct device_attribute *attr, 282 + const char *buf, size_t count) 283 + { 284 + struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); 285 + struct fcoe_fcf_device *fcf; 286 + unsigned long val; 287 + int rc; 288 + 289 + rc = fcoe_str_to_dev_loss(buf, &val); 290 + if (rc) 291 + return rc; 292 + 293 + fcoe_ctlr_fcf_dev_loss_tmo(ctlr) = val; 294 + mutex_lock(&ctlr->lock); 295 + list_for_each_entry(fcf, &ctlr->fcfs, peers) 296 + fcoe_fcf_set_dev_loss_tmo(fcf, val); 297 + mutex_unlock(&ctlr->lock); 298 + return count; 299 + } 300 + fcoe_ctlr_private_show_function(fcf_dev_loss_tmo, "%d\n", 20, ); 301 + static FCOE_DEVICE_ATTR(ctlr, fcf_dev_loss_tmo, S_IRUGO | S_IWUSR, 302 + show_fcoe_ctlr_device_fcf_dev_loss_tmo, 303 + store_private_fcoe_ctlr_fcf_dev_loss_tmo); 304 + 305 + /* Link Error Status Block (LESB) */ 306 + fcoe_ctlr_rd_attr(link_fail, "%u\n", 20); 307 + fcoe_ctlr_rd_attr(vlink_fail, "%u\n", 20); 308 + fcoe_ctlr_rd_attr(miss_fka, "%u\n", 20); 309 + fcoe_ctlr_rd_attr(symb_err, "%u\n", 20); 310 + fcoe_ctlr_rd_attr(err_block, "%u\n", 20); 311 + fcoe_ctlr_rd_attr(fcs_error, "%u\n", 20); 312 + 313 + fcoe_fcf_private_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long); 314 + fcoe_fcf_private_rd_attr_cast(switch_name, "0x%llx\n", 20, unsigned long long); 315 + fcoe_fcf_private_rd_attr(priority, "%u\n", 20); 316 + fcoe_fcf_private_rd_attr(fc_map, "0x%x\n", 20); 317 + fcoe_fcf_private_rd_attr(vfid, "%u\n", 20); 318 + fcoe_fcf_private_rd_attr(mac, "%pM\n", 20); 319 + fcoe_fcf_private_rd_attr(fka_period, "%u\n", 20); 320 + fcoe_fcf_rd_attr(selected, "%u\n", 20); 321 + fcoe_fcf_rd_attr(vlan_id, "%u\n", 20); 322 + 323 + fcoe_fcf_private_show_function(dev_loss_tmo, "%d\n", 20, ) 324 + static ssize_t 325 + store_fcoe_fcf_dev_loss_tmo(struct device *dev, struct device_attribute *attr, 326 + const char *buf, size_t count) 327 + { 328 + struct fcoe_fcf_device *fcf = dev_to_fcf(dev); 329 + unsigned long val; 330 + int rc; 331 + 332 + rc = fcoe_str_to_dev_loss(buf, &val); 333 + if (rc) 334 + return rc; 335 + 336 + rc = fcoe_fcf_set_dev_loss_tmo(fcf, val); 337 + if (rc) 338 + return rc; 339 + return count; 340 + } 341 + static FCOE_DEVICE_ATTR(fcf, dev_loss_tmo, S_IRUGO | S_IWUSR, 342 + show_fcoe_fcf_device_dev_loss_tmo, 343 + store_fcoe_fcf_dev_loss_tmo); 344 + 345 + static struct attribute *fcoe_ctlr_lesb_attrs[] = { 346 + &device_attr_fcoe_ctlr_link_fail.attr, 347 + &device_attr_fcoe_ctlr_vlink_fail.attr, 348 + &device_attr_fcoe_ctlr_miss_fka.attr, 349 + &device_attr_fcoe_ctlr_symb_err.attr, 350 + &device_attr_fcoe_ctlr_err_block.attr, 351 + &device_attr_fcoe_ctlr_fcs_error.attr, 352 + NULL, 353 + }; 354 + 355 + static struct attribute_group fcoe_ctlr_lesb_attr_group = { 356 + .name = "lesb", 357 + .attrs = fcoe_ctlr_lesb_attrs, 358 + }; 359 + 360 + static struct attribute *fcoe_ctlr_attrs[] = { 361 + &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr, 362 + &device_attr_fcoe_ctlr_mode.attr, 363 + NULL, 364 + }; 365 + 366 + static struct attribute_group fcoe_ctlr_attr_group = { 367 + .attrs = fcoe_ctlr_attrs, 368 + }; 369 + 370 + static const struct attribute_group *fcoe_ctlr_attr_groups[] = { 371 + &fcoe_ctlr_attr_group, 372 + &fcoe_ctlr_lesb_attr_group, 373 + NULL, 374 + }; 375 + 376 + static struct attribute *fcoe_fcf_attrs[] = { 377 + &device_attr_fcoe_fcf_fabric_name.attr, 378 + &device_attr_fcoe_fcf_switch_name.attr, 379 + &device_attr_fcoe_fcf_dev_loss_tmo.attr, 380 + &device_attr_fcoe_fcf_fc_map.attr, 381 + &device_attr_fcoe_fcf_vfid.attr, 382 + &device_attr_fcoe_fcf_mac.attr, 383 + &device_attr_fcoe_fcf_priority.attr, 384 + &device_attr_fcoe_fcf_fka_period.attr, 385 + &device_attr_fcoe_fcf_state.attr, 386 + &device_attr_fcoe_fcf_selected.attr, 387 + &device_attr_fcoe_fcf_vlan_id.attr, 388 + NULL 389 + }; 390 + 391 + static struct attribute_group fcoe_fcf_attr_group = { 392 + .attrs = fcoe_fcf_attrs, 393 + }; 394 + 395 + static const struct attribute_group *fcoe_fcf_attr_groups[] = { 396 + &fcoe_fcf_attr_group, 397 + NULL, 398 + }; 399 + 400 + struct bus_type fcoe_bus_type; 401 + 402 + static int fcoe_bus_match(struct device *dev, 403 + struct device_driver *drv) 404 + { 405 + if (dev->bus == &fcoe_bus_type) 406 + return 1; 407 + return 0; 408 + } 409 + 410 + /** 411 + * fcoe_ctlr_device_release() - Release the FIP ctlr memory 412 + * @dev: Pointer to the FIP ctlr's embedded device 413 + * 414 + * Called when the last FIP ctlr reference is released. 415 + */ 416 + static void fcoe_ctlr_device_release(struct device *dev) 417 + { 418 + struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); 419 + kfree(ctlr); 420 + } 421 + 422 + /** 423 + * fcoe_fcf_device_release() - Release the FIP fcf memory 424 + * @dev: Pointer to the fcf's embedded device 425 + * 426 + * Called when the last FIP fcf reference is released. 427 + */ 428 + static void fcoe_fcf_device_release(struct device *dev) 429 + { 430 + struct fcoe_fcf_device *fcf = dev_to_fcf(dev); 431 + kfree(fcf); 432 + } 433 + 434 + struct device_type fcoe_ctlr_device_type = { 435 + .name = "fcoe_ctlr", 436 + .groups = fcoe_ctlr_attr_groups, 437 + .release = fcoe_ctlr_device_release, 438 + }; 439 + 440 + struct device_type fcoe_fcf_device_type = { 441 + .name = "fcoe_fcf", 442 + .groups = fcoe_fcf_attr_groups, 443 + .release = fcoe_fcf_device_release, 444 + }; 445 + 446 + struct bus_type fcoe_bus_type = { 447 + .name = "fcoe", 448 + .match = &fcoe_bus_match, 449 + }; 450 + 451 + /** 452 + * fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue 453 + * @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed 454 + */ 455 + void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr) 456 + { 457 + if (!fcoe_ctlr_work_q(ctlr)) { 458 + printk(KERN_ERR 459 + "ERROR: FIP Ctlr '%d' attempted to flush work, " 460 + "when no workqueue created.\n", ctlr->id); 461 + dump_stack(); 462 + return; 463 + } 464 + 465 + flush_workqueue(fcoe_ctlr_work_q(ctlr)); 466 + } 467 + 468 + /** 469 + * fcoe_ctlr_device_queue_work() - Schedule work for a FIP ctlr's workqueue 470 + * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue 471 + * @work: Work to queue for execution 472 + * 473 + * Return value: 474 + * 1 on success / 0 already queued / < 0 for error 475 + */ 476 + int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr, 477 + struct work_struct *work) 478 + { 479 + if (unlikely(!fcoe_ctlr_work_q(ctlr))) { 480 + printk(KERN_ERR 481 + "ERROR: FIP Ctlr '%d' attempted to queue work, " 482 + "when no workqueue created.\n", ctlr->id); 483 + dump_stack(); 484 + 485 + return -EINVAL; 486 + } 487 + 488 + return queue_work(fcoe_ctlr_work_q(ctlr), work); 489 + } 490 + 491 + /** 492 + * fcoe_ctlr_device_flush_devloss() - Flush a FIP ctlr's devloss workqueue 493 + * @ctlr: Pointer to FIP ctlr whose workqueue is to be flushed 494 + */ 495 + void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr) 496 + { 497 + if (!fcoe_ctlr_devloss_work_q(ctlr)) { 498 + printk(KERN_ERR 499 + "ERROR: FIP Ctlr '%d' attempted to flush work, " 500 + "when no workqueue created.\n", ctlr->id); 501 + dump_stack(); 502 + return; 503 + } 504 + 505 + flush_workqueue(fcoe_ctlr_devloss_work_q(ctlr)); 506 + } 507 + 508 + /** 509 + * fcoe_ctlr_device_queue_devloss_work() - Schedule work for a FIP ctlr's devloss workqueue 510 + * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue 511 + * @work: Work to queue for execution 512 + * @delay: jiffies to delay the work queuing 513 + * 514 + * Return value: 515 + * 1 on success / 0 already queued / < 0 for error 516 + */ 517 + int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr, 518 + struct delayed_work *work, 519 + unsigned long delay) 520 + { 521 + if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) { 522 + printk(KERN_ERR 523 + "ERROR: FIP Ctlr '%d' attempted to queue work, " 524 + "when no workqueue created.\n", ctlr->id); 525 + dump_stack(); 526 + 527 + return -EINVAL; 528 + } 529 + 530 + return queue_delayed_work(fcoe_ctlr_devloss_work_q(ctlr), work, delay); 531 + } 532 + 533 + static int fcoe_fcf_device_match(struct fcoe_fcf_device *new, 534 + struct fcoe_fcf_device *old) 535 + { 536 + if (new->switch_name == old->switch_name && 537 + new->fabric_name == old->fabric_name && 538 + new->fc_map == old->fc_map && 539 + compare_ether_addr(new->mac, old->mac) == 0) 540 + return 1; 541 + return 0; 542 + } 543 + 544 + /** 545 + * fcoe_ctlr_device_add() - Add a FIP ctlr to sysfs 546 + * @parent: The parent device to which the fcoe_ctlr instance 547 + * should be attached 548 + * @f: The LLD's FCoE sysfs function template pointer 549 + * @priv_size: Size to be allocated with the fcoe_ctlr_device for the LLD 550 + * 551 + * This routine allocates a FIP ctlr object with some additional memory 552 + * for the LLD. The FIP ctlr is initialized, added to sysfs and then 553 + * attributes are added to it. 554 + */ 555 + struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, 556 + struct fcoe_sysfs_function_template *f, 557 + int priv_size) 558 + { 559 + struct fcoe_ctlr_device *ctlr; 560 + int error = 0; 561 + 562 + ctlr = kzalloc(sizeof(struct fcoe_ctlr_device) + priv_size, 563 + GFP_KERNEL); 564 + if (!ctlr) 565 + goto out; 566 + 567 + ctlr->id = atomic_inc_return(&ctlr_num) - 1; 568 + ctlr->f = f; 569 + INIT_LIST_HEAD(&ctlr->fcfs); 570 + mutex_init(&ctlr->lock); 571 + ctlr->dev.parent = parent; 572 + ctlr->dev.bus = &fcoe_bus_type; 573 + ctlr->dev.type = &fcoe_ctlr_device_type; 574 + 575 + ctlr->fcf_dev_loss_tmo = fcoe_fcf_dev_loss_tmo; 576 + 577 + snprintf(ctlr->work_q_name, sizeof(ctlr->work_q_name), 578 + "ctlr_wq_%d", ctlr->id); 579 + ctlr->work_q = create_singlethread_workqueue( 580 + ctlr->work_q_name); 581 + if (!ctlr->work_q) 582 + goto out_del; 583 + 584 + snprintf(ctlr->devloss_work_q_name, 585 + sizeof(ctlr->devloss_work_q_name), 586 + "ctlr_dl_wq_%d", ctlr->id); 587 + ctlr->devloss_work_q = create_singlethread_workqueue( 588 + ctlr->devloss_work_q_name); 589 + if (!ctlr->devloss_work_q) 590 + goto out_del_q; 591 + 592 + dev_set_name(&ctlr->dev, "ctlr_%d", ctlr->id); 593 + error = device_register(&ctlr->dev); 594 + if (error) 595 + goto out_del_q2; 596 + 597 + return ctlr; 598 + 599 + out_del_q2: 600 + destroy_workqueue(ctlr->devloss_work_q); 601 + ctlr->devloss_work_q = NULL; 602 + out_del_q: 603 + destroy_workqueue(ctlr->work_q); 604 + ctlr->work_q = NULL; 605 + out_del: 606 + kfree(ctlr); 607 + out: 608 + return NULL; 609 + } 610 + EXPORT_SYMBOL_GPL(fcoe_ctlr_device_add); 611 + 612 + /** 613 + * fcoe_ctlr_device_delete() - Delete a FIP ctlr and its subtree from sysfs 614 + * @ctlr: A pointer to the ctlr to be deleted 615 + * 616 + * Deletes a FIP ctlr and any fcfs attached 617 + * to it. Deleting fcfs will cause their childen 618 + * to be deleted as well. 619 + * 620 + * The ctlr is detached from sysfs and it's resources 621 + * are freed (work q), but the memory is not freed 622 + * until its last reference is released. 623 + * 624 + * This routine expects no locks to be held before 625 + * calling. 626 + * 627 + * TODO: Currently there are no callbacks to clean up LLD data 628 + * for a fcoe_fcf_device. LLDs must keep this in mind as they need 629 + * to clean up each of their LLD data for all fcoe_fcf_device before 630 + * calling fcoe_ctlr_device_delete. 631 + */ 632 + void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *ctlr) 633 + { 634 + struct fcoe_fcf_device *fcf, *next; 635 + /* Remove any attached fcfs */ 636 + mutex_lock(&ctlr->lock); 637 + list_for_each_entry_safe(fcf, next, 638 + &ctlr->fcfs, peers) { 639 + list_del(&fcf->peers); 640 + fcf->state = FCOE_FCF_STATE_DELETED; 641 + fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work); 642 + } 643 + mutex_unlock(&ctlr->lock); 644 + 645 + fcoe_ctlr_device_flush_work(ctlr); 646 + 647 + destroy_workqueue(ctlr->devloss_work_q); 648 + ctlr->devloss_work_q = NULL; 649 + destroy_workqueue(ctlr->work_q); 650 + ctlr->work_q = NULL; 651 + 652 + device_unregister(&ctlr->dev); 653 + } 654 + EXPORT_SYMBOL_GPL(fcoe_ctlr_device_delete); 655 + 656 + /** 657 + * fcoe_fcf_device_final_delete() - Final delete routine 658 + * @work: The FIP fcf's embedded work struct 659 + * 660 + * It is expected that the fcf has been removed from 661 + * the FIP ctlr's list before calling this routine. 662 + */ 663 + static void fcoe_fcf_device_final_delete(struct work_struct *work) 664 + { 665 + struct fcoe_fcf_device *fcf = 666 + container_of(work, struct fcoe_fcf_device, delete_work); 667 + struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); 668 + 669 + /* 670 + * Cancel any outstanding timers. These should really exist 671 + * only when rmmod'ing the LLDD and we're asking for 672 + * immediate termination of the rports 673 + */ 674 + if (!cancel_delayed_work(&fcf->dev_loss_work)) 675 + fcoe_ctlr_device_flush_devloss(ctlr); 676 + 677 + device_unregister(&fcf->dev); 678 + } 679 + 680 + /** 681 + * fip_timeout_deleted_fcf() - Delete a fcf when the devloss timer fires 682 + * @work: The FIP fcf's embedded work struct 683 + * 684 + * Removes the fcf from the FIP ctlr's list of fcfs and 685 + * queues the final deletion. 686 + */ 687 + static void fip_timeout_deleted_fcf(struct work_struct *work) 688 + { 689 + struct fcoe_fcf_device *fcf = 690 + container_of(work, struct fcoe_fcf_device, dev_loss_work.work); 691 + struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); 692 + 693 + mutex_lock(&ctlr->lock); 694 + 695 + /* 696 + * If the fcf is deleted or reconnected before the timer 697 + * fires the devloss queue will be flushed, but the state will 698 + * either be CONNECTED or DELETED. If that is the case we 699 + * cancel deleting the fcf. 700 + */ 701 + if (fcf->state != FCOE_FCF_STATE_DISCONNECTED) 702 + goto out; 703 + 704 + dev_printk(KERN_ERR, &fcf->dev, 705 + "FIP fcf connection time out: removing fcf\n"); 706 + 707 + list_del(&fcf->peers); 708 + fcf->state = FCOE_FCF_STATE_DELETED; 709 + fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work); 710 + 711 + out: 712 + mutex_unlock(&ctlr->lock); 713 + } 714 + 715 + /** 716 + * fcoe_fcf_device_delete() - Delete a FIP fcf 717 + * @fcf: Pointer to the fcf which is to be deleted 718 + * 719 + * Queues the FIP fcf on the devloss workqueue 720 + * 721 + * Expects the ctlr_attrs mutex to be held for fcf 722 + * state change. 723 + */ 724 + void fcoe_fcf_device_delete(struct fcoe_fcf_device *fcf) 725 + { 726 + struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); 727 + int timeout = fcf->dev_loss_tmo; 728 + 729 + if (fcf->state != FCOE_FCF_STATE_CONNECTED) 730 + return; 731 + 732 + fcf->state = FCOE_FCF_STATE_DISCONNECTED; 733 + 734 + /* 735 + * FCF will only be re-connected by the LLD calling 736 + * fcoe_fcf_device_add, and it should be setting up 737 + * priv then. 738 + */ 739 + fcf->priv = NULL; 740 + 741 + fcoe_ctlr_device_queue_devloss_work(ctlr, &fcf->dev_loss_work, 742 + timeout * HZ); 743 + } 744 + EXPORT_SYMBOL_GPL(fcoe_fcf_device_delete); 745 + 746 + /** 747 + * fcoe_fcf_device_add() - Add a FCoE sysfs fcoe_fcf_device to the system 748 + * @ctlr: The fcoe_ctlr_device that will be the fcoe_fcf_device parent 749 + * @new_fcf: A temporary FCF used for lookups on the current list of fcfs 750 + * 751 + * Expects to be called with the ctlr->lock held 752 + */ 753 + struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr, 754 + struct fcoe_fcf_device *new_fcf) 755 + { 756 + struct fcoe_fcf_device *fcf; 757 + int error = 0; 758 + 759 + list_for_each_entry(fcf, &ctlr->fcfs, peers) { 760 + if (fcoe_fcf_device_match(new_fcf, fcf)) { 761 + if (fcf->state == FCOE_FCF_STATE_CONNECTED) 762 + return fcf; 763 + 764 + fcf->state = FCOE_FCF_STATE_CONNECTED; 765 + 766 + if (!cancel_delayed_work(&fcf->dev_loss_work)) 767 + fcoe_ctlr_device_flush_devloss(ctlr); 768 + 769 + return fcf; 770 + } 771 + } 772 + 773 + fcf = kzalloc(sizeof(struct fcoe_fcf_device), GFP_ATOMIC); 774 + if (unlikely(!fcf)) 775 + goto out; 776 + 777 + INIT_WORK(&fcf->delete_work, fcoe_fcf_device_final_delete); 778 + INIT_DELAYED_WORK(&fcf->dev_loss_work, fip_timeout_deleted_fcf); 779 + 780 + fcf->dev.parent = &ctlr->dev; 781 + fcf->dev.bus = &fcoe_bus_type; 782 + fcf->dev.type = &fcoe_fcf_device_type; 783 + fcf->id = atomic_inc_return(&fcf_num) - 1; 784 + fcf->state = FCOE_FCF_STATE_UNKNOWN; 785 + 786 + fcf->dev_loss_tmo = ctlr->fcf_dev_loss_tmo; 787 + 788 + dev_set_name(&fcf->dev, "fcf_%d", fcf->id); 789 + 790 + fcf->fabric_name = new_fcf->fabric_name; 791 + fcf->switch_name = new_fcf->switch_name; 792 + fcf->fc_map = new_fcf->fc_map; 793 + fcf->vfid = new_fcf->vfid; 794 + memcpy(fcf->mac, new_fcf->mac, ETH_ALEN); 795 + fcf->priority = new_fcf->priority; 796 + fcf->fka_period = new_fcf->fka_period; 797 + fcf->selected = new_fcf->selected; 798 + 799 + error = device_register(&fcf->dev); 800 + if (error) 801 + goto out_del; 802 + 803 + fcf->state = FCOE_FCF_STATE_CONNECTED; 804 + list_add_tail(&fcf->peers, &ctlr->fcfs); 805 + 806 + return fcf; 807 + 808 + out_del: 809 + kfree(fcf); 810 + out: 811 + return NULL; 812 + } 813 + EXPORT_SYMBOL_GPL(fcoe_fcf_device_add); 814 + 815 + int __init fcoe_sysfs_setup(void) 816 + { 817 + int error; 818 + 819 + atomic_set(&ctlr_num, 0); 820 + atomic_set(&fcf_num, 0); 821 + 822 + error = bus_register(&fcoe_bus_type); 823 + if (error) 824 + return error; 825 + 826 + return 0; 827 + } 828 + 829 + void __exit fcoe_sysfs_teardown(void) 830 + { 831 + bus_unregister(&fcoe_bus_type); 832 + }
+11 -2
drivers/scsi/fcoe/fcoe_transport.c
··· 815 815 */ 816 816 static int __init libfcoe_init(void) 817 817 { 818 - fcoe_transport_init(); 818 + int rc = 0; 819 819 820 - return 0; 820 + rc = fcoe_transport_init(); 821 + if (rc) 822 + return rc; 823 + 824 + rc = fcoe_sysfs_setup(); 825 + if (rc) 826 + fcoe_transport_exit(); 827 + 828 + return rc; 821 829 } 822 830 module_init(libfcoe_init); 823 831 ··· 834 826 */ 835 827 static void __exit libfcoe_exit(void) 836 828 { 829 + fcoe_sysfs_teardown(); 837 830 fcoe_transport_exit(); 838 831 } 839 832 module_exit(libfcoe_exit);
+124
include/scsi/fcoe_sysfs.h
··· 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 + #ifndef FCOE_SYSFS 21 + #define FCOE_SYSFS 22 + 23 + #include <linux/if_ether.h> 24 + #include <linux/device.h> 25 + #include <scsi/fc/fc_fcoe.h> 26 + 27 + struct fcoe_ctlr_device; 28 + struct fcoe_fcf_device; 29 + 30 + struct fcoe_sysfs_function_template { 31 + void (*get_fcoe_ctlr_link_fail)(struct fcoe_ctlr_device *); 32 + void (*get_fcoe_ctlr_vlink_fail)(struct fcoe_ctlr_device *); 33 + void (*get_fcoe_ctlr_miss_fka)(struct fcoe_ctlr_device *); 34 + void (*get_fcoe_ctlr_symb_err)(struct fcoe_ctlr_device *); 35 + void (*get_fcoe_ctlr_err_block)(struct fcoe_ctlr_device *); 36 + void (*get_fcoe_ctlr_fcs_error)(struct fcoe_ctlr_device *); 37 + void (*get_fcoe_ctlr_mode)(struct fcoe_ctlr_device *); 38 + void (*get_fcoe_fcf_selected)(struct fcoe_fcf_device *); 39 + void (*get_fcoe_fcf_vlan_id)(struct fcoe_fcf_device *); 40 + }; 41 + 42 + #define dev_to_ctlr(d) \ 43 + container_of((d), struct fcoe_ctlr_device, dev) 44 + 45 + enum fip_conn_type { 46 + FIP_CONN_TYPE_UNKNOWN, 47 + FIP_CONN_TYPE_FABRIC, 48 + FIP_CONN_TYPE_VN2VN, 49 + }; 50 + 51 + struct fcoe_ctlr_device { 52 + u32 id; 53 + 54 + struct device dev; 55 + struct fcoe_sysfs_function_template *f; 56 + 57 + struct list_head fcfs; 58 + char work_q_name[20]; 59 + struct workqueue_struct *work_q; 60 + char devloss_work_q_name[20]; 61 + struct workqueue_struct *devloss_work_q; 62 + struct mutex lock; 63 + 64 + int fcf_dev_loss_tmo; 65 + enum fip_conn_type mode; 66 + 67 + /* expected in host order for displaying */ 68 + struct fcoe_fc_els_lesb lesb; 69 + }; 70 + 71 + static inline void *fcoe_ctlr_device_priv(const struct fcoe_ctlr_device *ctlr) 72 + { 73 + return (void *)(ctlr + 1); 74 + } 75 + 76 + /* fcf states */ 77 + enum fcf_state { 78 + FCOE_FCF_STATE_UNKNOWN, 79 + FCOE_FCF_STATE_DISCONNECTED, 80 + FCOE_FCF_STATE_CONNECTED, 81 + FCOE_FCF_STATE_DELETED, 82 + }; 83 + 84 + struct fcoe_fcf_device { 85 + u32 id; 86 + struct device dev; 87 + struct list_head peers; 88 + struct work_struct delete_work; 89 + struct delayed_work dev_loss_work; 90 + u32 dev_loss_tmo; 91 + void *priv; 92 + enum fcf_state state; 93 + 94 + u64 fabric_name; 95 + u64 switch_name; 96 + u32 fc_map; 97 + u16 vfid; 98 + u8 mac[ETH_ALEN]; 99 + u8 priority; 100 + u32 fka_period; 101 + u8 selected; 102 + u16 vlan_id; 103 + }; 104 + 105 + #define dev_to_fcf(d) \ 106 + container_of((d), struct fcoe_fcf_device, dev) 107 + /* parentage should never be missing */ 108 + #define fcoe_fcf_dev_to_ctlr_dev(x) \ 109 + dev_to_ctlr((x)->dev.parent) 110 + #define fcoe_fcf_device_priv(x) \ 111 + ((x)->priv) 112 + 113 + struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, 114 + struct fcoe_sysfs_function_template *f, 115 + int priv_size); 116 + void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *); 117 + struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *, 118 + struct fcoe_fcf_device *); 119 + void fcoe_fcf_device_delete(struct fcoe_fcf_device *); 120 + 121 + int __init fcoe_sysfs_setup(void); 122 + void __exit fcoe_sysfs_teardown(void); 123 + 124 + #endif /* FCOE_SYSFS */
+1
include/scsi/libfcoe.h
··· 29 29 #include <linux/random.h> 30 30 #include <scsi/fc/fc_fcoe.h> 31 31 #include <scsi/libfc.h> 32 + #include <scsi/fcoe_sysfs.h> 32 33 33 34 #define FCOE_MAX_CMD_LEN 16 /* Supported CDB length */ 34 35