x86-64: syscall-audit: fix 32/64 syscall hole
[linux-2.6/btrfs-unstable.git] / drivers / scsi / fcoe / fc_transport_fcoe.c
blobbf7fe6fc0820491ce90aebbbbecc16b565aacce1
1 /*
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
11 * more details.
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);
35 /**
36 * fcoe_transport_default - returns ptr to the default transport fcoe_sw
37 **/
38 struct fcoe_transport *fcoe_transport_default(void)
40 return &fcoe_sw_transport;
43 /**
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
48 **/
49 struct pci_dev *fcoe_transport_pcidev(const struct net_device *netdev)
51 if (!netdev->dev.parent)
52 return NULL;
53 return to_pci_dev(netdev->dev.parent);
56 /**
57 * fcoe_transport_device_lookup - find out netdev is managed by the
58 * transport
59 * assign a transport to a device
60 * @netdev: the netdev the transport to be attached to
62 * This will look for existing offload driver, if not found, it falls back to
63 * the default sw hba (fcoe_sw) as its fcoe transport.
65 * Returns: 0 for success
66 **/
67 static struct fcoe_transport_internal *fcoe_transport_device_lookup(
68 struct fcoe_transport *t, struct net_device *netdev)
70 struct fcoe_transport_internal *ti;
72 /* assign the transpor to this device */
73 mutex_lock(&t->devlock);
74 list_for_each_entry(ti, &t->devlist, list) {
75 if (ti->netdev == netdev) {
76 mutex_unlock(&t->devlock);
77 return ti;
80 mutex_unlock(&t->devlock);
81 return NULL;
83 /**
84 * fcoe_transport_device_add - assign a transport to a device
85 * @netdev: the netdev the transport to be attached to
87 * This will look for existing offload driver, if not found, it falls back to
88 * the default sw hba (fcoe_sw) as its fcoe transport.
90 * Returns: 0 for success
91 **/
92 static int fcoe_transport_device_add(struct fcoe_transport *t,
93 struct net_device *netdev)
95 struct fcoe_transport_internal *ti;
97 ti = fcoe_transport_device_lookup(t, netdev);
98 if (ti) {
99 printk(KERN_DEBUG "fcoe_transport_device_add:"
100 "device %s is already added to transport %s\n",
101 netdev->name, t->name);
102 return -EEXIST;
104 /* allocate an internal struct to host the netdev and the list */
105 ti = kzalloc(sizeof(*ti), GFP_KERNEL);
106 if (!ti)
107 return -ENOMEM;
109 ti->t = t;
110 ti->netdev = netdev;
111 INIT_LIST_HEAD(&ti->list);
112 dev_hold(ti->netdev);
114 mutex_lock(&t->devlock);
115 list_add(&ti->list, &t->devlist);
116 mutex_unlock(&t->devlock);
118 printk(KERN_DEBUG "fcoe_transport_device_add:"
119 "device %s added to transport %s\n",
120 netdev->name, t->name);
122 return 0;
126 * fcoe_transport_device_remove - remove a device from its transport
127 * @netdev: the netdev the transport to be attached to
129 * this removes the device from the transport so the given transport will
130 * not manage this device any more
132 * Returns: 0 for success
134 static int fcoe_transport_device_remove(struct fcoe_transport *t,
135 struct net_device *netdev)
137 struct fcoe_transport_internal *ti;
139 ti = fcoe_transport_device_lookup(t, netdev);
140 if (!ti) {
141 printk(KERN_DEBUG "fcoe_transport_device_remove:"
142 "device %s is not managed by transport %s\n",
143 netdev->name, t->name);
144 return -ENODEV;
146 mutex_lock(&t->devlock);
147 list_del(&ti->list);
148 mutex_unlock(&t->devlock);
149 printk(KERN_DEBUG "fcoe_transport_device_remove:"
150 "device %s removed from transport %s\n",
151 netdev->name, t->name);
152 dev_put(ti->netdev);
153 kfree(ti);
154 return 0;
158 * fcoe_transport_device_remove_all - remove all from transport devlist
160 * this removes the device from the transport so the given transport will
161 * not manage this device any more
163 * Returns: 0 for success
165 static void fcoe_transport_device_remove_all(struct fcoe_transport *t)
167 struct fcoe_transport_internal *ti, *tmp;
169 mutex_lock(&t->devlock);
170 list_for_each_entry_safe(ti, tmp, &t->devlist, list) {
171 list_del(&ti->list);
172 kfree(ti);
174 mutex_unlock(&t->devlock);
178 * fcoe_transport_match - use the bus device match function to match the hw
179 * @t: the fcoe transport
180 * @netdev:
182 * This function is used to check if the givne transport wants to manage the
183 * input netdev. if the transports implements the match function, it will be
184 * called, o.w. we just compare the pci vendor and device id.
186 * Returns: true for match up
188 static bool fcoe_transport_match(struct fcoe_transport *t,
189 struct net_device *netdev)
191 /* match transport by vendor and device id */
192 struct pci_dev *pci;
194 pci = fcoe_transport_pcidev(netdev);
196 if (pci) {
197 printk(KERN_DEBUG "fcoe_transport_match:"
198 "%s:%x:%x -- %s:%x:%x\n",
199 t->name, t->vendor, t->device,
200 netdev->name, pci->vendor, pci->device);
202 /* if transport supports match */
203 if (t->match)
204 return t->match(netdev);
206 /* else just compare the vendor and device id: pci only */
207 return (t->vendor == pci->vendor) && (t->device == pci->device);
209 return false;
213 * fcoe_transport_lookup - check if the transport is already registered
214 * @t: the transport to be looked up
216 * This compares the parent device (pci) vendor and device id
218 * Returns: NULL if not found
220 * TODO - return default sw transport if no other transport is found
222 static struct fcoe_transport *fcoe_transport_lookup(
223 struct net_device *netdev)
225 struct fcoe_transport *t;
227 mutex_lock(&fcoe_transports_lock);
228 list_for_each_entry(t, &fcoe_transports, list) {
229 if (fcoe_transport_match(t, netdev)) {
230 mutex_unlock(&fcoe_transports_lock);
231 return t;
234 mutex_unlock(&fcoe_transports_lock);
236 printk(KERN_DEBUG "fcoe_transport_lookup:"
237 "use default transport for %s\n", netdev->name);
238 return fcoe_transport_default();
242 * fcoe_transport_register - adds a fcoe transport to the fcoe transports list
243 * @t: ptr to the fcoe transport to be added
245 * Returns: 0 for success
247 int fcoe_transport_register(struct fcoe_transport *t)
249 struct fcoe_transport *tt;
251 /* TODO - add fcoe_transport specific initialization here */
252 mutex_lock(&fcoe_transports_lock);
253 list_for_each_entry(tt, &fcoe_transports, list) {
254 if (tt == t) {
255 mutex_unlock(&fcoe_transports_lock);
256 return -EEXIST;
259 list_add_tail(&t->list, &fcoe_transports);
260 mutex_unlock(&fcoe_transports_lock);
262 mutex_init(&t->devlock);
263 INIT_LIST_HEAD(&t->devlist);
265 printk(KERN_DEBUG "fcoe_transport_register:%s\n", t->name);
267 return 0;
269 EXPORT_SYMBOL_GPL(fcoe_transport_register);
272 * fcoe_transport_unregister - remove the tranport fro the fcoe transports list
273 * @t: ptr to the fcoe transport to be removed
275 * Returns: 0 for success
277 int fcoe_transport_unregister(struct fcoe_transport *t)
279 struct fcoe_transport *tt, *tmp;
281 mutex_lock(&fcoe_transports_lock);
282 list_for_each_entry_safe(tt, tmp, &fcoe_transports, list) {
283 if (tt == t) {
284 list_del(&t->list);
285 mutex_unlock(&fcoe_transports_lock);
286 fcoe_transport_device_remove_all(t);
287 printk(KERN_DEBUG "fcoe_transport_unregister:%s\n",
288 t->name);
289 return 0;
292 mutex_unlock(&fcoe_transports_lock);
293 return -ENODEV;
295 EXPORT_SYMBOL_GPL(fcoe_transport_unregister);
298 * fcoe_load_transport_driver - load an offload driver by alias name
299 * @netdev: the target net device
301 * Requests for an offload driver module as the fcoe transport, if fails, it
302 * falls back to use the SW HBA (fcoe_sw) as its transport
304 * TODO -
305 * 1. supports only PCI device
306 * 2. needs fix for VLAn and bonding
307 * 3. pure hw fcoe hba may not have netdev
309 * Returns: 0 for success
311 int fcoe_load_transport_driver(struct net_device *netdev)
313 struct pci_dev *pci;
314 struct device *dev = netdev->dev.parent;
316 if (fcoe_transport_lookup(netdev)) {
317 /* load default transport */
318 printk(KERN_DEBUG "fcoe: already loaded transport for %s\n",
319 netdev->name);
320 return -EEXIST;
323 pci = to_pci_dev(dev);
324 if (dev->bus != &pci_bus_type) {
325 printk(KERN_DEBUG "fcoe: support noly PCI device\n");
326 return -ENODEV;
328 printk(KERN_DEBUG "fcoe: loading driver fcoe-pci-0x%04x-0x%04x\n",
329 pci->vendor, pci->device);
331 return request_module("fcoe-pci-0x%04x-0x%04x",
332 pci->vendor, pci->device);
335 EXPORT_SYMBOL_GPL(fcoe_load_transport_driver);
338 * fcoe_transport_attach - load transport to fcoe
339 * @netdev: the netdev the transport to be attached to
341 * This will look for existing offload driver, if not found, it falls back to
342 * the default sw hba (fcoe_sw) as its fcoe transport.
344 * Returns: 0 for success
346 int fcoe_transport_attach(struct net_device *netdev)
348 struct fcoe_transport *t;
350 /* find the corresponding transport */
351 t = fcoe_transport_lookup(netdev);
352 if (!t) {
353 printk(KERN_DEBUG "fcoe_transport_attach"
354 ":no transport for %s:use %s\n",
355 netdev->name, t->name);
356 return -ENODEV;
358 /* add to the transport */
359 if (fcoe_transport_device_add(t, netdev)) {
360 printk(KERN_DEBUG "fcoe_transport_attach"
361 ":failed to add %s to tramsport %s\n",
362 netdev->name, t->name);
363 return -EIO;
365 /* transport create function */
366 if (t->create)
367 t->create(netdev);
369 printk(KERN_DEBUG "fcoe_transport_attach:transport %s for %s\n",
370 t->name, netdev->name);
371 return 0;
373 EXPORT_SYMBOL_GPL(fcoe_transport_attach);
376 * fcoe_transport_release - unload transport from fcoe
377 * @netdev: the net device on which fcoe is to be released
379 * Returns: 0 for success
381 int fcoe_transport_release(struct net_device *netdev)
383 struct fcoe_transport *t;
385 /* find the corresponding transport */
386 t = fcoe_transport_lookup(netdev);
387 if (!t) {
388 printk(KERN_DEBUG "fcoe_transport_release:"
389 "no transport for %s:use %s\n",
390 netdev->name, t->name);
391 return -ENODEV;
393 /* remove the device from the transport */
394 if (fcoe_transport_device_remove(t, netdev)) {
395 printk(KERN_DEBUG "fcoe_transport_release:"
396 "failed to add %s to tramsport %s\n",
397 netdev->name, t->name);
398 return -EIO;
400 /* transport destroy function */
401 if (t->destroy)
402 t->destroy(netdev);
404 printk(KERN_DEBUG "fcoe_transport_release:"
405 "device %s dettached from transport %s\n",
406 netdev->name, t->name);
408 return 0;
410 EXPORT_SYMBOL_GPL(fcoe_transport_release);
413 * fcoe_transport_init - initializes fcoe transport layer
415 * This prepares for the fcoe transport layer
417 * Returns: none
419 int __init fcoe_transport_init(void)
421 INIT_LIST_HEAD(&fcoe_transports);
422 mutex_init(&fcoe_transports_lock);
423 return 0;
427 * fcoe_transport_exit - cleans up the fcoe transport layer
428 * This cleans up the fcoe transport layer. removing any transport on the list,
429 * note that the transport destroy func is not called here.
431 * Returns: none
433 int __exit fcoe_transport_exit(void)
435 struct fcoe_transport *t, *tmp;
437 mutex_lock(&fcoe_transports_lock);
438 list_for_each_entry_safe(t, tmp, &fcoe_transports, list) {
439 list_del(&t->list);
440 mutex_unlock(&fcoe_transports_lock);
441 fcoe_transport_device_remove_all(t);
442 mutex_lock(&fcoe_transports_lock);
444 mutex_unlock(&fcoe_transports_lock);
445 return 0;