diff options
author | Joe Eykholt <jeykholt@cisco.com> | 2009-03-17 14:42:40 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-03 10:23:08 -0400 |
commit | 97c8389d54b9665c38105ea72a428a44b97ff2f6 (patch) | |
tree | 1548f9a3739241101f4e6f972418a16b45b52d57 /drivers/scsi/fcoe/fcoe.c | |
parent | af5f428763eefb6547d2bee055b559c903f2a749 (diff) |
[SCSI] fcoe, libfcoe: Add support for FIP. FCoE discovery and keep-alive.
FIP is the new standard way to discover Fibre-Channel Forwarders (FCFs)
by sending solicitations and listening for advertisements from FCFs.
It also provides for keep-alives and period advertisements so that both
parties know they have connectivity. If the FCF loses connectivity to
the storage fabric, it can send a Link Reset to inform the E_node.
This version is also compatible with pre-FIP implementations, so no
configured selection between FIP mode and non-FIP mode is required.
We wait a couple seconds after sending the initial solicitation
and then send an old-style FLOGI. If we receive any FIP frames,
we use FIP only mode. If the old FLOGI receives a response,
we disable FIP mode. After every reset or link up, this
determination is repeated.
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/fcoe/fcoe.c')
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 232 |
1 files changed, 113 insertions, 119 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index d5f009ad0388..94e1e3189773 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <net/rtnetlink.h> | 37 | #include <net/rtnetlink.h> |
38 | 38 | ||
39 | #include <scsi/fc/fc_encaps.h> | 39 | #include <scsi/fc/fc_encaps.h> |
40 | #include <scsi/fc/fc_fip.h> | ||
40 | 41 | ||
41 | #include <scsi/libfc.h> | 42 | #include <scsi/libfc.h> |
42 | #include <scsi/fc_frame.h> | 43 | #include <scsi/fc_frame.h> |
@@ -71,7 +72,6 @@ static int fcoe_hostlist_add(const struct fc_lport *); | |||
71 | static int fcoe_hostlist_remove(const struct fc_lport *); | 72 | static int fcoe_hostlist_remove(const struct fc_lport *); |
72 | 73 | ||
73 | static int fcoe_check_wait_queue(struct fc_lport *); | 74 | static int fcoe_check_wait_queue(struct fc_lport *); |
74 | static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); | ||
75 | static int fcoe_device_notification(struct notifier_block *, ulong, void *); | 75 | static int fcoe_device_notification(struct notifier_block *, ulong, void *); |
76 | static void fcoe_dev_setup(void); | 76 | static void fcoe_dev_setup(void); |
77 | static void fcoe_dev_cleanup(void); | 77 | static void fcoe_dev_cleanup(void); |
@@ -185,7 +185,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) | |||
185 | 185 | ||
186 | /* Setup lport private data to point to fcoe softc */ | 186 | /* Setup lport private data to point to fcoe softc */ |
187 | fc = lport_priv(lp); | 187 | fc = lport_priv(lp); |
188 | fc->lp = lp; | 188 | fc->ctlr.lp = lp; |
189 | fc->real_dev = netdev; | 189 | fc->real_dev = netdev; |
190 | fc->phys_dev = netdev; | 190 | fc->phys_dev = netdev; |
191 | 191 | ||
@@ -210,9 +210,6 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) | |||
210 | if (fc_set_mfs(lp, mfs)) | 210 | if (fc_set_mfs(lp, mfs)) |
211 | return -EINVAL; | 211 | return -EINVAL; |
212 | 212 | ||
213 | if (!fcoe_link_ok(lp)) | ||
214 | lp->link_up = 1; | ||
215 | |||
216 | /* offload features support */ | 213 | /* offload features support */ |
217 | if (fc->real_dev->features & NETIF_F_SG) | 214 | if (fc->real_dev->features & NETIF_F_SG) |
218 | lp->sg_supp = 1; | 215 | lp->sg_supp = 1; |
@@ -242,7 +239,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) | |||
242 | fc->fcoe_pending_queue_active = 0; | 239 | fc->fcoe_pending_queue_active = 0; |
243 | 240 | ||
244 | /* setup Source Mac Address */ | 241 | /* setup Source Mac Address */ |
245 | memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, | 242 | memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, |
246 | fc->real_dev->addr_len); | 243 | fc->real_dev->addr_len); |
247 | 244 | ||
248 | wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); | 245 | wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); |
@@ -358,6 +355,8 @@ static int fcoe_if_destroy(struct net_device *netdev) | |||
358 | 355 | ||
359 | /* Don't listen for Ethernet packets anymore */ | 356 | /* Don't listen for Ethernet packets anymore */ |
360 | dev_remove_pack(&fc->fcoe_packet_type); | 357 | dev_remove_pack(&fc->fcoe_packet_type); |
358 | dev_remove_pack(&fc->fip_packet_type); | ||
359 | fcoe_ctlr_destroy(&fc->ctlr); | ||
361 | 360 | ||
362 | /* Cleanup the fc_lport */ | 361 | /* Cleanup the fc_lport */ |
363 | fc_lport_destroy(lp); | 362 | fc_lport_destroy(lp); |
@@ -375,8 +374,10 @@ static int fcoe_if_destroy(struct net_device *netdev) | |||
375 | rtnl_lock(); | 374 | rtnl_lock(); |
376 | memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); | 375 | memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); |
377 | dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); | 376 | dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); |
378 | if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) | 377 | if (!is_zero_ether_addr(fc->ctlr.data_src_addr)) |
379 | dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); | 378 | dev_unicast_delete(fc->real_dev, |
379 | fc->ctlr.data_src_addr, ETH_ALEN); | ||
380 | dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); | ||
380 | rtnl_unlock(); | 381 | rtnl_unlock(); |
381 | 382 | ||
382 | /* Free the per-CPU revieve threads */ | 383 | /* Free the per-CPU revieve threads */ |
@@ -438,6 +439,58 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { | |||
438 | }; | 439 | }; |
439 | 440 | ||
440 | /** | 441 | /** |
442 | * fcoe_fip_recv - handle a received FIP frame. | ||
443 | * @skb: the receive skb | ||
444 | * @dev: associated &net_device | ||
445 | * @ptype: the &packet_type structure which was used to register this handler. | ||
446 | * @orig_dev: original receive &net_device, in case @dev is a bond. | ||
447 | * | ||
448 | * Returns: 0 for success | ||
449 | */ | ||
450 | static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, | ||
451 | struct packet_type *ptype, | ||
452 | struct net_device *orig_dev) | ||
453 | { | ||
454 | struct fcoe_softc *fc; | ||
455 | |||
456 | fc = container_of(ptype, struct fcoe_softc, fip_packet_type); | ||
457 | fcoe_ctlr_recv(&fc->ctlr, skb); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | /** | ||
462 | * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame. | ||
463 | * @fip: FCoE controller. | ||
464 | * @skb: FIP Packet. | ||
465 | */ | ||
466 | static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) | ||
467 | { | ||
468 | skb->dev = fcoe_from_ctlr(fip)->real_dev; | ||
469 | dev_queue_xmit(skb); | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * fcoe_update_src_mac() - Update Ethernet MAC filters. | ||
474 | * @fip: FCoE controller. | ||
475 | * @old: Unicast MAC address to delete if the MAC is non-zero. | ||
476 | * @new: Unicast MAC address to add. | ||
477 | * | ||
478 | * Remove any previously-set unicast MAC filter. | ||
479 | * Add secondary FCoE MAC address filter for our OUI. | ||
480 | */ | ||
481 | static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) | ||
482 | { | ||
483 | struct fcoe_softc *fc; | ||
484 | |||
485 | fc = fcoe_from_ctlr(fip); | ||
486 | rtnl_lock(); | ||
487 | if (!is_zero_ether_addr(old)) | ||
488 | dev_unicast_delete(fc->real_dev, old, ETH_ALEN); | ||
489 | dev_unicast_add(fc->real_dev, new, ETH_ALEN); | ||
490 | rtnl_unlock(); | ||
491 | } | ||
492 | |||
493 | /** | ||
441 | * fcoe_if_create() - this function creates the fcoe interface | 494 | * fcoe_if_create() - this function creates the fcoe interface |
442 | * @netdev: pointer the associated netdevice | 495 | * @netdev: pointer the associated netdevice |
443 | * | 496 | * |
@@ -485,6 +538,18 @@ static int fcoe_if_create(struct net_device *netdev) | |||
485 | goto out_host_put; | 538 | goto out_host_put; |
486 | } | 539 | } |
487 | 540 | ||
541 | /* | ||
542 | * Initialize FIP. | ||
543 | */ | ||
544 | fcoe_ctlr_init(&fc->ctlr); | ||
545 | fc->ctlr.send = fcoe_fip_send; | ||
546 | fc->ctlr.update_mac = fcoe_update_src_mac; | ||
547 | |||
548 | fc->fip_packet_type.func = fcoe_fip_recv; | ||
549 | fc->fip_packet_type.type = htons(ETH_P_FIP); | ||
550 | fc->fip_packet_type.dev = fc->real_dev; | ||
551 | dev_add_pack(&fc->fip_packet_type); | ||
552 | |||
488 | /* configure lport scsi host properties */ | 553 | /* configure lport scsi host properties */ |
489 | rc = fcoe_shost_config(lp, shost, &netdev->dev); | 554 | rc = fcoe_shost_config(lp, shost, &netdev->dev); |
490 | if (rc) { | 555 | if (rc) { |
@@ -513,6 +578,9 @@ static int fcoe_if_create(struct net_device *netdev) | |||
513 | 578 | ||
514 | fc_fabric_login(lp); | 579 | fc_fabric_login(lp); |
515 | 580 | ||
581 | if (!fcoe_link_ok(lp)) | ||
582 | fcoe_ctlr_link_up(&fc->ctlr); | ||
583 | |||
516 | dev_hold(netdev); | 584 | dev_hold(netdev); |
517 | 585 | ||
518 | return rc; | 586 | return rc; |
@@ -727,11 +795,13 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, | |||
727 | unsigned int cpu = 0; | 795 | unsigned int cpu = 0; |
728 | 796 | ||
729 | fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); | 797 | fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); |
730 | lp = fc->lp; | 798 | lp = fc->ctlr.lp; |
731 | if (unlikely(lp == NULL)) { | 799 | if (unlikely(lp == NULL)) { |
732 | FC_DBG("cannot find hba structure"); | 800 | FC_DBG("cannot find hba structure"); |
733 | goto err2; | 801 | goto err2; |
734 | } | 802 | } |
803 | if (!lp->link_up) | ||
804 | goto err2; | ||
735 | 805 | ||
736 | if (unlikely(debug_fcoe)) { | 806 | if (unlikely(debug_fcoe)) { |
737 | FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " | 807 | FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " |
@@ -929,7 +999,6 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) | |||
929 | unsigned int hlen; /* header length implies the version */ | 999 | unsigned int hlen; /* header length implies the version */ |
930 | unsigned int tlen; /* trailer length */ | 1000 | unsigned int tlen; /* trailer length */ |
931 | unsigned int elen; /* eth header, may include vlan */ | 1001 | unsigned int elen; /* eth header, may include vlan */ |
932 | int flogi_in_progress = 0; | ||
933 | struct fcoe_softc *fc; | 1002 | struct fcoe_softc *fc; |
934 | u8 sof, eof; | 1003 | u8 sof, eof; |
935 | struct fcoe_hdr *hp; | 1004 | struct fcoe_hdr *hp; |
@@ -937,31 +1006,19 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) | |||
937 | WARN_ON((fr_len(fp) % sizeof(u32)) != 0); | 1006 | WARN_ON((fr_len(fp) % sizeof(u32)) != 0); |
938 | 1007 | ||
939 | fc = lport_priv(lp); | 1008 | fc = lport_priv(lp); |
940 | /* | ||
941 | * if it is a flogi then we need to learn gw-addr | ||
942 | * and my own fcid | ||
943 | */ | ||
944 | fh = fc_frame_header_get(fp); | 1009 | fh = fc_frame_header_get(fp); |
945 | if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { | 1010 | skb = fp_skb(fp); |
946 | if (fc_frame_payload_op(fp) == ELS_FLOGI) { | 1011 | wlen = skb->len / FCOE_WORD_TO_BYTE; |
947 | fc->flogi_oxid = ntohs(fh->fh_ox_id); | 1012 | |
948 | fc->address_mode = FCOE_FCOUI_ADDR_MODE; | 1013 | if (!lp->link_up) { |
949 | fc->flogi_progress = 1; | 1014 | kfree(skb); |
950 | flogi_in_progress = 1; | 1015 | return 0; |
951 | } else if (fc->flogi_progress && ntoh24(fh->fh_s_id) != 0) { | ||
952 | /* | ||
953 | * Here we must've gotten an SID by accepting an FLOGI | ||
954 | * from a point-to-point connection. Switch to using | ||
955 | * the source mac based on the SID. The destination | ||
956 | * MAC in this case would have been set by receving the | ||
957 | * FLOGI. | ||
958 | */ | ||
959 | fc_fcoe_set_mac(fc->data_src_addr, fh->fh_s_id); | ||
960 | fc->flogi_progress = 0; | ||
961 | } | ||
962 | } | 1016 | } |
963 | 1017 | ||
964 | skb = fp_skb(fp); | 1018 | if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && |
1019 | fcoe_ctlr_els_send(&fc->ctlr, skb)) | ||
1020 | return 0; | ||
1021 | |||
965 | sof = fr_sof(fp); | 1022 | sof = fr_sof(fp); |
966 | eof = fr_eof(fp); | 1023 | eof = fr_eof(fp); |
967 | 1024 | ||
@@ -1016,16 +1073,16 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) | |||
1016 | /* fill up mac and fcoe headers */ | 1073 | /* fill up mac and fcoe headers */ |
1017 | eh = eth_hdr(skb); | 1074 | eh = eth_hdr(skb); |
1018 | eh->h_proto = htons(ETH_P_FCOE); | 1075 | eh->h_proto = htons(ETH_P_FCOE); |
1019 | if (fc->address_mode == FCOE_FCOUI_ADDR_MODE) | 1076 | if (fc->ctlr.map_dest) |
1020 | fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); | 1077 | fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); |
1021 | else | 1078 | else |
1022 | /* insert GW address */ | 1079 | /* insert GW address */ |
1023 | memcpy(eh->h_dest, fc->dest_addr, ETH_ALEN); | 1080 | memcpy(eh->h_dest, fc->ctlr.dest_addr, ETH_ALEN); |
1024 | 1081 | ||
1025 | if (unlikely(flogi_in_progress)) | 1082 | if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN)) |
1026 | memcpy(eh->h_source, fc->ctl_src_addr, ETH_ALEN); | 1083 | memcpy(eh->h_source, fc->ctlr.ctl_src_addr, ETH_ALEN); |
1027 | else | 1084 | else |
1028 | memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN); | 1085 | memcpy(eh->h_source, fc->ctlr.data_src_addr, ETH_ALEN); |
1029 | 1086 | ||
1030 | hp = (struct fcoe_hdr *)(eh + 1); | 1087 | hp = (struct fcoe_hdr *)(eh + 1); |
1031 | memset(hp, 0, sizeof(*hp)); | 1088 | memset(hp, 0, sizeof(*hp)); |
@@ -1125,11 +1182,9 @@ int fcoe_percpu_receive_thread(void *arg) | |||
1125 | * Save source MAC address before discarding header. | 1182 | * Save source MAC address before discarding header. |
1126 | */ | 1183 | */ |
1127 | fc = lport_priv(lp); | 1184 | fc = lport_priv(lp); |
1128 | if (unlikely(fc->flogi_progress)) | ||
1129 | mac = eth_hdr(skb)->h_source; | ||
1130 | |||
1131 | if (skb_is_nonlinear(skb)) | 1185 | if (skb_is_nonlinear(skb)) |
1132 | skb_linearize(skb); /* not ideal */ | 1186 | skb_linearize(skb); /* not ideal */ |
1187 | mac = eth_hdr(skb)->h_source; | ||
1133 | 1188 | ||
1134 | /* | 1189 | /* |
1135 | * Frame length checks and setting up the header pointers | 1190 | * Frame length checks and setting up the header pointers |
@@ -1204,72 +1259,17 @@ int fcoe_percpu_receive_thread(void *arg) | |||
1204 | } | 1259 | } |
1205 | fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; | 1260 | fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; |
1206 | } | 1261 | } |
1207 | /* non flogi and non data exchanges are handled here */ | 1262 | if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN) && |
1208 | if (unlikely(fc->flogi_progress)) | 1263 | fcoe_ctlr_recv_flogi(&fc->ctlr, fp, mac)) { |
1209 | fcoe_recv_flogi(fc, fp, mac); | 1264 | fc_frame_free(fp); |
1265 | continue; | ||
1266 | } | ||
1210 | fc_exch_recv(lp, lp->emp, fp); | 1267 | fc_exch_recv(lp, lp->emp, fp); |
1211 | } | 1268 | } |
1212 | return 0; | 1269 | return 0; |
1213 | } | 1270 | } |
1214 | 1271 | ||
1215 | /** | 1272 | /** |
1216 | * fcoe_recv_flogi() - flogi receive function | ||
1217 | * @fc: associated fcoe_softc | ||
1218 | * @fp: the recieved frame | ||
1219 | * @sa: the source address of this flogi | ||
1220 | * | ||
1221 | * This is responsible to parse the flogi response and sets the corresponding | ||
1222 | * mac address for the initiator, eitehr OUI based or GW based. | ||
1223 | * | ||
1224 | * Returns: none | ||
1225 | */ | ||
1226 | static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) | ||
1227 | { | ||
1228 | struct fc_frame_header *fh; | ||
1229 | u8 op; | ||
1230 | |||
1231 | fh = fc_frame_header_get(fp); | ||
1232 | if (fh->fh_type != FC_TYPE_ELS) | ||
1233 | return; | ||
1234 | op = fc_frame_payload_op(fp); | ||
1235 | if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && | ||
1236 | fc->flogi_oxid == ntohs(fh->fh_ox_id)) { | ||
1237 | /* | ||
1238 | * FLOGI accepted. | ||
1239 | * If the src mac addr is FC_OUI-based, then we mark the | ||
1240 | * address_mode flag to use FC_OUI-based Ethernet DA. | ||
1241 | * Otherwise we use the FCoE gateway addr | ||
1242 | */ | ||
1243 | if (!compare_ether_addr(sa, (u8[6]) FC_FCOE_FLOGI_MAC)) { | ||
1244 | fc->address_mode = FCOE_FCOUI_ADDR_MODE; | ||
1245 | } else { | ||
1246 | memcpy(fc->dest_addr, sa, ETH_ALEN); | ||
1247 | fc->address_mode = FCOE_GW_ADDR_MODE; | ||
1248 | } | ||
1249 | |||
1250 | /* | ||
1251 | * Remove any previously-set unicast MAC filter. | ||
1252 | * Add secondary FCoE MAC address filter for our OUI. | ||
1253 | */ | ||
1254 | rtnl_lock(); | ||
1255 | if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) | ||
1256 | dev_unicast_delete(fc->real_dev, fc->data_src_addr, | ||
1257 | ETH_ALEN); | ||
1258 | fc_fcoe_set_mac(fc->data_src_addr, fh->fh_d_id); | ||
1259 | dev_unicast_add(fc->real_dev, fc->data_src_addr, ETH_ALEN); | ||
1260 | rtnl_unlock(); | ||
1261 | |||
1262 | fc->flogi_progress = 0; | ||
1263 | } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { | ||
1264 | /* | ||
1265 | * Save source MAC for point-to-point responses. | ||
1266 | */ | ||
1267 | memcpy(fc->dest_addr, sa, ETH_ALEN); | ||
1268 | fc->address_mode = FCOE_GW_ADDR_MODE; | ||
1269 | } | ||
1270 | } | ||
1271 | |||
1272 | /** | ||
1273 | * fcoe_watchdog() - fcoe timer callback | 1273 | * fcoe_watchdog() - fcoe timer callback |
1274 | * @vp: | 1274 | * @vp: |
1275 | * | 1275 | * |
@@ -1285,8 +1285,8 @@ void fcoe_watchdog(ulong vp) | |||
1285 | 1285 | ||
1286 | read_lock(&fcoe_hostlist_lock); | 1286 | read_lock(&fcoe_hostlist_lock); |
1287 | list_for_each_entry(fc, &fcoe_hostlist, list) { | 1287 | list_for_each_entry(fc, &fcoe_hostlist, list) { |
1288 | if (fc->lp) | 1288 | if (fc->ctlr.lp) |
1289 | fcoe_check_wait_queue(fc->lp); | 1289 | fcoe_check_wait_queue(fc->ctlr.lp); |
1290 | } | 1290 | } |
1291 | read_unlock(&fcoe_hostlist_lock); | 1291 | read_unlock(&fcoe_hostlist_lock); |
1292 | 1292 | ||
@@ -1387,14 +1387,14 @@ static int fcoe_device_notification(struct notifier_block *notifier, | |||
1387 | struct net_device *real_dev = ptr; | 1387 | struct net_device *real_dev = ptr; |
1388 | struct fcoe_softc *fc; | 1388 | struct fcoe_softc *fc; |
1389 | struct fcoe_dev_stats *stats; | 1389 | struct fcoe_dev_stats *stats; |
1390 | u32 new_link_up; | 1390 | u32 link_possible = 1; |
1391 | u32 mfs; | 1391 | u32 mfs; |
1392 | int rc = NOTIFY_OK; | 1392 | int rc = NOTIFY_OK; |
1393 | 1393 | ||
1394 | read_lock(&fcoe_hostlist_lock); | 1394 | read_lock(&fcoe_hostlist_lock); |
1395 | list_for_each_entry(fc, &fcoe_hostlist, list) { | 1395 | list_for_each_entry(fc, &fcoe_hostlist, list) { |
1396 | if (fc->real_dev == real_dev) { | 1396 | if (fc->real_dev == real_dev) { |
1397 | lp = fc->lp; | 1397 | lp = fc->ctlr.lp; |
1398 | break; | 1398 | break; |
1399 | } | 1399 | } |
1400 | } | 1400 | } |
@@ -1404,15 +1404,13 @@ static int fcoe_device_notification(struct notifier_block *notifier, | |||
1404 | goto out; | 1404 | goto out; |
1405 | } | 1405 | } |
1406 | 1406 | ||
1407 | new_link_up = lp->link_up; | ||
1408 | switch (event) { | 1407 | switch (event) { |
1409 | case NETDEV_DOWN: | 1408 | case NETDEV_DOWN: |
1410 | case NETDEV_GOING_DOWN: | 1409 | case NETDEV_GOING_DOWN: |
1411 | new_link_up = 0; | 1410 | link_possible = 0; |
1412 | break; | 1411 | break; |
1413 | case NETDEV_UP: | 1412 | case NETDEV_UP: |
1414 | case NETDEV_CHANGE: | 1413 | case NETDEV_CHANGE: |
1415 | new_link_up = !fcoe_link_ok(lp); | ||
1416 | break; | 1414 | break; |
1417 | case NETDEV_CHANGEMTU: | 1415 | case NETDEV_CHANGEMTU: |
1418 | mfs = fc->real_dev->mtu - | 1416 | mfs = fc->real_dev->mtu - |
@@ -1420,22 +1418,18 @@ static int fcoe_device_notification(struct notifier_block *notifier, | |||
1420 | sizeof(struct fcoe_crc_eof)); | 1418 | sizeof(struct fcoe_crc_eof)); |
1421 | if (mfs >= FC_MIN_MAX_FRAME) | 1419 | if (mfs >= FC_MIN_MAX_FRAME) |
1422 | fc_set_mfs(lp, mfs); | 1420 | fc_set_mfs(lp, mfs); |
1423 | new_link_up = !fcoe_link_ok(lp); | ||
1424 | break; | 1421 | break; |
1425 | case NETDEV_REGISTER: | 1422 | case NETDEV_REGISTER: |
1426 | break; | 1423 | break; |
1427 | default: | 1424 | default: |
1428 | FC_DBG("unknown event %ld call", event); | 1425 | FC_DBG("Unknown event %ld from netdev netlink\n", event); |
1429 | } | 1426 | } |
1430 | if (lp->link_up != new_link_up) { | 1427 | if (link_possible && !fcoe_link_ok(lp)) |
1431 | if (new_link_up) | 1428 | fcoe_ctlr_link_up(&fc->ctlr); |
1432 | fc_linkup(lp); | 1429 | else if (fcoe_ctlr_link_down(&fc->ctlr)) { |
1433 | else { | 1430 | stats = fc_lport_get_stats(lp); |
1434 | stats = fc_lport_get_stats(lp); | 1431 | stats->LinkFailureCount++; |
1435 | stats->LinkFailureCount++; | 1432 | fcoe_clean_pending_queue(lp); |
1436 | fc_linkdown(lp); | ||
1437 | fcoe_clean_pending_queue(lp); | ||
1438 | } | ||
1439 | } | 1433 | } |
1440 | out: | 1434 | out: |
1441 | return rc; | 1435 | return rc; |
@@ -1761,7 +1755,7 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) | |||
1761 | 1755 | ||
1762 | fc = fcoe_hostlist_lookup_softc(netdev); | 1756 | fc = fcoe_hostlist_lookup_softc(netdev); |
1763 | 1757 | ||
1764 | return (fc) ? fc->lp : NULL; | 1758 | return (fc) ? fc->ctlr.lp : NULL; |
1765 | } | 1759 | } |
1766 | EXPORT_SYMBOL_GPL(fcoe_hostlist_lookup); | 1760 | EXPORT_SYMBOL_GPL(fcoe_hostlist_lookup); |
1767 | 1761 | ||