2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-21 19:53:59 +08:00

[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>
This commit is contained in:
Vasu Dev 2011-01-28 16:03:52 -08:00 committed by James Bottomley
parent 7287fb9114
commit 52ee832195

View File

@ -1619,6 +1619,56 @@ static void fcoe_percpu_flush_done(struct sk_buff *skb)
complete(&fcoe_flush_completion);
}
/**
* fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC
* @lport: The local port the frame was received on
* @fp: The received frame
*
* Return: 0 on passing filtering checks
*/
static inline int fcoe_filter_frames(struct fc_lport *lport,
struct fc_frame *fp)
{
struct fcoe_interface *fcoe;
struct fc_frame_header *fh;
struct sk_buff *skb = (struct sk_buff *)fp;
struct fcoe_dev_stats *stats;
/*
* We only check CRC if no offload is available and if it is
* it's solicited data, in which case, the FCP layer would
* check it during the copy.
*/
if (lport->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY)
fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
else
fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
fh = (struct fc_frame_header *) skb_transport_header(skb);
fh = fc_frame_header_get(fp);
if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP)
return 0;
fcoe = ((struct fcoe_port *)lport_priv(lport))->fcoe;
if (is_fip_mode(&fcoe->ctlr) && fc_frame_payload_op(fp) == ELS_LOGO &&
ntoh24(fh->fh_s_id) == FC_FID_FLOGI) {
FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n");
return -EINVAL;
}
if (!fr_flags(fp) & FCPHF_CRC_UNCHECKED ||
le32_to_cpu(fr_crc(fp)) == ~crc32(~0, skb->data, skb->len)) {
fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
return 0;
}
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
stats->InvalidCRCCount++;
if (stats->InvalidCRCCount < 5)
printk(KERN_WARNING "fcoe: dropping frame with CRC error\n");
return -EINVAL;
}
/**
* fcoe_recv_frame() - process a single received frame
* @skb: frame to process
@ -1629,7 +1679,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
struct fc_lport *lport;
struct fcoe_rcv_info *fr;
struct fcoe_dev_stats *stats;
struct fc_frame_header *fh;
struct fcoe_crc_eof crc_eof;
struct fc_frame *fp;
struct fcoe_port *port;
@ -1660,7 +1709,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
* was done in fcoe_rcv already.
*/
hp = (struct fcoe_hdr *) skb_network_header(skb);
fh = (struct fc_frame_header *) skb_transport_header(skb);
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
@ -1693,35 +1741,11 @@ static void fcoe_recv_frame(struct sk_buff *skb)
if (pskb_trim(skb, fr_len))
goto drop;
/*
* We only check CRC if no offload is available and if it is
* it's solicited data, in which case, the FCP layer would
* check it during the copy.
*/
if (lport->crc_offload &&
skb->ip_summed == CHECKSUM_UNNECESSARY)
fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
else
fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
fh = fc_frame_header_get(fp);
if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA ||
fh->fh_type != FC_TYPE_FCP) &&
(fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {
if (le32_to_cpu(fr_crc(fp)) !=
~crc32(~0, skb->data, fr_len)) {
if (stats->InvalidCRCCount < 5)
printk(KERN_WARNING "fcoe: dropping "
"frame with CRC error\n");
stats->InvalidCRCCount++;
goto drop;
}
fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
if (!fcoe_filter_frames(lport, fp)) {
put_cpu();
fc_exch_recv(lport, fp);
return;
}
put_cpu();
fc_exch_recv(lport, fp);
return;
drop:
stats->ErrorFrames++;
put_cpu();