Commit 8d55e507d24c6db7eb012c379c62912e642eb75e
Committed by
James Bottomley
1 parent
9a74e884ee
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
[SCSI] fcoe, bnx2fc, libfcoe: SW FCoE and bnx2fc use FCoE Syfs
This patch has the SW FCoE driver and the bnx2fc driver make use of the new fcoe_sysfs API added earlier in this patch series. After this patch a fcoe_ctlr_device is allocated with private data in this order. +------------------+ +------------------+ | fcoe_ctlr_device | | fcoe_ctlr_device | +------------------+ +------------------+ | fcoe_ctlr | | fcoe_ctlr | +------------------+ +------------------+ | fcoe_interface | | bnx2fc_interface | +------------------+ +------------------+ libfcoe also takes part in this new model since it discovers and manages fcoe_fcf instances. The memory allocation is different for FCFs. I didn't want to impact libfcoe's fcoe_fcf processing, so this patch creates fcoe_fcf_device instances for each discovered fcoe_fcf. The two are paired using a (void * priv) member of the fcoe_ctlr_device. This allows libfcoe to continue maintaining its list of fcoe_fcf instances and simply attaches and detaches them from existing or new fcoe_fcf_device instances. Signed-off-by: Robert Love <robert.w.love@intel.com> Tested-by: Ross Brattain <ross.b.brattain@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Showing 4 changed files with 285 additions and 25 deletions Side-by-side Diff
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
... | ... | @@ -54,6 +54,7 @@ |
54 | 54 | static struct libfc_function_template bnx2fc_libfc_fcn_templ; |
55 | 55 | static struct scsi_host_template bnx2fc_shost_template; |
56 | 56 | static struct fc_function_template bnx2fc_transport_function; |
57 | +static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ; | |
57 | 58 | static struct fc_function_template bnx2fc_vport_xport_function; |
58 | 59 | static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); |
59 | 60 | static void __bnx2fc_destroy(struct bnx2fc_interface *interface); |
... | ... | @@ -88,6 +89,7 @@ |
88 | 89 | static void bnx2fc_stop(struct bnx2fc_interface *interface); |
89 | 90 | static int __init bnx2fc_mod_init(void); |
90 | 91 | static void __exit bnx2fc_mod_exit(void); |
92 | +static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev); | |
91 | 93 | |
92 | 94 | unsigned int bnx2fc_debug_level; |
93 | 95 | module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); |
... | ... | @@ -118,6 +120,41 @@ |
118 | 120 | __fcoe_get_lesb(lport, fc_lesb, netdev); |
119 | 121 | } |
120 | 122 | |
123 | +static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev) | |
124 | +{ | |
125 | + struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); | |
126 | + struct net_device *netdev = bnx2fc_netdev(fip->lp); | |
127 | + struct fcoe_fc_els_lesb *fcoe_lesb; | |
128 | + struct fc_els_lesb fc_lesb; | |
129 | + | |
130 | + __fcoe_get_lesb(fip->lp, &fc_lesb, netdev); | |
131 | + fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb); | |
132 | + | |
133 | + ctlr_dev->lesb.lesb_link_fail = | |
134 | + ntohl(fcoe_lesb->lesb_link_fail); | |
135 | + ctlr_dev->lesb.lesb_vlink_fail = | |
136 | + ntohl(fcoe_lesb->lesb_vlink_fail); | |
137 | + ctlr_dev->lesb.lesb_miss_fka = | |
138 | + ntohl(fcoe_lesb->lesb_miss_fka); | |
139 | + ctlr_dev->lesb.lesb_symb_err = | |
140 | + ntohl(fcoe_lesb->lesb_symb_err); | |
141 | + ctlr_dev->lesb.lesb_err_block = | |
142 | + ntohl(fcoe_lesb->lesb_err_block); | |
143 | + ctlr_dev->lesb.lesb_fcs_error = | |
144 | + ntohl(fcoe_lesb->lesb_fcs_error); | |
145 | +} | |
146 | +EXPORT_SYMBOL(bnx2fc_ctlr_get_lesb); | |
147 | + | |
148 | +static void bnx2fc_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) | |
149 | +{ | |
150 | + struct fcoe_ctlr_device *ctlr_dev = | |
151 | + fcoe_fcf_dev_to_ctlr_dev(fcf_dev); | |
152 | + struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); | |
153 | + struct bnx2fc_interface *fcoe = fcoe_ctlr_priv(ctlr); | |
154 | + | |
155 | + fcf_dev->vlan_id = fcoe->vlan_id; | |
156 | +} | |
157 | + | |
121 | 158 | static void bnx2fc_clean_rx_queue(struct fc_lport *lp) |
122 | 159 | { |
123 | 160 | struct fcoe_percpu_s *bg; |
... | ... | @@ -1235,6 +1272,7 @@ |
1235 | 1272 | |
1236 | 1273 | static void bnx2fc_interface_release(struct kref *kref) |
1237 | 1274 | { |
1275 | + struct fcoe_ctlr_device *ctlr_dev; | |
1238 | 1276 | struct bnx2fc_interface *interface; |
1239 | 1277 | struct fcoe_ctlr *ctlr; |
1240 | 1278 | struct net_device *netdev; |
1241 | 1279 | |
... | ... | @@ -1243,13 +1281,14 @@ |
1243 | 1281 | BNX2FC_MISC_DBG("Interface is being released\n"); |
1244 | 1282 | |
1245 | 1283 | ctlr = bnx2fc_to_ctlr(interface); |
1284 | + ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); | |
1246 | 1285 | netdev = interface->netdev; |
1247 | 1286 | |
1248 | 1287 | /* tear-down FIP controller */ |
1249 | 1288 | if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) |
1250 | 1289 | fcoe_ctlr_destroy(ctlr); |
1251 | 1290 | |
1252 | - kfree(ctlr); | |
1291 | + fcoe_ctlr_device_delete(ctlr_dev); | |
1253 | 1292 | |
1254 | 1293 | dev_put(netdev); |
1255 | 1294 | module_put(THIS_MODULE); |
1256 | 1295 | |
1257 | 1296 | |
... | ... | @@ -1342,17 +1381,20 @@ |
1342 | 1381 | struct net_device *netdev, |
1343 | 1382 | enum fip_state fip_mode) |
1344 | 1383 | { |
1384 | + struct fcoe_ctlr_device *ctlr_dev; | |
1345 | 1385 | struct bnx2fc_interface *interface; |
1346 | 1386 | struct fcoe_ctlr *ctlr; |
1347 | 1387 | int size; |
1348 | 1388 | int rc = 0; |
1349 | 1389 | |
1350 | 1390 | size = (sizeof(*interface) + sizeof(struct fcoe_ctlr)); |
1351 | - ctlr = kzalloc(size, GFP_KERNEL); | |
1352 | - if (!ctlr) { | |
1391 | + ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &bnx2fc_fcoe_sysfs_templ, | |
1392 | + size); | |
1393 | + if (!ctlr_dev) { | |
1353 | 1394 | printk(KERN_ERR PFX "Unable to allocate interface structure\n"); |
1354 | 1395 | return NULL; |
1355 | 1396 | } |
1397 | + ctlr = fcoe_ctlr_device_priv(ctlr_dev); | |
1356 | 1398 | interface = fcoe_ctlr_priv(ctlr); |
1357 | 1399 | dev_hold(netdev); |
1358 | 1400 | kref_init(&interface->kref); |
... | ... | @@ -1372,7 +1414,7 @@ |
1372 | 1414 | |
1373 | 1415 | fcoe_ctlr_destroy(ctlr); |
1374 | 1416 | dev_put(netdev); |
1375 | - kfree(ctlr); | |
1417 | + fcoe_ctlr_device_delete(ctlr_dev); | |
1376 | 1418 | return NULL; |
1377 | 1419 | } |
1378 | 1420 | |
... | ... | @@ -2470,6 +2512,19 @@ |
2470 | 2512 | |
2471 | 2513 | module_init(bnx2fc_mod_init); |
2472 | 2514 | module_exit(bnx2fc_mod_exit); |
2515 | + | |
2516 | +static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = { | |
2517 | + .get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode, | |
2518 | + .get_fcoe_ctlr_link_fail = bnx2fc_ctlr_get_lesb, | |
2519 | + .get_fcoe_ctlr_vlink_fail = bnx2fc_ctlr_get_lesb, | |
2520 | + .get_fcoe_ctlr_miss_fka = bnx2fc_ctlr_get_lesb, | |
2521 | + .get_fcoe_ctlr_symb_err = bnx2fc_ctlr_get_lesb, | |
2522 | + .get_fcoe_ctlr_err_block = bnx2fc_ctlr_get_lesb, | |
2523 | + .get_fcoe_ctlr_fcs_error = bnx2fc_ctlr_get_lesb, | |
2524 | + | |
2525 | + .get_fcoe_fcf_selected = fcoe_fcf_get_selected, | |
2526 | + .get_fcoe_fcf_vlan_id = bnx2fc_fcf_get_vlan_id, | |
2527 | +}; | |
2473 | 2528 | |
2474 | 2529 | static struct fc_function_template bnx2fc_transport_function = { |
2475 | 2530 | .show_host_node_name = 1, |
drivers/scsi/fcoe/fcoe.c
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | |
42 | 42 | #include <scsi/fc/fc_encaps.h> |
43 | 43 | #include <scsi/fc/fc_fip.h> |
44 | +#include <scsi/fc/fc_fcoe.h> | |
44 | 45 | |
45 | 46 | #include <scsi/libfc.h> |
46 | 47 | #include <scsi/fc_frame.h> |
47 | 48 | |
... | ... | @@ -150,7 +151,22 @@ |
150 | 151 | static int fcoe_vport_disable(struct fc_vport *, bool disable); |
151 | 152 | static void fcoe_set_vport_symbolic_name(struct fc_vport *); |
152 | 153 | static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); |
154 | +static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *); | |
155 | +static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *); | |
153 | 156 | |
157 | +static struct fcoe_sysfs_function_template fcoe_sysfs_templ = { | |
158 | + .get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode, | |
159 | + .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, | |
160 | + .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, | |
161 | + .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb, | |
162 | + .get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb, | |
163 | + .get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb, | |
164 | + .get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb, | |
165 | + | |
166 | + .get_fcoe_fcf_selected = fcoe_fcf_get_selected, | |
167 | + .get_fcoe_fcf_vlan_id = fcoe_fcf_get_vlan_id, | |
168 | +}; | |
169 | + | |
154 | 170 | static struct libfc_function_template fcoe_libfc_fcn_templ = { |
155 | 171 | .frame_send = fcoe_xmit, |
156 | 172 | .ddp_setup = fcoe_ddp_setup, |
... | ... | @@ -366,6 +382,7 @@ |
366 | 382 | static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, |
367 | 383 | enum fip_state fip_mode) |
368 | 384 | { |
385 | + struct fcoe_ctlr_device *ctlr_dev; | |
369 | 386 | struct fcoe_ctlr *ctlr; |
370 | 387 | struct fcoe_interface *fcoe; |
371 | 388 | int size; |
372 | 389 | |
... | ... | @@ -379,14 +396,17 @@ |
379 | 396 | } |
380 | 397 | |
381 | 398 | size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface); |
382 | - ctlr = kzalloc(size, GFP_KERNEL); | |
383 | - fcoe = fcoe_ctlr_priv(ctlr); | |
384 | - if (!fcoe) { | |
385 | - FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); | |
399 | + ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &fcoe_sysfs_templ, | |
400 | + size); | |
401 | + if (!ctlr_dev) { | |
402 | + FCOE_DBG("Failed to add fcoe_ctlr_device\n"); | |
386 | 403 | fcoe = ERR_PTR(-ENOMEM); |
387 | 404 | goto out_putmod; |
388 | 405 | } |
389 | 406 | |
407 | + ctlr = fcoe_ctlr_device_priv(ctlr_dev); | |
408 | + fcoe = fcoe_ctlr_priv(ctlr); | |
409 | + | |
390 | 410 | dev_hold(netdev); |
391 | 411 | |
392 | 412 | /* |
... | ... | @@ -400,6 +420,7 @@ |
400 | 420 | err = fcoe_interface_setup(fcoe, netdev); |
401 | 421 | if (err) { |
402 | 422 | fcoe_ctlr_destroy(ctlr); |
423 | + fcoe_ctlr_device_delete(ctlr_dev); | |
403 | 424 | dev_put(netdev); |
404 | 425 | fcoe = ERR_PTR(err); |
405 | 426 | goto out_putmod; |
... | ... | @@ -466,6 +487,7 @@ |
466 | 487 | { |
467 | 488 | struct net_device *netdev = fcoe->netdev; |
468 | 489 | struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); |
490 | + struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); | |
469 | 491 | |
470 | 492 | rtnl_lock(); |
471 | 493 | if (!fcoe->removed) |
... | ... | @@ -476,7 +498,7 @@ |
476 | 498 | /* tear-down the FCoE controller */ |
477 | 499 | fcoe_ctlr_destroy(fip); |
478 | 500 | scsi_host_put(fip->lp->host); |
479 | - kfree(fip); | |
501 | + fcoe_ctlr_device_delete(ctlr_dev); | |
480 | 502 | dev_put(netdev); |
481 | 503 | module_put(THIS_MODULE); |
482 | 504 | } |
... | ... | @@ -2196,6 +2218,7 @@ |
2196 | 2218 | static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) |
2197 | 2219 | { |
2198 | 2220 | int rc = 0; |
2221 | + struct fcoe_ctlr_device *ctlr_dev; | |
2199 | 2222 | struct fcoe_ctlr *ctlr; |
2200 | 2223 | struct fcoe_interface *fcoe; |
2201 | 2224 | struct fc_lport *lport; |
... | ... | @@ -2216,8 +2239,8 @@ |
2216 | 2239 | } |
2217 | 2240 | |
2218 | 2241 | ctlr = fcoe_to_ctlr(fcoe); |
2219 | - | |
2220 | - lport = fcoe_if_create(fcoe, &netdev->dev, 0); | |
2242 | + ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); | |
2243 | + lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0); | |
2221 | 2244 | if (IS_ERR(lport)) { |
2222 | 2245 | printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", |
2223 | 2246 | netdev->name); |
... | ... | @@ -2766,6 +2789,40 @@ |
2766 | 2789 | struct net_device *netdev = fcoe_netdev(lport); |
2767 | 2790 | |
2768 | 2791 | __fcoe_get_lesb(lport, fc_lesb, netdev); |
2792 | +} | |
2793 | + | |
2794 | +static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev) | |
2795 | +{ | |
2796 | + struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); | |
2797 | + struct net_device *netdev = fcoe_netdev(fip->lp); | |
2798 | + struct fcoe_fc_els_lesb *fcoe_lesb; | |
2799 | + struct fc_els_lesb fc_lesb; | |
2800 | + | |
2801 | + __fcoe_get_lesb(fip->lp, &fc_lesb, netdev); | |
2802 | + fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb); | |
2803 | + | |
2804 | + ctlr_dev->lesb.lesb_link_fail = | |
2805 | + ntohl(fcoe_lesb->lesb_link_fail); | |
2806 | + ctlr_dev->lesb.lesb_vlink_fail = | |
2807 | + ntohl(fcoe_lesb->lesb_vlink_fail); | |
2808 | + ctlr_dev->lesb.lesb_miss_fka = | |
2809 | + ntohl(fcoe_lesb->lesb_miss_fka); | |
2810 | + ctlr_dev->lesb.lesb_symb_err = | |
2811 | + ntohl(fcoe_lesb->lesb_symb_err); | |
2812 | + ctlr_dev->lesb.lesb_err_block = | |
2813 | + ntohl(fcoe_lesb->lesb_err_block); | |
2814 | + ctlr_dev->lesb.lesb_fcs_error = | |
2815 | + ntohl(fcoe_lesb->lesb_fcs_error); | |
2816 | +} | |
2817 | + | |
2818 | +static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) | |
2819 | +{ | |
2820 | + struct fcoe_ctlr_device *ctlr_dev = | |
2821 | + fcoe_fcf_dev_to_ctlr_dev(fcf_dev); | |
2822 | + struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); | |
2823 | + struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr); | |
2824 | + | |
2825 | + fcf_dev->vlan_id = vlan_dev_vlan_id(fcoe->netdev); | |
2769 | 2826 | } |
2770 | 2827 | |
2771 | 2828 | /** |
drivers/scsi/fcoe/fcoe_ctlr.c
... | ... | @@ -160,6 +160,76 @@ |
160 | 160 | } |
161 | 161 | EXPORT_SYMBOL(fcoe_ctlr_init); |
162 | 162 | |
163 | +static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) | |
164 | +{ | |
165 | + struct fcoe_ctlr *fip = new->fip; | |
166 | + struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); | |
167 | + struct fcoe_fcf_device temp, *fcf_dev; | |
168 | + int rc = 0; | |
169 | + | |
170 | + LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n", | |
171 | + new->fabric_name, new->fcf_mac); | |
172 | + | |
173 | + mutex_lock(&ctlr_dev->lock); | |
174 | + | |
175 | + temp.fabric_name = new->fabric_name; | |
176 | + temp.switch_name = new->switch_name; | |
177 | + temp.fc_map = new->fc_map; | |
178 | + temp.vfid = new->vfid; | |
179 | + memcpy(temp.mac, new->fcf_mac, ETH_ALEN); | |
180 | + temp.priority = new->pri; | |
181 | + temp.fka_period = new->fka_period; | |
182 | + temp.selected = 0; /* default to unselected */ | |
183 | + | |
184 | + fcf_dev = fcoe_fcf_device_add(ctlr_dev, &temp); | |
185 | + if (unlikely(!fcf_dev)) { | |
186 | + rc = -ENOMEM; | |
187 | + goto out; | |
188 | + } | |
189 | + | |
190 | + /* | |
191 | + * The fcoe_sysfs layer can return a CONNECTED fcf that | |
192 | + * has a priv (fcf was never deleted) or a CONNECTED fcf | |
193 | + * that doesn't have a priv (fcf was deleted). However, | |
194 | + * libfcoe will always delete FCFs before trying to add | |
195 | + * them. This is ensured because both recv_adv and | |
196 | + * age_fcfs are protected by the the fcoe_ctlr's mutex. | |
197 | + * This means that we should never get a FCF with a | |
198 | + * non-NULL priv pointer. | |
199 | + */ | |
200 | + BUG_ON(fcf_dev->priv); | |
201 | + | |
202 | + fcf_dev->priv = new; | |
203 | + new->fcf_dev = fcf_dev; | |
204 | + | |
205 | + list_add(&new->list, &fip->fcfs); | |
206 | + fip->fcf_count++; | |
207 | + | |
208 | +out: | |
209 | + mutex_unlock(&ctlr_dev->lock); | |
210 | + return rc; | |
211 | +} | |
212 | + | |
213 | +static void fcoe_sysfs_fcf_del(struct fcoe_fcf *new) | |
214 | +{ | |
215 | + struct fcoe_ctlr *fip = new->fip; | |
216 | + struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); | |
217 | + struct fcoe_fcf_device *fcf_dev; | |
218 | + | |
219 | + list_del(&new->list); | |
220 | + fip->fcf_count--; | |
221 | + | |
222 | + mutex_lock(&ctlr_dev->lock); | |
223 | + | |
224 | + fcf_dev = fcoe_fcf_to_fcf_dev(new); | |
225 | + WARN_ON(!fcf_dev); | |
226 | + new->fcf_dev = NULL; | |
227 | + fcoe_fcf_device_delete(fcf_dev); | |
228 | + kfree(new); | |
229 | + | |
230 | + mutex_unlock(&ctlr_dev->lock); | |
231 | +} | |
232 | + | |
163 | 233 | /** |
164 | 234 | * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller |
165 | 235 | * @fip: The FCoE controller whose FCFs are to be reset |
166 | 236 | |
... | ... | @@ -173,10 +243,10 @@ |
173 | 243 | |
174 | 244 | fip->sel_fcf = NULL; |
175 | 245 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { |
176 | - list_del(&fcf->list); | |
177 | - kfree(fcf); | |
246 | + fcoe_sysfs_fcf_del(fcf); | |
178 | 247 | } |
179 | - fip->fcf_count = 0; | |
248 | + WARN_ON(fip->fcf_count); | |
249 | + | |
180 | 250 | fip->sel_time = 0; |
181 | 251 | } |
182 | 252 | |
183 | 253 | |
... | ... | @@ -717,8 +787,11 @@ |
717 | 787 | unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); |
718 | 788 | unsigned long deadline; |
719 | 789 | unsigned long sel_time = 0; |
790 | + struct list_head del_list; | |
720 | 791 | struct fcoe_dev_stats *stats; |
721 | 792 | |
793 | + INIT_LIST_HEAD(&del_list); | |
794 | + | |
722 | 795 | stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); |
723 | 796 | |
724 | 797 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { |
725 | 798 | |
... | ... | @@ -739,10 +812,13 @@ |
739 | 812 | if (time_after_eq(jiffies, deadline)) { |
740 | 813 | if (fip->sel_fcf == fcf) |
741 | 814 | fip->sel_fcf = NULL; |
815 | + /* | |
816 | + * Move to delete list so we can call | |
817 | + * fcoe_sysfs_fcf_del (which can sleep) | |
818 | + * after the put_cpu(). | |
819 | + */ | |
742 | 820 | list_del(&fcf->list); |
743 | - WARN_ON(!fip->fcf_count); | |
744 | - fip->fcf_count--; | |
745 | - kfree(fcf); | |
821 | + list_add(&fcf->list, &del_list); | |
746 | 822 | stats->VLinkFailureCount++; |
747 | 823 | } else { |
748 | 824 | if (time_after(next_timer, deadline)) |
... | ... | @@ -753,6 +829,12 @@ |
753 | 829 | } |
754 | 830 | } |
755 | 831 | put_cpu(); |
832 | + | |
833 | + list_for_each_entry_safe(fcf, next, &del_list, list) { | |
834 | + /* Removes fcf from current list */ | |
835 | + fcoe_sysfs_fcf_del(fcf); | |
836 | + } | |
837 | + | |
756 | 838 | if (sel_time && !fip->sel_fcf && !fip->sel_time) { |
757 | 839 | sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); |
758 | 840 | fip->sel_time = sel_time; |
759 | 841 | |
760 | 842 | |
761 | 843 | |
... | ... | @@ -903,23 +985,23 @@ |
903 | 985 | { |
904 | 986 | struct fcoe_fcf *fcf; |
905 | 987 | struct fcoe_fcf new; |
906 | - struct fcoe_fcf *found; | |
907 | 988 | unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); |
908 | 989 | int first = 0; |
909 | 990 | int mtu_valid; |
991 | + int found = 0; | |
992 | + int rc = 0; | |
910 | 993 | |
911 | 994 | if (fcoe_ctlr_parse_adv(fip, skb, &new)) |
912 | 995 | return; |
913 | 996 | |
914 | 997 | mutex_lock(&fip->ctlr_mutex); |
915 | 998 | first = list_empty(&fip->fcfs); |
916 | - found = NULL; | |
917 | 999 | list_for_each_entry(fcf, &fip->fcfs, list) { |
918 | 1000 | if (fcf->switch_name == new.switch_name && |
919 | 1001 | fcf->fabric_name == new.fabric_name && |
920 | 1002 | fcf->fc_map == new.fc_map && |
921 | 1003 | compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { |
922 | - found = fcf; | |
1004 | + found = 1; | |
923 | 1005 | break; |
924 | 1006 | } |
925 | 1007 | } |
926 | 1008 | |
... | ... | @@ -931,9 +1013,16 @@ |
931 | 1013 | if (!fcf) |
932 | 1014 | goto out; |
933 | 1015 | |
934 | - fip->fcf_count++; | |
935 | 1016 | memcpy(fcf, &new, sizeof(new)); |
936 | - list_add(&fcf->list, &fip->fcfs); | |
1017 | + fcf->fip = fip; | |
1018 | + rc = fcoe_sysfs_fcf_add(fcf); | |
1019 | + if (rc) { | |
1020 | + printk(KERN_ERR "Failed to allocate sysfs instance " | |
1021 | + "for FCF, fab %16.16llx mac %pM\n", | |
1022 | + new.fabric_name, new.fcf_mac); | |
1023 | + kfree(fcf); | |
1024 | + goto out; | |
1025 | + } | |
937 | 1026 | } else { |
938 | 1027 | /* |
939 | 1028 | * Update the FCF's keep-alive descriptor flags. |
... | ... | @@ -954,6 +1043,7 @@ |
954 | 1043 | fcf->fka_period = new.fka_period; |
955 | 1044 | memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); |
956 | 1045 | } |
1046 | + | |
957 | 1047 | mtu_valid = fcoe_ctlr_mtu_valid(fcf); |
958 | 1048 | fcf->time = jiffies; |
959 | 1049 | if (!found) |
... | ... | @@ -996,6 +1086,7 @@ |
996 | 1086 | time_before(fip->sel_time, fip->timer.expires)) |
997 | 1087 | mod_timer(&fip->timer, fip->sel_time); |
998 | 1088 | } |
1089 | + | |
999 | 1090 | out: |
1000 | 1091 | mutex_unlock(&fip->ctlr_mutex); |
1001 | 1092 | } |
... | ... | @@ -2718,9 +2809,9 @@ |
2718 | 2809 | |
2719 | 2810 | /** |
2720 | 2811 | * fcoe_libfc_config() - Sets up libfc related properties for local port |
2721 | - * @lp: The local port to configure libfc for | |
2722 | - * @fip: The FCoE controller in use by the local port | |
2723 | - * @tt: The libfc function template | |
2812 | + * @lport: The local port to configure libfc for | |
2813 | + * @fip: The FCoE controller in use by the local port | |
2814 | + * @tt: The libfc function template | |
2724 | 2815 | * @init_fcp: If non-zero, the FCP portion of libfc should be initialized |
2725 | 2816 | * |
2726 | 2817 | * Returns : 0 for success |
... | ... | @@ -2753,4 +2844,44 @@ |
2753 | 2844 | return 0; |
2754 | 2845 | } |
2755 | 2846 | EXPORT_SYMBOL_GPL(fcoe_libfc_config); |
2847 | + | |
2848 | +void fcoe_fcf_get_selected(struct fcoe_fcf_device *fcf_dev) | |
2849 | +{ | |
2850 | + struct fcoe_ctlr_device *ctlr_dev = fcoe_fcf_dev_to_ctlr_dev(fcf_dev); | |
2851 | + struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); | |
2852 | + struct fcoe_fcf *fcf; | |
2853 | + | |
2854 | + mutex_lock(&fip->ctlr_mutex); | |
2855 | + mutex_lock(&ctlr_dev->lock); | |
2856 | + | |
2857 | + fcf = fcoe_fcf_device_priv(fcf_dev); | |
2858 | + if (fcf) | |
2859 | + fcf_dev->selected = (fcf == fip->sel_fcf) ? 1 : 0; | |
2860 | + else | |
2861 | + fcf_dev->selected = 0; | |
2862 | + | |
2863 | + mutex_unlock(&ctlr_dev->lock); | |
2864 | + mutex_unlock(&fip->ctlr_mutex); | |
2865 | +} | |
2866 | +EXPORT_SYMBOL(fcoe_fcf_get_selected); | |
2867 | + | |
2868 | +void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *ctlr_dev) | |
2869 | +{ | |
2870 | + struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); | |
2871 | + | |
2872 | + mutex_lock(&ctlr->ctlr_mutex); | |
2873 | + switch (ctlr->mode) { | |
2874 | + case FIP_MODE_FABRIC: | |
2875 | + ctlr_dev->mode = FIP_CONN_TYPE_FABRIC; | |
2876 | + break; | |
2877 | + case FIP_MODE_VN2VN: | |
2878 | + ctlr_dev->mode = FIP_CONN_TYPE_VN2VN; | |
2879 | + break; | |
2880 | + default: | |
2881 | + ctlr_dev->mode = FIP_CONN_TYPE_UNKNOWN; | |
2882 | + break; | |
2883 | + } | |
2884 | + mutex_unlock(&ctlr->ctlr_mutex); | |
2885 | +} | |
2886 | +EXPORT_SYMBOL(fcoe_ctlr_get_fip_mode); |
include/scsi/libfcoe.h
... | ... | @@ -168,9 +168,16 @@ |
168 | 168 | return (void *)(ctlr + 1); |
169 | 169 | } |
170 | 170 | |
171 | +#define fcoe_ctlr_to_ctlr_dev(x) \ | |
172 | + (struct fcoe_ctlr_device *)(((struct fcoe_ctlr_device *)(x)) - 1) | |
173 | + | |
171 | 174 | /** |
172 | 175 | * struct fcoe_fcf - Fibre-Channel Forwarder |
173 | 176 | * @list: list linkage |
177 | + * @event_work: Work for FC Transport actions queue | |
178 | + * @event: The event to be processed | |
179 | + * @fip: The controller that the FCF was discovered on | |
180 | + * @fcf_dev: The associated fcoe_fcf_device instance | |
174 | 181 | * @time: system time (jiffies) when an advertisement was last received |
175 | 182 | * @switch_name: WWN of switch from advertisement |
176 | 183 | * @fabric_name: WWN of fabric from advertisement |
... | ... | @@ -192,6 +199,9 @@ |
192 | 199 | */ |
193 | 200 | struct fcoe_fcf { |
194 | 201 | struct list_head list; |
202 | + struct work_struct event_work; | |
203 | + struct fcoe_ctlr *fip; | |
204 | + struct fcoe_fcf_device *fcf_dev; | |
195 | 205 | unsigned long time; |
196 | 206 | |
197 | 207 | u64 switch_name; |
... | ... | @@ -208,6 +218,9 @@ |
208 | 218 | u8 fd_flags:1; |
209 | 219 | }; |
210 | 220 | |
221 | +#define fcoe_fcf_to_fcf_dev(x) \ | |
222 | + ((x)->fcf_dev) | |
223 | + | |
211 | 224 | /** |
212 | 225 | * struct fcoe_rport - VN2VN remote port |
213 | 226 | * @time: time of create or last beacon packet received from node |
... | ... | @@ -342,6 +355,10 @@ |
342 | 355 | void fcoe_queue_timer(ulong lport); |
343 | 356 | int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, |
344 | 357 | struct fcoe_percpu_s *fps); |
358 | + | |
359 | +/* FCoE Sysfs helpers */ | |
360 | +void fcoe_fcf_get_selected(struct fcoe_fcf_device *); | |
361 | +void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *); | |
345 | 362 | |
346 | 363 | /** |
347 | 364 | * struct netdev_list |