]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/scsi/fcoe/fc_transport_fcoe.c
[SCSI] libfc, fcoe: Cleanup function formatting and minor typos
[linux-2.6-omap-h63xx.git] / drivers / scsi / fcoe / fc_transport_fcoe.c
1 /*
2  * Copyright(c) 2007 - 2008 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/pci.h>
21 #include <scsi/libfcoe.h>
22 #include <scsi/fc_transport_fcoe.h>
23
24 /* internal fcoe transport */
25 struct fcoe_transport_internal {
26         struct fcoe_transport *t;
27         struct net_device *netdev;
28         struct list_head list;
29 };
30
31 /* fcoe transports list and its lock */
32 static LIST_HEAD(fcoe_transports);
33 static DEFINE_MUTEX(fcoe_transports_lock);
34
35 /**
36  * fcoe_transport_default() - Returns ptr to the default transport fcoe_sw
37  */
38 struct fcoe_transport *fcoe_transport_default(void)
39 {
40         return &fcoe_sw_transport;
41 }
42
43 /**
44  * fcoe_transport_to_pcidev() - get the pci dev from a netdev
45  * @netdev: the netdev that pci dev will be retrived from
46  *
47  * Returns: NULL or the corrsponding pci_dev
48  */
49 struct pci_dev *fcoe_transport_pcidev(const struct net_device *netdev)
50 {
51         if (!netdev->dev.parent)
52                 return NULL;
53         return to_pci_dev(netdev->dev.parent);
54 }
55
56 /**
57  * fcoe_transport_device_lookup() - Lookup a transport
58  * @netdev: the netdev the transport to be attached to
59  *
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.
62  *
63  * Returns: 0 for success
64  */
65 static struct fcoe_transport_internal *
66 fcoe_transport_device_lookup(struct fcoe_transport *t,
67                              struct net_device *netdev)
68 {
69         struct fcoe_transport_internal *ti;
70
71         /* assign the transpor to this device */
72         mutex_lock(&t->devlock);
73         list_for_each_entry(ti, &t->devlist, list) {
74                 if (ti->netdev == netdev) {
75                         mutex_unlock(&t->devlock);
76                         return ti;
77                 }
78         }
79         mutex_unlock(&t->devlock);
80         return NULL;
81 }
82 /**
83  * fcoe_transport_device_add() - Assign a transport to a device
84  * @netdev: the netdev the transport to be attached to
85  *
86  * This will look for existing offload driver, if not found, it falls back to
87  * the default sw hba (fcoe_sw) as its fcoe transport.
88  *
89  * Returns: 0 for success
90  */
91 static int fcoe_transport_device_add(struct fcoe_transport *t,
92                                      struct net_device *netdev)
93 {
94         struct fcoe_transport_internal *ti;
95
96         ti = fcoe_transport_device_lookup(t, netdev);
97         if (ti) {
98                 printk(KERN_DEBUG "fcoe_transport_device_add:"
99                        "device %s is already added to transport %s\n",
100                        netdev->name, t->name);
101                 return -EEXIST;
102         }
103         /* allocate an internal struct to host the netdev and the list */
104         ti = kzalloc(sizeof(*ti), GFP_KERNEL);
105         if (!ti)
106                 return -ENOMEM;
107
108         ti->t = t;
109         ti->netdev = netdev;
110         INIT_LIST_HEAD(&ti->list);
111         dev_hold(ti->netdev);
112
113         mutex_lock(&t->devlock);
114         list_add(&ti->list, &t->devlist);
115         mutex_unlock(&t->devlock);
116
117         printk(KERN_DEBUG "fcoe_transport_device_add:"
118                        "device %s added to transport %s\n",
119                        netdev->name, t->name);
120
121         return 0;
122 }
123
124 /**
125  * fcoe_transport_device_remove() - Remove a device from its transport
126  * @netdev: the netdev the transport to be attached to
127  *
128  * This removes the device from the transport so the given transport will
129  * not manage this device any more
130  *
131  * Returns: 0 for success
132  */
133 static int fcoe_transport_device_remove(struct fcoe_transport *t,
134                                         struct net_device *netdev)
135 {
136         struct fcoe_transport_internal *ti;
137
138         ti = fcoe_transport_device_lookup(t, netdev);
139         if (!ti) {
140                 printk(KERN_DEBUG "fcoe_transport_device_remove:"
141                        "device %s is not managed by transport %s\n",
142                        netdev->name, t->name);
143                 return -ENODEV;
144         }
145         mutex_lock(&t->devlock);
146         list_del(&ti->list);
147         mutex_unlock(&t->devlock);
148         printk(KERN_DEBUG "fcoe_transport_device_remove:"
149                "device %s removed from transport %s\n",
150                netdev->name, t->name);
151         dev_put(ti->netdev);
152         kfree(ti);
153         return 0;
154 }
155
156 /**
157  * fcoe_transport_device_remove_all() - Remove all from transport devlist
158  *
159  * This removes the device from the transport so the given transport will
160  * not manage this device any more
161  *
162  * Returns: 0 for success
163  */
164 static void fcoe_transport_device_remove_all(struct fcoe_transport *t)
165 {
166         struct fcoe_transport_internal *ti, *tmp;
167
168         mutex_lock(&t->devlock);
169         list_for_each_entry_safe(ti, tmp, &t->devlist, list) {
170                 list_del(&ti->list);
171                 kfree(ti);
172         }
173         mutex_unlock(&t->devlock);
174 }
175
176 /**
177  * fcoe_transport_match() - Use the bus device match function to match the hw
178  * @t: The fcoe transport to check
179  * @netdev: The netdev to match against
180  *
181  * This function is used to check if the given transport wants to manage the
182  * input netdev. if the transports implements the match function, it will be
183  * called, o.w. we just compare the pci vendor and device id.
184  *
185  * Returns: true for match up
186  */
187 static bool fcoe_transport_match(struct fcoe_transport *t,
188                                  struct net_device *netdev)
189 {
190         /* match transport by vendor and device id */
191         struct pci_dev *pci;
192
193         pci = fcoe_transport_pcidev(netdev);
194
195         if (pci) {
196                 printk(KERN_DEBUG "fcoe_transport_match:"
197                        "%s:%x:%x -- %s:%x:%x\n",
198                        t->name, t->vendor, t->device,
199                        netdev->name, pci->vendor, pci->device);
200
201                 /* if transport supports match */
202                 if (t->match)
203                         return t->match(netdev);
204
205                 /* else just compare the vendor and device id: pci only */
206                 return (t->vendor == pci->vendor) && (t->device == pci->device);
207         }
208         return false;
209 }
210
211 /**
212  * fcoe_transport_lookup() - Check if the transport is already registered
213  * @t: the transport to be looked up
214  *
215  * This compares the parent device (pci) vendor and device id
216  *
217  * Returns: NULL if not found
218  *
219  * TODO: return default sw transport if no other transport is found
220  */
221 static struct fcoe_transport *
222 fcoe_transport_lookup(struct net_device *netdev)
223 {
224         struct fcoe_transport *t;
225
226         mutex_lock(&fcoe_transports_lock);
227         list_for_each_entry(t, &fcoe_transports, list) {
228                 if (fcoe_transport_match(t, netdev)) {
229                         mutex_unlock(&fcoe_transports_lock);
230                         return t;
231                 }
232         }
233         mutex_unlock(&fcoe_transports_lock);
234
235         printk(KERN_DEBUG "fcoe_transport_lookup:"
236                "use default transport for %s\n", netdev->name);
237         return fcoe_transport_default();
238 }
239
240 /**
241  * fcoe_transport_register() - Adds a fcoe transport to the fcoe transports list
242  * @t: ptr to the fcoe transport to be added
243  *
244  * Returns: 0 for success
245  */
246 int fcoe_transport_register(struct fcoe_transport *t)
247 {
248         struct fcoe_transport *tt;
249
250         /* TODO - add fcoe_transport specific initialization here */
251         mutex_lock(&fcoe_transports_lock);
252         list_for_each_entry(tt, &fcoe_transports, list) {
253                 if (tt == t) {
254                         mutex_unlock(&fcoe_transports_lock);
255                         return -EEXIST;
256                 }
257         }
258         list_add_tail(&t->list, &fcoe_transports);
259         mutex_unlock(&fcoe_transports_lock);
260
261         mutex_init(&t->devlock);
262         INIT_LIST_HEAD(&t->devlist);
263
264         printk(KERN_DEBUG "fcoe_transport_register:%s\n", t->name);
265
266         return 0;
267 }
268 EXPORT_SYMBOL_GPL(fcoe_transport_register);
269
270 /**
271  * fcoe_transport_unregister() - Remove the tranport fro the fcoe transports list
272  * @t: ptr to the fcoe transport to be removed
273  *
274  * Returns: 0 for success
275  */
276 int fcoe_transport_unregister(struct fcoe_transport *t)
277 {
278         struct fcoe_transport *tt, *tmp;
279
280         mutex_lock(&fcoe_transports_lock);
281         list_for_each_entry_safe(tt, tmp, &fcoe_transports, list) {
282                 if (tt == t) {
283                         list_del(&t->list);
284                         mutex_unlock(&fcoe_transports_lock);
285                         fcoe_transport_device_remove_all(t);
286                         printk(KERN_DEBUG "fcoe_transport_unregister:%s\n",
287                                t->name);
288                         return 0;
289                 }
290         }
291         mutex_unlock(&fcoe_transports_lock);
292         return -ENODEV;
293 }
294 EXPORT_SYMBOL_GPL(fcoe_transport_unregister);
295
296 /**
297  * fcoe_load_transport_driver() - Load an offload driver by alias name
298  * @netdev: the target net device
299  *
300  * Requests for an offload driver module as the fcoe transport, if fails, it
301  * falls back to use the SW HBA (fcoe_sw) as its transport
302  *
303  * TODO -
304  *      1. supports only PCI device
305  *      2. needs fix for VLAn and bonding
306  *      3. pure hw fcoe hba may not have netdev
307  *
308  * Returns: 0 for success
309  */
310 int fcoe_load_transport_driver(struct net_device *netdev)
311 {
312         struct pci_dev *pci;
313         struct device *dev = netdev->dev.parent;
314
315         if (fcoe_transport_lookup(netdev)) {
316                 /* load default transport */
317                 printk(KERN_DEBUG "fcoe: already loaded transport for %s\n",
318                        netdev->name);
319                 return -EEXIST;
320         }
321
322         pci = to_pci_dev(dev);
323         if (dev->bus != &pci_bus_type) {
324                 printk(KERN_DEBUG "fcoe: support noly PCI device\n");
325                 return -ENODEV;
326         }
327         printk(KERN_DEBUG "fcoe: loading driver fcoe-pci-0x%04x-0x%04x\n",
328                pci->vendor, pci->device);
329
330         return request_module("fcoe-pci-0x%04x-0x%04x",
331                               pci->vendor, pci->device);
332
333 }
334 EXPORT_SYMBOL_GPL(fcoe_load_transport_driver);
335
336 /**
337  * fcoe_transport_attach() - Load transport to fcoe
338  * @netdev: the netdev the transport to be attached to
339  *
340  * This will look for existing offload driver, if not found, it falls back to
341  * the default sw hba (fcoe_sw) as its fcoe transport.
342  *
343  * Returns: 0 for success
344  */
345 int fcoe_transport_attach(struct net_device *netdev)
346 {
347         struct fcoe_transport *t;
348
349         /* find the corresponding transport */
350         t = fcoe_transport_lookup(netdev);
351         if (!t) {
352                 printk(KERN_DEBUG "fcoe_transport_attach"
353                        ":no transport for %s:use %s\n",
354                        netdev->name, t->name);
355                 return -ENODEV;
356         }
357         /* add to the transport */
358         if (fcoe_transport_device_add(t, netdev)) {
359                 printk(KERN_DEBUG "fcoe_transport_attach"
360                        ":failed to add %s to tramsport %s\n",
361                        netdev->name, t->name);
362                 return -EIO;
363         }
364         /* transport create function */
365         if (t->create)
366                 t->create(netdev);
367
368         printk(KERN_DEBUG "fcoe_transport_attach:transport %s for %s\n",
369                t->name, netdev->name);
370         return 0;
371 }
372 EXPORT_SYMBOL_GPL(fcoe_transport_attach);
373
374 /**
375  * fcoe_transport_release() - Unload transport from fcoe
376  * @netdev: the net device on which fcoe is to be released
377  *
378  * Returns: 0 for success
379  */
380 int fcoe_transport_release(struct net_device *netdev)
381 {
382         struct fcoe_transport *t;
383
384         /* find the corresponding transport */
385         t = fcoe_transport_lookup(netdev);
386         if (!t) {
387                 printk(KERN_DEBUG "fcoe_transport_release:"
388                        "no transport for %s:use %s\n",
389                        netdev->name, t->name);
390                 return -ENODEV;
391         }
392         /* remove the device from the transport */
393         if (fcoe_transport_device_remove(t, netdev)) {
394                 printk(KERN_DEBUG "fcoe_transport_release:"
395                        "failed to add %s to tramsport %s\n",
396                        netdev->name, t->name);
397                 return -EIO;
398         }
399         /* transport destroy function */
400         if (t->destroy)
401                 t->destroy(netdev);
402
403         printk(KERN_DEBUG "fcoe_transport_release:"
404                "device %s dettached from transport %s\n",
405                netdev->name, t->name);
406
407         return 0;
408 }
409 EXPORT_SYMBOL_GPL(fcoe_transport_release);
410
411 /**
412  * fcoe_transport_init() - Initializes fcoe transport layer
413  *
414  * This prepares for the fcoe transport layer
415  *
416  * Returns: none
417  */
418 int __init fcoe_transport_init(void)
419 {
420         INIT_LIST_HEAD(&fcoe_transports);
421         mutex_init(&fcoe_transports_lock);
422         return 0;
423 }
424
425 /**
426  * fcoe_transport_exit() - Cleans up the fcoe transport layer
427  *
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.
430  *
431  * Returns: none
432  */
433 int __exit fcoe_transport_exit(void)
434 {
435         struct fcoe_transport *t, *tmp;
436
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);
443         }
444         mutex_unlock(&fcoe_transports_lock);
445         return 0;
446 }