xref: /OK3568_Linux_fs/kernel/drivers/scsi/qedf/qedf_fip.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  QLogic FCoE Offload Driver
4*4882a593Smuzhiyun  *  Copyright (c) 2016-2018 Cavium Inc.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include <linux/if_ether.h>
7*4882a593Smuzhiyun #include <linux/if_vlan.h>
8*4882a593Smuzhiyun #include "qedf.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun extern const struct qed_fcoe_ops *qed_ops;
11*4882a593Smuzhiyun /*
12*4882a593Smuzhiyun  * FIP VLAN functions that will eventually move to libfcoe.
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
qedf_fcoe_send_vlan_req(struct qedf_ctx * qedf)15*4882a593Smuzhiyun void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	struct sk_buff *skb;
18*4882a593Smuzhiyun 	char *eth_fr;
19*4882a593Smuzhiyun 	struct fip_vlan *vlan;
20*4882a593Smuzhiyun #define MY_FIP_ALL_FCF_MACS        ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
21*4882a593Smuzhiyun 	static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS;
22*4882a593Smuzhiyun 	unsigned long flags = 0;
23*4882a593Smuzhiyun 	int rc;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	skb = dev_alloc_skb(sizeof(struct fip_vlan));
26*4882a593Smuzhiyun 	if (!skb) {
27*4882a593Smuzhiyun 		QEDF_ERR(&qedf->dbg_ctx,
28*4882a593Smuzhiyun 			 "Failed to allocate skb.\n");
29*4882a593Smuzhiyun 		return;
30*4882a593Smuzhiyun 	}
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	eth_fr = (char *)skb->data;
33*4882a593Smuzhiyun 	vlan = (struct fip_vlan *)eth_fr;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	memset(vlan, 0, sizeof(*vlan));
36*4882a593Smuzhiyun 	ether_addr_copy(vlan->eth.h_source, qedf->mac);
37*4882a593Smuzhiyun 	ether_addr_copy(vlan->eth.h_dest, my_fcoe_all_fcfs);
38*4882a593Smuzhiyun 	vlan->eth.h_proto = htons(ETH_P_FIP);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	vlan->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
41*4882a593Smuzhiyun 	vlan->fip.fip_op = htons(FIP_OP_VLAN);
42*4882a593Smuzhiyun 	vlan->fip.fip_subcode = FIP_SC_VL_REQ;
43*4882a593Smuzhiyun 	vlan->fip.fip_dl_len = htons(sizeof(vlan->desc) / FIP_BPW);
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	vlan->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC;
46*4882a593Smuzhiyun 	vlan->desc.mac.fd_desc.fip_dlen = sizeof(vlan->desc.mac) / FIP_BPW;
47*4882a593Smuzhiyun 	ether_addr_copy(vlan->desc.mac.fd_mac, qedf->mac);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	vlan->desc.wwnn.fd_desc.fip_dtype = FIP_DT_NAME;
50*4882a593Smuzhiyun 	vlan->desc.wwnn.fd_desc.fip_dlen = sizeof(vlan->desc.wwnn) / FIP_BPW;
51*4882a593Smuzhiyun 	put_unaligned_be64(qedf->lport->wwnn, &vlan->desc.wwnn.fd_wwn);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	skb_put(skb, sizeof(*vlan));
54*4882a593Smuzhiyun 	skb->protocol = htons(ETH_P_FIP);
55*4882a593Smuzhiyun 	skb_reset_mac_header(skb);
56*4882a593Smuzhiyun 	skb_reset_network_header(skb);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Sending FIP VLAN "
59*4882a593Smuzhiyun 		   "request.");
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) {
62*4882a593Smuzhiyun 		QEDF_WARN(&(qedf->dbg_ctx), "Cannot send vlan request "
63*4882a593Smuzhiyun 		    "because link is not up.\n");
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 		kfree_skb(skb);
66*4882a593Smuzhiyun 		return;
67*4882a593Smuzhiyun 	}
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	set_bit(QED_LL2_XMIT_FLAGS_FIP_DISCOVERY, &flags);
70*4882a593Smuzhiyun 	rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, flags);
71*4882a593Smuzhiyun 	if (rc) {
72*4882a593Smuzhiyun 		QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc);
73*4882a593Smuzhiyun 		kfree_skb(skb);
74*4882a593Smuzhiyun 		return;
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
qedf_fcoe_process_vlan_resp(struct qedf_ctx * qedf,struct sk_buff * skb)79*4882a593Smuzhiyun static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf,
80*4882a593Smuzhiyun 	struct sk_buff *skb)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	struct fip_header *fiph;
83*4882a593Smuzhiyun 	struct fip_desc *desc;
84*4882a593Smuzhiyun 	u16 vid = 0;
85*4882a593Smuzhiyun 	ssize_t rlen;
86*4882a593Smuzhiyun 	size_t dlen;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	fiph = (struct fip_header *)(((void *)skb->data) + 2 * ETH_ALEN + 2);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	rlen = ntohs(fiph->fip_dl_len) * 4;
91*4882a593Smuzhiyun 	desc = (struct fip_desc *)(fiph + 1);
92*4882a593Smuzhiyun 	while (rlen > 0) {
93*4882a593Smuzhiyun 		dlen = desc->fip_dlen * FIP_BPW;
94*4882a593Smuzhiyun 		switch (desc->fip_dtype) {
95*4882a593Smuzhiyun 		case FIP_DT_VLAN:
96*4882a593Smuzhiyun 			vid = ntohs(((struct fip_vlan_desc *)desc)->fd_vlan);
97*4882a593Smuzhiyun 			break;
98*4882a593Smuzhiyun 		}
99*4882a593Smuzhiyun 		desc = (struct fip_desc *)((char *)desc + dlen);
100*4882a593Smuzhiyun 		rlen -= dlen;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) {
104*4882a593Smuzhiyun 		QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
105*4882a593Smuzhiyun 			  "Dropping VLAN response as link is down.\n");
106*4882a593Smuzhiyun 		return;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "VLAN response, "
110*4882a593Smuzhiyun 		   "vid=0x%x.\n", vid);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	if (vid > 0 && qedf->vlan_id != vid) {
113*4882a593Smuzhiyun 		qedf_set_vlan_id(qedf, vid);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 		/* Inform waiter that it's ok to call fcoe_ctlr_link up() */
116*4882a593Smuzhiyun 		if (!completion_done(&qedf->fipvlan_compl))
117*4882a593Smuzhiyun 			complete(&qedf->fipvlan_compl);
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
qedf_fip_send(struct fcoe_ctlr * fip,struct sk_buff * skb)121*4882a593Smuzhiyun void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	struct qedf_ctx *qedf = container_of(fip, struct qedf_ctx, ctlr);
124*4882a593Smuzhiyun 	struct ethhdr *eth_hdr;
125*4882a593Smuzhiyun 	struct fip_header *fiph;
126*4882a593Smuzhiyun 	u16 op, vlan_tci = 0;
127*4882a593Smuzhiyun 	u8 sub;
128*4882a593Smuzhiyun 	int rc = -1;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) {
131*4882a593Smuzhiyun 		QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n");
132*4882a593Smuzhiyun 		kfree_skb(skb);
133*4882a593Smuzhiyun 		return;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2);
137*4882a593Smuzhiyun 	eth_hdr = (struct ethhdr *)skb_mac_header(skb);
138*4882a593Smuzhiyun 	op = ntohs(fiph->fip_op);
139*4882a593Smuzhiyun 	sub = fiph->fip_subcode;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/*
142*4882a593Smuzhiyun 	 * Add VLAN tag to non-offload FIP frame based on current stored VLAN
143*4882a593Smuzhiyun 	 * for FIP/FCoE traffic.
144*4882a593Smuzhiyun 	 */
145*4882a593Smuzhiyun 	__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), qedf->vlan_id);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* Get VLAN ID from skb for printing purposes */
148*4882a593Smuzhiyun 	__vlan_hwaccel_get_tag(skb, &vlan_tci);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame send: "
151*4882a593Smuzhiyun 	    "dest=%pM op=%x sub=%x vlan=%04x.", eth_hdr->h_dest, op, sub,
152*4882a593Smuzhiyun 	    vlan_tci);
153*4882a593Smuzhiyun 	if (qedf_dump_frames)
154*4882a593Smuzhiyun 		print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1,
155*4882a593Smuzhiyun 		    skb->data, skb->len, false);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
158*4882a593Smuzhiyun 	if (rc) {
159*4882a593Smuzhiyun 		QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc);
160*4882a593Smuzhiyun 		kfree_skb(skb);
161*4882a593Smuzhiyun 		return;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun /* Process incoming FIP frames. */
qedf_fip_recv(struct qedf_ctx * qedf,struct sk_buff * skb)168*4882a593Smuzhiyun void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	struct ethhdr *eth_hdr;
171*4882a593Smuzhiyun 	struct fip_header *fiph;
172*4882a593Smuzhiyun 	struct fip_desc *desc;
173*4882a593Smuzhiyun 	struct fip_mac_desc *mp;
174*4882a593Smuzhiyun 	struct fip_wwn_desc *wp;
175*4882a593Smuzhiyun 	struct fip_vn_desc *vp;
176*4882a593Smuzhiyun 	size_t rlen, dlen;
177*4882a593Smuzhiyun 	u16 op;
178*4882a593Smuzhiyun 	u8 sub;
179*4882a593Smuzhiyun 	bool fcf_valid = false;
180*4882a593Smuzhiyun 	/* Default is to handle CVL regardless of fabric id descriptor */
181*4882a593Smuzhiyun 	bool fabric_id_valid = true;
182*4882a593Smuzhiyun 	bool fc_wwpn_valid = false;
183*4882a593Smuzhiyun 	u64 switch_name;
184*4882a593Smuzhiyun 	u16 vlan = 0;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	eth_hdr = (struct ethhdr *)skb_mac_header(skb);
187*4882a593Smuzhiyun 	fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2);
188*4882a593Smuzhiyun 	op = ntohs(fiph->fip_op);
189*4882a593Smuzhiyun 	sub = fiph->fip_subcode;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
192*4882a593Smuzhiyun 		  "FIP frame received: skb=%p fiph=%p source=%pM destn=%pM op=%x sub=%x vlan=%04x",
193*4882a593Smuzhiyun 		  skb, fiph, eth_hdr->h_source, eth_hdr->h_dest, op,
194*4882a593Smuzhiyun 		  sub, vlan);
195*4882a593Smuzhiyun 	if (qedf_dump_frames)
196*4882a593Smuzhiyun 		print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1,
197*4882a593Smuzhiyun 		    skb->data, skb->len, false);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (!ether_addr_equal(eth_hdr->h_dest, qedf->mac) &&
200*4882a593Smuzhiyun 	    !ether_addr_equal(eth_hdr->h_dest, fcoe_all_enode) &&
201*4882a593Smuzhiyun 		!ether_addr_equal(eth_hdr->h_dest, qedf->data_src_addr)) {
202*4882a593Smuzhiyun 		QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
203*4882a593Smuzhiyun 			  "Dropping FIP type 0x%x pkt due to destination MAC mismatch dest_mac=%pM ctlr.dest_addr=%pM data_src_addr=%pM.\n",
204*4882a593Smuzhiyun 			  op, eth_hdr->h_dest, qedf->mac,
205*4882a593Smuzhiyun 			  qedf->data_src_addr);
206*4882a593Smuzhiyun 		kfree_skb(skb);
207*4882a593Smuzhiyun 		return;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* Handle FIP VLAN resp in the driver */
211*4882a593Smuzhiyun 	if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) {
212*4882a593Smuzhiyun 		qedf_fcoe_process_vlan_resp(qedf, skb);
213*4882a593Smuzhiyun 		kfree_skb(skb);
214*4882a593Smuzhiyun 	} else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK) {
215*4882a593Smuzhiyun 		QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Clear virtual "
216*4882a593Smuzhiyun 			   "link received.\n");
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 		/* Check that an FCF has been selected by fcoe */
219*4882a593Smuzhiyun 		if (qedf->ctlr.sel_fcf == NULL) {
220*4882a593Smuzhiyun 			QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
221*4882a593Smuzhiyun 			    "Dropping CVL since FCF has not been selected "
222*4882a593Smuzhiyun 			    "yet.");
223*4882a593Smuzhiyun 			kfree_skb(skb);
224*4882a593Smuzhiyun 			return;
225*4882a593Smuzhiyun 		}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 		/*
228*4882a593Smuzhiyun 		 * We need to loop through the CVL descriptors to determine
229*4882a593Smuzhiyun 		 * if we want to reset the fcoe link
230*4882a593Smuzhiyun 		 */
231*4882a593Smuzhiyun 		rlen = ntohs(fiph->fip_dl_len) * FIP_BPW;
232*4882a593Smuzhiyun 		desc = (struct fip_desc *)(fiph + 1);
233*4882a593Smuzhiyun 		while (rlen >= sizeof(*desc)) {
234*4882a593Smuzhiyun 			dlen = desc->fip_dlen * FIP_BPW;
235*4882a593Smuzhiyun 			switch (desc->fip_dtype) {
236*4882a593Smuzhiyun 			case FIP_DT_MAC:
237*4882a593Smuzhiyun 				mp = (struct fip_mac_desc *)desc;
238*4882a593Smuzhiyun 				QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
239*4882a593Smuzhiyun 					  "Switch fd_mac=%pM.\n", mp->fd_mac);
240*4882a593Smuzhiyun 				if (ether_addr_equal(mp->fd_mac,
241*4882a593Smuzhiyun 				    qedf->ctlr.sel_fcf->fcf_mac))
242*4882a593Smuzhiyun 					fcf_valid = true;
243*4882a593Smuzhiyun 				break;
244*4882a593Smuzhiyun 			case FIP_DT_NAME:
245*4882a593Smuzhiyun 				wp = (struct fip_wwn_desc *)desc;
246*4882a593Smuzhiyun 				switch_name = get_unaligned_be64(&wp->fd_wwn);
247*4882a593Smuzhiyun 				QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
248*4882a593Smuzhiyun 					  "Switch fd_wwn=%016llx fcf_switch_name=%016llx.\n",
249*4882a593Smuzhiyun 					  switch_name,
250*4882a593Smuzhiyun 					  qedf->ctlr.sel_fcf->switch_name);
251*4882a593Smuzhiyun 				if (switch_name ==
252*4882a593Smuzhiyun 				    qedf->ctlr.sel_fcf->switch_name)
253*4882a593Smuzhiyun 					fc_wwpn_valid = true;
254*4882a593Smuzhiyun 				break;
255*4882a593Smuzhiyun 			case FIP_DT_VN_ID:
256*4882a593Smuzhiyun 				fabric_id_valid = false;
257*4882a593Smuzhiyun 				vp = (struct fip_vn_desc *)desc;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 				QEDF_ERR(&qedf->dbg_ctx,
260*4882a593Smuzhiyun 					 "CVL vx_port fd_fc_id=0x%x fd_mac=%pM fd_wwpn=%016llx.\n",
261*4882a593Smuzhiyun 					 ntoh24(vp->fd_fc_id), vp->fd_mac,
262*4882a593Smuzhiyun 					 get_unaligned_be64(&vp->fd_wwpn));
263*4882a593Smuzhiyun 				/* Check for vx_port wwpn OR Check vx_port
264*4882a593Smuzhiyun 				 * fabric ID OR Check vx_port MAC
265*4882a593Smuzhiyun 				 */
266*4882a593Smuzhiyun 				if ((get_unaligned_be64(&vp->fd_wwpn) ==
267*4882a593Smuzhiyun 					qedf->wwpn) ||
268*4882a593Smuzhiyun 				   (ntoh24(vp->fd_fc_id) ==
269*4882a593Smuzhiyun 					qedf->lport->port_id) ||
270*4882a593Smuzhiyun 				   (ether_addr_equal(vp->fd_mac,
271*4882a593Smuzhiyun 					qedf->data_src_addr))) {
272*4882a593Smuzhiyun 					fabric_id_valid = true;
273*4882a593Smuzhiyun 				}
274*4882a593Smuzhiyun 				break;
275*4882a593Smuzhiyun 			default:
276*4882a593Smuzhiyun 				/* Ignore anything else */
277*4882a593Smuzhiyun 				break;
278*4882a593Smuzhiyun 			}
279*4882a593Smuzhiyun 			desc = (struct fip_desc *)((char *)desc + dlen);
280*4882a593Smuzhiyun 			rlen -= dlen;
281*4882a593Smuzhiyun 		}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
284*4882a593Smuzhiyun 			  "fcf_valid=%d fabric_id_valid=%d fc_wwpn_valid=%d.\n",
285*4882a593Smuzhiyun 			  fcf_valid, fabric_id_valid, fc_wwpn_valid);
286*4882a593Smuzhiyun 		if (fcf_valid && fabric_id_valid && fc_wwpn_valid)
287*4882a593Smuzhiyun 			qedf_ctx_soft_reset(qedf->lport);
288*4882a593Smuzhiyun 		kfree_skb(skb);
289*4882a593Smuzhiyun 	} else {
290*4882a593Smuzhiyun 		/* Everything else is handled by libfcoe */
291*4882a593Smuzhiyun 		__skb_pull(skb, ETH_HLEN);
292*4882a593Smuzhiyun 		fcoe_ctlr_recv(&qedf->ctlr, skb);
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
qedf_get_src_mac(struct fc_lport * lport)296*4882a593Smuzhiyun u8 *qedf_get_src_mac(struct fc_lport *lport)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	struct qedf_ctx *qedf = lport_priv(lport);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	return qedf->data_src_addr;
301*4882a593Smuzhiyun }
302