aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qedf/qedf_fip.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qedf/qedf_fip.c')
-rw-r--r--drivers/scsi/qedf/qedf_fip.c95
1 files changed, 70 insertions, 25 deletions
diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c
index 3fd3af799b3d..d4741f8dcb41 100644
--- a/drivers/scsi/qedf/qedf_fip.c
+++ b/drivers/scsi/qedf/qedf_fip.c
@@ -19,17 +19,16 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf)
{
struct sk_buff *skb;
char *eth_fr;
- int fr_len;
struct fip_vlan *vlan;
#define MY_FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS;
unsigned long flags = 0;
+ int rc = -1;
skb = dev_alloc_skb(sizeof(struct fip_vlan));
if (!skb)
return;
- fr_len = sizeof(*vlan);
eth_fr = (char *)skb->data;
vlan = (struct fip_vlan *)eth_fr;
@@ -68,7 +67,13 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf)
}
set_bit(QED_LL2_XMIT_FLAGS_FIP_DISCOVERY, &flags);
- qed_ops->ll2->start_xmit(qedf->cdev, skb, flags);
+ rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, flags);
+ if (rc) {
+ QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc);
+ kfree_skb(skb);
+ return;
+ }
+
}
static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf,
@@ -95,6 +100,12 @@ static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf,
rlen -= dlen;
}
+ if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Dropping VLAN response as link is down.\n");
+ return;
+ }
+
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "VLAN response, "
"vid=0x%x.\n", vid);
@@ -114,6 +125,7 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
struct fip_header *fiph;
u16 op, vlan_tci = 0;
u8 sub;
+ int rc = -1;
if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) {
QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n");
@@ -142,9 +154,16 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb->len, false);
- qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
+ rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
+ if (rc) {
+ QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc);
+ kfree_skb(skb);
+ return;
+ }
}
+static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
+
/* Process incoming FIP frames. */
void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
{
@@ -157,20 +176,37 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
size_t rlen, dlen;
u16 op;
u8 sub;
- bool do_reset = false;
+ bool fcf_valid = false;
+ /* Default is to handle CVL regardless of fabric id descriptor */
+ bool fabric_id_valid = true;
+ bool fc_wwpn_valid = false;
+ u64 switch_name;
+ u16 vlan = 0;
eth_hdr = (struct ethhdr *)skb_mac_header(skb);
fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2);
op = ntohs(fiph->fip_op);
sub = fiph->fip_subcode;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame received: "
- "skb=%p fiph=%p source=%pM op=%x sub=%x", skb, fiph,
- eth_hdr->h_source, op, sub);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
+ "FIP frame received: skb=%p fiph=%p source=%pM destn=%pM op=%x sub=%x vlan=%04x",
+ skb, fiph, eth_hdr->h_source, eth_hdr->h_dest, op,
+ sub, vlan);
if (qedf_dump_frames)
print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb->len, false);
+ if (!ether_addr_equal(eth_hdr->h_dest, qedf->mac) &&
+ !ether_addr_equal(eth_hdr->h_dest, fcoe_all_enode) &&
+ !ether_addr_equal(eth_hdr->h_dest, qedf->data_src_addr)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
+ "Dropping FIP type 0x%x pkt due to destination MAC mismatch dest_mac=%pM ctlr.dest_addr=%pM data_src_addr=%pM.\n",
+ op, eth_hdr->h_dest, qedf->mac,
+ qedf->data_src_addr);
+ kfree_skb(skb);
+ return;
+ }
+
/* Handle FIP VLAN resp in the driver */
if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) {
qedf_fcoe_process_vlan_resp(qedf, skb);
@@ -199,25 +235,36 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
switch (desc->fip_dtype) {
case FIP_DT_MAC:
mp = (struct fip_mac_desc *)desc;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "fd_mac=%pM\n", mp->fd_mac);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Switch fd_mac=%pM.\n", mp->fd_mac);
if (ether_addr_equal(mp->fd_mac,
qedf->ctlr.sel_fcf->fcf_mac))
- do_reset = true;
+ fcf_valid = true;
break;
case FIP_DT_NAME:
wp = (struct fip_wwn_desc *)desc;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "fc_wwpn=%016llx.\n",
- get_unaligned_be64(&wp->fd_wwn));
+ switch_name = get_unaligned_be64(&wp->fd_wwn);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Switch fd_wwn=%016llx fcf_switch_name=%016llx.\n",
+ switch_name,
+ qedf->ctlr.sel_fcf->switch_name);
+ if (switch_name ==
+ qedf->ctlr.sel_fcf->switch_name)
+ fc_wwpn_valid = true;
break;
case FIP_DT_VN_ID:
vp = (struct fip_vn_desc *)desc;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id));
- if (ntoh24(vp->fd_fc_id) ==
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "vx_port fd_fc_id=%x fd_mac=%pM.\n",
+ ntoh24(vp->fd_fc_id), vp->fd_mac);
+ /* Check vx_port fabric ID */
+ if (ntoh24(vp->fd_fc_id) !=
qedf->lport->port_id)
- do_reset = true;
+ fabric_id_valid = false;
+ /* Check vx_port MAC */
+ if (!ether_addr_equal(vp->fd_mac,
+ qedf->data_src_addr))
+ fabric_id_valid = false;
break;
default:
/* Ignore anything else */
@@ -227,13 +274,11 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
rlen -= dlen;
}
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "do_reset=%d.\n", do_reset);
- if (do_reset) {
- fcoe_ctlr_link_down(&qedf->ctlr);
- qedf_wait_for_upload(qedf);
- fcoe_ctlr_link_up(&qedf->ctlr);
- }
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "fcf_valid=%d fabric_id_valid=%d fc_wwpn_valid=%d.\n",
+ fcf_valid, fabric_id_valid, fc_wwpn_valid);
+ if (fcf_valid && fabric_id_valid && fc_wwpn_valid)
+ qedf_ctx_soft_reset(qedf->lport);
kfree_skb(skb);
} else {
/* Everything else is handled by libfcoe */