aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVasu Dev <vasu.dev@linux.intel.com>2011-01-28 19:03:52 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-02-12 12:00:04 -0500
commit52ee832195b0ae33f12e334e61cf43d1087f24d6 (patch)
tree253e53bbf292d3a33f3bcf6fdad82ef4fea5f052
parent7287fb9114096503eddfffb7b2ed691c809a6106 (diff)
[SCSI] fcoe: drop FCoE LOGO in FIP mode
Allowing FCoE LOGO followed by CVL in this case prevents FIP login back to the FCF and then keeps lport offline, only FIP LOGO and CLV needs to be processed while in FIP mode, therefore this patch drops FCoE LOGO in FIP mode. Added fcoe_filter_frames() to filter out above mentioned LOGO in fcoe rx path along with other existing filtering in code for bad CRC frames. Adding separate fcoe_filter_frames function helped with better code indentations and if needed then same will allow adding more filters at one place in future. This LOGO drop is added after FCP frames passed up to avoid any additional checks on fast path for this. 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@suse.de>
-rw-r--r--drivers/scsi/fcoe/fcoe.c84
1 files changed, 54 insertions, 30 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 452b42169c4..d1146994a1b 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1620,6 +1620,56 @@ static void fcoe_percpu_flush_done(struct sk_buff *skb)
1620} 1620}
1621 1621
1622/** 1622/**
1623 * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC
1624 * @lport: The local port the frame was received on
1625 * @fp: The received frame
1626 *
1627 * Return: 0 on passing filtering checks
1628 */
1629static inline int fcoe_filter_frames(struct fc_lport *lport,
1630 struct fc_frame *fp)
1631{
1632 struct fcoe_interface *fcoe;
1633 struct fc_frame_header *fh;
1634 struct sk_buff *skb = (struct sk_buff *)fp;
1635 struct fcoe_dev_stats *stats;
1636
1637 /*
1638 * We only check CRC if no offload is available and if it is
1639 * it's solicited data, in which case, the FCP layer would
1640 * check it during the copy.
1641 */
1642 if (lport->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY)
1643 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1644 else
1645 fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
1646
1647 fh = (struct fc_frame_header *) skb_transport_header(skb);
1648 fh = fc_frame_header_get(fp);
1649 if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP)
1650 return 0;
1651
1652 fcoe = ((struct fcoe_port *)lport_priv(lport))->fcoe;
1653 if (is_fip_mode(&fcoe->ctlr) && fc_frame_payload_op(fp) == ELS_LOGO &&
1654 ntoh24(fh->fh_s_id) == FC_FID_FLOGI) {
1655 FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n");
1656 return -EINVAL;
1657 }
1658
1659 if (!fr_flags(fp) & FCPHF_CRC_UNCHECKED ||
1660 le32_to_cpu(fr_crc(fp)) == ~crc32(~0, skb->data, skb->len)) {
1661 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1662 return 0;
1663 }
1664
1665 stats = per_cpu_ptr(lport->dev_stats, get_cpu());
1666 stats->InvalidCRCCount++;
1667 if (stats->InvalidCRCCount < 5)
1668 printk(KERN_WARNING "fcoe: dropping frame with CRC error\n");
1669 return -EINVAL;
1670}
1671
1672/**
1623 * fcoe_recv_frame() - process a single received frame 1673 * fcoe_recv_frame() - process a single received frame
1624 * @skb: frame to process 1674 * @skb: frame to process
1625 */ 1675 */
@@ -1629,7 +1679,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
1629 struct fc_lport *lport; 1679 struct fc_lport *lport;
1630 struct fcoe_rcv_info *fr; 1680 struct fcoe_rcv_info *fr;
1631 struct fcoe_dev_stats *stats; 1681 struct fcoe_dev_stats *stats;
1632 struct fc_frame_header *fh;
1633 struct fcoe_crc_eof crc_eof; 1682 struct fcoe_crc_eof crc_eof;
1634 struct fc_frame *fp; 1683 struct fc_frame *fp;
1635 struct fcoe_port *port; 1684 struct fcoe_port *port;
@@ -1660,7 +1709,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
1660 * was done in fcoe_rcv already. 1709 * was done in fcoe_rcv already.
1661 */ 1710 */
1662 hp = (struct fcoe_hdr *) skb_network_header(skb); 1711 hp = (struct fcoe_hdr *) skb_network_header(skb);
1663 fh = (struct fc_frame_header *) skb_transport_header(skb);
1664 1712
1665 stats = per_cpu_ptr(lport->dev_stats, get_cpu()); 1713 stats = per_cpu_ptr(lport->dev_stats, get_cpu());
1666 if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { 1714 if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
@@ -1693,35 +1741,11 @@ static void fcoe_recv_frame(struct sk_buff *skb)
1693 if (pskb_trim(skb, fr_len)) 1741 if (pskb_trim(skb, fr_len))
1694 goto drop; 1742 goto drop;
1695 1743
1696 /* 1744 if (!fcoe_filter_frames(lport, fp)) {
1697 * We only check CRC if no offload is available and if it is 1745 put_cpu();
1698 * it's solicited data, in which case, the FCP layer would 1746 fc_exch_recv(lport, fp);
1699 * check it during the copy. 1747 return;
1700 */
1701 if (lport->crc_offload &&
1702 skb->ip_summed == CHECKSUM_UNNECESSARY)
1703 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1704 else
1705 fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
1706
1707 fh = fc_frame_header_get(fp);
1708 if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA ||
1709 fh->fh_type != FC_TYPE_FCP) &&
1710 (fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {
1711 if (le32_to_cpu(fr_crc(fp)) !=
1712 ~crc32(~0, skb->data, fr_len)) {
1713 if (stats->InvalidCRCCount < 5)
1714 printk(KERN_WARNING "fcoe: dropping "
1715 "frame with CRC error\n");
1716 stats->InvalidCRCCount++;
1717 goto drop;
1718 }
1719 fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1720 } 1748 }
1721 put_cpu();
1722 fc_exch_recv(lport, fp);
1723 return;
1724
1725drop: 1749drop:
1726 stats->ErrorFrames++; 1750 stats->ErrorFrames++;
1727 put_cpu(); 1751 put_cpu();