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