xref: /linux/drivers/scsi/bnx2fc/bnx2fc_els.c (revision 0898782247ae533d1f4e47a06bc5d4870931b284)
1853e2bd2SBhanu Gollapudi /*
2de909d87SChad Dupuis  * bnx2fc_els.c: QLogic Linux FCoE offload driver.
3853e2bd2SBhanu Gollapudi  * This file contains helper routines that handle ELS requests
4853e2bd2SBhanu Gollapudi  * and responses.
5853e2bd2SBhanu Gollapudi  *
6cf122191SBhanu Prakash Gollapudi  * Copyright (c) 2008-2013 Broadcom Corporation
721144b80SChad Dupuis  * Copyright (c) 2014-2016 QLogic Corporation
821144b80SChad Dupuis  * Copyright (c) 2016-2017 Cavium Inc.
9853e2bd2SBhanu Gollapudi  *
10853e2bd2SBhanu Gollapudi  * This program is free software; you can redistribute it and/or modify
11853e2bd2SBhanu Gollapudi  * it under the terms of the GNU General Public License as published by
12853e2bd2SBhanu Gollapudi  * the Free Software Foundation.
13853e2bd2SBhanu Gollapudi  *
14853e2bd2SBhanu Gollapudi  * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
15853e2bd2SBhanu Gollapudi  */
16853e2bd2SBhanu Gollapudi 
17853e2bd2SBhanu Gollapudi #include "bnx2fc.h"
18853e2bd2SBhanu Gollapudi 
19853e2bd2SBhanu Gollapudi static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp,
20853e2bd2SBhanu Gollapudi 			     void *arg);
21853e2bd2SBhanu Gollapudi static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
22853e2bd2SBhanu Gollapudi 			      void *arg);
23853e2bd2SBhanu Gollapudi static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
24853e2bd2SBhanu Gollapudi 			void *data, u32 data_len,
25853e2bd2SBhanu Gollapudi 			void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
26853e2bd2SBhanu Gollapudi 			struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec);
27853e2bd2SBhanu Gollapudi 
bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg * cb_arg)28853e2bd2SBhanu Gollapudi static void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg *cb_arg)
29853e2bd2SBhanu Gollapudi {
30853e2bd2SBhanu Gollapudi 	struct bnx2fc_cmd *orig_io_req;
31853e2bd2SBhanu Gollapudi 	struct bnx2fc_cmd *rrq_req;
32853e2bd2SBhanu Gollapudi 	int rc = 0;
33853e2bd2SBhanu Gollapudi 
34853e2bd2SBhanu Gollapudi 	BUG_ON(!cb_arg);
35853e2bd2SBhanu Gollapudi 	rrq_req = cb_arg->io_req;
36853e2bd2SBhanu Gollapudi 	orig_io_req = cb_arg->aborted_io_req;
37853e2bd2SBhanu Gollapudi 	BUG_ON(!orig_io_req);
38853e2bd2SBhanu Gollapudi 	BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n",
39853e2bd2SBhanu Gollapudi 		   orig_io_req->xid, rrq_req->xid);
40853e2bd2SBhanu Gollapudi 
41853e2bd2SBhanu Gollapudi 	kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
42853e2bd2SBhanu Gollapudi 
43853e2bd2SBhanu Gollapudi 	if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rrq_req->req_flags)) {
44853e2bd2SBhanu Gollapudi 		/*
45853e2bd2SBhanu Gollapudi 		 * els req is timed out. cleanup the IO with FW and
46853e2bd2SBhanu Gollapudi 		 * drop the completion. Remove from active_cmd_queue.
47853e2bd2SBhanu Gollapudi 		 */
48853e2bd2SBhanu Gollapudi 		BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n",
49853e2bd2SBhanu Gollapudi 			   rrq_req->xid);
50853e2bd2SBhanu Gollapudi 
51853e2bd2SBhanu Gollapudi 		if (rrq_req->on_active_queue) {
52853e2bd2SBhanu Gollapudi 			list_del_init(&rrq_req->link);
53853e2bd2SBhanu Gollapudi 			rrq_req->on_active_queue = 0;
54853e2bd2SBhanu Gollapudi 			rc = bnx2fc_initiate_cleanup(rrq_req);
55853e2bd2SBhanu Gollapudi 			BUG_ON(rc);
56853e2bd2SBhanu Gollapudi 		}
57853e2bd2SBhanu Gollapudi 	}
58853e2bd2SBhanu Gollapudi 	kfree(cb_arg);
59853e2bd2SBhanu Gollapudi }
bnx2fc_send_rrq(struct bnx2fc_cmd * aborted_io_req)60853e2bd2SBhanu Gollapudi int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req)
61853e2bd2SBhanu Gollapudi {
62853e2bd2SBhanu Gollapudi 
63853e2bd2SBhanu Gollapudi 	struct fc_els_rrq rrq;
64853e2bd2SBhanu Gollapudi 	struct bnx2fc_rport *tgt = aborted_io_req->tgt;
65de08f46bSChad Dupuis 	struct fc_lport *lport = NULL;
66853e2bd2SBhanu Gollapudi 	struct bnx2fc_els_cb_arg *cb_arg = NULL;
67de08f46bSChad Dupuis 	u32 sid = 0;
68de08f46bSChad Dupuis 	u32 r_a_tov = 0;
69853e2bd2SBhanu Gollapudi 	unsigned long start = jiffies;
70853e2bd2SBhanu Gollapudi 	int rc;
71853e2bd2SBhanu Gollapudi 
72de08f46bSChad Dupuis 	if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))
73de08f46bSChad Dupuis 		return -EINVAL;
74de08f46bSChad Dupuis 
75de08f46bSChad Dupuis 	lport = tgt->rdata->local_port;
76de08f46bSChad Dupuis 	sid = tgt->sid;
77de08f46bSChad Dupuis 	r_a_tov = lport->r_a_tov;
78de08f46bSChad Dupuis 
79853e2bd2SBhanu Gollapudi 	BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n",
80853e2bd2SBhanu Gollapudi 		   aborted_io_req->xid);
81853e2bd2SBhanu Gollapudi 	memset(&rrq, 0, sizeof(rrq));
82853e2bd2SBhanu Gollapudi 
83853e2bd2SBhanu Gollapudi 	cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO);
84853e2bd2SBhanu Gollapudi 	if (!cb_arg) {
85853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n");
86853e2bd2SBhanu Gollapudi 		rc = -ENOMEM;
87853e2bd2SBhanu Gollapudi 		goto rrq_err;
88853e2bd2SBhanu Gollapudi 	}
89853e2bd2SBhanu Gollapudi 
90853e2bd2SBhanu Gollapudi 	cb_arg->aborted_io_req = aborted_io_req;
91853e2bd2SBhanu Gollapudi 
92853e2bd2SBhanu Gollapudi 	rrq.rrq_cmd = ELS_RRQ;
93853e2bd2SBhanu Gollapudi 	hton24(rrq.rrq_s_id, sid);
94853e2bd2SBhanu Gollapudi 	rrq.rrq_ox_id = htons(aborted_io_req->xid);
95619c5cb6SVlad Zolotarov 	rrq.rrq_rx_id = htons(aborted_io_req->task->rxwr_txrd.var_ctx.rx_id);
96853e2bd2SBhanu Gollapudi 
97853e2bd2SBhanu Gollapudi retry_rrq:
98853e2bd2SBhanu Gollapudi 	rc = bnx2fc_initiate_els(tgt, ELS_RRQ, &rrq, sizeof(rrq),
99853e2bd2SBhanu Gollapudi 				 bnx2fc_rrq_compl, cb_arg,
100853e2bd2SBhanu Gollapudi 				 r_a_tov);
101853e2bd2SBhanu Gollapudi 	if (rc == -ENOMEM) {
102853e2bd2SBhanu Gollapudi 		if (time_after(jiffies, start + (10 * HZ))) {
103853e2bd2SBhanu Gollapudi 			BNX2FC_ELS_DBG("rrq Failed\n");
104853e2bd2SBhanu Gollapudi 			rc = FAILED;
105853e2bd2SBhanu Gollapudi 			goto rrq_err;
106853e2bd2SBhanu Gollapudi 		}
107853e2bd2SBhanu Gollapudi 		msleep(20);
108853e2bd2SBhanu Gollapudi 		goto retry_rrq;
109853e2bd2SBhanu Gollapudi 	}
110853e2bd2SBhanu Gollapudi rrq_err:
111853e2bd2SBhanu Gollapudi 	if (rc) {
112853e2bd2SBhanu Gollapudi 		BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n",
113853e2bd2SBhanu Gollapudi 			aborted_io_req->xid);
114853e2bd2SBhanu Gollapudi 		kfree(cb_arg);
115853e2bd2SBhanu Gollapudi 		spin_lock_bh(&tgt->tgt_lock);
116853e2bd2SBhanu Gollapudi 		kref_put(&aborted_io_req->refcount, bnx2fc_cmd_release);
117853e2bd2SBhanu Gollapudi 		spin_unlock_bh(&tgt->tgt_lock);
118853e2bd2SBhanu Gollapudi 	}
119853e2bd2SBhanu Gollapudi 	return rc;
120853e2bd2SBhanu Gollapudi }
121853e2bd2SBhanu Gollapudi 
bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg * cb_arg)122853e2bd2SBhanu Gollapudi static void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg *cb_arg)
123853e2bd2SBhanu Gollapudi {
124853e2bd2SBhanu Gollapudi 	struct bnx2fc_cmd *els_req;
125853e2bd2SBhanu Gollapudi 	struct bnx2fc_rport *tgt;
126853e2bd2SBhanu Gollapudi 	struct bnx2fc_mp_req *mp_req;
127853e2bd2SBhanu Gollapudi 	struct fc_frame_header *fc_hdr;
128853e2bd2SBhanu Gollapudi 	unsigned char *buf;
129853e2bd2SBhanu Gollapudi 	void *resp_buf;
130853e2bd2SBhanu Gollapudi 	u32 resp_len, hdr_len;
131853e2bd2SBhanu Gollapudi 	u16 l2_oxid;
132853e2bd2SBhanu Gollapudi 	int frame_len;
133853e2bd2SBhanu Gollapudi 	int rc = 0;
134853e2bd2SBhanu Gollapudi 
135853e2bd2SBhanu Gollapudi 	l2_oxid = cb_arg->l2_oxid;
136853e2bd2SBhanu Gollapudi 	BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n", l2_oxid);
137853e2bd2SBhanu Gollapudi 
138853e2bd2SBhanu Gollapudi 	els_req = cb_arg->io_req;
139853e2bd2SBhanu Gollapudi 	if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &els_req->req_flags)) {
140853e2bd2SBhanu Gollapudi 		/*
141853e2bd2SBhanu Gollapudi 		 * els req is timed out. cleanup the IO with FW and
142853e2bd2SBhanu Gollapudi 		 * drop the completion. libfc will handle the els timeout
143853e2bd2SBhanu Gollapudi 		 */
144853e2bd2SBhanu Gollapudi 		if (els_req->on_active_queue) {
145853e2bd2SBhanu Gollapudi 			list_del_init(&els_req->link);
146853e2bd2SBhanu Gollapudi 			els_req->on_active_queue = 0;
147853e2bd2SBhanu Gollapudi 			rc = bnx2fc_initiate_cleanup(els_req);
148853e2bd2SBhanu Gollapudi 			BUG_ON(rc);
149853e2bd2SBhanu Gollapudi 		}
150853e2bd2SBhanu Gollapudi 		goto free_arg;
151853e2bd2SBhanu Gollapudi 	}
152853e2bd2SBhanu Gollapudi 
153853e2bd2SBhanu Gollapudi 	tgt = els_req->tgt;
154853e2bd2SBhanu Gollapudi 	mp_req = &(els_req->mp_req);
155853e2bd2SBhanu Gollapudi 	fc_hdr = &(mp_req->resp_fc_hdr);
156853e2bd2SBhanu Gollapudi 	resp_len = mp_req->resp_len;
157853e2bd2SBhanu Gollapudi 	resp_buf = mp_req->resp_buf;
158853e2bd2SBhanu Gollapudi 
159853e2bd2SBhanu Gollapudi 	buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
160853e2bd2SBhanu Gollapudi 	if (!buf) {
161853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "Unable to alloc mp buf\n");
162853e2bd2SBhanu Gollapudi 		goto free_arg;
163853e2bd2SBhanu Gollapudi 	}
164853e2bd2SBhanu Gollapudi 	hdr_len = sizeof(*fc_hdr);
165853e2bd2SBhanu Gollapudi 	if (hdr_len + resp_len > PAGE_SIZE) {
166853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "l2_els_compl: resp len is "
167853e2bd2SBhanu Gollapudi 				    "beyond page size\n");
168853e2bd2SBhanu Gollapudi 		goto free_buf;
169853e2bd2SBhanu Gollapudi 	}
170853e2bd2SBhanu Gollapudi 	memcpy(buf, fc_hdr, hdr_len);
171853e2bd2SBhanu Gollapudi 	memcpy(buf + hdr_len, resp_buf, resp_len);
172853e2bd2SBhanu Gollapudi 	frame_len = hdr_len + resp_len;
173853e2bd2SBhanu Gollapudi 
174853e2bd2SBhanu Gollapudi 	bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, l2_oxid);
175853e2bd2SBhanu Gollapudi 
176853e2bd2SBhanu Gollapudi free_buf:
177853e2bd2SBhanu Gollapudi 	kfree(buf);
178853e2bd2SBhanu Gollapudi free_arg:
179853e2bd2SBhanu Gollapudi 	kfree(cb_arg);
180853e2bd2SBhanu Gollapudi }
181853e2bd2SBhanu Gollapudi 
bnx2fc_send_adisc(struct bnx2fc_rport * tgt,struct fc_frame * fp)182853e2bd2SBhanu Gollapudi int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp)
183853e2bd2SBhanu Gollapudi {
184853e2bd2SBhanu Gollapudi 	struct fc_els_adisc *adisc;
185853e2bd2SBhanu Gollapudi 	struct fc_frame_header *fh;
186853e2bd2SBhanu Gollapudi 	struct bnx2fc_els_cb_arg *cb_arg;
187853e2bd2SBhanu Gollapudi 	struct fc_lport *lport = tgt->rdata->local_port;
188853e2bd2SBhanu Gollapudi 	u32 r_a_tov = lport->r_a_tov;
189853e2bd2SBhanu Gollapudi 	int rc;
190853e2bd2SBhanu Gollapudi 
191853e2bd2SBhanu Gollapudi 	fh = fc_frame_header_get(fp);
192853e2bd2SBhanu Gollapudi 	cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
193853e2bd2SBhanu Gollapudi 	if (!cb_arg) {
194853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n");
195853e2bd2SBhanu Gollapudi 		return -ENOMEM;
196853e2bd2SBhanu Gollapudi 	}
197853e2bd2SBhanu Gollapudi 
198853e2bd2SBhanu Gollapudi 	cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
199853e2bd2SBhanu Gollapudi 
200853e2bd2SBhanu Gollapudi 	BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n", cb_arg->l2_oxid);
201853e2bd2SBhanu Gollapudi 	adisc = fc_frame_payload_get(fp, sizeof(*adisc));
202853e2bd2SBhanu Gollapudi 	/* adisc is initialized by libfc */
203853e2bd2SBhanu Gollapudi 	rc = bnx2fc_initiate_els(tgt, ELS_ADISC, adisc, sizeof(*adisc),
204853e2bd2SBhanu Gollapudi 				 bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
205853e2bd2SBhanu Gollapudi 	if (rc)
206853e2bd2SBhanu Gollapudi 		kfree(cb_arg);
207853e2bd2SBhanu Gollapudi 	return rc;
208853e2bd2SBhanu Gollapudi }
209853e2bd2SBhanu Gollapudi 
bnx2fc_send_logo(struct bnx2fc_rport * tgt,struct fc_frame * fp)210853e2bd2SBhanu Gollapudi int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp)
211853e2bd2SBhanu Gollapudi {
212853e2bd2SBhanu Gollapudi 	struct fc_els_logo *logo;
213853e2bd2SBhanu Gollapudi 	struct fc_frame_header *fh;
214853e2bd2SBhanu Gollapudi 	struct bnx2fc_els_cb_arg *cb_arg;
215853e2bd2SBhanu Gollapudi 	struct fc_lport *lport = tgt->rdata->local_port;
216853e2bd2SBhanu Gollapudi 	u32 r_a_tov = lport->r_a_tov;
217853e2bd2SBhanu Gollapudi 	int rc;
218853e2bd2SBhanu Gollapudi 
219853e2bd2SBhanu Gollapudi 	fh = fc_frame_header_get(fp);
220853e2bd2SBhanu Gollapudi 	cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
221853e2bd2SBhanu Gollapudi 	if (!cb_arg) {
222853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n");
223853e2bd2SBhanu Gollapudi 		return -ENOMEM;
224853e2bd2SBhanu Gollapudi 	}
225853e2bd2SBhanu Gollapudi 
226853e2bd2SBhanu Gollapudi 	cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
227853e2bd2SBhanu Gollapudi 
228853e2bd2SBhanu Gollapudi 	BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n", cb_arg->l2_oxid);
229853e2bd2SBhanu Gollapudi 	logo = fc_frame_payload_get(fp, sizeof(*logo));
230853e2bd2SBhanu Gollapudi 	/* logo is initialized by libfc */
231853e2bd2SBhanu Gollapudi 	rc = bnx2fc_initiate_els(tgt, ELS_LOGO, logo, sizeof(*logo),
232853e2bd2SBhanu Gollapudi 				 bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
233853e2bd2SBhanu Gollapudi 	if (rc)
234853e2bd2SBhanu Gollapudi 		kfree(cb_arg);
235853e2bd2SBhanu Gollapudi 	return rc;
236853e2bd2SBhanu Gollapudi }
237853e2bd2SBhanu Gollapudi 
bnx2fc_send_rls(struct bnx2fc_rport * tgt,struct fc_frame * fp)238853e2bd2SBhanu Gollapudi int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp)
239853e2bd2SBhanu Gollapudi {
240853e2bd2SBhanu Gollapudi 	struct fc_els_rls *rls;
241853e2bd2SBhanu Gollapudi 	struct fc_frame_header *fh;
242853e2bd2SBhanu Gollapudi 	struct bnx2fc_els_cb_arg *cb_arg;
243853e2bd2SBhanu Gollapudi 	struct fc_lport *lport = tgt->rdata->local_port;
244853e2bd2SBhanu Gollapudi 	u32 r_a_tov = lport->r_a_tov;
245853e2bd2SBhanu Gollapudi 	int rc;
246853e2bd2SBhanu Gollapudi 
247853e2bd2SBhanu Gollapudi 	fh = fc_frame_header_get(fp);
248853e2bd2SBhanu Gollapudi 	cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
249853e2bd2SBhanu Gollapudi 	if (!cb_arg) {
250853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n");
251853e2bd2SBhanu Gollapudi 		return -ENOMEM;
252853e2bd2SBhanu Gollapudi 	}
253853e2bd2SBhanu Gollapudi 
254853e2bd2SBhanu Gollapudi 	cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
255853e2bd2SBhanu Gollapudi 
256853e2bd2SBhanu Gollapudi 	rls = fc_frame_payload_get(fp, sizeof(*rls));
257853e2bd2SBhanu Gollapudi 	/* rls is initialized by libfc */
258853e2bd2SBhanu Gollapudi 	rc = bnx2fc_initiate_els(tgt, ELS_RLS, rls, sizeof(*rls),
259853e2bd2SBhanu Gollapudi 				  bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
260853e2bd2SBhanu Gollapudi 	if (rc)
261853e2bd2SBhanu Gollapudi 		kfree(cb_arg);
262853e2bd2SBhanu Gollapudi 	return rc;
263853e2bd2SBhanu Gollapudi }
264853e2bd2SBhanu Gollapudi 
bnx2fc_srr_compl(struct bnx2fc_els_cb_arg * cb_arg)2653f7d67daSBaoyou Xie static void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg)
26674446954SBhanu Prakash Gollapudi {
26774446954SBhanu Prakash Gollapudi 	struct bnx2fc_mp_req *mp_req;
26874446954SBhanu Prakash Gollapudi 	struct fc_frame_header *fc_hdr, *fh;
26974446954SBhanu Prakash Gollapudi 	struct bnx2fc_cmd *srr_req;
27074446954SBhanu Prakash Gollapudi 	struct bnx2fc_cmd *orig_io_req;
27174446954SBhanu Prakash Gollapudi 	struct fc_frame *fp;
27274446954SBhanu Prakash Gollapudi 	unsigned char *buf;
27374446954SBhanu Prakash Gollapudi 	void *resp_buf;
27474446954SBhanu Prakash Gollapudi 	u32 resp_len, hdr_len;
27574446954SBhanu Prakash Gollapudi 	u8 opcode;
27674446954SBhanu Prakash Gollapudi 	int rc = 0;
27774446954SBhanu Prakash Gollapudi 
27874446954SBhanu Prakash Gollapudi 	orig_io_req = cb_arg->aborted_io_req;
27974446954SBhanu Prakash Gollapudi 	srr_req = cb_arg->io_req;
28074446954SBhanu Prakash Gollapudi 	if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) {
28174446954SBhanu Prakash Gollapudi 		/* SRR timedout */
28274446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(srr_req, "srr timed out, abort "
28374446954SBhanu Prakash Gollapudi 		       "orig_io - 0x%x\n",
28474446954SBhanu Prakash Gollapudi 			orig_io_req->xid);
28574446954SBhanu Prakash Gollapudi 		rc = bnx2fc_initiate_abts(srr_req);
28674446954SBhanu Prakash Gollapudi 		if (rc != SUCCESS) {
28774446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
28874446954SBhanu Prakash Gollapudi 				"failed. issue cleanup\n");
28974446954SBhanu Prakash Gollapudi 			bnx2fc_initiate_cleanup(srr_req);
29074446954SBhanu Prakash Gollapudi 		}
29132c30454SBhanu Prakash Gollapudi 		if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) ||
29232c30454SBhanu Prakash Gollapudi 		    test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
29332c30454SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(srr_req, "srr_compl:xid 0x%x flags = %lx",
29432c30454SBhanu Prakash Gollapudi 				      orig_io_req->xid, orig_io_req->req_flags);
29532c30454SBhanu Prakash Gollapudi 			goto srr_compl_done;
29632c30454SBhanu Prakash Gollapudi 		}
29774446954SBhanu Prakash Gollapudi 		orig_io_req->srr_retry++;
29874446954SBhanu Prakash Gollapudi 		if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) {
29974446954SBhanu Prakash Gollapudi 			struct bnx2fc_rport *tgt = orig_io_req->tgt;
30074446954SBhanu Prakash Gollapudi 			spin_unlock_bh(&tgt->tgt_lock);
30174446954SBhanu Prakash Gollapudi 			rc = bnx2fc_send_srr(orig_io_req,
30274446954SBhanu Prakash Gollapudi 					     orig_io_req->srr_offset,
30374446954SBhanu Prakash Gollapudi 					     orig_io_req->srr_rctl);
30474446954SBhanu Prakash Gollapudi 			spin_lock_bh(&tgt->tgt_lock);
30574446954SBhanu Prakash Gollapudi 			if (!rc)
30674446954SBhanu Prakash Gollapudi 				goto srr_compl_done;
30774446954SBhanu Prakash Gollapudi 		}
30874446954SBhanu Prakash Gollapudi 
30974446954SBhanu Prakash Gollapudi 		rc = bnx2fc_initiate_abts(orig_io_req);
31074446954SBhanu Prakash Gollapudi 		if (rc != SUCCESS) {
31174446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
31274446954SBhanu Prakash Gollapudi 				"failed xid = 0x%x. issue cleanup\n",
31374446954SBhanu Prakash Gollapudi 				orig_io_req->xid);
31474446954SBhanu Prakash Gollapudi 			bnx2fc_initiate_cleanup(orig_io_req);
31574446954SBhanu Prakash Gollapudi 		}
31674446954SBhanu Prakash Gollapudi 		goto srr_compl_done;
31774446954SBhanu Prakash Gollapudi 	}
31832c30454SBhanu Prakash Gollapudi 	if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) ||
31932c30454SBhanu Prakash Gollapudi 	    test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
32032c30454SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(srr_req, "srr_compl:xid - 0x%x flags = %lx",
32132c30454SBhanu Prakash Gollapudi 			      orig_io_req->xid, orig_io_req->req_flags);
32232c30454SBhanu Prakash Gollapudi 		goto srr_compl_done;
32332c30454SBhanu Prakash Gollapudi 	}
32474446954SBhanu Prakash Gollapudi 	mp_req = &(srr_req->mp_req);
32574446954SBhanu Prakash Gollapudi 	fc_hdr = &(mp_req->resp_fc_hdr);
32674446954SBhanu Prakash Gollapudi 	resp_len = mp_req->resp_len;
32774446954SBhanu Prakash Gollapudi 	resp_buf = mp_req->resp_buf;
32874446954SBhanu Prakash Gollapudi 
32974446954SBhanu Prakash Gollapudi 	hdr_len = sizeof(*fc_hdr);
33074446954SBhanu Prakash Gollapudi 	buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
33174446954SBhanu Prakash Gollapudi 	if (!buf) {
33274446954SBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "srr buf: mem alloc failure\n");
33374446954SBhanu Prakash Gollapudi 		goto srr_compl_done;
33474446954SBhanu Prakash Gollapudi 	}
33574446954SBhanu Prakash Gollapudi 	memcpy(buf, fc_hdr, hdr_len);
33674446954SBhanu Prakash Gollapudi 	memcpy(buf + hdr_len, resp_buf, resp_len);
33774446954SBhanu Prakash Gollapudi 
33874446954SBhanu Prakash Gollapudi 	fp = fc_frame_alloc(NULL, resp_len);
33974446954SBhanu Prakash Gollapudi 	if (!fp) {
34074446954SBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "fc_frame_alloc failure\n");
34174446954SBhanu Prakash Gollapudi 		goto free_buf;
34274446954SBhanu Prakash Gollapudi 	}
34374446954SBhanu Prakash Gollapudi 
34474446954SBhanu Prakash Gollapudi 	fh = (struct fc_frame_header *) fc_frame_header_get(fp);
34574446954SBhanu Prakash Gollapudi 	/* Copy FC Frame header and payload into the frame */
34674446954SBhanu Prakash Gollapudi 	memcpy(fh, buf, hdr_len + resp_len);
34774446954SBhanu Prakash Gollapudi 
34874446954SBhanu Prakash Gollapudi 	opcode = fc_frame_payload_op(fp);
34974446954SBhanu Prakash Gollapudi 	switch (opcode) {
35074446954SBhanu Prakash Gollapudi 	case ELS_LS_ACC:
35174446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(srr_req, "SRR success\n");
35274446954SBhanu Prakash Gollapudi 		break;
35374446954SBhanu Prakash Gollapudi 	case ELS_LS_RJT:
35474446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(srr_req, "SRR rejected\n");
35574446954SBhanu Prakash Gollapudi 		rc = bnx2fc_initiate_abts(orig_io_req);
35674446954SBhanu Prakash Gollapudi 		if (rc != SUCCESS) {
35774446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
35874446954SBhanu Prakash Gollapudi 				"failed xid = 0x%x. issue cleanup\n",
35974446954SBhanu Prakash Gollapudi 				orig_io_req->xid);
36074446954SBhanu Prakash Gollapudi 			bnx2fc_initiate_cleanup(orig_io_req);
36174446954SBhanu Prakash Gollapudi 		}
36274446954SBhanu Prakash Gollapudi 		break;
36374446954SBhanu Prakash Gollapudi 	default:
36474446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(srr_req, "srr compl - invalid opcode = %d\n",
36574446954SBhanu Prakash Gollapudi 			opcode);
36674446954SBhanu Prakash Gollapudi 		break;
36774446954SBhanu Prakash Gollapudi 	}
36874446954SBhanu Prakash Gollapudi 	fc_frame_free(fp);
36974446954SBhanu Prakash Gollapudi free_buf:
37074446954SBhanu Prakash Gollapudi 	kfree(buf);
37174446954SBhanu Prakash Gollapudi srr_compl_done:
37274446954SBhanu Prakash Gollapudi 	kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
37374446954SBhanu Prakash Gollapudi }
37474446954SBhanu Prakash Gollapudi 
bnx2fc_rec_compl(struct bnx2fc_els_cb_arg * cb_arg)3753f7d67daSBaoyou Xie static void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg)
37674446954SBhanu Prakash Gollapudi {
37774446954SBhanu Prakash Gollapudi 	struct bnx2fc_cmd *orig_io_req, *new_io_req;
37874446954SBhanu Prakash Gollapudi 	struct bnx2fc_cmd *rec_req;
37974446954SBhanu Prakash Gollapudi 	struct bnx2fc_mp_req *mp_req;
38074446954SBhanu Prakash Gollapudi 	struct fc_frame_header *fc_hdr, *fh;
38174446954SBhanu Prakash Gollapudi 	struct fc_els_ls_rjt *rjt;
38274446954SBhanu Prakash Gollapudi 	struct fc_els_rec_acc *acc;
38374446954SBhanu Prakash Gollapudi 	struct bnx2fc_rport *tgt;
38474446954SBhanu Prakash Gollapudi 	struct fcoe_err_report_entry *err_entry;
38574446954SBhanu Prakash Gollapudi 	struct scsi_cmnd *sc_cmd;
38674446954SBhanu Prakash Gollapudi 	enum fc_rctl r_ctl;
38774446954SBhanu Prakash Gollapudi 	unsigned char *buf;
38874446954SBhanu Prakash Gollapudi 	void *resp_buf;
38974446954SBhanu Prakash Gollapudi 	struct fc_frame *fp;
39074446954SBhanu Prakash Gollapudi 	u8 opcode;
39174446954SBhanu Prakash Gollapudi 	u32 offset;
39274446954SBhanu Prakash Gollapudi 	u32 e_stat;
39374446954SBhanu Prakash Gollapudi 	u32 resp_len, hdr_len;
39474446954SBhanu Prakash Gollapudi 	int rc = 0;
39574446954SBhanu Prakash Gollapudi 	bool send_seq_clnp = false;
39674446954SBhanu Prakash Gollapudi 	bool abort_io = false;
39774446954SBhanu Prakash Gollapudi 
39874446954SBhanu Prakash Gollapudi 	BNX2FC_MISC_DBG("Entered rec_compl callback\n");
39974446954SBhanu Prakash Gollapudi 	rec_req = cb_arg->io_req;
40074446954SBhanu Prakash Gollapudi 	orig_io_req = cb_arg->aborted_io_req;
40174446954SBhanu Prakash Gollapudi 	BNX2FC_IO_DBG(rec_req, "rec_compl: orig xid = 0x%x", orig_io_req->xid);
40274446954SBhanu Prakash Gollapudi 	tgt = orig_io_req->tgt;
40374446954SBhanu Prakash Gollapudi 
40474446954SBhanu Prakash Gollapudi 	/* Handle REC timeout case */
40574446954SBhanu Prakash Gollapudi 	if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rec_req->req_flags)) {
40674446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(rec_req, "timed out, abort "
40774446954SBhanu Prakash Gollapudi 		       "orig_io - 0x%x\n",
40874446954SBhanu Prakash Gollapudi 			orig_io_req->xid);
40974446954SBhanu Prakash Gollapudi 		/* els req is timed out. send abts for els */
41074446954SBhanu Prakash Gollapudi 		rc = bnx2fc_initiate_abts(rec_req);
41174446954SBhanu Prakash Gollapudi 		if (rc != SUCCESS) {
41274446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
41374446954SBhanu Prakash Gollapudi 				"failed. issue cleanup\n");
41474446954SBhanu Prakash Gollapudi 			bnx2fc_initiate_cleanup(rec_req);
41574446954SBhanu Prakash Gollapudi 		}
41674446954SBhanu Prakash Gollapudi 		orig_io_req->rec_retry++;
41774446954SBhanu Prakash Gollapudi 		/* REC timedout. send ABTS to the orig IO req */
41874446954SBhanu Prakash Gollapudi 		if (orig_io_req->rec_retry <= REC_RETRY_COUNT) {
41974446954SBhanu Prakash Gollapudi 			spin_unlock_bh(&tgt->tgt_lock);
42074446954SBhanu Prakash Gollapudi 			rc = bnx2fc_send_rec(orig_io_req);
42174446954SBhanu Prakash Gollapudi 			spin_lock_bh(&tgt->tgt_lock);
42274446954SBhanu Prakash Gollapudi 			if (!rc)
42374446954SBhanu Prakash Gollapudi 				goto rec_compl_done;
42474446954SBhanu Prakash Gollapudi 		}
42574446954SBhanu Prakash Gollapudi 		rc = bnx2fc_initiate_abts(orig_io_req);
42674446954SBhanu Prakash Gollapudi 		if (rc != SUCCESS) {
42774446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
42874446954SBhanu Prakash Gollapudi 				"failed xid = 0x%x. issue cleanup\n",
42974446954SBhanu Prakash Gollapudi 				orig_io_req->xid);
43074446954SBhanu Prakash Gollapudi 			bnx2fc_initiate_cleanup(orig_io_req);
43174446954SBhanu Prakash Gollapudi 		}
43274446954SBhanu Prakash Gollapudi 		goto rec_compl_done;
43374446954SBhanu Prakash Gollapudi 	}
434c1c16bd5SBhanu Prakash Gollapudi 
435c1c16bd5SBhanu Prakash Gollapudi 	if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) {
436c1c16bd5SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(rec_req, "completed"
437c1c16bd5SBhanu Prakash Gollapudi 		       "orig_io - 0x%x\n",
438c1c16bd5SBhanu Prakash Gollapudi 			orig_io_req->xid);
439c1c16bd5SBhanu Prakash Gollapudi 		goto rec_compl_done;
440c1c16bd5SBhanu Prakash Gollapudi 	}
441c1c16bd5SBhanu Prakash Gollapudi 	if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
442c1c16bd5SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(rec_req, "abts in prog "
443c1c16bd5SBhanu Prakash Gollapudi 		       "orig_io - 0x%x\n",
444c1c16bd5SBhanu Prakash Gollapudi 			orig_io_req->xid);
445c1c16bd5SBhanu Prakash Gollapudi 		goto rec_compl_done;
446c1c16bd5SBhanu Prakash Gollapudi 	}
447c1c16bd5SBhanu Prakash Gollapudi 
44874446954SBhanu Prakash Gollapudi 	mp_req = &(rec_req->mp_req);
44974446954SBhanu Prakash Gollapudi 	fc_hdr = &(mp_req->resp_fc_hdr);
45074446954SBhanu Prakash Gollapudi 	resp_len = mp_req->resp_len;
45174446954SBhanu Prakash Gollapudi 	acc = resp_buf = mp_req->resp_buf;
45274446954SBhanu Prakash Gollapudi 
45374446954SBhanu Prakash Gollapudi 	hdr_len = sizeof(*fc_hdr);
45474446954SBhanu Prakash Gollapudi 
45574446954SBhanu Prakash Gollapudi 	buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
45674446954SBhanu Prakash Gollapudi 	if (!buf) {
45774446954SBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "rec buf: mem alloc failure\n");
45874446954SBhanu Prakash Gollapudi 		goto rec_compl_done;
45974446954SBhanu Prakash Gollapudi 	}
46074446954SBhanu Prakash Gollapudi 	memcpy(buf, fc_hdr, hdr_len);
46174446954SBhanu Prakash Gollapudi 	memcpy(buf + hdr_len, resp_buf, resp_len);
46274446954SBhanu Prakash Gollapudi 
46374446954SBhanu Prakash Gollapudi 	fp = fc_frame_alloc(NULL, resp_len);
46474446954SBhanu Prakash Gollapudi 	if (!fp) {
46574446954SBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "fc_frame_alloc failure\n");
46674446954SBhanu Prakash Gollapudi 		goto free_buf;
46774446954SBhanu Prakash Gollapudi 	}
46874446954SBhanu Prakash Gollapudi 
46974446954SBhanu Prakash Gollapudi 	fh = (struct fc_frame_header *) fc_frame_header_get(fp);
47074446954SBhanu Prakash Gollapudi 	/* Copy FC Frame header and payload into the frame */
47174446954SBhanu Prakash Gollapudi 	memcpy(fh, buf, hdr_len + resp_len);
47274446954SBhanu Prakash Gollapudi 
47374446954SBhanu Prakash Gollapudi 	opcode = fc_frame_payload_op(fp);
47474446954SBhanu Prakash Gollapudi 	if (opcode == ELS_LS_RJT) {
47574446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(rec_req, "opcode is RJT\n");
47674446954SBhanu Prakash Gollapudi 		rjt = fc_frame_payload_get(fp, sizeof(*rjt));
47774446954SBhanu Prakash Gollapudi 		if ((rjt->er_reason == ELS_RJT_LOGIC ||
47874446954SBhanu Prakash Gollapudi 		    rjt->er_reason == ELS_RJT_UNAB) &&
47974446954SBhanu Prakash Gollapudi 		    rjt->er_explan == ELS_EXPL_OXID_RXID) {
48074446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "handle CMD LOST case\n");
48174446954SBhanu Prakash Gollapudi 			new_io_req = bnx2fc_cmd_alloc(tgt);
48274446954SBhanu Prakash Gollapudi 			if (!new_io_req)
48374446954SBhanu Prakash Gollapudi 				goto abort_io;
48474446954SBhanu Prakash Gollapudi 			new_io_req->sc_cmd = orig_io_req->sc_cmd;
48574446954SBhanu Prakash Gollapudi 			/* cleanup orig_io_req that is with the FW */
48674446954SBhanu Prakash Gollapudi 			set_bit(BNX2FC_FLAG_CMD_LOST,
48774446954SBhanu Prakash Gollapudi 				&orig_io_req->req_flags);
48874446954SBhanu Prakash Gollapudi 			bnx2fc_initiate_cleanup(orig_io_req);
48974446954SBhanu Prakash Gollapudi 			/* Post a new IO req with the same sc_cmd */
49074446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "Post IO request again\n");
49174446954SBhanu Prakash Gollapudi 			rc = bnx2fc_post_io_req(tgt, new_io_req);
49274446954SBhanu Prakash Gollapudi 			if (!rc)
49374446954SBhanu Prakash Gollapudi 				goto free_frame;
49474446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "REC: io post err\n");
49574446954SBhanu Prakash Gollapudi 		}
49674446954SBhanu Prakash Gollapudi abort_io:
49774446954SBhanu Prakash Gollapudi 		rc = bnx2fc_initiate_abts(orig_io_req);
49874446954SBhanu Prakash Gollapudi 		if (rc != SUCCESS) {
49974446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
50074446954SBhanu Prakash Gollapudi 				"failed. issue cleanup\n");
50174446954SBhanu Prakash Gollapudi 			bnx2fc_initiate_cleanup(orig_io_req);
50274446954SBhanu Prakash Gollapudi 		}
50374446954SBhanu Prakash Gollapudi 	} else if (opcode == ELS_LS_ACC) {
50474446954SBhanu Prakash Gollapudi 		/* REVISIT: Check if the exchange is already aborted */
50574446954SBhanu Prakash Gollapudi 		offset = ntohl(acc->reca_fc4value);
50674446954SBhanu Prakash Gollapudi 		e_stat = ntohl(acc->reca_e_stat);
50774446954SBhanu Prakash Gollapudi 		if (e_stat & ESB_ST_SEQ_INIT)  {
50874446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "target has the seq init\n");
50974446954SBhanu Prakash Gollapudi 			goto free_frame;
51074446954SBhanu Prakash Gollapudi 		}
51174446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(rec_req, "e_stat = 0x%x, offset = 0x%x\n",
51274446954SBhanu Prakash Gollapudi 			e_stat, offset);
51374446954SBhanu Prakash Gollapudi 		/* Seq initiative is with us */
51474446954SBhanu Prakash Gollapudi 		err_entry = (struct fcoe_err_report_entry *)
51574446954SBhanu Prakash Gollapudi 			     &orig_io_req->err_entry;
51674446954SBhanu Prakash Gollapudi 		sc_cmd = orig_io_req->sc_cmd;
51774446954SBhanu Prakash Gollapudi 		if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
51874446954SBhanu Prakash Gollapudi 			/* SCSI WRITE command */
51974446954SBhanu Prakash Gollapudi 			if (offset == orig_io_req->data_xfer_len) {
52074446954SBhanu Prakash Gollapudi 				BNX2FC_IO_DBG(rec_req, "WRITE - resp lost\n");
52174446954SBhanu Prakash Gollapudi 				/* FCP_RSP lost */
52274446954SBhanu Prakash Gollapudi 				r_ctl = FC_RCTL_DD_CMD_STATUS;
52374446954SBhanu Prakash Gollapudi 				offset = 0;
52474446954SBhanu Prakash Gollapudi 			} else  {
52574446954SBhanu Prakash Gollapudi 				/* start transmitting from offset */
52674446954SBhanu Prakash Gollapudi 				BNX2FC_IO_DBG(rec_req, "XFER_RDY/DATA lost\n");
52774446954SBhanu Prakash Gollapudi 				send_seq_clnp = true;
52874446954SBhanu Prakash Gollapudi 				r_ctl = FC_RCTL_DD_DATA_DESC;
52974446954SBhanu Prakash Gollapudi 				if (bnx2fc_initiate_seq_cleanup(orig_io_req,
53074446954SBhanu Prakash Gollapudi 								offset, r_ctl))
53174446954SBhanu Prakash Gollapudi 					abort_io = true;
53274446954SBhanu Prakash Gollapudi 				/* XFER_RDY */
53374446954SBhanu Prakash Gollapudi 			}
53474446954SBhanu Prakash Gollapudi 		} else {
53574446954SBhanu Prakash Gollapudi 			/* SCSI READ command */
53674446954SBhanu Prakash Gollapudi 			if (err_entry->data.rx_buf_off ==
53774446954SBhanu Prakash Gollapudi 					orig_io_req->data_xfer_len) {
53874446954SBhanu Prakash Gollapudi 				/* FCP_RSP lost */
53974446954SBhanu Prakash Gollapudi 				BNX2FC_IO_DBG(rec_req, "READ - resp lost\n");
54074446954SBhanu Prakash Gollapudi 				r_ctl = FC_RCTL_DD_CMD_STATUS;
54174446954SBhanu Prakash Gollapudi 				offset = 0;
54274446954SBhanu Prakash Gollapudi 			} else  {
54374446954SBhanu Prakash Gollapudi 				/* request retransmission from this offset */
54474446954SBhanu Prakash Gollapudi 				send_seq_clnp = true;
54574446954SBhanu Prakash Gollapudi 				offset = err_entry->data.rx_buf_off;
54674446954SBhanu Prakash Gollapudi 				BNX2FC_IO_DBG(rec_req, "RD DATA lost\n");
54774446954SBhanu Prakash Gollapudi 				/* FCP_DATA lost */
54874446954SBhanu Prakash Gollapudi 				r_ctl = FC_RCTL_DD_SOL_DATA;
54974446954SBhanu Prakash Gollapudi 				if (bnx2fc_initiate_seq_cleanup(orig_io_req,
55074446954SBhanu Prakash Gollapudi 								offset, r_ctl))
55174446954SBhanu Prakash Gollapudi 					abort_io = true;
55274446954SBhanu Prakash Gollapudi 			}
55374446954SBhanu Prakash Gollapudi 		}
55474446954SBhanu Prakash Gollapudi 		if (abort_io) {
55574446954SBhanu Prakash Gollapudi 			rc = bnx2fc_initiate_abts(orig_io_req);
55674446954SBhanu Prakash Gollapudi 			if (rc != SUCCESS) {
55774446954SBhanu Prakash Gollapudi 				BNX2FC_IO_DBG(rec_req, "rec_compl:initiate_abts"
55874446954SBhanu Prakash Gollapudi 					      " failed. issue cleanup\n");
55974446954SBhanu Prakash Gollapudi 				bnx2fc_initiate_cleanup(orig_io_req);
56074446954SBhanu Prakash Gollapudi 			}
56174446954SBhanu Prakash Gollapudi 		} else if (!send_seq_clnp) {
56274446954SBhanu Prakash Gollapudi 			BNX2FC_IO_DBG(rec_req, "Send SRR - FCP_RSP\n");
56374446954SBhanu Prakash Gollapudi 			spin_unlock_bh(&tgt->tgt_lock);
56474446954SBhanu Prakash Gollapudi 			rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl);
56574446954SBhanu Prakash Gollapudi 			spin_lock_bh(&tgt->tgt_lock);
56674446954SBhanu Prakash Gollapudi 
56774446954SBhanu Prakash Gollapudi 			if (rc) {
56874446954SBhanu Prakash Gollapudi 				BNX2FC_IO_DBG(rec_req, "Unable to send SRR"
56974446954SBhanu Prakash Gollapudi 					" IO will abort\n");
57074446954SBhanu Prakash Gollapudi 			}
57174446954SBhanu Prakash Gollapudi 		}
57274446954SBhanu Prakash Gollapudi 	}
57374446954SBhanu Prakash Gollapudi free_frame:
57474446954SBhanu Prakash Gollapudi 	fc_frame_free(fp);
57574446954SBhanu Prakash Gollapudi free_buf:
57674446954SBhanu Prakash Gollapudi 	kfree(buf);
57774446954SBhanu Prakash Gollapudi rec_compl_done:
57874446954SBhanu Prakash Gollapudi 	kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
57974446954SBhanu Prakash Gollapudi 	kfree(cb_arg);
58074446954SBhanu Prakash Gollapudi }
58174446954SBhanu Prakash Gollapudi 
bnx2fc_send_rec(struct bnx2fc_cmd * orig_io_req)5826c5a7ce4SBhanu Prakash Gollapudi int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req)
5836c5a7ce4SBhanu Prakash Gollapudi {
58474446954SBhanu Prakash Gollapudi 	struct fc_els_rec rec;
58574446954SBhanu Prakash Gollapudi 	struct bnx2fc_rport *tgt = orig_io_req->tgt;
58674446954SBhanu Prakash Gollapudi 	struct fc_lport *lport = tgt->rdata->local_port;
58774446954SBhanu Prakash Gollapudi 	struct bnx2fc_els_cb_arg *cb_arg = NULL;
58874446954SBhanu Prakash Gollapudi 	u32 sid = tgt->sid;
58974446954SBhanu Prakash Gollapudi 	u32 r_a_tov = lport->r_a_tov;
59074446954SBhanu Prakash Gollapudi 	int rc;
59174446954SBhanu Prakash Gollapudi 
59274446954SBhanu Prakash Gollapudi 	BNX2FC_IO_DBG(orig_io_req, "Sending REC\n");
59374446954SBhanu Prakash Gollapudi 	memset(&rec, 0, sizeof(rec));
59474446954SBhanu Prakash Gollapudi 
59574446954SBhanu Prakash Gollapudi 	cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
59674446954SBhanu Prakash Gollapudi 	if (!cb_arg) {
59774446954SBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n");
59874446954SBhanu Prakash Gollapudi 		rc = -ENOMEM;
59974446954SBhanu Prakash Gollapudi 		goto rec_err;
60074446954SBhanu Prakash Gollapudi 	}
60174446954SBhanu Prakash Gollapudi 	kref_get(&orig_io_req->refcount);
60274446954SBhanu Prakash Gollapudi 
60374446954SBhanu Prakash Gollapudi 	cb_arg->aborted_io_req = orig_io_req;
60474446954SBhanu Prakash Gollapudi 
60574446954SBhanu Prakash Gollapudi 	rec.rec_cmd = ELS_REC;
60674446954SBhanu Prakash Gollapudi 	hton24(rec.rec_s_id, sid);
60774446954SBhanu Prakash Gollapudi 	rec.rec_ox_id = htons(orig_io_req->xid);
60874446954SBhanu Prakash Gollapudi 	rec.rec_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
60974446954SBhanu Prakash Gollapudi 
61074446954SBhanu Prakash Gollapudi 	rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec),
61174446954SBhanu Prakash Gollapudi 				 bnx2fc_rec_compl, cb_arg,
61274446954SBhanu Prakash Gollapudi 				 r_a_tov);
61374446954SBhanu Prakash Gollapudi 	if (rc) {
61474446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n");
61574446954SBhanu Prakash Gollapudi 		spin_lock_bh(&tgt->tgt_lock);
61674446954SBhanu Prakash Gollapudi 		kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
61774446954SBhanu Prakash Gollapudi 		spin_unlock_bh(&tgt->tgt_lock);
61874446954SBhanu Prakash Gollapudi 		kfree(cb_arg);
61974446954SBhanu Prakash Gollapudi 	}
620177709c0SLin Yi rec_err:
62174446954SBhanu Prakash Gollapudi 	return rc;
6226c5a7ce4SBhanu Prakash Gollapudi }
6236c5a7ce4SBhanu Prakash Gollapudi 
bnx2fc_send_srr(struct bnx2fc_cmd * orig_io_req,u32 offset,u8 r_ctl)6246c5a7ce4SBhanu Prakash Gollapudi int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl)
6256c5a7ce4SBhanu Prakash Gollapudi {
62674446954SBhanu Prakash Gollapudi 	struct fcp_srr srr;
62774446954SBhanu Prakash Gollapudi 	struct bnx2fc_rport *tgt = orig_io_req->tgt;
62874446954SBhanu Prakash Gollapudi 	struct fc_lport *lport = tgt->rdata->local_port;
62974446954SBhanu Prakash Gollapudi 	struct bnx2fc_els_cb_arg *cb_arg = NULL;
63074446954SBhanu Prakash Gollapudi 	u32 r_a_tov = lport->r_a_tov;
63174446954SBhanu Prakash Gollapudi 	int rc;
63274446954SBhanu Prakash Gollapudi 
63374446954SBhanu Prakash Gollapudi 	BNX2FC_IO_DBG(orig_io_req, "Sending SRR\n");
63474446954SBhanu Prakash Gollapudi 	memset(&srr, 0, sizeof(srr));
63574446954SBhanu Prakash Gollapudi 
63674446954SBhanu Prakash Gollapudi 	cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
63774446954SBhanu Prakash Gollapudi 	if (!cb_arg) {
63874446954SBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n");
63974446954SBhanu Prakash Gollapudi 		rc = -ENOMEM;
64074446954SBhanu Prakash Gollapudi 		goto srr_err;
6416c5a7ce4SBhanu Prakash Gollapudi 	}
64274446954SBhanu Prakash Gollapudi 	kref_get(&orig_io_req->refcount);
6436c5a7ce4SBhanu Prakash Gollapudi 
64474446954SBhanu Prakash Gollapudi 	cb_arg->aborted_io_req = orig_io_req;
6456c5a7ce4SBhanu Prakash Gollapudi 
64674446954SBhanu Prakash Gollapudi 	srr.srr_op = ELS_SRR;
64774446954SBhanu Prakash Gollapudi 	srr.srr_ox_id = htons(orig_io_req->xid);
64874446954SBhanu Prakash Gollapudi 	srr.srr_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
64974446954SBhanu Prakash Gollapudi 	srr.srr_rel_off = htonl(offset);
65074446954SBhanu Prakash Gollapudi 	srr.srr_r_ctl = r_ctl;
65174446954SBhanu Prakash Gollapudi 	orig_io_req->srr_offset = offset;
65274446954SBhanu Prakash Gollapudi 	orig_io_req->srr_rctl = r_ctl;
65374446954SBhanu Prakash Gollapudi 
65474446954SBhanu Prakash Gollapudi 	rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr),
65574446954SBhanu Prakash Gollapudi 				 bnx2fc_srr_compl, cb_arg,
65674446954SBhanu Prakash Gollapudi 				 r_a_tov);
65774446954SBhanu Prakash Gollapudi 	if (rc) {
65874446954SBhanu Prakash Gollapudi 		BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n");
65974446954SBhanu Prakash Gollapudi 		spin_lock_bh(&tgt->tgt_lock);
66074446954SBhanu Prakash Gollapudi 		kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
66174446954SBhanu Prakash Gollapudi 		spin_unlock_bh(&tgt->tgt_lock);
66274446954SBhanu Prakash Gollapudi 		kfree(cb_arg);
66374446954SBhanu Prakash Gollapudi 	} else
66474446954SBhanu Prakash Gollapudi 		set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags);
66574446954SBhanu Prakash Gollapudi 
666*7bfe5ae5SLin Yi srr_err:
66774446954SBhanu Prakash Gollapudi 	return rc;
66874446954SBhanu Prakash Gollapudi }
6696c5a7ce4SBhanu Prakash Gollapudi 
bnx2fc_initiate_els(struct bnx2fc_rport * tgt,unsigned int op,void * data,u32 data_len,void (* cb_func)(struct bnx2fc_els_cb_arg * cb_arg),struct bnx2fc_els_cb_arg * cb_arg,u32 timer_msec)670853e2bd2SBhanu Gollapudi static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
671853e2bd2SBhanu Gollapudi 			void *data, u32 data_len,
672853e2bd2SBhanu Gollapudi 			void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
673853e2bd2SBhanu Gollapudi 			struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec)
674853e2bd2SBhanu Gollapudi {
675853e2bd2SBhanu Gollapudi 	struct fcoe_port *port = tgt->port;
676aea71a02SBhanu Prakash Gollapudi 	struct bnx2fc_interface *interface = port->priv;
677853e2bd2SBhanu Gollapudi 	struct fc_rport *rport = tgt->rport;
678853e2bd2SBhanu Gollapudi 	struct fc_lport *lport = port->lport;
679853e2bd2SBhanu Gollapudi 	struct bnx2fc_cmd *els_req;
680853e2bd2SBhanu Gollapudi 	struct bnx2fc_mp_req *mp_req;
681853e2bd2SBhanu Gollapudi 	struct fc_frame_header *fc_hdr;
682853e2bd2SBhanu Gollapudi 	struct fcoe_task_ctx_entry *task;
683853e2bd2SBhanu Gollapudi 	struct fcoe_task_ctx_entry *task_page;
684853e2bd2SBhanu Gollapudi 	int rc = 0;
685853e2bd2SBhanu Gollapudi 	int task_idx, index;
686853e2bd2SBhanu Gollapudi 	u32 did, sid;
687853e2bd2SBhanu Gollapudi 	u16 xid;
688853e2bd2SBhanu Gollapudi 
689853e2bd2SBhanu Gollapudi 	rc = fc_remote_port_chkready(rport);
690853e2bd2SBhanu Gollapudi 	if (rc) {
691b2a554ffSBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "els 0x%x: rport not ready\n", op);
692853e2bd2SBhanu Gollapudi 		rc = -EINVAL;
693853e2bd2SBhanu Gollapudi 		goto els_err;
694853e2bd2SBhanu Gollapudi 	}
695853e2bd2SBhanu Gollapudi 	if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
696b2a554ffSBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "els 0x%x: link is not ready\n", op);
697853e2bd2SBhanu Gollapudi 		rc = -EINVAL;
698853e2bd2SBhanu Gollapudi 		goto els_err;
699853e2bd2SBhanu Gollapudi 	}
70050a87414SChad Dupuis 	if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) {
701853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op);
702853e2bd2SBhanu Gollapudi 		rc = -EINVAL;
703853e2bd2SBhanu Gollapudi 		goto els_err;
704853e2bd2SBhanu Gollapudi 	}
705853e2bd2SBhanu Gollapudi 	els_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ELS);
706853e2bd2SBhanu Gollapudi 	if (!els_req) {
707853e2bd2SBhanu Gollapudi 		rc = -ENOMEM;
708853e2bd2SBhanu Gollapudi 		goto els_err;
709853e2bd2SBhanu Gollapudi 	}
710853e2bd2SBhanu Gollapudi 
711853e2bd2SBhanu Gollapudi 	els_req->sc_cmd = NULL;
712853e2bd2SBhanu Gollapudi 	els_req->port = port;
713853e2bd2SBhanu Gollapudi 	els_req->tgt = tgt;
714853e2bd2SBhanu Gollapudi 	els_req->cb_func = cb_func;
715853e2bd2SBhanu Gollapudi 	cb_arg->io_req = els_req;
716853e2bd2SBhanu Gollapudi 	els_req->cb_arg = cb_arg;
7171fffa199SChad Dupuis 	els_req->data_xfer_len = data_len;
718853e2bd2SBhanu Gollapudi 
719853e2bd2SBhanu Gollapudi 	mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req);
720853e2bd2SBhanu Gollapudi 	rc = bnx2fc_init_mp_req(els_req);
721853e2bd2SBhanu Gollapudi 	if (rc == FAILED) {
722b2a554ffSBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "ELS MP request init failed\n");
723853e2bd2SBhanu Gollapudi 		spin_lock_bh(&tgt->tgt_lock);
724853e2bd2SBhanu Gollapudi 		kref_put(&els_req->refcount, bnx2fc_cmd_release);
725853e2bd2SBhanu Gollapudi 		spin_unlock_bh(&tgt->tgt_lock);
726853e2bd2SBhanu Gollapudi 		rc = -ENOMEM;
727853e2bd2SBhanu Gollapudi 		goto els_err;
728853e2bd2SBhanu Gollapudi 	} else {
729853e2bd2SBhanu Gollapudi 		/* rc SUCCESS */
730853e2bd2SBhanu Gollapudi 		rc = 0;
731853e2bd2SBhanu Gollapudi 	}
732853e2bd2SBhanu Gollapudi 
733853e2bd2SBhanu Gollapudi 	/* Set the data_xfer_len to the size of ELS payload */
734853e2bd2SBhanu Gollapudi 	mp_req->req_len = data_len;
735853e2bd2SBhanu Gollapudi 	els_req->data_xfer_len = mp_req->req_len;
736853e2bd2SBhanu Gollapudi 
737853e2bd2SBhanu Gollapudi 	/* Fill ELS Payload */
738853e2bd2SBhanu Gollapudi 	if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) {
739853e2bd2SBhanu Gollapudi 		memcpy(mp_req->req_buf, data, data_len);
740853e2bd2SBhanu Gollapudi 	} else {
741b2a554ffSBhanu Prakash Gollapudi 		printk(KERN_ERR PFX "Invalid ELS op 0x%x\n", op);
742853e2bd2SBhanu Gollapudi 		els_req->cb_func = NULL;
743853e2bd2SBhanu Gollapudi 		els_req->cb_arg = NULL;
744853e2bd2SBhanu Gollapudi 		spin_lock_bh(&tgt->tgt_lock);
745853e2bd2SBhanu Gollapudi 		kref_put(&els_req->refcount, bnx2fc_cmd_release);
746853e2bd2SBhanu Gollapudi 		spin_unlock_bh(&tgt->tgt_lock);
747853e2bd2SBhanu Gollapudi 		rc = -EINVAL;
748853e2bd2SBhanu Gollapudi 	}
749853e2bd2SBhanu Gollapudi 
750853e2bd2SBhanu Gollapudi 	if (rc)
751853e2bd2SBhanu Gollapudi 		goto els_err;
752853e2bd2SBhanu Gollapudi 
753853e2bd2SBhanu Gollapudi 	/* Fill FC header */
754853e2bd2SBhanu Gollapudi 	fc_hdr = &(mp_req->req_fc_hdr);
755853e2bd2SBhanu Gollapudi 
756853e2bd2SBhanu Gollapudi 	did = tgt->rport->port_id;
757853e2bd2SBhanu Gollapudi 	sid = tgt->sid;
758853e2bd2SBhanu Gollapudi 
75974446954SBhanu Prakash Gollapudi 	if (op == ELS_SRR)
76074446954SBhanu Prakash Gollapudi 		__fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS4_REQ, did, sid,
76174446954SBhanu Prakash Gollapudi 				   FC_TYPE_FCP, FC_FC_FIRST_SEQ |
76274446954SBhanu Prakash Gollapudi 				   FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
76374446954SBhanu Prakash Gollapudi 	else
764853e2bd2SBhanu Gollapudi 		__fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid,
76574446954SBhanu Prakash Gollapudi 				   FC_TYPE_ELS, FC_FC_FIRST_SEQ |
76674446954SBhanu Prakash Gollapudi 				   FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
767853e2bd2SBhanu Gollapudi 
768853e2bd2SBhanu Gollapudi 	/* Obtain exchange id */
769853e2bd2SBhanu Gollapudi 	xid = els_req->xid;
770853e2bd2SBhanu Gollapudi 	task_idx = xid/BNX2FC_TASKS_PER_PAGE;
771853e2bd2SBhanu Gollapudi 	index = xid % BNX2FC_TASKS_PER_PAGE;
772853e2bd2SBhanu Gollapudi 
773853e2bd2SBhanu Gollapudi 	/* Initialize task context for this IO request */
774aea71a02SBhanu Prakash Gollapudi 	task_page = (struct fcoe_task_ctx_entry *)
775aea71a02SBhanu Prakash Gollapudi 			interface->hba->task_ctx[task_idx];
776853e2bd2SBhanu Gollapudi 	task = &(task_page[index]);
777853e2bd2SBhanu Gollapudi 	bnx2fc_init_mp_task(els_req, task);
778853e2bd2SBhanu Gollapudi 
779853e2bd2SBhanu Gollapudi 	spin_lock_bh(&tgt->tgt_lock);
780853e2bd2SBhanu Gollapudi 
781853e2bd2SBhanu Gollapudi 	if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
782853e2bd2SBhanu Gollapudi 		printk(KERN_ERR PFX "initiate_els.. session not ready\n");
783853e2bd2SBhanu Gollapudi 		els_req->cb_func = NULL;
784853e2bd2SBhanu Gollapudi 		els_req->cb_arg = NULL;
785853e2bd2SBhanu Gollapudi 		kref_put(&els_req->refcount, bnx2fc_cmd_release);
786853e2bd2SBhanu Gollapudi 		spin_unlock_bh(&tgt->tgt_lock);
787853e2bd2SBhanu Gollapudi 		return -EINVAL;
788853e2bd2SBhanu Gollapudi 	}
789853e2bd2SBhanu Gollapudi 
790853e2bd2SBhanu Gollapudi 	if (timer_msec)
791853e2bd2SBhanu Gollapudi 		bnx2fc_cmd_timer_set(els_req, timer_msec);
792853e2bd2SBhanu Gollapudi 	bnx2fc_add_2_sq(tgt, xid);
793853e2bd2SBhanu Gollapudi 
794853e2bd2SBhanu Gollapudi 	els_req->on_active_queue = 1;
795853e2bd2SBhanu Gollapudi 	list_add_tail(&els_req->link, &tgt->els_queue);
796853e2bd2SBhanu Gollapudi 
797853e2bd2SBhanu Gollapudi 	/* Ring doorbell */
798853e2bd2SBhanu Gollapudi 	bnx2fc_ring_doorbell(tgt);
799853e2bd2SBhanu Gollapudi 	spin_unlock_bh(&tgt->tgt_lock);
800853e2bd2SBhanu Gollapudi 
801853e2bd2SBhanu Gollapudi els_err:
802853e2bd2SBhanu Gollapudi 	return rc;
803853e2bd2SBhanu Gollapudi }
804853e2bd2SBhanu Gollapudi 
bnx2fc_process_els_compl(struct bnx2fc_cmd * els_req,struct fcoe_task_ctx_entry * task,u8 num_rq)805853e2bd2SBhanu Gollapudi void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
806853e2bd2SBhanu Gollapudi 			      struct fcoe_task_ctx_entry *task, u8 num_rq)
807853e2bd2SBhanu Gollapudi {
808853e2bd2SBhanu Gollapudi 	struct bnx2fc_mp_req *mp_req;
809853e2bd2SBhanu Gollapudi 	struct fc_frame_header *fc_hdr;
810853e2bd2SBhanu Gollapudi 	u64 *hdr;
811853e2bd2SBhanu Gollapudi 	u64 *temp_hdr;
812853e2bd2SBhanu Gollapudi 
813853e2bd2SBhanu Gollapudi 	BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x"
814853e2bd2SBhanu Gollapudi 			"cmd_type = %d\n", els_req->xid, els_req->cmd_type);
815853e2bd2SBhanu Gollapudi 
816853e2bd2SBhanu Gollapudi 	if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE,
817853e2bd2SBhanu Gollapudi 			     &els_req->req_flags)) {
818853e2bd2SBhanu Gollapudi 		BNX2FC_ELS_DBG("Timer context finished processing this "
819853e2bd2SBhanu Gollapudi 			   "els - 0x%x\n", els_req->xid);
82025985edcSLucas De Marchi 		/* This IO doesn't receive cleanup completion */
821853e2bd2SBhanu Gollapudi 		kref_put(&els_req->refcount, bnx2fc_cmd_release);
822853e2bd2SBhanu Gollapudi 		return;
823853e2bd2SBhanu Gollapudi 	}
824853e2bd2SBhanu Gollapudi 
825853e2bd2SBhanu Gollapudi 	/* Cancel the timeout_work, as we received the response */
826853e2bd2SBhanu Gollapudi 	if (cancel_delayed_work(&els_req->timeout_work))
827853e2bd2SBhanu Gollapudi 		kref_put(&els_req->refcount,
828853e2bd2SBhanu Gollapudi 			 bnx2fc_cmd_release); /* drop timer hold */
829853e2bd2SBhanu Gollapudi 
830853e2bd2SBhanu Gollapudi 	if (els_req->on_active_queue) {
831853e2bd2SBhanu Gollapudi 		list_del_init(&els_req->link);
832853e2bd2SBhanu Gollapudi 		els_req->on_active_queue = 0;
833853e2bd2SBhanu Gollapudi 	}
834853e2bd2SBhanu Gollapudi 
835853e2bd2SBhanu Gollapudi 	mp_req = &(els_req->mp_req);
836853e2bd2SBhanu Gollapudi 	fc_hdr = &(mp_req->resp_fc_hdr);
837853e2bd2SBhanu Gollapudi 
838853e2bd2SBhanu Gollapudi 	hdr = (u64 *)fc_hdr;
839853e2bd2SBhanu Gollapudi 	temp_hdr = (u64 *)
840619c5cb6SVlad Zolotarov 		&task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr;
841853e2bd2SBhanu Gollapudi 	hdr[0] = cpu_to_be64(temp_hdr[0]);
842853e2bd2SBhanu Gollapudi 	hdr[1] = cpu_to_be64(temp_hdr[1]);
843853e2bd2SBhanu Gollapudi 	hdr[2] = cpu_to_be64(temp_hdr[2]);
844853e2bd2SBhanu Gollapudi 
845619c5cb6SVlad Zolotarov 	mp_req->resp_len =
846619c5cb6SVlad Zolotarov 		task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len;
847853e2bd2SBhanu Gollapudi 
848853e2bd2SBhanu Gollapudi 	/* Parse ELS response */
849853e2bd2SBhanu Gollapudi 	if ((els_req->cb_func) && (els_req->cb_arg)) {
850853e2bd2SBhanu Gollapudi 		els_req->cb_func(els_req->cb_arg);
851853e2bd2SBhanu Gollapudi 		els_req->cb_arg = NULL;
852853e2bd2SBhanu Gollapudi 	}
853853e2bd2SBhanu Gollapudi 
854853e2bd2SBhanu Gollapudi 	kref_put(&els_req->refcount, bnx2fc_cmd_release);
855853e2bd2SBhanu Gollapudi }
856853e2bd2SBhanu Gollapudi 
8574adb451cSChad Dupuis #define		BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC	1
8584adb451cSChad Dupuis #define		BNX2FC_FCOE_MAC_METHOD_FCF_MAP		2
8594adb451cSChad Dupuis #define		BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC	3
bnx2fc_flogi_resp(struct fc_seq * seq,struct fc_frame * fp,void * arg)860853e2bd2SBhanu Gollapudi static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
861853e2bd2SBhanu Gollapudi 			      void *arg)
862853e2bd2SBhanu Gollapudi {
863853e2bd2SBhanu Gollapudi 	struct fcoe_ctlr *fip = arg;
864853e2bd2SBhanu Gollapudi 	struct fc_exch *exch = fc_seq_exch(seq);
865853e2bd2SBhanu Gollapudi 	struct fc_lport *lport = exch->lp;
8664adb451cSChad Dupuis 
8674adb451cSChad Dupuis 	struct fc_frame_header *fh;
8684adb451cSChad Dupuis 	u8 *granted_mac;
8694adb451cSChad Dupuis 	u8 fcoe_mac[6];
8704adb451cSChad Dupuis 	u8 fc_map[3];
8714adb451cSChad Dupuis 	int method;
872853e2bd2SBhanu Gollapudi 
873853e2bd2SBhanu Gollapudi 	if (IS_ERR(fp))
874853e2bd2SBhanu Gollapudi 		goto done;
875853e2bd2SBhanu Gollapudi 
8764adb451cSChad Dupuis 	fh = fc_frame_header_get(fp);
8774adb451cSChad Dupuis 	granted_mac = fr_cb(fp)->granted_mac;
8784adb451cSChad Dupuis 
8794adb451cSChad Dupuis 	/*
8804adb451cSChad Dupuis 	 * We set the source MAC for FCoE traffic based on the Granted MAC
8814adb451cSChad Dupuis 	 * address from the switch.
8824adb451cSChad Dupuis 	 *
8834adb451cSChad Dupuis 	 * If granted_mac is non-zero, we use that.
8844adb451cSChad Dupuis 	 * If the granted_mac is zeroed out, create the FCoE MAC based on
8854adb451cSChad Dupuis 	 * the sel_fcf->fc_map and the d_id fo the FLOGI frame.
8864adb451cSChad Dupuis 	 * If sel_fcf->fc_map is 0, then we use the default FCF-MAC plus the
8874adb451cSChad Dupuis 	 * d_id of the FLOGI frame.
8884adb451cSChad Dupuis 	 */
8894adb451cSChad Dupuis 	if (!is_zero_ether_addr(granted_mac)) {
8904adb451cSChad Dupuis 		ether_addr_copy(fcoe_mac, granted_mac);
8914adb451cSChad Dupuis 		method = BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC;
8924adb451cSChad Dupuis 	} else if (fip->sel_fcf && fip->sel_fcf->fc_map != 0) {
8934adb451cSChad Dupuis 		hton24(fc_map, fip->sel_fcf->fc_map);
8944adb451cSChad Dupuis 		fcoe_mac[0] = fc_map[0];
8954adb451cSChad Dupuis 		fcoe_mac[1] = fc_map[1];
8964adb451cSChad Dupuis 		fcoe_mac[2] = fc_map[2];
8974adb451cSChad Dupuis 		fcoe_mac[3] = fh->fh_d_id[0];
8984adb451cSChad Dupuis 		fcoe_mac[4] = fh->fh_d_id[1];
8994adb451cSChad Dupuis 		fcoe_mac[5] = fh->fh_d_id[2];
9004adb451cSChad Dupuis 		method = BNX2FC_FCOE_MAC_METHOD_FCF_MAP;
9014adb451cSChad Dupuis 	} else {
9024adb451cSChad Dupuis 		fc_fcoe_set_mac(fcoe_mac, fh->fh_d_id);
9034adb451cSChad Dupuis 		method = BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC;
904853e2bd2SBhanu Gollapudi 	}
9054adb451cSChad Dupuis 
9064adb451cSChad Dupuis 	BNX2FC_HBA_DBG(lport, "fcoe_mac=%pM method=%d\n", fcoe_mac, method);
9074adb451cSChad Dupuis 	fip->update_mac(lport, fcoe_mac);
908853e2bd2SBhanu Gollapudi done:
909853e2bd2SBhanu Gollapudi 	fc_lport_flogi_resp(seq, fp, lport);
910853e2bd2SBhanu Gollapudi }
911853e2bd2SBhanu Gollapudi 
bnx2fc_logo_resp(struct fc_seq * seq,struct fc_frame * fp,void * arg)912853e2bd2SBhanu Gollapudi static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp,
913853e2bd2SBhanu Gollapudi 			     void *arg)
914853e2bd2SBhanu Gollapudi {
915853e2bd2SBhanu Gollapudi 	struct fcoe_ctlr *fip = arg;
916853e2bd2SBhanu Gollapudi 	struct fc_exch *exch = fc_seq_exch(seq);
917853e2bd2SBhanu Gollapudi 	struct fc_lport *lport = exch->lp;
918853e2bd2SBhanu Gollapudi 	static u8 zero_mac[ETH_ALEN] = { 0 };
919853e2bd2SBhanu Gollapudi 
920853e2bd2SBhanu Gollapudi 	if (!IS_ERR(fp))
921853e2bd2SBhanu Gollapudi 		fip->update_mac(lport, zero_mac);
922853e2bd2SBhanu Gollapudi 	fc_lport_logo_resp(seq, fp, lport);
923853e2bd2SBhanu Gollapudi }
924853e2bd2SBhanu Gollapudi 
bnx2fc_elsct_send(struct fc_lport * lport,u32 did,struct fc_frame * fp,unsigned int op,void (* resp)(struct fc_seq *,struct fc_frame *,void *),void * arg,u32 timeout)925853e2bd2SBhanu Gollapudi struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
926853e2bd2SBhanu Gollapudi 				      struct fc_frame *fp, unsigned int op,
927853e2bd2SBhanu Gollapudi 				      void (*resp)(struct fc_seq *,
928853e2bd2SBhanu Gollapudi 						   struct fc_frame *,
929853e2bd2SBhanu Gollapudi 						   void *),
930853e2bd2SBhanu Gollapudi 				      void *arg, u32 timeout)
931853e2bd2SBhanu Gollapudi {
932853e2bd2SBhanu Gollapudi 	struct fcoe_port *port = lport_priv(lport);
933aea71a02SBhanu Prakash Gollapudi 	struct bnx2fc_interface *interface = port->priv;
934fd8f8902SRobert Love 	struct fcoe_ctlr *fip = bnx2fc_to_ctlr(interface);
935853e2bd2SBhanu Gollapudi 	struct fc_frame_header *fh = fc_frame_header_get(fp);
936853e2bd2SBhanu Gollapudi 
937853e2bd2SBhanu Gollapudi 	switch (op) {
938853e2bd2SBhanu Gollapudi 	case ELS_FLOGI:
939853e2bd2SBhanu Gollapudi 	case ELS_FDISC:
940853e2bd2SBhanu Gollapudi 		return fc_elsct_send(lport, did, fp, op, bnx2fc_flogi_resp,
941853e2bd2SBhanu Gollapudi 				     fip, timeout);
942853e2bd2SBhanu Gollapudi 	case ELS_LOGO:
943853e2bd2SBhanu Gollapudi 		/* only hook onto fabric logouts, not port logouts */
944853e2bd2SBhanu Gollapudi 		if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
945853e2bd2SBhanu Gollapudi 			break;
946853e2bd2SBhanu Gollapudi 		return fc_elsct_send(lport, did, fp, op, bnx2fc_logo_resp,
947853e2bd2SBhanu Gollapudi 				     fip, timeout);
948853e2bd2SBhanu Gollapudi 	}
949853e2bd2SBhanu Gollapudi 	return fc_elsct_send(lport, did, fp, op, resp, arg, timeout);
950853e2bd2SBhanu Gollapudi }
951