.. | .. |
---|
| 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 */ |
---|