[SCSI] libfcoe: Add fcoe_sysfs
[linux-2.6-block.git] / drivers / scsi / fcoe / fcoe_sysfs.c
CommitLineData
9a74e884
RL
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
27static atomic_t ctlr_num;
28static 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 */
34static unsigned int fcoe_fcf_dev_loss_tmo = 1800; /* seconds */
35
36module_param_named(fcf_dev_loss_tmo, fcoe_fcf_dev_loss_tmo,
37 uint, S_IRUGO|S_IWUSR);
38MODULE_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 */
100static 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
116static 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) \
134struct 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) \
138static 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) \
150static 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) \
163static 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) \
172static 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) \
211static 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
225static 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};
233fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names)
234#define FCOE_FCF_STATE_MAX_NAMELEN 50
235
236static 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}
247static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL);
248
249static 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};
257fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)
258#define FCOE_CTLR_MODE_MAX_NAMELEN 50
259
260static 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}
276static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO,
277 show_ctlr_mode, NULL);
278
279static ssize_t
280store_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}
300fcoe_ctlr_private_show_function(fcf_dev_loss_tmo, "%d\n", 20, );
301static 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) */
306fcoe_ctlr_rd_attr(link_fail, "%u\n", 20);
307fcoe_ctlr_rd_attr(vlink_fail, "%u\n", 20);
308fcoe_ctlr_rd_attr(miss_fka, "%u\n", 20);
309fcoe_ctlr_rd_attr(symb_err, "%u\n", 20);
310fcoe_ctlr_rd_attr(err_block, "%u\n", 20);
311fcoe_ctlr_rd_attr(fcs_error, "%u\n", 20);
312
313fcoe_fcf_private_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);
314fcoe_fcf_private_rd_attr_cast(switch_name, "0x%llx\n", 20, unsigned long long);
315fcoe_fcf_private_rd_attr(priority, "%u\n", 20);
316fcoe_fcf_private_rd_attr(fc_map, "0x%x\n", 20);
317fcoe_fcf_private_rd_attr(vfid, "%u\n", 20);
318fcoe_fcf_private_rd_attr(mac, "%pM\n", 20);
319fcoe_fcf_private_rd_attr(fka_period, "%u\n", 20);
320fcoe_fcf_rd_attr(selected, "%u\n", 20);
321fcoe_fcf_rd_attr(vlan_id, "%u\n", 20);
322
323fcoe_fcf_private_show_function(dev_loss_tmo, "%d\n", 20, )
324static ssize_t
325store_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}
341static 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
345static 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
355static struct attribute_group fcoe_ctlr_lesb_attr_group = {
356 .name = "lesb",
357 .attrs = fcoe_ctlr_lesb_attrs,
358};
359
360static 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
366static struct attribute_group fcoe_ctlr_attr_group = {
367 .attrs = fcoe_ctlr_attrs,
368};
369
370static const struct attribute_group *fcoe_ctlr_attr_groups[] = {
371 &fcoe_ctlr_attr_group,
372 &fcoe_ctlr_lesb_attr_group,
373 NULL,
374};
375
376static 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
391static struct attribute_group fcoe_fcf_attr_group = {
392 .attrs = fcoe_fcf_attrs,
393};
394
395static const struct attribute_group *fcoe_fcf_attr_groups[] = {
396 &fcoe_fcf_attr_group,
397 NULL,
398};
399
400struct bus_type fcoe_bus_type;
401
402static 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 */
416static 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 */
428static void fcoe_fcf_device_release(struct device *dev)
429{
430 struct fcoe_fcf_device *fcf = dev_to_fcf(dev);
431 kfree(fcf);
432}
433
434struct device_type fcoe_ctlr_device_type = {
435 .name = "fcoe_ctlr",
436 .groups = fcoe_ctlr_attr_groups,
437 .release = fcoe_ctlr_device_release,
438};
439
440struct device_type fcoe_fcf_device_type = {
441 .name = "fcoe_fcf",
442 .groups = fcoe_fcf_attr_groups,
443 .release = fcoe_fcf_device_release,
444};
445
446struct 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 */
455void 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 */
476int 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 */
495void 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 */
517int 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
533static 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 */
555struct 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
599out_del_q2:
600 destroy_workqueue(ctlr->devloss_work_q);
601 ctlr->devloss_work_q = NULL;
602out_del_q:
603 destroy_workqueue(ctlr->work_q);
604 ctlr->work_q = NULL;
605out_del:
606 kfree(ctlr);
607out:
608 return NULL;
609}
610EXPORT_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 */
632void 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}
654EXPORT_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 */
663static 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 */
687static 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
711out:
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 */
724void 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}
744EXPORT_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 */
753struct 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
808out_del:
809 kfree(fcf);
810out:
811 return NULL;
812}
813EXPORT_SYMBOL_GPL(fcoe_fcf_device_add);
814
815int __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
829void __exit fcoe_sysfs_teardown(void)
830{
831 bus_unregister(&fcoe_bus_type);
832}