1 | /* |
2 | * bnx2fc_els.c: QLogic Linux FCoE offload driver. |
3 | * This file contains helper routines that handle ELS requests |
4 | * and responses. |
5 | * |
6 | * Copyright (c) 2008-2013 Broadcom Corporation |
7 | * Copyright (c) 2014-2016 QLogic Corporation |
8 | * Copyright (c) 2016-2017 Cavium Inc. |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation. |
13 | * |
14 | * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) |
15 | */ |
16 | |
17 | #include "bnx2fc.h" |
18 | |
19 | static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, |
20 | void *arg); |
21 | static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, |
22 | void *arg); |
23 | static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, |
24 | void *data, u32 data_len, |
25 | void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), |
26 | struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec); |
27 | |
28 | static void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg *cb_arg) |
29 | { |
30 | struct bnx2fc_cmd *orig_io_req; |
31 | struct bnx2fc_cmd *rrq_req; |
32 | int rc = 0; |
33 | |
34 | BUG_ON(!cb_arg); |
35 | rrq_req = cb_arg->io_req; |
36 | orig_io_req = cb_arg->aborted_io_req; |
37 | BUG_ON(!orig_io_req); |
38 | BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n" , |
39 | orig_io_req->xid, rrq_req->xid); |
40 | |
41 | kref_put(kref: &orig_io_req->refcount, release: bnx2fc_cmd_release); |
42 | |
43 | if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, addr: &rrq_req->req_flags)) { |
44 | /* |
45 | * els req is timed out. cleanup the IO with FW and |
46 | * drop the completion. Remove from active_cmd_queue. |
47 | */ |
48 | BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n" , |
49 | rrq_req->xid); |
50 | |
51 | if (rrq_req->on_active_queue) { |
52 | list_del_init(entry: &rrq_req->link); |
53 | rrq_req->on_active_queue = 0; |
54 | rc = bnx2fc_initiate_cleanup(io_req: rrq_req); |
55 | BUG_ON(rc); |
56 | } |
57 | } |
58 | kfree(objp: cb_arg); |
59 | } |
60 | int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req) |
61 | { |
62 | |
63 | struct fc_els_rrq rrq; |
64 | struct bnx2fc_rport *tgt = aborted_io_req->tgt; |
65 | struct fc_lport *lport = NULL; |
66 | struct bnx2fc_els_cb_arg *cb_arg = NULL; |
67 | u32 sid = 0; |
68 | u32 r_a_tov = 0; |
69 | unsigned long start = jiffies; |
70 | int rc; |
71 | |
72 | if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) |
73 | return -EINVAL; |
74 | |
75 | lport = tgt->rdata->local_port; |
76 | sid = tgt->sid; |
77 | r_a_tov = lport->r_a_tov; |
78 | |
79 | BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n" , |
80 | aborted_io_req->xid); |
81 | memset(&rrq, 0, sizeof(rrq)); |
82 | |
83 | cb_arg = kzalloc(size: sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO); |
84 | if (!cb_arg) { |
85 | printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n" ); |
86 | rc = -ENOMEM; |
87 | goto rrq_err; |
88 | } |
89 | |
90 | cb_arg->aborted_io_req = aborted_io_req; |
91 | |
92 | rrq.rrq_cmd = ELS_RRQ; |
93 | hton24(p: rrq.rrq_s_id, v: sid); |
94 | rrq.rrq_ox_id = htons(aborted_io_req->xid); |
95 | rrq.rrq_rx_id = htons(aborted_io_req->task->rxwr_txrd.var_ctx.rx_id); |
96 | |
97 | retry_rrq: |
98 | rc = bnx2fc_initiate_els(tgt, op: ELS_RRQ, data: &rrq, data_len: sizeof(rrq), |
99 | cb_func: bnx2fc_rrq_compl, cb_arg, |
100 | timer_msec: r_a_tov); |
101 | if (rc == -ENOMEM) { |
102 | if (time_after(jiffies, start + (10 * HZ))) { |
103 | BNX2FC_ELS_DBG("rrq Failed\n" ); |
104 | rc = FAILED; |
105 | goto rrq_err; |
106 | } |
107 | msleep(msecs: 20); |
108 | goto retry_rrq; |
109 | } |
110 | rrq_err: |
111 | if (rc) { |
112 | BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n" , |
113 | aborted_io_req->xid); |
114 | kfree(objp: cb_arg); |
115 | spin_lock_bh(lock: &tgt->tgt_lock); |
116 | kref_put(kref: &aborted_io_req->refcount, release: bnx2fc_cmd_release); |
117 | spin_unlock_bh(lock: &tgt->tgt_lock); |
118 | } |
119 | return rc; |
120 | } |
121 | |
122 | static void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg *cb_arg) |
123 | { |
124 | struct bnx2fc_cmd *els_req; |
125 | struct bnx2fc_rport *tgt; |
126 | struct bnx2fc_mp_req *mp_req; |
127 | struct fc_frame_header *fc_hdr; |
128 | unsigned char *buf; |
129 | void *resp_buf; |
130 | u32 resp_len, hdr_len; |
131 | u16 l2_oxid; |
132 | int frame_len; |
133 | int rc = 0; |
134 | |
135 | l2_oxid = cb_arg->l2_oxid; |
136 | BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n" , l2_oxid); |
137 | |
138 | els_req = cb_arg->io_req; |
139 | if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, addr: &els_req->req_flags)) { |
140 | /* |
141 | * els req is timed out. cleanup the IO with FW and |
142 | * drop the completion. libfc will handle the els timeout |
143 | */ |
144 | if (els_req->on_active_queue) { |
145 | list_del_init(entry: &els_req->link); |
146 | els_req->on_active_queue = 0; |
147 | rc = bnx2fc_initiate_cleanup(io_req: els_req); |
148 | BUG_ON(rc); |
149 | } |
150 | goto free_arg; |
151 | } |
152 | |
153 | tgt = els_req->tgt; |
154 | mp_req = &(els_req->mp_req); |
155 | fc_hdr = &(mp_req->resp_fc_hdr); |
156 | resp_len = mp_req->resp_len; |
157 | resp_buf = mp_req->resp_buf; |
158 | |
159 | buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); |
160 | if (!buf) { |
161 | printk(KERN_ERR PFX "Unable to alloc mp buf\n" ); |
162 | goto free_arg; |
163 | } |
164 | hdr_len = sizeof(*fc_hdr); |
165 | if (hdr_len + resp_len > PAGE_SIZE) { |
166 | printk(KERN_ERR PFX "l2_els_compl: resp len is " |
167 | "beyond page size\n" ); |
168 | goto free_buf; |
169 | } |
170 | memcpy(buf, fc_hdr, hdr_len); |
171 | memcpy(buf + hdr_len, resp_buf, resp_len); |
172 | frame_len = hdr_len + resp_len; |
173 | |
174 | bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, l2_oxid); |
175 | |
176 | free_buf: |
177 | kfree(objp: buf); |
178 | free_arg: |
179 | kfree(objp: cb_arg); |
180 | } |
181 | |
182 | int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp) |
183 | { |
184 | struct fc_els_adisc *adisc; |
185 | struct fc_frame_header *fh; |
186 | struct bnx2fc_els_cb_arg *cb_arg; |
187 | struct fc_lport *lport = tgt->rdata->local_port; |
188 | u32 r_a_tov = lport->r_a_tov; |
189 | int rc; |
190 | |
191 | fh = fc_frame_header_get(fp); |
192 | cb_arg = kzalloc(size: sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); |
193 | if (!cb_arg) { |
194 | printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n" ); |
195 | return -ENOMEM; |
196 | } |
197 | |
198 | cb_arg->l2_oxid = ntohs(fh->fh_ox_id); |
199 | |
200 | BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n" , cb_arg->l2_oxid); |
201 | adisc = fc_frame_payload_get(fp, len: sizeof(*adisc)); |
202 | /* adisc is initialized by libfc */ |
203 | rc = bnx2fc_initiate_els(tgt, op: ELS_ADISC, data: adisc, data_len: sizeof(*adisc), |
204 | cb_func: bnx2fc_l2_els_compl, cb_arg, timer_msec: 2 * r_a_tov); |
205 | if (rc) |
206 | kfree(objp: cb_arg); |
207 | return rc; |
208 | } |
209 | |
210 | int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp) |
211 | { |
212 | struct fc_els_logo *logo; |
213 | struct fc_frame_header *fh; |
214 | struct bnx2fc_els_cb_arg *cb_arg; |
215 | struct fc_lport *lport = tgt->rdata->local_port; |
216 | u32 r_a_tov = lport->r_a_tov; |
217 | int rc; |
218 | |
219 | fh = fc_frame_header_get(fp); |
220 | cb_arg = kzalloc(size: sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); |
221 | if (!cb_arg) { |
222 | printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n" ); |
223 | return -ENOMEM; |
224 | } |
225 | |
226 | cb_arg->l2_oxid = ntohs(fh->fh_ox_id); |
227 | |
228 | BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n" , cb_arg->l2_oxid); |
229 | logo = fc_frame_payload_get(fp, len: sizeof(*logo)); |
230 | /* logo is initialized by libfc */ |
231 | rc = bnx2fc_initiate_els(tgt, op: ELS_LOGO, data: logo, data_len: sizeof(*logo), |
232 | cb_func: bnx2fc_l2_els_compl, cb_arg, timer_msec: 2 * r_a_tov); |
233 | if (rc) |
234 | kfree(objp: cb_arg); |
235 | return rc; |
236 | } |
237 | |
238 | int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp) |
239 | { |
240 | struct fc_els_rls *rls; |
241 | struct fc_frame_header *fh; |
242 | struct bnx2fc_els_cb_arg *cb_arg; |
243 | struct fc_lport *lport = tgt->rdata->local_port; |
244 | u32 r_a_tov = lport->r_a_tov; |
245 | int rc; |
246 | |
247 | fh = fc_frame_header_get(fp); |
248 | cb_arg = kzalloc(size: sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); |
249 | if (!cb_arg) { |
250 | printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n" ); |
251 | return -ENOMEM; |
252 | } |
253 | |
254 | cb_arg->l2_oxid = ntohs(fh->fh_ox_id); |
255 | |
256 | rls = fc_frame_payload_get(fp, len: sizeof(*rls)); |
257 | /* rls is initialized by libfc */ |
258 | rc = bnx2fc_initiate_els(tgt, op: ELS_RLS, data: rls, data_len: sizeof(*rls), |
259 | cb_func: bnx2fc_l2_els_compl, cb_arg, timer_msec: 2 * r_a_tov); |
260 | if (rc) |
261 | kfree(objp: cb_arg); |
262 | return rc; |
263 | } |
264 | |
265 | static void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) |
266 | { |
267 | struct bnx2fc_mp_req *mp_req; |
268 | struct fc_frame_header *fc_hdr, *fh; |
269 | struct bnx2fc_cmd *srr_req; |
270 | struct bnx2fc_cmd *orig_io_req; |
271 | struct fc_frame *fp; |
272 | unsigned char *buf; |
273 | void *resp_buf; |
274 | u32 resp_len, hdr_len; |
275 | u8 opcode; |
276 | int rc = 0; |
277 | |
278 | orig_io_req = cb_arg->aborted_io_req; |
279 | srr_req = cb_arg->io_req; |
280 | if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, addr: &srr_req->req_flags)) { |
281 | /* SRR timedout */ |
282 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "srr timed out, abort " |
283 | "orig_io - 0x%x\n" , |
284 | orig_io_req->xid); |
285 | rc = bnx2fc_initiate_abts(io_req: srr_req); |
286 | if (rc != SUCCESS) { |
287 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "srr_compl: initiate_abts " |
288 | "failed. issue cleanup\n" ); |
289 | bnx2fc_initiate_cleanup(io_req: srr_req); |
290 | } |
291 | if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || |
292 | test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { |
293 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "srr_compl:xid 0x%x flags = %lx" , |
294 | orig_io_req->xid, orig_io_req->req_flags); |
295 | goto srr_compl_done; |
296 | } |
297 | orig_io_req->srr_retry++; |
298 | if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) { |
299 | struct bnx2fc_rport *tgt = orig_io_req->tgt; |
300 | spin_unlock_bh(lock: &tgt->tgt_lock); |
301 | rc = bnx2fc_send_srr(orig_io_req, |
302 | offset: orig_io_req->srr_offset, |
303 | r_ctl: orig_io_req->srr_rctl); |
304 | spin_lock_bh(lock: &tgt->tgt_lock); |
305 | if (!rc) |
306 | goto srr_compl_done; |
307 | } |
308 | |
309 | rc = bnx2fc_initiate_abts(io_req: orig_io_req); |
310 | if (rc != SUCCESS) { |
311 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "srr_compl: initiate_abts " |
312 | "failed xid = 0x%x. issue cleanup\n" , |
313 | orig_io_req->xid); |
314 | bnx2fc_initiate_cleanup(io_req: orig_io_req); |
315 | } |
316 | goto srr_compl_done; |
317 | } |
318 | if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || |
319 | test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { |
320 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "srr_compl:xid - 0x%x flags = %lx" , |
321 | orig_io_req->xid, orig_io_req->req_flags); |
322 | goto srr_compl_done; |
323 | } |
324 | mp_req = &(srr_req->mp_req); |
325 | fc_hdr = &(mp_req->resp_fc_hdr); |
326 | resp_len = mp_req->resp_len; |
327 | resp_buf = mp_req->resp_buf; |
328 | |
329 | hdr_len = sizeof(*fc_hdr); |
330 | buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); |
331 | if (!buf) { |
332 | printk(KERN_ERR PFX "srr buf: mem alloc failure\n" ); |
333 | goto srr_compl_done; |
334 | } |
335 | memcpy(buf, fc_hdr, hdr_len); |
336 | memcpy(buf + hdr_len, resp_buf, resp_len); |
337 | |
338 | fp = fc_frame_alloc(NULL, len: resp_len); |
339 | if (!fp) { |
340 | printk(KERN_ERR PFX "fc_frame_alloc failure\n" ); |
341 | goto free_buf; |
342 | } |
343 | |
344 | fh = (struct fc_frame_header *) fc_frame_header_get(fp); |
345 | /* Copy FC Frame header and payload into the frame */ |
346 | memcpy(fh, buf, hdr_len + resp_len); |
347 | |
348 | opcode = fc_frame_payload_op(fp); |
349 | switch (opcode) { |
350 | case ELS_LS_ACC: |
351 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "SRR success\n" ); |
352 | break; |
353 | case ELS_LS_RJT: |
354 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "SRR rejected\n" ); |
355 | rc = bnx2fc_initiate_abts(io_req: orig_io_req); |
356 | if (rc != SUCCESS) { |
357 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "srr_compl: initiate_abts " |
358 | "failed xid = 0x%x. issue cleanup\n" , |
359 | orig_io_req->xid); |
360 | bnx2fc_initiate_cleanup(io_req: orig_io_req); |
361 | } |
362 | break; |
363 | default: |
364 | BNX2FC_IO_DBG(io_req: srr_req, fmt: "srr compl - invalid opcode = %d\n" , |
365 | opcode); |
366 | break; |
367 | } |
368 | fc_frame_free(fp); |
369 | free_buf: |
370 | kfree(objp: buf); |
371 | srr_compl_done: |
372 | kref_put(kref: &orig_io_req->refcount, release: bnx2fc_cmd_release); |
373 | } |
374 | |
375 | static void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg) |
376 | { |
377 | struct bnx2fc_cmd *orig_io_req, *new_io_req; |
378 | struct bnx2fc_cmd *rec_req; |
379 | struct bnx2fc_mp_req *mp_req; |
380 | struct fc_frame_header *fc_hdr, *fh; |
381 | struct fc_els_ls_rjt *rjt; |
382 | struct fc_els_rec_acc *acc; |
383 | struct bnx2fc_rport *tgt; |
384 | struct fcoe_err_report_entry *err_entry; |
385 | struct scsi_cmnd *sc_cmd; |
386 | enum fc_rctl r_ctl; |
387 | unsigned char *buf; |
388 | void *resp_buf; |
389 | struct fc_frame *fp; |
390 | u8 opcode; |
391 | u32 offset; |
392 | u32 e_stat; |
393 | u32 resp_len, hdr_len; |
394 | int rc = 0; |
395 | bool send_seq_clnp = false; |
396 | bool abort_io = false; |
397 | |
398 | BNX2FC_MISC_DBG("Entered rec_compl callback\n" ); |
399 | rec_req = cb_arg->io_req; |
400 | orig_io_req = cb_arg->aborted_io_req; |
401 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "rec_compl: orig xid = 0x%x" , orig_io_req->xid); |
402 | tgt = orig_io_req->tgt; |
403 | |
404 | /* Handle REC timeout case */ |
405 | if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, addr: &rec_req->req_flags)) { |
406 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "timed out, abort " |
407 | "orig_io - 0x%x\n" , |
408 | orig_io_req->xid); |
409 | /* els req is timed out. send abts for els */ |
410 | rc = bnx2fc_initiate_abts(io_req: rec_req); |
411 | if (rc != SUCCESS) { |
412 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "rec_compl: initiate_abts " |
413 | "failed. issue cleanup\n" ); |
414 | bnx2fc_initiate_cleanup(io_req: rec_req); |
415 | } |
416 | orig_io_req->rec_retry++; |
417 | /* REC timedout. send ABTS to the orig IO req */ |
418 | if (orig_io_req->rec_retry <= REC_RETRY_COUNT) { |
419 | spin_unlock_bh(lock: &tgt->tgt_lock); |
420 | rc = bnx2fc_send_rec(orig_io_req); |
421 | spin_lock_bh(lock: &tgt->tgt_lock); |
422 | if (!rc) |
423 | goto rec_compl_done; |
424 | } |
425 | rc = bnx2fc_initiate_abts(io_req: orig_io_req); |
426 | if (rc != SUCCESS) { |
427 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "rec_compl: initiate_abts " |
428 | "failed xid = 0x%x. issue cleanup\n" , |
429 | orig_io_req->xid); |
430 | bnx2fc_initiate_cleanup(io_req: orig_io_req); |
431 | } |
432 | goto rec_compl_done; |
433 | } |
434 | |
435 | if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) { |
436 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "completed" |
437 | "orig_io - 0x%x\n" , |
438 | orig_io_req->xid); |
439 | goto rec_compl_done; |
440 | } |
441 | if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { |
442 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "abts in prog " |
443 | "orig_io - 0x%x\n" , |
444 | orig_io_req->xid); |
445 | goto rec_compl_done; |
446 | } |
447 | |
448 | mp_req = &(rec_req->mp_req); |
449 | fc_hdr = &(mp_req->resp_fc_hdr); |
450 | resp_len = mp_req->resp_len; |
451 | acc = resp_buf = mp_req->resp_buf; |
452 | |
453 | hdr_len = sizeof(*fc_hdr); |
454 | |
455 | buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); |
456 | if (!buf) { |
457 | printk(KERN_ERR PFX "rec buf: mem alloc failure\n" ); |
458 | goto rec_compl_done; |
459 | } |
460 | memcpy(buf, fc_hdr, hdr_len); |
461 | memcpy(buf + hdr_len, resp_buf, resp_len); |
462 | |
463 | fp = fc_frame_alloc(NULL, len: resp_len); |
464 | if (!fp) { |
465 | printk(KERN_ERR PFX "fc_frame_alloc failure\n" ); |
466 | goto free_buf; |
467 | } |
468 | |
469 | fh = (struct fc_frame_header *) fc_frame_header_get(fp); |
470 | /* Copy FC Frame header and payload into the frame */ |
471 | memcpy(fh, buf, hdr_len + resp_len); |
472 | |
473 | opcode = fc_frame_payload_op(fp); |
474 | if (opcode == ELS_LS_RJT) { |
475 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "opcode is RJT\n" ); |
476 | rjt = fc_frame_payload_get(fp, len: sizeof(*rjt)); |
477 | if ((rjt->er_reason == ELS_RJT_LOGIC || |
478 | rjt->er_reason == ELS_RJT_UNAB) && |
479 | rjt->er_explan == ELS_EXPL_OXID_RXID) { |
480 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "handle CMD LOST case\n" ); |
481 | new_io_req = bnx2fc_cmd_alloc(tgt); |
482 | if (!new_io_req) |
483 | goto abort_io; |
484 | new_io_req->sc_cmd = orig_io_req->sc_cmd; |
485 | /* cleanup orig_io_req that is with the FW */ |
486 | set_bit(BNX2FC_FLAG_CMD_LOST, |
487 | addr: &orig_io_req->req_flags); |
488 | bnx2fc_initiate_cleanup(io_req: orig_io_req); |
489 | /* Post a new IO req with the same sc_cmd */ |
490 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "Post IO request again\n" ); |
491 | rc = bnx2fc_post_io_req(tgt, io_req: new_io_req); |
492 | if (!rc) |
493 | goto free_frame; |
494 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "REC: io post err\n" ); |
495 | } |
496 | abort_io: |
497 | rc = bnx2fc_initiate_abts(io_req: orig_io_req); |
498 | if (rc != SUCCESS) { |
499 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "rec_compl: initiate_abts " |
500 | "failed. issue cleanup\n" ); |
501 | bnx2fc_initiate_cleanup(io_req: orig_io_req); |
502 | } |
503 | } else if (opcode == ELS_LS_ACC) { |
504 | /* REVISIT: Check if the exchange is already aborted */ |
505 | offset = ntohl(acc->reca_fc4value); |
506 | e_stat = ntohl(acc->reca_e_stat); |
507 | if (e_stat & ESB_ST_SEQ_INIT) { |
508 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "target has the seq init\n" ); |
509 | goto free_frame; |
510 | } |
511 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "e_stat = 0x%x, offset = 0x%x\n" , |
512 | e_stat, offset); |
513 | /* Seq initiative is with us */ |
514 | err_entry = (struct fcoe_err_report_entry *) |
515 | &orig_io_req->err_entry; |
516 | sc_cmd = orig_io_req->sc_cmd; |
517 | if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { |
518 | /* SCSI WRITE command */ |
519 | if (offset == orig_io_req->data_xfer_len) { |
520 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "WRITE - resp lost\n" ); |
521 | /* FCP_RSP lost */ |
522 | r_ctl = FC_RCTL_DD_CMD_STATUS; |
523 | offset = 0; |
524 | } else { |
525 | /* start transmitting from offset */ |
526 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "XFER_RDY/DATA lost\n" ); |
527 | send_seq_clnp = true; |
528 | r_ctl = FC_RCTL_DD_DATA_DESC; |
529 | if (bnx2fc_initiate_seq_cleanup(orig_io_req, |
530 | offset, r_ctl)) |
531 | abort_io = true; |
532 | /* XFER_RDY */ |
533 | } |
534 | } else { |
535 | /* SCSI READ command */ |
536 | if (err_entry->data.rx_buf_off == |
537 | orig_io_req->data_xfer_len) { |
538 | /* FCP_RSP lost */ |
539 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "READ - resp lost\n" ); |
540 | r_ctl = FC_RCTL_DD_CMD_STATUS; |
541 | offset = 0; |
542 | } else { |
543 | /* request retransmission from this offset */ |
544 | send_seq_clnp = true; |
545 | offset = err_entry->data.rx_buf_off; |
546 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "RD DATA lost\n" ); |
547 | /* FCP_DATA lost */ |
548 | r_ctl = FC_RCTL_DD_SOL_DATA; |
549 | if (bnx2fc_initiate_seq_cleanup(orig_io_req, |
550 | offset, r_ctl)) |
551 | abort_io = true; |
552 | } |
553 | } |
554 | if (abort_io) { |
555 | rc = bnx2fc_initiate_abts(io_req: orig_io_req); |
556 | if (rc != SUCCESS) { |
557 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "rec_compl:initiate_abts" |
558 | " failed. issue cleanup\n" ); |
559 | bnx2fc_initiate_cleanup(io_req: orig_io_req); |
560 | } |
561 | } else if (!send_seq_clnp) { |
562 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "Send SRR - FCP_RSP\n" ); |
563 | spin_unlock_bh(lock: &tgt->tgt_lock); |
564 | rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl); |
565 | spin_lock_bh(lock: &tgt->tgt_lock); |
566 | |
567 | if (rc) { |
568 | BNX2FC_IO_DBG(io_req: rec_req, fmt: "Unable to send SRR" |
569 | " IO will abort\n" ); |
570 | } |
571 | } |
572 | } |
573 | free_frame: |
574 | fc_frame_free(fp); |
575 | free_buf: |
576 | kfree(objp: buf); |
577 | rec_compl_done: |
578 | kref_put(kref: &orig_io_req->refcount, release: bnx2fc_cmd_release); |
579 | kfree(objp: cb_arg); |
580 | } |
581 | |
582 | int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req) |
583 | { |
584 | struct fc_els_rec rec; |
585 | struct bnx2fc_rport *tgt = orig_io_req->tgt; |
586 | struct fc_lport *lport = tgt->rdata->local_port; |
587 | struct bnx2fc_els_cb_arg *cb_arg = NULL; |
588 | u32 sid = tgt->sid; |
589 | u32 r_a_tov = lport->r_a_tov; |
590 | int rc; |
591 | |
592 | BNX2FC_IO_DBG(io_req: orig_io_req, fmt: "Sending REC\n" ); |
593 | memset(&rec, 0, sizeof(rec)); |
594 | |
595 | cb_arg = kzalloc(size: sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); |
596 | if (!cb_arg) { |
597 | printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n" ); |
598 | rc = -ENOMEM; |
599 | goto rec_err; |
600 | } |
601 | kref_get(kref: &orig_io_req->refcount); |
602 | |
603 | cb_arg->aborted_io_req = orig_io_req; |
604 | |
605 | rec.rec_cmd = ELS_REC; |
606 | hton24(p: rec.rec_s_id, v: sid); |
607 | rec.rec_ox_id = htons(orig_io_req->xid); |
608 | rec.rec_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id); |
609 | |
610 | rc = bnx2fc_initiate_els(tgt, op: ELS_REC, data: &rec, data_len: sizeof(rec), |
611 | cb_func: bnx2fc_rec_compl, cb_arg, |
612 | timer_msec: r_a_tov); |
613 | if (rc) { |
614 | BNX2FC_IO_DBG(io_req: orig_io_req, fmt: "REC failed - release\n" ); |
615 | spin_lock_bh(lock: &tgt->tgt_lock); |
616 | kref_put(kref: &orig_io_req->refcount, release: bnx2fc_cmd_release); |
617 | spin_unlock_bh(lock: &tgt->tgt_lock); |
618 | kfree(objp: cb_arg); |
619 | } |
620 | rec_err: |
621 | return rc; |
622 | } |
623 | |
624 | int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl) |
625 | { |
626 | struct fcp_srr srr; |
627 | struct bnx2fc_rport *tgt = orig_io_req->tgt; |
628 | struct fc_lport *lport = tgt->rdata->local_port; |
629 | struct bnx2fc_els_cb_arg *cb_arg = NULL; |
630 | u32 r_a_tov = lport->r_a_tov; |
631 | int rc; |
632 | |
633 | BNX2FC_IO_DBG(io_req: orig_io_req, fmt: "Sending SRR\n" ); |
634 | memset(&srr, 0, sizeof(srr)); |
635 | |
636 | cb_arg = kzalloc(size: sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); |
637 | if (!cb_arg) { |
638 | printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n" ); |
639 | rc = -ENOMEM; |
640 | goto srr_err; |
641 | } |
642 | kref_get(kref: &orig_io_req->refcount); |
643 | |
644 | cb_arg->aborted_io_req = orig_io_req; |
645 | |
646 | srr.srr_op = ELS_SRR; |
647 | srr.srr_ox_id = htons(orig_io_req->xid); |
648 | srr.srr_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id); |
649 | srr.srr_rel_off = htonl(offset); |
650 | srr.srr_r_ctl = r_ctl; |
651 | orig_io_req->srr_offset = offset; |
652 | orig_io_req->srr_rctl = r_ctl; |
653 | |
654 | rc = bnx2fc_initiate_els(tgt, op: ELS_SRR, data: &srr, data_len: sizeof(srr), |
655 | cb_func: bnx2fc_srr_compl, cb_arg, |
656 | timer_msec: r_a_tov); |
657 | if (rc) { |
658 | BNX2FC_IO_DBG(io_req: orig_io_req, fmt: "SRR failed - release\n" ); |
659 | spin_lock_bh(lock: &tgt->tgt_lock); |
660 | kref_put(kref: &orig_io_req->refcount, release: bnx2fc_cmd_release); |
661 | spin_unlock_bh(lock: &tgt->tgt_lock); |
662 | kfree(objp: cb_arg); |
663 | } else |
664 | set_bit(BNX2FC_FLAG_SRR_SENT, addr: &orig_io_req->req_flags); |
665 | |
666 | srr_err: |
667 | return rc; |
668 | } |
669 | |
670 | static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, |
671 | void *data, u32 data_len, |
672 | void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), |
673 | struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec) |
674 | { |
675 | struct fcoe_port *port = tgt->port; |
676 | struct bnx2fc_interface *interface = port->priv; |
677 | struct fc_rport *rport = tgt->rport; |
678 | struct fc_lport *lport = port->lport; |
679 | struct bnx2fc_cmd *els_req; |
680 | struct bnx2fc_mp_req *mp_req; |
681 | struct fc_frame_header *fc_hdr; |
682 | struct fcoe_task_ctx_entry *task; |
683 | struct fcoe_task_ctx_entry *task_page; |
684 | int rc = 0; |
685 | int task_idx, index; |
686 | u32 did, sid; |
687 | u16 xid; |
688 | |
689 | rc = fc_remote_port_chkready(rport); |
690 | if (rc) { |
691 | printk(KERN_ERR PFX "els 0x%x: rport not ready\n" , op); |
692 | rc = -EINVAL; |
693 | goto els_err; |
694 | } |
695 | if (lport->state != LPORT_ST_READY || !(lport->link_up)) { |
696 | printk(KERN_ERR PFX "els 0x%x: link is not ready\n" , op); |
697 | rc = -EINVAL; |
698 | goto els_err; |
699 | } |
700 | if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) { |
701 | printk(KERN_ERR PFX "els 0x%x: tgt not ready\n" , op); |
702 | rc = -EINVAL; |
703 | goto els_err; |
704 | } |
705 | els_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ELS); |
706 | if (!els_req) { |
707 | rc = -ENOMEM; |
708 | goto els_err; |
709 | } |
710 | |
711 | els_req->sc_cmd = NULL; |
712 | els_req->port = port; |
713 | els_req->tgt = tgt; |
714 | els_req->cb_func = cb_func; |
715 | cb_arg->io_req = els_req; |
716 | els_req->cb_arg = cb_arg; |
717 | els_req->data_xfer_len = data_len; |
718 | |
719 | mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req); |
720 | rc = bnx2fc_init_mp_req(io_req: els_req); |
721 | if (rc == FAILED) { |
722 | printk(KERN_ERR PFX "ELS MP request init failed\n" ); |
723 | spin_lock_bh(lock: &tgt->tgt_lock); |
724 | kref_put(kref: &els_req->refcount, release: bnx2fc_cmd_release); |
725 | spin_unlock_bh(lock: &tgt->tgt_lock); |
726 | rc = -ENOMEM; |
727 | goto els_err; |
728 | } else { |
729 | /* rc SUCCESS */ |
730 | rc = 0; |
731 | } |
732 | |
733 | /* Set the data_xfer_len to the size of ELS payload */ |
734 | mp_req->req_len = data_len; |
735 | els_req->data_xfer_len = mp_req->req_len; |
736 | |
737 | /* Fill ELS Payload */ |
738 | if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) { |
739 | memcpy(mp_req->req_buf, data, data_len); |
740 | } else { |
741 | printk(KERN_ERR PFX "Invalid ELS op 0x%x\n" , op); |
742 | els_req->cb_func = NULL; |
743 | els_req->cb_arg = NULL; |
744 | spin_lock_bh(lock: &tgt->tgt_lock); |
745 | kref_put(kref: &els_req->refcount, release: bnx2fc_cmd_release); |
746 | spin_unlock_bh(lock: &tgt->tgt_lock); |
747 | rc = -EINVAL; |
748 | } |
749 | |
750 | if (rc) |
751 | goto els_err; |
752 | |
753 | /* Fill FC header */ |
754 | fc_hdr = &(mp_req->req_fc_hdr); |
755 | |
756 | did = tgt->rport->port_id; |
757 | sid = tgt->sid; |
758 | |
759 | if (op == ELS_SRR) |
760 | __fc_fill_fc_hdr(fh: fc_hdr, r_ctl: FC_RCTL_ELS4_REQ, did, sid, |
761 | type: FC_TYPE_FCP, FC_FC_FIRST_SEQ | |
762 | FC_FC_END_SEQ | FC_FC_SEQ_INIT, parm_offset: 0); |
763 | else |
764 | __fc_fill_fc_hdr(fh: fc_hdr, r_ctl: FC_RCTL_ELS_REQ, did, sid, |
765 | type: FC_TYPE_ELS, FC_FC_FIRST_SEQ | |
766 | FC_FC_END_SEQ | FC_FC_SEQ_INIT, parm_offset: 0); |
767 | |
768 | /* Obtain exchange id */ |
769 | xid = els_req->xid; |
770 | task_idx = xid/BNX2FC_TASKS_PER_PAGE; |
771 | index = xid % BNX2FC_TASKS_PER_PAGE; |
772 | |
773 | /* Initialize task context for this IO request */ |
774 | task_page = (struct fcoe_task_ctx_entry *) |
775 | interface->hba->task_ctx[task_idx]; |
776 | task = &(task_page[index]); |
777 | bnx2fc_init_mp_task(io_req: els_req, task); |
778 | |
779 | spin_lock_bh(lock: &tgt->tgt_lock); |
780 | |
781 | if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { |
782 | printk(KERN_ERR PFX "initiate_els.. session not ready\n" ); |
783 | els_req->cb_func = NULL; |
784 | els_req->cb_arg = NULL; |
785 | kref_put(kref: &els_req->refcount, release: bnx2fc_cmd_release); |
786 | spin_unlock_bh(lock: &tgt->tgt_lock); |
787 | return -EINVAL; |
788 | } |
789 | |
790 | if (timer_msec) |
791 | bnx2fc_cmd_timer_set(io_req: els_req, timer_msec); |
792 | bnx2fc_add_2_sq(tgt, xid); |
793 | |
794 | els_req->on_active_queue = 1; |
795 | list_add_tail(new: &els_req->link, head: &tgt->els_queue); |
796 | |
797 | /* Ring doorbell */ |
798 | bnx2fc_ring_doorbell(tgt); |
799 | spin_unlock_bh(lock: &tgt->tgt_lock); |
800 | |
801 | els_err: |
802 | return rc; |
803 | } |
804 | |
805 | void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, |
806 | struct fcoe_task_ctx_entry *task, u8 num_rq) |
807 | { |
808 | struct bnx2fc_mp_req *mp_req; |
809 | struct fc_frame_header *fc_hdr; |
810 | u64 *hdr; |
811 | u64 *temp_hdr; |
812 | |
813 | BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x" |
814 | "cmd_type = %d\n" , els_req->xid, els_req->cmd_type); |
815 | |
816 | if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE, |
817 | addr: &els_req->req_flags)) { |
818 | BNX2FC_ELS_DBG("Timer context finished processing this " |
819 | "els - 0x%x\n" , els_req->xid); |
820 | /* This IO doesn't receive cleanup completion */ |
821 | kref_put(kref: &els_req->refcount, release: bnx2fc_cmd_release); |
822 | return; |
823 | } |
824 | |
825 | /* Cancel the timeout_work, as we received the response */ |
826 | if (cancel_delayed_work(dwork: &els_req->timeout_work)) |
827 | kref_put(kref: &els_req->refcount, |
828 | release: bnx2fc_cmd_release); /* drop timer hold */ |
829 | |
830 | if (els_req->on_active_queue) { |
831 | list_del_init(entry: &els_req->link); |
832 | els_req->on_active_queue = 0; |
833 | } |
834 | |
835 | mp_req = &(els_req->mp_req); |
836 | fc_hdr = &(mp_req->resp_fc_hdr); |
837 | |
838 | hdr = (u64 *)fc_hdr; |
839 | temp_hdr = (u64 *) |
840 | &task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr; |
841 | hdr[0] = cpu_to_be64(temp_hdr[0]); |
842 | hdr[1] = cpu_to_be64(temp_hdr[1]); |
843 | hdr[2] = cpu_to_be64(temp_hdr[2]); |
844 | |
845 | mp_req->resp_len = |
846 | task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len; |
847 | |
848 | /* Parse ELS response */ |
849 | if ((els_req->cb_func) && (els_req->cb_arg)) { |
850 | els_req->cb_func(els_req->cb_arg); |
851 | els_req->cb_arg = NULL; |
852 | } |
853 | |
854 | kref_put(kref: &els_req->refcount, release: bnx2fc_cmd_release); |
855 | } |
856 | |
857 | #define BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC 1 |
858 | #define BNX2FC_FCOE_MAC_METHOD_FCF_MAP 2 |
859 | #define BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC 3 |
860 | static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, |
861 | void *arg) |
862 | { |
863 | struct fcoe_ctlr *fip = arg; |
864 | struct fc_exch *exch = fc_seq_exch(seq); |
865 | struct fc_lport *lport = exch->lp; |
866 | |
867 | struct fc_frame_header *fh; |
868 | u8 *granted_mac; |
869 | u8 fcoe_mac[6]; |
870 | u8 fc_map[3]; |
871 | int method; |
872 | |
873 | if (IS_ERR(ptr: fp)) |
874 | goto done; |
875 | |
876 | fh = fc_frame_header_get(fp); |
877 | granted_mac = fr_cb(fp)->granted_mac; |
878 | |
879 | /* |
880 | * We set the source MAC for FCoE traffic based on the Granted MAC |
881 | * address from the switch. |
882 | * |
883 | * If granted_mac is non-zero, we use that. |
884 | * If the granted_mac is zeroed out, create the FCoE MAC based on |
885 | * the sel_fcf->fc_map and the d_id fo the FLOGI frame. |
886 | * If sel_fcf->fc_map is 0, then we use the default FCF-MAC plus the |
887 | * d_id of the FLOGI frame. |
888 | */ |
889 | if (!is_zero_ether_addr(addr: granted_mac)) { |
890 | ether_addr_copy(dst: fcoe_mac, src: granted_mac); |
891 | method = BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC; |
892 | } else if (fip->sel_fcf && fip->sel_fcf->fc_map != 0) { |
893 | hton24(p: fc_map, v: fip->sel_fcf->fc_map); |
894 | fcoe_mac[0] = fc_map[0]; |
895 | fcoe_mac[1] = fc_map[1]; |
896 | fcoe_mac[2] = fc_map[2]; |
897 | fcoe_mac[3] = fh->fh_d_id[0]; |
898 | fcoe_mac[4] = fh->fh_d_id[1]; |
899 | fcoe_mac[5] = fh->fh_d_id[2]; |
900 | method = BNX2FC_FCOE_MAC_METHOD_FCF_MAP; |
901 | } else { |
902 | fc_fcoe_set_mac(mac: fcoe_mac, did: fh->fh_d_id); |
903 | method = BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC; |
904 | } |
905 | |
906 | BNX2FC_HBA_DBG(lport, fmt: "fcoe_mac=%pM method=%d\n" , fcoe_mac, method); |
907 | fip->update_mac(lport, fcoe_mac); |
908 | done: |
909 | fc_lport_flogi_resp(seq, fp, lport); |
910 | } |
911 | |
912 | static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, |
913 | void *arg) |
914 | { |
915 | struct fcoe_ctlr *fip = arg; |
916 | struct fc_exch *exch = fc_seq_exch(seq); |
917 | struct fc_lport *lport = exch->lp; |
918 | static u8 zero_mac[ETH_ALEN] = { 0 }; |
919 | |
920 | if (!IS_ERR(ptr: fp)) |
921 | fip->update_mac(lport, zero_mac); |
922 | fc_lport_logo_resp(seq, fp, lport); |
923 | } |
924 | |
925 | struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did, |
926 | struct fc_frame *fp, unsigned int op, |
927 | void (*resp)(struct fc_seq *, |
928 | struct fc_frame *, |
929 | void *), |
930 | void *arg, u32 timeout) |
931 | { |
932 | struct fcoe_port *port = lport_priv(lport); |
933 | struct bnx2fc_interface *interface = port->priv; |
934 | struct fcoe_ctlr *fip = bnx2fc_to_ctlr(interface); |
935 | struct fc_frame_header *fh = fc_frame_header_get(fp); |
936 | |
937 | switch (op) { |
938 | case ELS_FLOGI: |
939 | case ELS_FDISC: |
940 | return fc_elsct_send(lport, did, fp, op, resp: bnx2fc_flogi_resp, |
941 | arg: fip, timer_msec: timeout); |
942 | case ELS_LOGO: |
943 | /* only hook onto fabric logouts, not port logouts */ |
944 | if (ntoh24(p: fh->fh_d_id) != FC_FID_FLOGI) |
945 | break; |
946 | return fc_elsct_send(lport, did, fp, op, resp: bnx2fc_logo_resp, |
947 | arg: fip, timer_msec: timeout); |
948 | } |
949 | return fc_elsct_send(lport, did, fp, op, resp, arg, timer_msec: timeout); |
950 | } |
951 | |