diff options
| author | Robert Love <robert.w.love@intel.com> | 2012-05-22 22:06:26 -0400 |
|---|---|---|
| committer | James Bottomley <JBottomley@Parallels.com> | 2012-05-23 04:43:13 -0400 |
| commit | 8d55e507d24c6db7eb012c379c62912e642eb75e (patch) | |
| tree | 5118b221cf9eab4ad040c9e1bcabb794e57dc906 | |
| parent | 9a74e884ee71dbf3d0967b0321d7b4529a04826c (diff) | |
[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>
| -rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 63 | ||||
| -rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 71 | ||||
| -rw-r--r-- | drivers/scsi/fcoe/fcoe_ctlr.c | 159 | ||||
| -rw-r--r-- | include/scsi/libfcoe.h | 17 |
4 files changed, 285 insertions, 25 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index cb9bf364170b..f52f668fd247 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c | |||
| @@ -54,6 +54,7 @@ static struct cnic_ulp_ops bnx2fc_cnic_cb; | |||
| 54 | static struct libfc_function_template bnx2fc_libfc_fcn_templ; | 54 | static struct libfc_function_template bnx2fc_libfc_fcn_templ; |
| 55 | static struct scsi_host_template bnx2fc_shost_template; | 55 | static struct scsi_host_template bnx2fc_shost_template; |
| 56 | static struct fc_function_template bnx2fc_transport_function; | 56 | static struct fc_function_template bnx2fc_transport_function; |
| 57 | static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ; | ||
| 57 | static struct fc_function_template bnx2fc_vport_xport_function; | 58 | static struct fc_function_template bnx2fc_vport_xport_function; |
| 58 | static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); | 59 | static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); |
| 59 | static void __bnx2fc_destroy(struct bnx2fc_interface *interface); | 60 | static void __bnx2fc_destroy(struct bnx2fc_interface *interface); |
| @@ -88,6 +89,7 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport); | |||
| 88 | static void bnx2fc_stop(struct bnx2fc_interface *interface); | 89 | static void bnx2fc_stop(struct bnx2fc_interface *interface); |
| 89 | static int __init bnx2fc_mod_init(void); | 90 | static int __init bnx2fc_mod_init(void); |
| 90 | static void __exit bnx2fc_mod_exit(void); | 91 | static void __exit bnx2fc_mod_exit(void); |
| 92 | static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev); | ||
| 91 | 93 | ||
| 92 | unsigned int bnx2fc_debug_level; | 94 | unsigned int bnx2fc_debug_level; |
| 93 | module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); | 95 | module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); |
| @@ -118,6 +120,41 @@ static void bnx2fc_get_lesb(struct fc_lport *lport, | |||
| 118 | __fcoe_get_lesb(lport, fc_lesb, netdev); | 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 | static void bnx2fc_clean_rx_queue(struct fc_lport *lp) | 158 | static void bnx2fc_clean_rx_queue(struct fc_lport *lp) |
| 122 | { | 159 | { |
| 123 | struct fcoe_percpu_s *bg; | 160 | struct fcoe_percpu_s *bg; |
| @@ -1235,6 +1272,7 @@ static void bnx2fc_release_transport(void) | |||
| 1235 | 1272 | ||
| 1236 | static void bnx2fc_interface_release(struct kref *kref) | 1273 | static void bnx2fc_interface_release(struct kref *kref) |
| 1237 | { | 1274 | { |
| 1275 | struct fcoe_ctlr_device *ctlr_dev; | ||
| 1238 | struct bnx2fc_interface *interface; | 1276 | struct bnx2fc_interface *interface; |
| 1239 | struct fcoe_ctlr *ctlr; | 1277 | struct fcoe_ctlr *ctlr; |
| 1240 | struct net_device *netdev; | 1278 | struct net_device *netdev; |
| @@ -1243,13 +1281,14 @@ static void bnx2fc_interface_release(struct kref *kref) | |||
| 1243 | BNX2FC_MISC_DBG("Interface is being released\n"); | 1281 | BNX2FC_MISC_DBG("Interface is being released\n"); |
| 1244 | 1282 | ||
| 1245 | ctlr = bnx2fc_to_ctlr(interface); | 1283 | ctlr = bnx2fc_to_ctlr(interface); |
| 1284 | ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); | ||
| 1246 | netdev = interface->netdev; | 1285 | netdev = interface->netdev; |
| 1247 | 1286 | ||
| 1248 | /* tear-down FIP controller */ | 1287 | /* tear-down FIP controller */ |
| 1249 | if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) | 1288 | if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) |
| 1250 | fcoe_ctlr_destroy(ctlr); | 1289 | fcoe_ctlr_destroy(ctlr); |
| 1251 | 1290 | ||
| 1252 | kfree(ctlr); | 1291 | fcoe_ctlr_device_delete(ctlr_dev); |
| 1253 | 1292 | ||
| 1254 | dev_put(netdev); | 1293 | dev_put(netdev); |
| 1255 | module_put(THIS_MODULE); | 1294 | module_put(THIS_MODULE); |
| @@ -1342,17 +1381,20 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, | |||
| 1342 | struct net_device *netdev, | 1381 | struct net_device *netdev, |
| 1343 | enum fip_state fip_mode) | 1382 | enum fip_state fip_mode) |
| 1344 | { | 1383 | { |
| 1384 | struct fcoe_ctlr_device *ctlr_dev; | ||
| 1345 | struct bnx2fc_interface *interface; | 1385 | struct bnx2fc_interface *interface; |
| 1346 | struct fcoe_ctlr *ctlr; | 1386 | struct fcoe_ctlr *ctlr; |
| 1347 | int size; | 1387 | int size; |
| 1348 | int rc = 0; | 1388 | int rc = 0; |
| 1349 | 1389 | ||
| 1350 | size = (sizeof(*interface) + sizeof(struct fcoe_ctlr)); | 1390 | size = (sizeof(*interface) + sizeof(struct fcoe_ctlr)); |
| 1351 | ctlr = kzalloc(size, GFP_KERNEL); | 1391 | ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &bnx2fc_fcoe_sysfs_templ, |
| 1352 | if (!ctlr) { | 1392 | size); |
| 1393 | if (!ctlr_dev) { | ||
| 1353 | printk(KERN_ERR PFX "Unable to allocate interface structure\n"); | 1394 | printk(KERN_ERR PFX "Unable to allocate interface structure\n"); |
| 1354 | return NULL; | 1395 | return NULL; |
| 1355 | } | 1396 | } |
| 1397 | ctlr = fcoe_ctlr_device_priv(ctlr_dev); | ||
| 1356 | interface = fcoe_ctlr_priv(ctlr); | 1398 | interface = fcoe_ctlr_priv(ctlr); |
| 1357 | dev_hold(netdev); | 1399 | dev_hold(netdev); |
| 1358 | kref_init(&interface->kref); | 1400 | kref_init(&interface->kref); |
| @@ -1372,7 +1414,7 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, | |||
| 1372 | 1414 | ||
| 1373 | fcoe_ctlr_destroy(ctlr); | 1415 | fcoe_ctlr_destroy(ctlr); |
| 1374 | dev_put(netdev); | 1416 | dev_put(netdev); |
| 1375 | kfree(ctlr); | 1417 | fcoe_ctlr_device_delete(ctlr_dev); |
| 1376 | return NULL; | 1418 | return NULL; |
| 1377 | } | 1419 | } |
| 1378 | 1420 | ||
| @@ -2471,6 +2513,19 @@ static void __exit bnx2fc_mod_exit(void) | |||
| 2471 | module_init(bnx2fc_mod_init); | 2513 | module_init(bnx2fc_mod_init); |
| 2472 | module_exit(bnx2fc_mod_exit); | 2514 | module_exit(bnx2fc_mod_exit); |
| 2473 | 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 | }; | ||
| 2528 | |||
| 2474 | static struct fc_function_template bnx2fc_transport_function = { | 2529 | static struct fc_function_template bnx2fc_transport_function = { |
| 2475 | .show_host_node_name = 1, | 2530 | .show_host_node_name = 1, |
| 2476 | .show_host_port_name = 1, | 2531 | .show_host_port_name = 1, |
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 4bb42e19d537..fe30b1b65e1d 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | 41 | ||
| 42 | #include <scsi/fc/fc_encaps.h> | 42 | #include <scsi/fc/fc_encaps.h> |
| 43 | #include <scsi/fc/fc_fip.h> | 43 | #include <scsi/fc/fc_fip.h> |
| 44 | #include <scsi/fc/fc_fcoe.h> | ||
| 44 | 45 | ||
| 45 | #include <scsi/libfc.h> | 46 | #include <scsi/libfc.h> |
| 46 | #include <scsi/fc_frame.h> | 47 | #include <scsi/fc_frame.h> |
| @@ -150,6 +151,21 @@ static int fcoe_vport_create(struct fc_vport *, bool disabled); | |||
| 150 | static int fcoe_vport_disable(struct fc_vport *, bool disable); | 151 | static int fcoe_vport_disable(struct fc_vport *, bool disable); |
| 151 | static void fcoe_set_vport_symbolic_name(struct fc_vport *); | 152 | static void fcoe_set_vport_symbolic_name(struct fc_vport *); |
| 152 | static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); | 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 *); | ||
| 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 | }; | ||
| 153 | 169 | ||
| 154 | static struct libfc_function_template fcoe_libfc_fcn_templ = { | 170 | static struct libfc_function_template fcoe_libfc_fcn_templ = { |
| 155 | .frame_send = fcoe_xmit, | 171 | .frame_send = fcoe_xmit, |
| @@ -366,6 +382,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, | |||
| 366 | static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, | 382 | static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, |
| 367 | enum fip_state fip_mode) | 383 | enum fip_state fip_mode) |
| 368 | { | 384 | { |
| 385 | struct fcoe_ctlr_device *ctlr_dev; | ||
| 369 | struct fcoe_ctlr *ctlr; | 386 | struct fcoe_ctlr *ctlr; |
| 370 | struct fcoe_interface *fcoe; | 387 | struct fcoe_interface *fcoe; |
| 371 | int size; | 388 | int size; |
| @@ -379,14 +396,17 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, | |||
| 379 | } | 396 | } |
| 380 | 397 | ||
| 381 | size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface); | 398 | size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface); |
| 382 | ctlr = kzalloc(size, GFP_KERNEL); | 399 | ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &fcoe_sysfs_templ, |
| 383 | fcoe = fcoe_ctlr_priv(ctlr); | 400 | size); |
| 384 | if (!fcoe) { | 401 | if (!ctlr_dev) { |
| 385 | FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); | 402 | FCOE_DBG("Failed to add fcoe_ctlr_device\n"); |
| 386 | fcoe = ERR_PTR(-ENOMEM); | 403 | fcoe = ERR_PTR(-ENOMEM); |
| 387 | goto out_putmod; | 404 | goto out_putmod; |
| 388 | } | 405 | } |
| 389 | 406 | ||
| 407 | ctlr = fcoe_ctlr_device_priv(ctlr_dev); | ||
| 408 | fcoe = fcoe_ctlr_priv(ctlr); | ||
| 409 | |||
| 390 | dev_hold(netdev); | 410 | dev_hold(netdev); |
| 391 | 411 | ||
| 392 | /* | 412 | /* |
| @@ -400,6 +420,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, | |||
| 400 | err = fcoe_interface_setup(fcoe, netdev); | 420 | err = fcoe_interface_setup(fcoe, netdev); |
| 401 | if (err) { | 421 | if (err) { |
| 402 | fcoe_ctlr_destroy(ctlr); | 422 | fcoe_ctlr_destroy(ctlr); |
| 423 | fcoe_ctlr_device_delete(ctlr_dev); | ||
| 403 | dev_put(netdev); | 424 | dev_put(netdev); |
| 404 | fcoe = ERR_PTR(err); | 425 | fcoe = ERR_PTR(err); |
| 405 | goto out_putmod; | 426 | goto out_putmod; |
| @@ -466,6 +487,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) | |||
| 466 | { | 487 | { |
| 467 | struct net_device *netdev = fcoe->netdev; | 488 | struct net_device *netdev = fcoe->netdev; |
| 468 | struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); | 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 | rtnl_lock(); | 492 | rtnl_lock(); |
| 471 | if (!fcoe->removed) | 493 | if (!fcoe->removed) |
| @@ -476,7 +498,7 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) | |||
| 476 | /* tear-down the FCoE controller */ | 498 | /* tear-down the FCoE controller */ |
| 477 | fcoe_ctlr_destroy(fip); | 499 | fcoe_ctlr_destroy(fip); |
| 478 | scsi_host_put(fip->lp->host); | 500 | scsi_host_put(fip->lp->host); |
| 479 | kfree(fip); | 501 | fcoe_ctlr_device_delete(ctlr_dev); |
| 480 | dev_put(netdev); | 502 | dev_put(netdev); |
| 481 | module_put(THIS_MODULE); | 503 | module_put(THIS_MODULE); |
| 482 | } | 504 | } |
| @@ -2196,6 +2218,7 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe) | |||
| 2196 | static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) | 2218 | static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) |
| 2197 | { | 2219 | { |
| 2198 | int rc = 0; | 2220 | int rc = 0; |
| 2221 | struct fcoe_ctlr_device *ctlr_dev; | ||
| 2199 | struct fcoe_ctlr *ctlr; | 2222 | struct fcoe_ctlr *ctlr; |
| 2200 | struct fcoe_interface *fcoe; | 2223 | struct fcoe_interface *fcoe; |
| 2201 | struct fc_lport *lport; | 2224 | struct fc_lport *lport; |
| @@ -2216,8 +2239,8 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) | |||
| 2216 | } | 2239 | } |
| 2217 | 2240 | ||
| 2218 | ctlr = fcoe_to_ctlr(fcoe); | 2241 | ctlr = fcoe_to_ctlr(fcoe); |
| 2219 | 2242 | ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); | |
| 2220 | lport = fcoe_if_create(fcoe, &netdev->dev, 0); | 2243 | lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0); |
| 2221 | if (IS_ERR(lport)) { | 2244 | if (IS_ERR(lport)) { |
| 2222 | printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", | 2245 | printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", |
| 2223 | netdev->name); | 2246 | netdev->name); |
| @@ -2768,6 +2791,40 @@ static void fcoe_get_lesb(struct fc_lport *lport, | |||
| 2768 | __fcoe_get_lesb(lport, fc_lesb, netdev); | 2791 | __fcoe_get_lesb(lport, fc_lesb, netdev); |
| 2769 | } | 2792 | } |
| 2770 | 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); | ||
| 2826 | } | ||
| 2827 | |||
| 2771 | /** | 2828 | /** |
| 2772 | * fcoe_set_port_id() - Callback from libfc when Port_ID is set. | 2829 | * fcoe_set_port_id() - Callback from libfc when Port_ID is set. |
| 2773 | * @lport: the local port | 2830 | * @lport: the local port |
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 5a4c7250aa77..d68d57241ee6 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c | |||
| @@ -160,6 +160,76 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) | |||
| 160 | } | 160 | } |
| 161 | EXPORT_SYMBOL(fcoe_ctlr_init); | 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 | * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller | 234 | * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller |
| 165 | * @fip: The FCoE controller whose FCFs are to be reset | 235 | * @fip: The FCoE controller whose FCFs are to be reset |
| @@ -173,10 +243,10 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) | |||
| 173 | 243 | ||
| 174 | fip->sel_fcf = NULL; | 244 | fip->sel_fcf = NULL; |
| 175 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { | 245 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { |
| 176 | list_del(&fcf->list); | 246 | fcoe_sysfs_fcf_del(fcf); |
| 177 | kfree(fcf); | ||
| 178 | } | 247 | } |
| 179 | fip->fcf_count = 0; | 248 | WARN_ON(fip->fcf_count); |
| 249 | |||
| 180 | fip->sel_time = 0; | 250 | fip->sel_time = 0; |
| 181 | } | 251 | } |
| 182 | 252 | ||
| @@ -717,8 +787,11 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) | |||
| 717 | unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); | 787 | unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); |
| 718 | unsigned long deadline; | 788 | unsigned long deadline; |
| 719 | unsigned long sel_time = 0; | 789 | unsigned long sel_time = 0; |
| 790 | struct list_head del_list; | ||
| 720 | struct fcoe_dev_stats *stats; | 791 | struct fcoe_dev_stats *stats; |
| 721 | 792 | ||
| 793 | INIT_LIST_HEAD(&del_list); | ||
| 794 | |||
| 722 | stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); | 795 | stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); |
| 723 | 796 | ||
| 724 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { | 797 | list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { |
| @@ -739,10 +812,13 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) | |||
| 739 | if (time_after_eq(jiffies, deadline)) { | 812 | if (time_after_eq(jiffies, deadline)) { |
| 740 | if (fip->sel_fcf == fcf) | 813 | if (fip->sel_fcf == fcf) |
| 741 | fip->sel_fcf = NULL; | 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 | list_del(&fcf->list); | 820 | list_del(&fcf->list); |
| 743 | WARN_ON(!fip->fcf_count); | 821 | list_add(&fcf->list, &del_list); |
| 744 | fip->fcf_count--; | ||
| 745 | kfree(fcf); | ||
| 746 | stats->VLinkFailureCount++; | 822 | stats->VLinkFailureCount++; |
| 747 | } else { | 823 | } else { |
| 748 | if (time_after(next_timer, deadline)) | 824 | if (time_after(next_timer, deadline)) |
| @@ -753,6 +829,12 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) | |||
| 753 | } | 829 | } |
| 754 | } | 830 | } |
| 755 | put_cpu(); | 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 | if (sel_time && !fip->sel_fcf && !fip->sel_time) { | 838 | if (sel_time && !fip->sel_fcf && !fip->sel_time) { |
| 757 | sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); | 839 | sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); |
| 758 | fip->sel_time = sel_time; | 840 | fip->sel_time = sel_time; |
| @@ -903,23 +985,23 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
| 903 | { | 985 | { |
| 904 | struct fcoe_fcf *fcf; | 986 | struct fcoe_fcf *fcf; |
| 905 | struct fcoe_fcf new; | 987 | struct fcoe_fcf new; |
| 906 | struct fcoe_fcf *found; | ||
| 907 | unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); | 988 | unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); |
| 908 | int first = 0; | 989 | int first = 0; |
| 909 | int mtu_valid; | 990 | int mtu_valid; |
| 991 | int found = 0; | ||
| 992 | int rc = 0; | ||
| 910 | 993 | ||
| 911 | if (fcoe_ctlr_parse_adv(fip, skb, &new)) | 994 | if (fcoe_ctlr_parse_adv(fip, skb, &new)) |
| 912 | return; | 995 | return; |
| 913 | 996 | ||
| 914 | mutex_lock(&fip->ctlr_mutex); | 997 | mutex_lock(&fip->ctlr_mutex); |
| 915 | first = list_empty(&fip->fcfs); | 998 | first = list_empty(&fip->fcfs); |
| 916 | found = NULL; | ||
| 917 | list_for_each_entry(fcf, &fip->fcfs, list) { | 999 | list_for_each_entry(fcf, &fip->fcfs, list) { |
| 918 | if (fcf->switch_name == new.switch_name && | 1000 | if (fcf->switch_name == new.switch_name && |
| 919 | fcf->fabric_name == new.fabric_name && | 1001 | fcf->fabric_name == new.fabric_name && |
| 920 | fcf->fc_map == new.fc_map && | 1002 | fcf->fc_map == new.fc_map && |
| 921 | compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { | 1003 | compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { |
| 922 | found = fcf; | 1004 | found = 1; |
| 923 | break; | 1005 | break; |
| 924 | } | 1006 | } |
| 925 | } | 1007 | } |
| @@ -931,9 +1013,16 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
| 931 | if (!fcf) | 1013 | if (!fcf) |
| 932 | goto out; | 1014 | goto out; |
| 933 | 1015 | ||
| 934 | fip->fcf_count++; | ||
| 935 | memcpy(fcf, &new, sizeof(new)); | 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 | } else { | 1026 | } else { |
| 938 | /* | 1027 | /* |
| 939 | * Update the FCF's keep-alive descriptor flags. | 1028 | * Update the FCF's keep-alive descriptor flags. |
| @@ -954,6 +1043,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
| 954 | fcf->fka_period = new.fka_period; | 1043 | fcf->fka_period = new.fka_period; |
| 955 | memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); | 1044 | memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); |
| 956 | } | 1045 | } |
| 1046 | |||
| 957 | mtu_valid = fcoe_ctlr_mtu_valid(fcf); | 1047 | mtu_valid = fcoe_ctlr_mtu_valid(fcf); |
| 958 | fcf->time = jiffies; | 1048 | fcf->time = jiffies; |
| 959 | if (!found) | 1049 | if (!found) |
| @@ -996,6 +1086,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) | |||
| 996 | time_before(fip->sel_time, fip->timer.expires)) | 1086 | time_before(fip->sel_time, fip->timer.expires)) |
| 997 | mod_timer(&fip->timer, fip->sel_time); | 1087 | mod_timer(&fip->timer, fip->sel_time); |
| 998 | } | 1088 | } |
| 1089 | |||
| 999 | out: | 1090 | out: |
| 1000 | mutex_unlock(&fip->ctlr_mutex); | 1091 | mutex_unlock(&fip->ctlr_mutex); |
| 1001 | } | 1092 | } |
| @@ -2718,9 +2809,9 @@ unlock: | |||
| 2718 | 2809 | ||
| 2719 | /** | 2810 | /** |
| 2720 | * fcoe_libfc_config() - Sets up libfc related properties for local port | 2811 | * fcoe_libfc_config() - Sets up libfc related properties for local port |
| 2721 | * @lp: The local port to configure libfc for | 2812 | * @lport: The local port to configure libfc for |
| 2722 | * @fip: The FCoE controller in use by the local port | 2813 | * @fip: The FCoE controller in use by the local port |
| 2723 | * @tt: The libfc function template | 2814 | * @tt: The libfc function template |
| 2724 | * @init_fcp: If non-zero, the FCP portion of libfc should be initialized | 2815 | * @init_fcp: If non-zero, the FCP portion of libfc should be initialized |
| 2725 | * | 2816 | * |
| 2726 | * Returns : 0 for success | 2817 | * Returns : 0 for success |
| @@ -2753,3 +2844,43 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, | |||
| 2753 | return 0; | 2844 | return 0; |
| 2754 | } | 2845 | } |
| 2755 | EXPORT_SYMBOL_GPL(fcoe_libfc_config); | 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); | ||
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 7b93f211b935..22b07cc99808 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h | |||
| @@ -168,9 +168,16 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr) | |||
| 168 | return (void *)(ctlr + 1); | 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 | * struct fcoe_fcf - Fibre-Channel Forwarder | 175 | * struct fcoe_fcf - Fibre-Channel Forwarder |
| 173 | * @list: list linkage | 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 | * @time: system time (jiffies) when an advertisement was last received | 181 | * @time: system time (jiffies) when an advertisement was last received |
| 175 | * @switch_name: WWN of switch from advertisement | 182 | * @switch_name: WWN of switch from advertisement |
| 176 | * @fabric_name: WWN of fabric from advertisement | 183 | * @fabric_name: WWN of fabric from advertisement |
| @@ -192,6 +199,9 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr) | |||
| 192 | */ | 199 | */ |
| 193 | struct fcoe_fcf { | 200 | struct fcoe_fcf { |
| 194 | struct list_head list; | 201 | struct list_head list; |
| 202 | struct work_struct event_work; | ||
| 203 | struct fcoe_ctlr *fip; | ||
| 204 | struct fcoe_fcf_device *fcf_dev; | ||
| 195 | unsigned long time; | 205 | unsigned long time; |
| 196 | 206 | ||
| 197 | u64 switch_name; | 207 | u64 switch_name; |
| @@ -208,6 +218,9 @@ struct fcoe_fcf { | |||
| 208 | u8 fd_flags:1; | 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 | * struct fcoe_rport - VN2VN remote port | 225 | * struct fcoe_rport - VN2VN remote port |
| 213 | * @time: time of create or last beacon packet received from node | 226 | * @time: time of create or last beacon packet received from node |
| @@ -343,6 +356,10 @@ void fcoe_queue_timer(ulong lport); | |||
| 343 | int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, | 356 | int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, |
| 344 | struct fcoe_percpu_s *fps); | 357 | struct fcoe_percpu_s *fps); |
| 345 | 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 *); | ||
| 362 | |||
| 346 | /** | 363 | /** |
| 347 | * struct netdev_list | 364 | * struct netdev_list |
| 348 | * A mapping from netdevice to fcoe_transport | 365 | * A mapping from netdevice to fcoe_transport |
