| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * QLogic FCoE Offload Driver |
|---|
| 3 | 4 | * Copyright (c) 2016-2018 Cavium Inc. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This software is available under the terms of the GNU General Public License |
|---|
| 6 | | - * (GPL) Version 2, available from the file COPYING in the main directory of |
|---|
| 7 | | - * this source tree. |
|---|
| 8 | 5 | */ |
|---|
| 9 | 6 | #include <linux/if_ether.h> |
|---|
| 10 | 7 | #include <linux/if_vlan.h> |
|---|
| .. | .. |
|---|
| 19 | 16 | { |
|---|
| 20 | 17 | struct sk_buff *skb; |
|---|
| 21 | 18 | char *eth_fr; |
|---|
| 22 | | - int fr_len; |
|---|
| 23 | 19 | struct fip_vlan *vlan; |
|---|
| 24 | 20 | #define MY_FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 }) |
|---|
| 25 | 21 | static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS; |
|---|
| 26 | 22 | unsigned long flags = 0; |
|---|
| 23 | + int rc; |
|---|
| 27 | 24 | |
|---|
| 28 | 25 | skb = dev_alloc_skb(sizeof(struct fip_vlan)); |
|---|
| 29 | | - if (!skb) |
|---|
| 26 | + if (!skb) { |
|---|
| 27 | + QEDF_ERR(&qedf->dbg_ctx, |
|---|
| 28 | + "Failed to allocate skb.\n"); |
|---|
| 30 | 29 | return; |
|---|
| 30 | + } |
|---|
| 31 | 31 | |
|---|
| 32 | | - fr_len = sizeof(*vlan); |
|---|
| 33 | 32 | eth_fr = (char *)skb->data; |
|---|
| 34 | 33 | vlan = (struct fip_vlan *)eth_fr; |
|---|
| 35 | 34 | |
|---|
| .. | .. |
|---|
| 68 | 67 | } |
|---|
| 69 | 68 | |
|---|
| 70 | 69 | set_bit(QED_LL2_XMIT_FLAGS_FIP_DISCOVERY, &flags); |
|---|
| 71 | | - qed_ops->ll2->start_xmit(qedf->cdev, skb, flags); |
|---|
| 70 | + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, flags); |
|---|
| 71 | + if (rc) { |
|---|
| 72 | + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); |
|---|
| 73 | + kfree_skb(skb); |
|---|
| 74 | + return; |
|---|
| 75 | + } |
|---|
| 76 | + |
|---|
| 72 | 77 | } |
|---|
| 73 | 78 | |
|---|
| 74 | 79 | static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf, |
|---|
| .. | .. |
|---|
| 95 | 100 | rlen -= dlen; |
|---|
| 96 | 101 | } |
|---|
| 97 | 102 | |
|---|
| 103 | + if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) { |
|---|
| 104 | + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, |
|---|
| 105 | + "Dropping VLAN response as link is down.\n"); |
|---|
| 106 | + return; |
|---|
| 107 | + } |
|---|
| 108 | + |
|---|
| 98 | 109 | QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "VLAN response, " |
|---|
| 99 | 110 | "vid=0x%x.\n", vid); |
|---|
| 100 | 111 | |
|---|
| .. | .. |
|---|
| 114 | 125 | struct fip_header *fiph; |
|---|
| 115 | 126 | u16 op, vlan_tci = 0; |
|---|
| 116 | 127 | u8 sub; |
|---|
| 128 | + int rc = -1; |
|---|
| 117 | 129 | |
|---|
| 118 | 130 | if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) { |
|---|
| 119 | 131 | QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n"); |
|---|
| .. | .. |
|---|
| 142 | 154 | print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, |
|---|
| 143 | 155 | skb->data, skb->len, false); |
|---|
| 144 | 156 | |
|---|
| 145 | | - qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); |
|---|
| 157 | + rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0); |
|---|
| 158 | + if (rc) { |
|---|
| 159 | + QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc); |
|---|
| 160 | + kfree_skb(skb); |
|---|
| 161 | + return; |
|---|
| 162 | + } |
|---|
| 146 | 163 | } |
|---|
| 164 | + |
|---|
| 165 | +static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS; |
|---|
| 147 | 166 | |
|---|
| 148 | 167 | /* Process incoming FIP frames. */ |
|---|
| 149 | 168 | void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) |
|---|
| .. | .. |
|---|
| 157 | 176 | size_t rlen, dlen; |
|---|
| 158 | 177 | u16 op; |
|---|
| 159 | 178 | u8 sub; |
|---|
| 160 | | - bool do_reset = false; |
|---|
| 179 | + bool fcf_valid = false; |
|---|
| 180 | + /* Default is to handle CVL regardless of fabric id descriptor */ |
|---|
| 181 | + bool fabric_id_valid = true; |
|---|
| 182 | + bool fc_wwpn_valid = false; |
|---|
| 183 | + u64 switch_name; |
|---|
| 184 | + u16 vlan = 0; |
|---|
| 161 | 185 | |
|---|
| 162 | 186 | eth_hdr = (struct ethhdr *)skb_mac_header(skb); |
|---|
| 163 | 187 | fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2); |
|---|
| 164 | 188 | op = ntohs(fiph->fip_op); |
|---|
| 165 | 189 | sub = fiph->fip_subcode; |
|---|
| 166 | 190 | |
|---|
| 167 | | - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame received: " |
|---|
| 168 | | - "skb=%p fiph=%p source=%pM op=%x sub=%x", skb, fiph, |
|---|
| 169 | | - eth_hdr->h_source, op, sub); |
|---|
| 191 | + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, |
|---|
| 192 | + "FIP frame received: skb=%p fiph=%p source=%pM destn=%pM op=%x sub=%x vlan=%04x", |
|---|
| 193 | + skb, fiph, eth_hdr->h_source, eth_hdr->h_dest, op, |
|---|
| 194 | + sub, vlan); |
|---|
| 170 | 195 | if (qedf_dump_frames) |
|---|
| 171 | 196 | print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1, |
|---|
| 172 | 197 | skb->data, skb->len, false); |
|---|
| 198 | + |
|---|
| 199 | + if (!ether_addr_equal(eth_hdr->h_dest, qedf->mac) && |
|---|
| 200 | + !ether_addr_equal(eth_hdr->h_dest, fcoe_all_enode) && |
|---|
| 201 | + !ether_addr_equal(eth_hdr->h_dest, qedf->data_src_addr)) { |
|---|
| 202 | + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, |
|---|
| 203 | + "Dropping FIP type 0x%x pkt due to destination MAC mismatch dest_mac=%pM ctlr.dest_addr=%pM data_src_addr=%pM.\n", |
|---|
| 204 | + op, eth_hdr->h_dest, qedf->mac, |
|---|
| 205 | + qedf->data_src_addr); |
|---|
| 206 | + kfree_skb(skb); |
|---|
| 207 | + return; |
|---|
| 208 | + } |
|---|
| 173 | 209 | |
|---|
| 174 | 210 | /* Handle FIP VLAN resp in the driver */ |
|---|
| 175 | 211 | if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) { |
|---|
| .. | .. |
|---|
| 199 | 235 | switch (desc->fip_dtype) { |
|---|
| 200 | 236 | case FIP_DT_MAC: |
|---|
| 201 | 237 | mp = (struct fip_mac_desc *)desc; |
|---|
| 202 | | - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, |
|---|
| 203 | | - "fd_mac=%pM\n", mp->fd_mac); |
|---|
| 238 | + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, |
|---|
| 239 | + "Switch fd_mac=%pM.\n", mp->fd_mac); |
|---|
| 204 | 240 | if (ether_addr_equal(mp->fd_mac, |
|---|
| 205 | 241 | qedf->ctlr.sel_fcf->fcf_mac)) |
|---|
| 206 | | - do_reset = true; |
|---|
| 242 | + fcf_valid = true; |
|---|
| 207 | 243 | break; |
|---|
| 208 | 244 | case FIP_DT_NAME: |
|---|
| 209 | 245 | wp = (struct fip_wwn_desc *)desc; |
|---|
| 210 | | - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, |
|---|
| 211 | | - "fc_wwpn=%016llx.\n", |
|---|
| 212 | | - get_unaligned_be64(&wp->fd_wwn)); |
|---|
| 246 | + switch_name = get_unaligned_be64(&wp->fd_wwn); |
|---|
| 247 | + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, |
|---|
| 248 | + "Switch fd_wwn=%016llx fcf_switch_name=%016llx.\n", |
|---|
| 249 | + switch_name, |
|---|
| 250 | + qedf->ctlr.sel_fcf->switch_name); |
|---|
| 251 | + if (switch_name == |
|---|
| 252 | + qedf->ctlr.sel_fcf->switch_name) |
|---|
| 253 | + fc_wwpn_valid = true; |
|---|
| 213 | 254 | break; |
|---|
| 214 | 255 | case FIP_DT_VN_ID: |
|---|
| 256 | + fabric_id_valid = false; |
|---|
| 215 | 257 | vp = (struct fip_vn_desc *)desc; |
|---|
| 216 | | - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, |
|---|
| 217 | | - "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id)); |
|---|
| 218 | | - if (ntoh24(vp->fd_fc_id) == |
|---|
| 219 | | - qedf->lport->port_id) |
|---|
| 220 | | - do_reset = true; |
|---|
| 258 | + |
|---|
| 259 | + QEDF_ERR(&qedf->dbg_ctx, |
|---|
| 260 | + "CVL vx_port fd_fc_id=0x%x fd_mac=%pM fd_wwpn=%016llx.\n", |
|---|
| 261 | + ntoh24(vp->fd_fc_id), vp->fd_mac, |
|---|
| 262 | + get_unaligned_be64(&vp->fd_wwpn)); |
|---|
| 263 | + /* Check for vx_port wwpn OR Check vx_port |
|---|
| 264 | + * fabric ID OR Check vx_port MAC |
|---|
| 265 | + */ |
|---|
| 266 | + if ((get_unaligned_be64(&vp->fd_wwpn) == |
|---|
| 267 | + qedf->wwpn) || |
|---|
| 268 | + (ntoh24(vp->fd_fc_id) == |
|---|
| 269 | + qedf->lport->port_id) || |
|---|
| 270 | + (ether_addr_equal(vp->fd_mac, |
|---|
| 271 | + qedf->data_src_addr))) { |
|---|
| 272 | + fabric_id_valid = true; |
|---|
| 273 | + } |
|---|
| 221 | 274 | break; |
|---|
| 222 | 275 | default: |
|---|
| 223 | 276 | /* Ignore anything else */ |
|---|
| .. | .. |
|---|
| 227 | 280 | rlen -= dlen; |
|---|
| 228 | 281 | } |
|---|
| 229 | 282 | |
|---|
| 230 | | - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, |
|---|
| 231 | | - "do_reset=%d.\n", do_reset); |
|---|
| 232 | | - if (do_reset) { |
|---|
| 233 | | - fcoe_ctlr_link_down(&qedf->ctlr); |
|---|
| 234 | | - qedf_wait_for_upload(qedf); |
|---|
| 235 | | - fcoe_ctlr_link_up(&qedf->ctlr); |
|---|
| 236 | | - } |
|---|
| 283 | + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, |
|---|
| 284 | + "fcf_valid=%d fabric_id_valid=%d fc_wwpn_valid=%d.\n", |
|---|
| 285 | + fcf_valid, fabric_id_valid, fc_wwpn_valid); |
|---|
| 286 | + if (fcf_valid && fabric_id_valid && fc_wwpn_valid) |
|---|
| 287 | + qedf_ctx_soft_reset(qedf->lport); |
|---|
| 237 | 288 | kfree_skb(skb); |
|---|
| 238 | 289 | } else { |
|---|
| 239 | 290 | /* Everything else is handled by libfcoe */ |
|---|