aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/fcoe
diff options
context:
space:
mode:
authorYi Zou <yi.zou@intel.com>2011-01-28 19:04:55 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-02-12 12:06:06 -0500
commitfdecf31b7c7b9bb79516344884388f660fd5d5a7 (patch)
tree9112929117f8b23de21c9573fae90b56b927366f /drivers/scsi/fcoe
parent0ade7d290b6aa8b1626a4077b853c02cd12415c2 (diff)
[SCSI] libfcoe: add implementation to support fcoe transport
Add the new fcoe_transport.c file that implements basic fcoe transport interface. Eventually, the sysfs entries to create/destroy/enable/disable an FCoE instance will be coming to the fcoe transport layer, who does a look-up to find the corresponding transport provide and pass the corresponding action over to the identified provider. The fcoe.ko will become the default fcoe transport provider that can support FCoE on any given netdev interfaces, as the Open-FCoE.org's default software FCoE HBA solution. Any vendor specific FCoE HBA driver that is built on top of Open-FCoE's kernel stack of libfc & libfcoe as well as the user land tool of fcoe-utils can easily plug-in and start running FCoE on their network interfaces. The fcoe.ko will be converted to act as the default provider if no vendor specific transport provider is found, as it is always added to the very end of the list of attached transports. Signed-off-by: Yi Zou <yi.zou@intel.com> Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/fcoe')
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c518
-rw-r--r--drivers/scsi/fcoe/libfcoe.h6
2 files changed, 524 insertions, 0 deletions
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
new file mode 100644
index 000000000000..41d69bedd4b4
--- /dev/null
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -0,0 +1,518 @@
1/*
2 * Copyright(c) 2008 - 2011 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/types.h>
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/list.h>
24#include <linux/netdevice.h>
25#include <linux/errno.h>
26#include <scsi/libfcoe.h>
27
28#include "libfcoe.h"
29
30static int fcoe_transport_create(const char *, struct kernel_param *);
31static int fcoe_transport_destroy(const char *, struct kernel_param *);
32static int fcoe_transport_show(char *buffer, const struct kernel_param *kp);
33static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
34static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
35static int fcoe_transport_enable(const char *, struct kernel_param *);
36static int fcoe_transport_disable(const char *, struct kernel_param *);
37
38static LIST_HEAD(fcoe_transports);
39static LIST_HEAD(fcoe_netdevs);
40static DEFINE_MUTEX(ft_mutex);
41
42module_param_call(show, NULL, fcoe_transport_show, NULL, S_IRUSR);
43__MODULE_PARM_TYPE(show, "string");
44MODULE_PARM_DESC(show, " Show attached FCoE transports");
45
46module_param_call(create, fcoe_transport_create, NULL,
47 (void *)FIP_MODE_FABRIC, S_IWUSR);
48__MODULE_PARM_TYPE(create, "string");
49MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
50
51module_param_call(create_vn2vn, fcoe_transport_create, NULL,
52 (void *)FIP_MODE_VN2VN, S_IWUSR);
53__MODULE_PARM_TYPE(create_vn2vn, "string");
54MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
55 "on an Ethernet interface");
56
57module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR);
58__MODULE_PARM_TYPE(destroy, "string");
59MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
60
61module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR);
62__MODULE_PARM_TYPE(enable, "string");
63MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface.");
64
65module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
66__MODULE_PARM_TYPE(disable, "string");
67MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
68
69/**
70 * fcoe_transport_lookup - find an fcoe transport that matches a netdev
71 * @netdev: The netdev to look for from all attached transports
72 *
73 * Returns : ptr to the fcoe transport that supports this netdev or NULL
74 * if not found.
75 *
76 * The ft_mutex should be held when this is called
77 */
78static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev)
79{
80 struct fcoe_transport *ft = NULL;
81
82 list_for_each_entry(ft, &fcoe_transports, list)
83 if (ft->match && ft->match(netdev))
84 return ft;
85 return NULL;
86}
87
88/**
89 * fcoe_transport_attach - Attaches an FCoE transport
90 * @ft: The fcoe transport to be attached
91 *
92 * Returns : 0 for success
93 */
94int fcoe_transport_attach(struct fcoe_transport *ft)
95{
96 int rc = 0;
97
98 mutex_lock(&ft_mutex);
99 if (ft->attached) {
100 LIBFCOE_TRANSPORT_DBG("transport %s already attached\n",
101 ft->name);
102 rc = -EEXIST;
103 goto out_attach;
104 }
105
106 /* Add default transport to the tail */
107 if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT))
108 list_add(&ft->list, &fcoe_transports);
109 else
110 list_add_tail(&ft->list, &fcoe_transports);
111
112 ft->attached = true;
113 LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name);
114
115out_attach:
116 mutex_unlock(&ft_mutex);
117 return rc;
118}
119EXPORT_SYMBOL(fcoe_transport_attach);
120
121/**
122 * fcoe_transport_attach - Detaches an FCoE transport
123 * @ft: The fcoe transport to be attached
124 *
125 * Returns : 0 for success
126 */
127int fcoe_transport_detach(struct fcoe_transport *ft)
128{
129 int rc = 0;
130
131 mutex_lock(&ft_mutex);
132 if (!ft->attached) {
133 LIBFCOE_TRANSPORT_DBG("transport %s already detached\n",
134 ft->name);
135 rc = -ENODEV;
136 goto out_attach;
137 }
138
139 list_del(&ft->list);
140 ft->attached = false;
141 LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name);
142
143out_attach:
144 mutex_unlock(&ft_mutex);
145 return rc;
146
147}
148EXPORT_SYMBOL(fcoe_transport_detach);
149
150static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
151{
152 int i, j;
153 struct fcoe_transport *ft = NULL;
154
155 i = j = sprintf(buffer, "Attached FCoE transports:");
156 mutex_lock(&ft_mutex);
157 list_for_each_entry(ft, &fcoe_transports, list) {
158 i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
159 if (i >= PAGE_SIZE)
160 break;
161 }
162 mutex_unlock(&ft_mutex);
163 if (i == j)
164 i += snprintf(&buffer[i], IFNAMSIZ, "none");
165 return i;
166}
167
168static int __init fcoe_transport_init(void)
169{
170 return 0;
171}
172
173static int __exit fcoe_transport_exit(void)
174{
175 struct fcoe_transport *ft;
176
177 mutex_lock(&ft_mutex);
178 list_for_each_entry(ft, &fcoe_transports, list)
179 printk(KERN_ERR "FCoE transport %s is still attached!\n",
180 ft->name);
181 mutex_unlock(&ft_mutex);
182 return 0;
183}
184
185
186static int fcoe_add_netdev_mapping(struct net_device *netdev,
187 struct fcoe_transport *ft)
188{
189 struct fcoe_netdev_mapping *nm;
190
191 nm = kmalloc(sizeof(*nm), GFP_KERNEL);
192 if (!nm) {
193 printk(KERN_ERR "Unable to allocate netdev_mapping");
194 return -ENOMEM;
195 }
196
197 nm->netdev = netdev;
198 nm->ft = ft;
199
200 list_add(&nm->list, &fcoe_netdevs);
201 return 0;
202}
203
204
205static void fcoe_del_netdev_mapping(struct net_device *netdev)
206{
207 struct fcoe_netdev_mapping *nm = NULL, *tmp;
208
209 list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
210 if (nm->netdev == netdev) {
211 list_del(&nm->list);
212 kfree(nm);
213 return;
214 }
215 }
216}
217
218
219/**
220 * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which
221 * it was created
222 *
223 * Returns : ptr to the fcoe transport that supports this netdev or NULL
224 * if not found.
225 *
226 * The ft_mutex should be held when this is called
227 */
228static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
229{
230 struct fcoe_transport *ft = NULL;
231 struct fcoe_netdev_mapping *nm;
232
233 list_for_each_entry(nm, &fcoe_netdevs, list) {
234 if (netdev == nm->netdev) {
235 ft = nm->ft;
236 return ft;
237 }
238 }
239
240 return NULL;
241}
242
243/**
244 * fcoe_if_to_netdev() - Parse a name buffer to get a net device
245 * @buffer: The name of the net device
246 *
247 * Returns: NULL or a ptr to net_device
248 */
249static struct net_device *fcoe_if_to_netdev(const char *buffer)
250{
251 char *cp;
252 char ifname[IFNAMSIZ + 2];
253
254 if (buffer) {
255 strlcpy(ifname, buffer, IFNAMSIZ);
256 cp = ifname + strlen(ifname);
257 while (--cp >= ifname && *cp == '\n')
258 *cp = '\0';
259 return dev_get_by_name(&init_net, ifname);
260 }
261 return NULL;
262}
263
264/**
265 * fcoe_transport_create() - Create a fcoe interface
266 * @buffer: The name of the Ethernet interface to create on
267 * @kp: The associated kernel param
268 *
269 * Called from sysfs. This holds the ft_mutex while calling the
270 * registered fcoe transport's create function.
271 *
272 * Returns: 0 for success
273 */
274static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
275{
276 int rc = -ENODEV;
277 struct net_device *netdev = NULL;
278 struct fcoe_transport *ft = NULL;
279 enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
280
281 if (!mutex_trylock(&ft_mutex))
282 return restart_syscall();
283
284#ifdef CONFIG_LIBFCOE_MODULE
285 /*
286 * Make sure the module has been initialized, and is not about to be
287 * removed. Module parameter sysfs files are writable before the
288 * module_init function is called and after module_exit.
289 */
290 if (THIS_MODULE->state != MODULE_STATE_LIVE)
291 goto out_nodev;
292#endif
293
294 netdev = fcoe_if_to_netdev(buffer);
295 if (!netdev) {
296 LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer);
297 goto out_nodev;
298 }
299
300 ft = fcoe_netdev_map_lookup(netdev);
301 if (ft) {
302 LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
303 "FCoE instance on %s.\n",
304 ft->name, netdev->name);
305 rc = -EEXIST;
306 goto out_putdev;
307 }
308
309 ft = fcoe_transport_lookup(netdev);
310 if (!ft) {
311 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
312 netdev->name);
313 goto out_putdev;
314 }
315
316 rc = fcoe_add_netdev_mapping(netdev, ft);
317 if (rc) {
318 LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
319 "for FCoE transport %s for %s.\n",
320 ft->name, netdev->name);
321 goto out_putdev;
322 }
323
324 /* pass to transport create */
325 rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV;
326 if (rc)
327 fcoe_del_netdev_mapping(netdev);
328
329 LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
330 ft->name, (rc) ? "failed" : "succeeded",
331 netdev->name);
332
333out_putdev:
334 dev_put(netdev);
335out_nodev:
336 mutex_unlock(&ft_mutex);
337 if (rc == -ERESTARTSYS)
338 return restart_syscall();
339 else
340 return rc;
341}
342
343/**
344 * fcoe_transport_destroy() - Destroy a FCoE interface
345 * @buffer: The name of the Ethernet interface to be destroyed
346 * @kp: The associated kernel parameter
347 *
348 * Called from sysfs. This holds the ft_mutex while calling the
349 * registered fcoe transport's destroy function.
350 *
351 * Returns: 0 for success
352 */
353static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
354{
355 int rc = -ENODEV;
356 struct net_device *netdev = NULL;
357 struct fcoe_transport *ft = NULL;
358
359 if (!mutex_trylock(&ft_mutex))
360 return restart_syscall();
361
362#ifdef CONFIG_LIBFCOE_MODULE
363 /*
364 * Make sure the module has been initialized, and is not about to be
365 * removed. Module parameter sysfs files are writable before the
366 * module_init function is called and after module_exit.
367 */
368 if (THIS_MODULE->state != MODULE_STATE_LIVE)
369 goto out_nodev;
370#endif
371
372 netdev = fcoe_if_to_netdev(buffer);
373 if (!netdev) {
374 LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer);
375 goto out_nodev;
376 }
377
378 ft = fcoe_netdev_map_lookup(netdev);
379 if (!ft) {
380 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
381 netdev->name);
382 goto out_putdev;
383 }
384
385 /* pass to transport destroy */
386 rc = ft->destroy ? ft->destroy(netdev) : -ENODEV;
387 fcoe_del_netdev_mapping(netdev);
388 LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
389 ft->name, (rc) ? "failed" : "succeeded",
390 netdev->name);
391
392out_putdev:
393 dev_put(netdev);
394out_nodev:
395 mutex_unlock(&ft_mutex);
396
397 if (rc == -ERESTARTSYS)
398 return restart_syscall();
399 else
400 return rc;
401}
402
403/**
404 * fcoe_transport_disable() - Disables a FCoE interface
405 * @buffer: The name of the Ethernet interface to be disabled
406 * @kp: The associated kernel parameter
407 *
408 * Called from sysfs.
409 *
410 * Returns: 0 for success
411 */
412static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
413{
414 int rc = -ENODEV;
415 struct net_device *netdev = NULL;
416 struct fcoe_transport *ft = NULL;
417
418 if (!mutex_trylock(&ft_mutex))
419 return restart_syscall();
420
421#ifdef CONFIG_LIBFCOE_MODULE
422 /*
423 * Make sure the module has been initialized, and is not about to be
424 * removed. Module parameter sysfs files are writable before the
425 * module_init function is called and after module_exit.
426 */
427 if (THIS_MODULE->state != MODULE_STATE_LIVE)
428 goto out_nodev;
429#endif
430
431 netdev = fcoe_if_to_netdev(buffer);
432 if (!netdev)
433 goto out_nodev;
434
435 ft = fcoe_netdev_map_lookup(netdev);
436 if (!ft)
437 goto out_putdev;
438
439 rc = ft->disable ? ft->disable(netdev) : -ENODEV;
440
441out_putdev:
442 dev_put(netdev);
443out_nodev:
444 mutex_unlock(&ft_mutex);
445
446 if (rc == -ERESTARTSYS)
447 return restart_syscall();
448 else
449 return rc;
450}
451
452/**
453 * fcoe_transport_enable() - Enables a FCoE interface
454 * @buffer: The name of the Ethernet interface to be enabled
455 * @kp: The associated kernel parameter
456 *
457 * Called from sysfs.
458 *
459 * Returns: 0 for success
460 */
461static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
462{
463 int rc = -ENODEV;
464 struct net_device *netdev = NULL;
465 struct fcoe_transport *ft = NULL;
466
467 if (!mutex_trylock(&ft_mutex))
468 return restart_syscall();
469
470#ifdef CONFIG_LIBFCOE_MODULE
471 /*
472 * Make sure the module has been initialized, and is not about to be
473 * removed. Module parameter sysfs files are writable before the
474 * module_init function is called and after module_exit.
475 */
476 if (THIS_MODULE->state != MODULE_STATE_LIVE)
477 goto out_nodev;
478#endif
479
480 netdev = fcoe_if_to_netdev(buffer);
481 if (!netdev)
482 goto out_nodev;
483
484 ft = fcoe_netdev_map_lookup(netdev);
485 if (!ft)
486 goto out_putdev;
487
488 rc = ft->enable ? ft->enable(netdev) : -ENODEV;
489
490out_putdev:
491 dev_put(netdev);
492out_nodev:
493 mutex_unlock(&ft_mutex);
494 if (rc == -ERESTARTSYS)
495 return restart_syscall();
496 else
497 return rc;
498}
499
500/**
501 * libfcoe_init() - Initialization routine for libfcoe.ko
502 */
503static int __init libfcoe_init(void)
504{
505 fcoe_transport_init();
506
507 return 0;
508}
509module_init(libfcoe_init);
510
511/**
512 * libfcoe_exit() - Tear down libfcoe.ko
513 */
514static void __exit libfcoe_exit(void)
515{
516 fcoe_transport_exit();
517}
518module_exit(libfcoe_exit);
diff --git a/drivers/scsi/fcoe/libfcoe.h b/drivers/scsi/fcoe/libfcoe.h
index c3fe3167ff71..6af5fc3a17d8 100644
--- a/drivers/scsi/fcoe/libfcoe.h
+++ b/drivers/scsi/fcoe/libfcoe.h
@@ -4,6 +4,7 @@
4extern unsigned int libfcoe_debug_logging; 4extern unsigned int libfcoe_debug_logging;
5#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */ 5#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
6#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */ 6#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
7#define LIBFCOE_TRANSPORT_LOGGING 0x04 /* FCoE transport logging */
7 8
8#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \ 9#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
9do { \ 10do { \
@@ -22,4 +23,9 @@ do { \
22 printk(KERN_INFO "host%d: fip: " fmt, \ 23 printk(KERN_INFO "host%d: fip: " fmt, \
23 (fip)->lp->host->host_no, ##args);) 24 (fip)->lp->host->host_no, ##args);)
24 25
26#define LIBFCOE_TRANSPORT_DBG(fmt, args...) \
27 LIBFCOE_CHECK_LOGGING(LIBFCOE_TRANSPORT_LOGGING, \
28 printk(KERN_INFO "%s: " fmt, \
29 __func__, ##args);)
30
25#endif /* _FCOE_LIBFCOE_H_ */ 31#endif /* _FCOE_LIBFCOE_H_ */