diff options
Diffstat (limited to 'drivers/scsi/fcoe/fcoe.c')
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 194 |
1 files changed, 128 insertions, 66 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index f01b9b44e8aa..ba75a98c960c 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c | |||
@@ -74,6 +74,7 @@ static int fcoe_rcv(struct sk_buff *, struct net_device *, | |||
74 | static int fcoe_percpu_receive_thread(void *); | 74 | static int fcoe_percpu_receive_thread(void *); |
75 | static void fcoe_clean_pending_queue(struct fc_lport *); | 75 | static void fcoe_clean_pending_queue(struct fc_lport *); |
76 | static void fcoe_percpu_clean(struct fc_lport *); | 76 | static void fcoe_percpu_clean(struct fc_lport *); |
77 | static int fcoe_link_speed_update(struct fc_lport *); | ||
77 | static int fcoe_link_ok(struct fc_lport *); | 78 | static int fcoe_link_ok(struct fc_lport *); |
78 | 79 | ||
79 | static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); | 80 | static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); |
@@ -146,6 +147,7 @@ static int fcoe_vport_destroy(struct fc_vport *); | |||
146 | static int fcoe_vport_create(struct fc_vport *, bool disabled); | 147 | static int fcoe_vport_create(struct fc_vport *, bool disabled); |
147 | static int fcoe_vport_disable(struct fc_vport *, bool disable); | 148 | static int fcoe_vport_disable(struct fc_vport *, bool disable); |
148 | static void fcoe_set_vport_symbolic_name(struct fc_vport *); | 149 | static void fcoe_set_vport_symbolic_name(struct fc_vport *); |
150 | static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); | ||
149 | 151 | ||
150 | static struct libfc_function_template fcoe_libfc_fcn_templ = { | 152 | static struct libfc_function_template fcoe_libfc_fcn_templ = { |
151 | .frame_send = fcoe_xmit, | 153 | .frame_send = fcoe_xmit, |
@@ -153,6 +155,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { | |||
153 | .ddp_done = fcoe_ddp_done, | 155 | .ddp_done = fcoe_ddp_done, |
154 | .elsct_send = fcoe_elsct_send, | 156 | .elsct_send = fcoe_elsct_send, |
155 | .get_lesb = fcoe_get_lesb, | 157 | .get_lesb = fcoe_get_lesb, |
158 | .lport_set_port_id = fcoe_set_port_id, | ||
156 | }; | 159 | }; |
157 | 160 | ||
158 | struct fc_function_template fcoe_transport_function = { | 161 | struct fc_function_template fcoe_transport_function = { |
@@ -629,6 +632,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) | |||
629 | port->fcoe_pending_queue_active = 0; | 632 | port->fcoe_pending_queue_active = 0; |
630 | setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport); | 633 | setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport); |
631 | 634 | ||
635 | fcoe_link_speed_update(lport); | ||
636 | |||
632 | if (!lport->vport) { | 637 | if (!lport->vport) { |
633 | /* | 638 | /* |
634 | * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN: | 639 | * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN: |
@@ -653,15 +658,13 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) | |||
653 | /** | 658 | /** |
654 | * fcoe_shost_config() - Set up the SCSI host associated with a local port | 659 | * fcoe_shost_config() - Set up the SCSI host associated with a local port |
655 | * @lport: The local port | 660 | * @lport: The local port |
656 | * @shost: The SCSI host to associate with the local port | ||
657 | * @dev: The device associated with the SCSI host | 661 | * @dev: The device associated with the SCSI host |
658 | * | 662 | * |
659 | * Must be called after fcoe_lport_config() and fcoe_netdev_config() | 663 | * Must be called after fcoe_lport_config() and fcoe_netdev_config() |
660 | * | 664 | * |
661 | * Returns: 0 for success | 665 | * Returns: 0 for success |
662 | */ | 666 | */ |
663 | static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost, | 667 | static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) |
664 | struct device *dev) | ||
665 | { | 668 | { |
666 | int rc = 0; | 669 | int rc = 0; |
667 | 670 | ||
@@ -669,6 +672,8 @@ static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost, | |||
669 | lport->host->max_lun = FCOE_MAX_LUN; | 672 | lport->host->max_lun = FCOE_MAX_LUN; |
670 | lport->host->max_id = FCOE_MAX_FCP_TARGET; | 673 | lport->host->max_id = FCOE_MAX_FCP_TARGET; |
671 | lport->host->max_channel = 0; | 674 | lport->host->max_channel = 0; |
675 | lport->host->max_cmd_len = FCOE_MAX_CMD_LEN; | ||
676 | |||
672 | if (lport->vport) | 677 | if (lport->vport) |
673 | lport->host->transportt = fcoe_vport_transport_template; | 678 | lport->host->transportt = fcoe_vport_transport_template; |
674 | else | 679 | else |
@@ -796,6 +801,12 @@ skip_oem: | |||
796 | /** | 801 | /** |
797 | * fcoe_if_destroy() - Tear down a SW FCoE instance | 802 | * fcoe_if_destroy() - Tear down a SW FCoE instance |
798 | * @lport: The local port to be destroyed | 803 | * @lport: The local port to be destroyed |
804 | * | ||
805 | * Locking: must be called with the RTNL mutex held and RTNL mutex | ||
806 | * needed to be dropped by this function since not dropping RTNL | ||
807 | * would cause circular locking warning on synchronous fip worker | ||
808 | * cancelling thru fcoe_interface_put invoked by this function. | ||
809 | * | ||
799 | */ | 810 | */ |
800 | static void fcoe_if_destroy(struct fc_lport *lport) | 811 | static void fcoe_if_destroy(struct fc_lport *lport) |
801 | { | 812 | { |
@@ -818,7 +829,6 @@ static void fcoe_if_destroy(struct fc_lport *lport) | |||
818 | /* Free existing transmit skbs */ | 829 | /* Free existing transmit skbs */ |
819 | fcoe_clean_pending_queue(lport); | 830 | fcoe_clean_pending_queue(lport); |
820 | 831 | ||
821 | rtnl_lock(); | ||
822 | if (!is_zero_ether_addr(port->data_src_addr)) | 832 | if (!is_zero_ether_addr(port->data_src_addr)) |
823 | dev_unicast_delete(netdev, port->data_src_addr); | 833 | dev_unicast_delete(netdev, port->data_src_addr); |
824 | rtnl_unlock(); | 834 | rtnl_unlock(); |
@@ -841,6 +851,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) | |||
841 | 851 | ||
842 | /* Release the Scsi_Host */ | 852 | /* Release the Scsi_Host */ |
843 | scsi_host_put(lport->host); | 853 | scsi_host_put(lport->host); |
854 | module_put(THIS_MODULE); | ||
844 | } | 855 | } |
845 | 856 | ||
846 | /** | 857 | /** |
@@ -897,7 +908,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, | |||
897 | struct net_device *netdev = fcoe->netdev; | 908 | struct net_device *netdev = fcoe->netdev; |
898 | struct fc_lport *lport = NULL; | 909 | struct fc_lport *lport = NULL; |
899 | struct fcoe_port *port; | 910 | struct fcoe_port *port; |
900 | struct Scsi_Host *shost; | ||
901 | int rc; | 911 | int rc; |
902 | /* | 912 | /* |
903 | * parent is only a vport if npiv is 1, | 913 | * parent is only a vport if npiv is 1, |
@@ -919,7 +929,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, | |||
919 | rc = -ENOMEM; | 929 | rc = -ENOMEM; |
920 | goto out; | 930 | goto out; |
921 | } | 931 | } |
922 | shost = lport->host; | ||
923 | port = lport_priv(lport); | 932 | port = lport_priv(lport); |
924 | port->lport = lport; | 933 | port->lport = lport; |
925 | port->fcoe = fcoe; | 934 | port->fcoe = fcoe; |
@@ -934,7 +943,8 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, | |||
934 | } | 943 | } |
935 | 944 | ||
936 | if (npiv) { | 945 | if (npiv) { |
937 | FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n", | 946 | FCOE_NETDEV_DBG(netdev, "Setting vport names, " |
947 | "%16.16llx %16.16llx\n", | ||
938 | vport->node_name, vport->port_name); | 948 | vport->node_name, vport->port_name); |
939 | fc_set_wwnn(lport, vport->node_name); | 949 | fc_set_wwnn(lport, vport->node_name); |
940 | fc_set_wwpn(lport, vport->port_name); | 950 | fc_set_wwpn(lport, vport->port_name); |
@@ -949,7 +959,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, | |||
949 | } | 959 | } |
950 | 960 | ||
951 | /* configure lport scsi host properties */ | 961 | /* configure lport scsi host properties */ |
952 | rc = fcoe_shost_config(lport, shost, parent); | 962 | rc = fcoe_shost_config(lport, parent); |
953 | if (rc) { | 963 | if (rc) { |
954 | FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " | 964 | FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " |
955 | "interface\n"); | 965 | "interface\n"); |
@@ -1073,7 +1083,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu) | |||
1073 | struct sk_buff *skb; | 1083 | struct sk_buff *skb; |
1074 | #ifdef CONFIG_SMP | 1084 | #ifdef CONFIG_SMP |
1075 | struct fcoe_percpu_s *p0; | 1085 | struct fcoe_percpu_s *p0; |
1076 | unsigned targ_cpu = smp_processor_id(); | 1086 | unsigned targ_cpu = get_cpu(); |
1077 | #endif /* CONFIG_SMP */ | 1087 | #endif /* CONFIG_SMP */ |
1078 | 1088 | ||
1079 | FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); | 1089 | FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); |
@@ -1129,6 +1139,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu) | |||
1129 | kfree_skb(skb); | 1139 | kfree_skb(skb); |
1130 | spin_unlock_bh(&p->fcoe_rx_list.lock); | 1140 | spin_unlock_bh(&p->fcoe_rx_list.lock); |
1131 | } | 1141 | } |
1142 | put_cpu(); | ||
1132 | #else | 1143 | #else |
1133 | /* | 1144 | /* |
1134 | * This a non-SMP scenario where the singular Rx thread is | 1145 | * This a non-SMP scenario where the singular Rx thread is |
@@ -1297,8 +1308,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, | |||
1297 | 1308 | ||
1298 | return 0; | 1309 | return 0; |
1299 | err: | 1310 | err: |
1300 | fc_lport_get_stats(lport)->ErrorFrames++; | 1311 | per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++; |
1301 | 1312 | put_cpu(); | |
1302 | err2: | 1313 | err2: |
1303 | kfree_skb(skb); | 1314 | kfree_skb(skb); |
1304 | return -1; | 1315 | return -1; |
@@ -1444,7 +1455,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) | |||
1444 | return 0; | 1455 | return 0; |
1445 | } | 1456 | } |
1446 | 1457 | ||
1447 | if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && | 1458 | if (unlikely(fh->fh_type == FC_TYPE_ELS) && |
1448 | fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb)) | 1459 | fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb)) |
1449 | return 0; | 1460 | return 0; |
1450 | 1461 | ||
@@ -1527,9 +1538,10 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) | |||
1527 | skb_shinfo(skb)->gso_size = 0; | 1538 | skb_shinfo(skb)->gso_size = 0; |
1528 | } | 1539 | } |
1529 | /* update tx stats: regardless if LLD fails */ | 1540 | /* update tx stats: regardless if LLD fails */ |
1530 | stats = fc_lport_get_stats(lport); | 1541 | stats = per_cpu_ptr(lport->dev_stats, get_cpu()); |
1531 | stats->TxFrames++; | 1542 | stats->TxFrames++; |
1532 | stats->TxWords += wlen; | 1543 | stats->TxWords += wlen; |
1544 | put_cpu(); | ||
1533 | 1545 | ||
1534 | /* send down to lld */ | 1546 | /* send down to lld */ |
1535 | fr_dev(fp) = lport; | 1547 | fr_dev(fp) = lport; |
@@ -1563,7 +1575,6 @@ static void fcoe_recv_frame(struct sk_buff *skb) | |||
1563 | struct fc_frame_header *fh; | 1575 | struct fc_frame_header *fh; |
1564 | struct fcoe_crc_eof crc_eof; | 1576 | struct fcoe_crc_eof crc_eof; |
1565 | struct fc_frame *fp; | 1577 | struct fc_frame *fp; |
1566 | u8 *mac = NULL; | ||
1567 | struct fcoe_port *port; | 1578 | struct fcoe_port *port; |
1568 | struct fcoe_hdr *hp; | 1579 | struct fcoe_hdr *hp; |
1569 | 1580 | ||
@@ -1583,13 +1594,9 @@ static void fcoe_recv_frame(struct sk_buff *skb) | |||
1583 | skb_end_pointer(skb), skb->csum, | 1594 | skb_end_pointer(skb), skb->csum, |
1584 | skb->dev ? skb->dev->name : "<NULL>"); | 1595 | skb->dev ? skb->dev->name : "<NULL>"); |
1585 | 1596 | ||
1586 | /* | ||
1587 | * Save source MAC address before discarding header. | ||
1588 | */ | ||
1589 | port = lport_priv(lport); | 1597 | port = lport_priv(lport); |
1590 | if (skb_is_nonlinear(skb)) | 1598 | if (skb_is_nonlinear(skb)) |
1591 | skb_linearize(skb); /* not ideal */ | 1599 | skb_linearize(skb); /* not ideal */ |
1592 | mac = eth_hdr(skb)->h_source; | ||
1593 | 1600 | ||
1594 | /* | 1601 | /* |
1595 | * Frame length checks and setting up the header pointers | 1602 | * Frame length checks and setting up the header pointers |
@@ -1598,7 +1605,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) | |||
1598 | hp = (struct fcoe_hdr *) skb_network_header(skb); | 1605 | hp = (struct fcoe_hdr *) skb_network_header(skb); |
1599 | fh = (struct fc_frame_header *) skb_transport_header(skb); | 1606 | fh = (struct fc_frame_header *) skb_transport_header(skb); |
1600 | 1607 | ||
1601 | stats = fc_lport_get_stats(lport); | 1608 | stats = per_cpu_ptr(lport->dev_stats, get_cpu()); |
1602 | if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { | 1609 | if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { |
1603 | if (stats->ErrorFrames < 5) | 1610 | if (stats->ErrorFrames < 5) |
1604 | printk(KERN_WARNING "fcoe: FCoE version " | 1611 | printk(KERN_WARNING "fcoe: FCoE version " |
@@ -1607,9 +1614,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) | |||
1607 | "initiator supports version " | 1614 | "initiator supports version " |
1608 | "%x\n", FC_FCOE_DECAPS_VER(hp), | 1615 | "%x\n", FC_FCOE_DECAPS_VER(hp), |
1609 | FC_FCOE_VER); | 1616 | FC_FCOE_VER); |
1610 | stats->ErrorFrames++; | 1617 | goto drop; |
1611 | kfree_skb(skb); | ||
1612 | return; | ||
1613 | } | 1618 | } |
1614 | 1619 | ||
1615 | skb_pull(skb, sizeof(struct fcoe_hdr)); | 1620 | skb_pull(skb, sizeof(struct fcoe_hdr)); |
@@ -1624,16 +1629,12 @@ static void fcoe_recv_frame(struct sk_buff *skb) | |||
1624 | fr_sof(fp) = hp->fcoe_sof; | 1629 | fr_sof(fp) = hp->fcoe_sof; |
1625 | 1630 | ||
1626 | /* Copy out the CRC and EOF trailer for access */ | 1631 | /* Copy out the CRC and EOF trailer for access */ |
1627 | if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { | 1632 | if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) |
1628 | kfree_skb(skb); | 1633 | goto drop; |
1629 | return; | ||
1630 | } | ||
1631 | fr_eof(fp) = crc_eof.fcoe_eof; | 1634 | fr_eof(fp) = crc_eof.fcoe_eof; |
1632 | fr_crc(fp) = crc_eof.fcoe_crc32; | 1635 | fr_crc(fp) = crc_eof.fcoe_crc32; |
1633 | if (pskb_trim(skb, fr_len)) { | 1636 | if (pskb_trim(skb, fr_len)) |
1634 | kfree_skb(skb); | 1637 | goto drop; |
1635 | return; | ||
1636 | } | ||
1637 | 1638 | ||
1638 | /* | 1639 | /* |
1639 | * We only check CRC if no offload is available and if it is | 1640 | * We only check CRC if no offload is available and if it is |
@@ -1647,25 +1648,27 @@ static void fcoe_recv_frame(struct sk_buff *skb) | |||
1647 | fr_flags(fp) |= FCPHF_CRC_UNCHECKED; | 1648 | fr_flags(fp) |= FCPHF_CRC_UNCHECKED; |
1648 | 1649 | ||
1649 | fh = fc_frame_header_get(fp); | 1650 | fh = fc_frame_header_get(fp); |
1650 | if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && | 1651 | if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA || |
1651 | fh->fh_type == FC_TYPE_FCP) { | 1652 | fh->fh_type != FC_TYPE_FCP) && |
1652 | fc_exch_recv(lport, fp); | 1653 | (fr_flags(fp) & FCPHF_CRC_UNCHECKED)) { |
1653 | return; | ||
1654 | } | ||
1655 | if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { | ||
1656 | if (le32_to_cpu(fr_crc(fp)) != | 1654 | if (le32_to_cpu(fr_crc(fp)) != |
1657 | ~crc32(~0, skb->data, fr_len)) { | 1655 | ~crc32(~0, skb->data, fr_len)) { |
1658 | if (stats->InvalidCRCCount < 5) | 1656 | if (stats->InvalidCRCCount < 5) |
1659 | printk(KERN_WARNING "fcoe: dropping " | 1657 | printk(KERN_WARNING "fcoe: dropping " |
1660 | "frame with CRC error\n"); | 1658 | "frame with CRC error\n"); |
1661 | stats->InvalidCRCCount++; | 1659 | stats->InvalidCRCCount++; |
1662 | stats->ErrorFrames++; | 1660 | goto drop; |
1663 | fc_frame_free(fp); | ||
1664 | return; | ||
1665 | } | 1661 | } |
1666 | fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; | 1662 | fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; |
1667 | } | 1663 | } |
1664 | put_cpu(); | ||
1668 | fc_exch_recv(lport, fp); | 1665 | fc_exch_recv(lport, fp); |
1666 | return; | ||
1667 | |||
1668 | drop: | ||
1669 | stats->ErrorFrames++; | ||
1670 | put_cpu(); | ||
1671 | kfree_skb(skb); | ||
1669 | } | 1672 | } |
1670 | 1673 | ||
1671 | /** | 1674 | /** |
@@ -1835,11 +1838,15 @@ static int fcoe_device_notification(struct notifier_block *notifier, | |||
1835 | FCOE_NETDEV_DBG(netdev, "Unknown event %ld " | 1838 | FCOE_NETDEV_DBG(netdev, "Unknown event %ld " |
1836 | "from netdev netlink\n", event); | 1839 | "from netdev netlink\n", event); |
1837 | } | 1840 | } |
1841 | |||
1842 | fcoe_link_speed_update(lport); | ||
1843 | |||
1838 | if (link_possible && !fcoe_link_ok(lport)) | 1844 | if (link_possible && !fcoe_link_ok(lport)) |
1839 | fcoe_ctlr_link_up(&fcoe->ctlr); | 1845 | fcoe_ctlr_link_up(&fcoe->ctlr); |
1840 | else if (fcoe_ctlr_link_down(&fcoe->ctlr)) { | 1846 | else if (fcoe_ctlr_link_down(&fcoe->ctlr)) { |
1841 | stats = fc_lport_get_stats(lport); | 1847 | stats = per_cpu_ptr(lport->dev_stats, get_cpu()); |
1842 | stats->LinkFailureCount++; | 1848 | stats->LinkFailureCount++; |
1849 | put_cpu(); | ||
1843 | fcoe_clean_pending_queue(lport); | 1850 | fcoe_clean_pending_queue(lport); |
1844 | } | 1851 | } |
1845 | out: | 1852 | out: |
@@ -1901,13 +1908,19 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp) | |||
1901 | goto out_nodev; | 1908 | goto out_nodev; |
1902 | } | 1909 | } |
1903 | 1910 | ||
1904 | rtnl_lock(); | 1911 | if (!rtnl_trylock()) { |
1912 | dev_put(netdev); | ||
1913 | mutex_unlock(&fcoe_config_mutex); | ||
1914 | return restart_syscall(); | ||
1915 | } | ||
1916 | |||
1905 | fcoe = fcoe_hostlist_lookup_port(netdev); | 1917 | fcoe = fcoe_hostlist_lookup_port(netdev); |
1906 | rtnl_unlock(); | 1918 | rtnl_unlock(); |
1907 | 1919 | ||
1908 | if (fcoe) | 1920 | if (fcoe) { |
1909 | fc_fabric_logoff(fcoe->ctlr.lp); | 1921 | fc_fabric_logoff(fcoe->ctlr.lp); |
1910 | else | 1922 | fcoe_ctlr_link_down(&fcoe->ctlr); |
1923 | } else | ||
1911 | rc = -ENODEV; | 1924 | rc = -ENODEV; |
1912 | 1925 | ||
1913 | dev_put(netdev); | 1926 | dev_put(netdev); |
@@ -1950,13 +1963,20 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp) | |||
1950 | goto out_nodev; | 1963 | goto out_nodev; |
1951 | } | 1964 | } |
1952 | 1965 | ||
1953 | rtnl_lock(); | 1966 | if (!rtnl_trylock()) { |
1967 | dev_put(netdev); | ||
1968 | mutex_unlock(&fcoe_config_mutex); | ||
1969 | return restart_syscall(); | ||
1970 | } | ||
1971 | |||
1954 | fcoe = fcoe_hostlist_lookup_port(netdev); | 1972 | fcoe = fcoe_hostlist_lookup_port(netdev); |
1955 | rtnl_unlock(); | 1973 | rtnl_unlock(); |
1956 | 1974 | ||
1957 | if (fcoe) | 1975 | if (fcoe) { |
1976 | if (!fcoe_link_ok(fcoe->ctlr.lp)) | ||
1977 | fcoe_ctlr_link_up(&fcoe->ctlr); | ||
1958 | rc = fc_fabric_login(fcoe->ctlr.lp); | 1978 | rc = fc_fabric_login(fcoe->ctlr.lp); |
1959 | else | 1979 | } else |
1960 | rc = -ENODEV; | 1980 | rc = -ENODEV; |
1961 | 1981 | ||
1962 | dev_put(netdev); | 1982 | dev_put(netdev); |
@@ -1999,7 +2019,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) | |||
1999 | goto out_nodev; | 2019 | goto out_nodev; |
2000 | } | 2020 | } |
2001 | 2021 | ||
2002 | rtnl_lock(); | 2022 | if (!rtnl_trylock()) { |
2023 | dev_put(netdev); | ||
2024 | mutex_unlock(&fcoe_config_mutex); | ||
2025 | return restart_syscall(); | ||
2026 | } | ||
2027 | |||
2003 | fcoe = fcoe_hostlist_lookup_port(netdev); | 2028 | fcoe = fcoe_hostlist_lookup_port(netdev); |
2004 | if (!fcoe) { | 2029 | if (!fcoe) { |
2005 | rtnl_unlock(); | 2030 | rtnl_unlock(); |
@@ -2008,9 +2033,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) | |||
2008 | } | 2033 | } |
2009 | list_del(&fcoe->list); | 2034 | list_del(&fcoe->list); |
2010 | fcoe_interface_cleanup(fcoe); | 2035 | fcoe_interface_cleanup(fcoe); |
2011 | rtnl_unlock(); | 2036 | /* RTNL mutex is dropped by fcoe_if_destroy */ |
2012 | fcoe_if_destroy(fcoe->ctlr.lp); | 2037 | fcoe_if_destroy(fcoe->ctlr.lp); |
2013 | module_put(THIS_MODULE); | ||
2014 | 2038 | ||
2015 | out_putdev: | 2039 | out_putdev: |
2016 | dev_put(netdev); | 2040 | dev_put(netdev); |
@@ -2029,6 +2053,8 @@ static void fcoe_destroy_work(struct work_struct *work) | |||
2029 | 2053 | ||
2030 | port = container_of(work, struct fcoe_port, destroy_work); | 2054 | port = container_of(work, struct fcoe_port, destroy_work); |
2031 | mutex_lock(&fcoe_config_mutex); | 2055 | mutex_lock(&fcoe_config_mutex); |
2056 | rtnl_lock(); | ||
2057 | /* RTNL mutex is dropped by fcoe_if_destroy */ | ||
2032 | fcoe_if_destroy(port->lport); | 2058 | fcoe_if_destroy(port->lport); |
2033 | mutex_unlock(&fcoe_config_mutex); | 2059 | mutex_unlock(&fcoe_config_mutex); |
2034 | } | 2060 | } |
@@ -2050,6 +2076,12 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) | |||
2050 | struct net_device *netdev; | 2076 | struct net_device *netdev; |
2051 | 2077 | ||
2052 | mutex_lock(&fcoe_config_mutex); | 2078 | mutex_lock(&fcoe_config_mutex); |
2079 | |||
2080 | if (!rtnl_trylock()) { | ||
2081 | mutex_unlock(&fcoe_config_mutex); | ||
2082 | return restart_syscall(); | ||
2083 | } | ||
2084 | |||
2053 | #ifdef CONFIG_FCOE_MODULE | 2085 | #ifdef CONFIG_FCOE_MODULE |
2054 | /* | 2086 | /* |
2055 | * Make sure the module has been initialized, and is not about to be | 2087 | * Make sure the module has been initialized, and is not about to be |
@@ -2058,7 +2090,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) | |||
2058 | */ | 2090 | */ |
2059 | if (THIS_MODULE->state != MODULE_STATE_LIVE) { | 2091 | if (THIS_MODULE->state != MODULE_STATE_LIVE) { |
2060 | rc = -ENODEV; | 2092 | rc = -ENODEV; |
2061 | goto out_nodev; | 2093 | goto out_nomod; |
2062 | } | 2094 | } |
2063 | #endif | 2095 | #endif |
2064 | 2096 | ||
@@ -2067,7 +2099,6 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) | |||
2067 | goto out_nomod; | 2099 | goto out_nomod; |
2068 | } | 2100 | } |
2069 | 2101 | ||
2070 | rtnl_lock(); | ||
2071 | netdev = fcoe_if_to_netdev(buffer); | 2102 | netdev = fcoe_if_to_netdev(buffer); |
2072 | if (!netdev) { | 2103 | if (!netdev) { |
2073 | rc = -ENODEV; | 2104 | rc = -ENODEV; |
@@ -2122,35 +2153,27 @@ out_free: | |||
2122 | out_putdev: | 2153 | out_putdev: |
2123 | dev_put(netdev); | 2154 | dev_put(netdev); |
2124 | out_nodev: | 2155 | out_nodev: |
2125 | rtnl_unlock(); | ||
2126 | module_put(THIS_MODULE); | 2156 | module_put(THIS_MODULE); |
2127 | out_nomod: | 2157 | out_nomod: |
2158 | rtnl_unlock(); | ||
2128 | mutex_unlock(&fcoe_config_mutex); | 2159 | mutex_unlock(&fcoe_config_mutex); |
2129 | return rc; | 2160 | return rc; |
2130 | } | 2161 | } |
2131 | 2162 | ||
2132 | /** | 2163 | /** |
2133 | * fcoe_link_ok() - Check if the link is OK for a local port | 2164 | * fcoe_link_speed_update() - Update the supported and actual link speeds |
2134 | * @lport: The local port to check link on | 2165 | * @lport: The local port to update speeds for |
2135 | * | ||
2136 | * Any permanently-disqualifying conditions have been previously checked. | ||
2137 | * This also updates the speed setting, which may change with link for 100/1000. | ||
2138 | * | ||
2139 | * This function should probably be checking for PAUSE support at some point | ||
2140 | * in the future. Currently Per-priority-pause is not determinable using | ||
2141 | * ethtool, so we shouldn't be restrictive until that problem is resolved. | ||
2142 | * | ||
2143 | * Returns: 0 if link is OK for use by FCoE. | ||
2144 | * | 2166 | * |
2167 | * Returns: 0 if the ethtool query was successful | ||
2168 | * -1 if the ethtool query failed | ||
2145 | */ | 2169 | */ |
2146 | int fcoe_link_ok(struct fc_lport *lport) | 2170 | int fcoe_link_speed_update(struct fc_lport *lport) |
2147 | { | 2171 | { |
2148 | struct fcoe_port *port = lport_priv(lport); | 2172 | struct fcoe_port *port = lport_priv(lport); |
2149 | struct net_device *netdev = port->fcoe->netdev; | 2173 | struct net_device *netdev = port->fcoe->netdev; |
2150 | struct ethtool_cmd ecmd = { ETHTOOL_GSET }; | 2174 | struct ethtool_cmd ecmd = { ETHTOOL_GSET }; |
2151 | 2175 | ||
2152 | if ((netdev->flags & IFF_UP) && netif_carrier_ok(netdev) && | 2176 | if (!dev_ethtool_get_settings(netdev, &ecmd)) { |
2153 | (!dev_ethtool_get_settings(netdev, &ecmd))) { | ||
2154 | lport->link_supported_speeds &= | 2177 | lport->link_supported_speeds &= |
2155 | ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); | 2178 | ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); |
2156 | if (ecmd.supported & (SUPPORTED_1000baseT_Half | | 2179 | if (ecmd.supported & (SUPPORTED_1000baseT_Half | |
@@ -2170,6 +2193,23 @@ int fcoe_link_ok(struct fc_lport *lport) | |||
2170 | } | 2193 | } |
2171 | 2194 | ||
2172 | /** | 2195 | /** |
2196 | * fcoe_link_ok() - Check if the link is OK for a local port | ||
2197 | * @lport: The local port to check link on | ||
2198 | * | ||
2199 | * Returns: 0 if link is UP and OK, -1 if not | ||
2200 | * | ||
2201 | */ | ||
2202 | int fcoe_link_ok(struct fc_lport *lport) | ||
2203 | { | ||
2204 | struct fcoe_port *port = lport_priv(lport); | ||
2205 | struct net_device *netdev = port->fcoe->netdev; | ||
2206 | |||
2207 | if (netif_oper_up(netdev)) | ||
2208 | return 0; | ||
2209 | return -1; | ||
2210 | } | ||
2211 | |||
2212 | /** | ||
2173 | * fcoe_percpu_clean() - Clear all pending skbs for an local port | 2213 | * fcoe_percpu_clean() - Clear all pending skbs for an local port |
2174 | * @lport: The local port whose skbs are to be cleared | 2214 | * @lport: The local port whose skbs are to be cleared |
2175 | * | 2215 | * |
@@ -2631,3 +2671,25 @@ static void fcoe_get_lesb(struct fc_lport *lport, | |||
2631 | lesb->lesb_miss_fka = htonl(mdac); | 2671 | lesb->lesb_miss_fka = htonl(mdac); |
2632 | lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors); | 2672 | lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors); |
2633 | } | 2673 | } |
2674 | |||
2675 | /** | ||
2676 | * fcoe_set_port_id() - Callback from libfc when Port_ID is set. | ||
2677 | * @lport: the local port | ||
2678 | * @port_id: the port ID | ||
2679 | * @fp: the received frame, if any, that caused the port_id to be set. | ||
2680 | * | ||
2681 | * This routine handles the case where we received a FLOGI and are | ||
2682 | * entering point-to-point mode. We need to call fcoe_ctlr_recv_flogi() | ||
2683 | * so it can set the non-mapped mode and gateway address. | ||
2684 | * | ||
2685 | * The FLOGI LS_ACC is handled by fcoe_flogi_resp(). | ||
2686 | */ | ||
2687 | static void fcoe_set_port_id(struct fc_lport *lport, | ||
2688 | u32 port_id, struct fc_frame *fp) | ||
2689 | { | ||
2690 | struct fcoe_port *port = lport_priv(lport); | ||
2691 | struct fcoe_interface *fcoe = port->fcoe; | ||
2692 | |||
2693 | if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) | ||
2694 | fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp); | ||
2695 | } | ||