2 * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
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.
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
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.
17 * Maintained at www.Open-FCoE.org
20 #include <linux/pci.h>
21 #include <scsi/libfcoe.h>
22 #include <scsi/fc_transport_fcoe.h>
24 /* internal fcoe transport */
25 struct fcoe_transport_internal {
26 struct fcoe_transport *t;
27 struct net_device *netdev;
28 struct list_head list;
31 /* fcoe transports list and its lock */
32 static LIST_HEAD(fcoe_transports);
33 static DEFINE_MUTEX(fcoe_transports_lock);
36 * fcoe_transport_default() - Returns ptr to the default transport fcoe_sw
38 struct fcoe_transport *fcoe_transport_default(void)
40 return &fcoe_sw_transport;
44 * fcoe_transport_to_pcidev() - get the pci dev from a netdev
45 * @netdev: the netdev that pci dev will be retrived from
47 * Returns: NULL or the corrsponding pci_dev
49 struct pci_dev *fcoe_transport_pcidev(const struct net_device *netdev)
51 if (!netdev->dev.parent)
53 return to_pci_dev(netdev->dev.parent);
57 * fcoe_transport_device_lookup() - Lookup a transport
58 * @netdev: the netdev the transport to be attached to
60 * This will look for existing offload driver, if not found, it falls back to
61 * the default sw hba (fcoe_sw) as its fcoe transport.
63 * Returns: 0 for success
65 static struct fcoe_transport_internal *fcoe_transport_device_lookup(
66 struct fcoe_transport *t, struct net_device *netdev)
68 struct fcoe_transport_internal *ti;
70 /* assign the transpor to this device */
71 mutex_lock(&t->devlock);
72 list_for_each_entry(ti, &t->devlist, list) {
73 if (ti->netdev == netdev) {
74 mutex_unlock(&t->devlock);
78 mutex_unlock(&t->devlock);
82 * fcoe_transport_device_add() - Assign a transport to a device
83 * @netdev: the netdev the transport to be attached to
85 * This will look for existing offload driver, if not found, it falls back to
86 * the default sw hba (fcoe_sw) as its fcoe transport.
88 * Returns: 0 for success
90 static int fcoe_transport_device_add(struct fcoe_transport *t,
91 struct net_device *netdev)
93 struct fcoe_transport_internal *ti;
95 ti = fcoe_transport_device_lookup(t, netdev);
97 printk(KERN_DEBUG "fcoe_transport_device_add:"
98 "device %s is already added to transport %s\n",
99 netdev->name, t->name);
102 /* allocate an internal struct to host the netdev and the list */
103 ti = kzalloc(sizeof(*ti), GFP_KERNEL);
109 INIT_LIST_HEAD(&ti->list);
110 dev_hold(ti->netdev);
112 mutex_lock(&t->devlock);
113 list_add(&ti->list, &t->devlist);
114 mutex_unlock(&t->devlock);
116 printk(KERN_DEBUG "fcoe_transport_device_add:"
117 "device %s added to transport %s\n",
118 netdev->name, t->name);
124 * fcoe_transport_device_remove() - Remove a device from its transport
125 * @netdev: the netdev the transport to be attached to
127 * This removes the device from the transport so the given transport will
128 * not manage this device any more
130 * Returns: 0 for success
132 static int fcoe_transport_device_remove(struct fcoe_transport *t,
133 struct net_device *netdev)
135 struct fcoe_transport_internal *ti;
137 ti = fcoe_transport_device_lookup(t, netdev);
139 printk(KERN_DEBUG "fcoe_transport_device_remove:"
140 "device %s is not managed by transport %s\n",
141 netdev->name, t->name);
144 mutex_lock(&t->devlock);
146 mutex_unlock(&t->devlock);
147 printk(KERN_DEBUG "fcoe_transport_device_remove:"
148 "device %s removed from transport %s\n",
149 netdev->name, t->name);
156 * fcoe_transport_device_remove_all() - Remove all from transport devlist
158 * This removes the device from the transport so the given transport will
159 * not manage this device any more
161 * Returns: 0 for success
163 static void fcoe_transport_device_remove_all(struct fcoe_transport *t)
165 struct fcoe_transport_internal *ti, *tmp;
167 mutex_lock(&t->devlock);
168 list_for_each_entry_safe(ti, tmp, &t->devlist, list) {
172 mutex_unlock(&t->devlock);
176 * fcoe_transport_match() - Use the bus device match function to match the hw
177 * @t: The fcoe transport to check
178 * @netdev: The netdev to match against
180 * This function is used to check if the given transport wants to manage the
181 * input netdev. if the transports implements the match function, it will be
182 * called, o.w. we just compare the pci vendor and device id.
184 * Returns: true for match up
186 static bool fcoe_transport_match(struct fcoe_transport *t,
187 struct net_device *netdev)
189 /* match transport by vendor and device id */
192 pci = fcoe_transport_pcidev(netdev);
195 printk(KERN_DEBUG "fcoe_transport_match:"
196 "%s:%x:%x -- %s:%x:%x\n",
197 t->name, t->vendor, t->device,
198 netdev->name, pci->vendor, pci->device);
200 /* if transport supports match */
202 return t->match(netdev);
204 /* else just compare the vendor and device id: pci only */
205 return (t->vendor == pci->vendor) && (t->device == pci->device);
211 * fcoe_transport_lookup() - Check if the transport is already registered
212 * @t: the transport to be looked up
214 * This compares the parent device (pci) vendor and device id
216 * Returns: NULL if not found
218 * TODO: return default sw transport if no other transport is found
220 static struct fcoe_transport *fcoe_transport_lookup(
221 struct net_device *netdev)
223 struct fcoe_transport *t;
225 mutex_lock(&fcoe_transports_lock);
226 list_for_each_entry(t, &fcoe_transports, list) {
227 if (fcoe_transport_match(t, netdev)) {
228 mutex_unlock(&fcoe_transports_lock);
232 mutex_unlock(&fcoe_transports_lock);
234 printk(KERN_DEBUG "fcoe_transport_lookup:"
235 "use default transport for %s\n", netdev->name);
236 return fcoe_transport_default();
240 * fcoe_transport_register() - Adds a fcoe transport to the fcoe transports list
241 * @t: ptr to the fcoe transport to be added
243 * Returns: 0 for success
245 int fcoe_transport_register(struct fcoe_transport *t)
247 struct fcoe_transport *tt;
249 /* TODO - add fcoe_transport specific initialization here */
250 mutex_lock(&fcoe_transports_lock);
251 list_for_each_entry(tt, &fcoe_transports, list) {
253 mutex_unlock(&fcoe_transports_lock);
257 list_add_tail(&t->list, &fcoe_transports);
258 mutex_unlock(&fcoe_transports_lock);
260 mutex_init(&t->devlock);
261 INIT_LIST_HEAD(&t->devlist);
263 printk(KERN_DEBUG "fcoe_transport_register:%s\n", t->name);
267 EXPORT_SYMBOL_GPL(fcoe_transport_register);
270 * fcoe_transport_unregister() - Remove the tranport fro the fcoe transports list
271 * @t: ptr to the fcoe transport to be removed
273 * Returns: 0 for success
275 int fcoe_transport_unregister(struct fcoe_transport *t)
277 struct fcoe_transport *tt, *tmp;
279 mutex_lock(&fcoe_transports_lock);
280 list_for_each_entry_safe(tt, tmp, &fcoe_transports, list) {
283 mutex_unlock(&fcoe_transports_lock);
284 fcoe_transport_device_remove_all(t);
285 printk(KERN_DEBUG "fcoe_transport_unregister:%s\n",
290 mutex_unlock(&fcoe_transports_lock);
293 EXPORT_SYMBOL_GPL(fcoe_transport_unregister);
296 * fcoe_load_transport_driver() - Load an offload driver by alias name
297 * @netdev: the target net device
299 * Requests for an offload driver module as the fcoe transport, if fails, it
300 * falls back to use the SW HBA (fcoe_sw) as its transport
303 * 1. supports only PCI device
304 * 2. needs fix for VLAn and bonding
305 * 3. pure hw fcoe hba may not have netdev
307 * Returns: 0 for success
309 int fcoe_load_transport_driver(struct net_device *netdev)
312 struct device *dev = netdev->dev.parent;
314 if (fcoe_transport_lookup(netdev)) {
315 /* load default transport */
316 printk(KERN_DEBUG "fcoe: already loaded transport for %s\n",
321 pci = to_pci_dev(dev);
322 if (dev->bus != &pci_bus_type) {
323 printk(KERN_DEBUG "fcoe: support noly PCI device\n");
326 printk(KERN_DEBUG "fcoe: loading driver fcoe-pci-0x%04x-0x%04x\n",
327 pci->vendor, pci->device);
329 return request_module("fcoe-pci-0x%04x-0x%04x",
330 pci->vendor, pci->device);
333 EXPORT_SYMBOL_GPL(fcoe_load_transport_driver);
336 * fcoe_transport_attach() - Load transport to fcoe
337 * @netdev: the netdev the transport to be attached to
339 * This will look for existing offload driver, if not found, it falls back to
340 * the default sw hba (fcoe_sw) as its fcoe transport.
342 * Returns: 0 for success
344 int fcoe_transport_attach(struct net_device *netdev)
346 struct fcoe_transport *t;
348 /* find the corresponding transport */
349 t = fcoe_transport_lookup(netdev);
351 printk(KERN_DEBUG "fcoe_transport_attach"
352 ":no transport for %s:use %s\n",
353 netdev->name, t->name);
356 /* add to the transport */
357 if (fcoe_transport_device_add(t, netdev)) {
358 printk(KERN_DEBUG "fcoe_transport_attach"
359 ":failed to add %s to tramsport %s\n",
360 netdev->name, t->name);
363 /* transport create function */
367 printk(KERN_DEBUG "fcoe_transport_attach:transport %s for %s\n",
368 t->name, netdev->name);
371 EXPORT_SYMBOL_GPL(fcoe_transport_attach);
374 * fcoe_transport_release() - Unload transport from fcoe
375 * @netdev: the net device on which fcoe is to be released
377 * Returns: 0 for success
379 int fcoe_transport_release(struct net_device *netdev)
381 struct fcoe_transport *t;
383 /* find the corresponding transport */
384 t = fcoe_transport_lookup(netdev);
386 printk(KERN_DEBUG "fcoe_transport_release:"
387 "no transport for %s:use %s\n",
388 netdev->name, t->name);
391 /* remove the device from the transport */
392 if (fcoe_transport_device_remove(t, netdev)) {
393 printk(KERN_DEBUG "fcoe_transport_release:"
394 "failed to add %s to tramsport %s\n",
395 netdev->name, t->name);
398 /* transport destroy function */
402 printk(KERN_DEBUG "fcoe_transport_release:"
403 "device %s dettached from transport %s\n",
404 netdev->name, t->name);
408 EXPORT_SYMBOL_GPL(fcoe_transport_release);
411 * fcoe_transport_init() - Initializes fcoe transport layer
413 * This prepares for the fcoe transport layer
417 int __init fcoe_transport_init(void)
419 INIT_LIST_HEAD(&fcoe_transports);
420 mutex_init(&fcoe_transports_lock);
425 * fcoe_transport_exit() - Cleans up the fcoe transport layer
427 * This cleans up the fcoe transport layer. removing any transport on the list,
428 * note that the transport destroy func is not called here.
432 int __exit fcoe_transport_exit(void)
434 struct fcoe_transport *t, *tmp;
436 mutex_lock(&fcoe_transports_lock);
437 list_for_each_entry_safe(t, tmp, &fcoe_transports, list) {
439 mutex_unlock(&fcoe_transports_lock);
440 fcoe_transport_device_remove_all(t);
441 mutex_lock(&fcoe_transports_lock);
443 mutex_unlock(&fcoe_transports_lock);