2 * bnx2fc_els.c: Broadcom NetXtreme II Linux FCoE offload driver.
3 * This file contains helper routines that handle ELS requests
6 * Copyright (c) 2008 - 2010 Broadcom Corporation
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation.
12 * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
17 static void bnx2fc_logo_resp(struct fc_seq
*seq
, struct fc_frame
*fp
,
19 static void bnx2fc_flogi_resp(struct fc_seq
*seq
, struct fc_frame
*fp
,
21 static int bnx2fc_initiate_els(struct bnx2fc_rport
*tgt
, unsigned int op
,
22 void *data
, u32 data_len
,
23 void (*cb_func
)(struct bnx2fc_els_cb_arg
*cb_arg
),
24 struct bnx2fc_els_cb_arg
*cb_arg
, u32 timer_msec
);
26 static void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg
*cb_arg
)
28 struct bnx2fc_cmd
*orig_io_req
;
29 struct bnx2fc_cmd
*rrq_req
;
33 rrq_req
= cb_arg
->io_req
;
34 orig_io_req
= cb_arg
->aborted_io_req
;
36 BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n",
37 orig_io_req
->xid
, rrq_req
->xid
);
39 kref_put(&orig_io_req
->refcount
, bnx2fc_cmd_release
);
41 if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT
, &rrq_req
->req_flags
)) {
43 * els req is timed out. cleanup the IO with FW and
44 * drop the completion. Remove from active_cmd_queue.
46 BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n",
49 if (rrq_req
->on_active_queue
) {
50 list_del_init(&rrq_req
->link
);
51 rrq_req
->on_active_queue
= 0;
52 rc
= bnx2fc_initiate_cleanup(rrq_req
);
58 int bnx2fc_send_rrq(struct bnx2fc_cmd
*aborted_io_req
)
61 struct fc_els_rrq rrq
;
62 struct bnx2fc_rport
*tgt
= aborted_io_req
->tgt
;
63 struct fc_lport
*lport
= tgt
->rdata
->local_port
;
64 struct bnx2fc_els_cb_arg
*cb_arg
= NULL
;
66 u32 r_a_tov
= lport
->r_a_tov
;
67 unsigned long start
= jiffies
;
70 BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n",
72 memset(&rrq
, 0, sizeof(rrq
));
74 cb_arg
= kzalloc(sizeof(struct bnx2fc_els_cb_arg
), GFP_NOIO
);
76 printk(KERN_ERR PFX
"Unable to allocate cb_arg for RRQ\n");
81 cb_arg
->aborted_io_req
= aborted_io_req
;
83 rrq
.rrq_cmd
= ELS_RRQ
;
84 hton24(rrq
.rrq_s_id
, sid
);
85 rrq
.rrq_ox_id
= htons(aborted_io_req
->xid
);
86 rrq
.rrq_rx_id
= htons(aborted_io_req
->task
->rx_wr_tx_rd
.rx_id
);
89 rc
= bnx2fc_initiate_els(tgt
, ELS_RRQ
, &rrq
, sizeof(rrq
),
90 bnx2fc_rrq_compl
, cb_arg
,
93 if (time_after(jiffies
, start
+ (10 * HZ
))) {
94 BNX2FC_ELS_DBG("rrq Failed\n");
103 BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n",
104 aborted_io_req
->xid
);
106 spin_lock_bh(&tgt
->tgt_lock
);
107 kref_put(&aborted_io_req
->refcount
, bnx2fc_cmd_release
);
108 spin_unlock_bh(&tgt
->tgt_lock
);
113 static void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg
*cb_arg
)
115 struct bnx2fc_cmd
*els_req
;
116 struct bnx2fc_rport
*tgt
;
117 struct bnx2fc_mp_req
*mp_req
;
118 struct fc_frame_header
*fc_hdr
;
121 u32 resp_len
, hdr_len
;
126 l2_oxid
= cb_arg
->l2_oxid
;
127 BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n", l2_oxid
);
129 els_req
= cb_arg
->io_req
;
130 if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT
, &els_req
->req_flags
)) {
132 * els req is timed out. cleanup the IO with FW and
133 * drop the completion. libfc will handle the els timeout
135 if (els_req
->on_active_queue
) {
136 list_del_init(&els_req
->link
);
137 els_req
->on_active_queue
= 0;
138 rc
= bnx2fc_initiate_cleanup(els_req
);
145 mp_req
= &(els_req
->mp_req
);
146 fc_hdr
= &(mp_req
->resp_fc_hdr
);
147 resp_len
= mp_req
->resp_len
;
148 resp_buf
= mp_req
->resp_buf
;
150 buf
= kzalloc(PAGE_SIZE
, GFP_ATOMIC
);
152 printk(KERN_ERR PFX
"Unable to alloc mp buf\n");
155 hdr_len
= sizeof(*fc_hdr
);
156 if (hdr_len
+ resp_len
> PAGE_SIZE
) {
157 printk(KERN_ERR PFX
"l2_els_compl: resp len is "
158 "beyond page size\n");
161 memcpy(buf
, fc_hdr
, hdr_len
);
162 memcpy(buf
+ hdr_len
, resp_buf
, resp_len
);
163 frame_len
= hdr_len
+ resp_len
;
165 bnx2fc_process_l2_frame_compl(tgt
, buf
, frame_len
, l2_oxid
);
173 int bnx2fc_send_adisc(struct bnx2fc_rport
*tgt
, struct fc_frame
*fp
)
175 struct fc_els_adisc
*adisc
;
176 struct fc_frame_header
*fh
;
177 struct bnx2fc_els_cb_arg
*cb_arg
;
178 struct fc_lport
*lport
= tgt
->rdata
->local_port
;
179 u32 r_a_tov
= lport
->r_a_tov
;
182 fh
= fc_frame_header_get(fp
);
183 cb_arg
= kzalloc(sizeof(struct bnx2fc_els_cb_arg
), GFP_ATOMIC
);
185 printk(KERN_ERR PFX
"Unable to allocate cb_arg for ADISC\n");
189 cb_arg
->l2_oxid
= ntohs(fh
->fh_ox_id
);
191 BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n", cb_arg
->l2_oxid
);
192 adisc
= fc_frame_payload_get(fp
, sizeof(*adisc
));
193 /* adisc is initialized by libfc */
194 rc
= bnx2fc_initiate_els(tgt
, ELS_ADISC
, adisc
, sizeof(*adisc
),
195 bnx2fc_l2_els_compl
, cb_arg
, 2 * r_a_tov
);
201 int bnx2fc_send_logo(struct bnx2fc_rport
*tgt
, struct fc_frame
*fp
)
203 struct fc_els_logo
*logo
;
204 struct fc_frame_header
*fh
;
205 struct bnx2fc_els_cb_arg
*cb_arg
;
206 struct fc_lport
*lport
= tgt
->rdata
->local_port
;
207 u32 r_a_tov
= lport
->r_a_tov
;
210 fh
= fc_frame_header_get(fp
);
211 cb_arg
= kzalloc(sizeof(struct bnx2fc_els_cb_arg
), GFP_ATOMIC
);
213 printk(KERN_ERR PFX
"Unable to allocate cb_arg for LOGO\n");
217 cb_arg
->l2_oxid
= ntohs(fh
->fh_ox_id
);
219 BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n", cb_arg
->l2_oxid
);
220 logo
= fc_frame_payload_get(fp
, sizeof(*logo
));
221 /* logo is initialized by libfc */
222 rc
= bnx2fc_initiate_els(tgt
, ELS_LOGO
, logo
, sizeof(*logo
),
223 bnx2fc_l2_els_compl
, cb_arg
, 2 * r_a_tov
);
229 int bnx2fc_send_rls(struct bnx2fc_rport
*tgt
, struct fc_frame
*fp
)
231 struct fc_els_rls
*rls
;
232 struct fc_frame_header
*fh
;
233 struct bnx2fc_els_cb_arg
*cb_arg
;
234 struct fc_lport
*lport
= tgt
->rdata
->local_port
;
235 u32 r_a_tov
= lport
->r_a_tov
;
238 fh
= fc_frame_header_get(fp
);
239 cb_arg
= kzalloc(sizeof(struct bnx2fc_els_cb_arg
), GFP_ATOMIC
);
241 printk(KERN_ERR PFX
"Unable to allocate cb_arg for LOGO\n");
245 cb_arg
->l2_oxid
= ntohs(fh
->fh_ox_id
);
247 rls
= fc_frame_payload_get(fp
, sizeof(*rls
));
248 /* rls is initialized by libfc */
249 rc
= bnx2fc_initiate_els(tgt
, ELS_RLS
, rls
, sizeof(*rls
),
250 bnx2fc_l2_els_compl
, cb_arg
, 2 * r_a_tov
);
256 static int bnx2fc_initiate_els(struct bnx2fc_rport
*tgt
, unsigned int op
,
257 void *data
, u32 data_len
,
258 void (*cb_func
)(struct bnx2fc_els_cb_arg
*cb_arg
),
259 struct bnx2fc_els_cb_arg
*cb_arg
, u32 timer_msec
)
261 struct fcoe_port
*port
= tgt
->port
;
262 struct bnx2fc_hba
*hba
= port
->priv
;
263 struct fc_rport
*rport
= tgt
->rport
;
264 struct fc_lport
*lport
= port
->lport
;
265 struct bnx2fc_cmd
*els_req
;
266 struct bnx2fc_mp_req
*mp_req
;
267 struct fc_frame_header
*fc_hdr
;
268 struct fcoe_task_ctx_entry
*task
;
269 struct fcoe_task_ctx_entry
*task_page
;
275 rc
= fc_remote_port_chkready(rport
);
277 printk(KERN_ALERT PFX
"els 0x%x: rport not ready\n", op
);
281 if (lport
->state
!= LPORT_ST_READY
|| !(lport
->link_up
)) {
282 printk(KERN_ALERT PFX
"els 0x%x: link is not ready\n", op
);
286 if (!(test_bit(BNX2FC_FLAG_SESSION_READY
, &tgt
->flags
)) ||
287 (test_bit(BNX2FC_FLAG_EXPL_LOGO
, &tgt
->flags
))) {
288 printk(KERN_ERR PFX
"els 0x%x: tgt not ready\n", op
);
292 els_req
= bnx2fc_elstm_alloc(tgt
, BNX2FC_ELS
);
298 els_req
->sc_cmd
= NULL
;
299 els_req
->port
= port
;
301 els_req
->cb_func
= cb_func
;
302 cb_arg
->io_req
= els_req
;
303 els_req
->cb_arg
= cb_arg
;
305 mp_req
= (struct bnx2fc_mp_req
*)&(els_req
->mp_req
);
306 rc
= bnx2fc_init_mp_req(els_req
);
308 printk(KERN_ALERT PFX
"ELS MP request init failed\n");
309 spin_lock_bh(&tgt
->tgt_lock
);
310 kref_put(&els_req
->refcount
, bnx2fc_cmd_release
);
311 spin_unlock_bh(&tgt
->tgt_lock
);
319 /* Set the data_xfer_len to the size of ELS payload */
320 mp_req
->req_len
= data_len
;
321 els_req
->data_xfer_len
= mp_req
->req_len
;
323 /* Fill ELS Payload */
324 if ((op
>= ELS_LS_RJT
) && (op
<= ELS_AUTH_ELS
)) {
325 memcpy(mp_req
->req_buf
, data
, data_len
);
327 printk(KERN_ALERT PFX
"Invalid ELS op 0x%x\n", op
);
328 els_req
->cb_func
= NULL
;
329 els_req
->cb_arg
= NULL
;
330 spin_lock_bh(&tgt
->tgt_lock
);
331 kref_put(&els_req
->refcount
, bnx2fc_cmd_release
);
332 spin_unlock_bh(&tgt
->tgt_lock
);
340 fc_hdr
= &(mp_req
->req_fc_hdr
);
342 did
= tgt
->rport
->port_id
;
345 __fc_fill_fc_hdr(fc_hdr
, FC_RCTL_ELS_REQ
, did
, sid
,
346 FC_TYPE_ELS
, FC_FC_FIRST_SEQ
| FC_FC_END_SEQ
|
349 /* Obtain exchange id */
351 task_idx
= xid
/BNX2FC_TASKS_PER_PAGE
;
352 index
= xid
% BNX2FC_TASKS_PER_PAGE
;
354 /* Initialize task context for this IO request */
355 task_page
= (struct fcoe_task_ctx_entry
*) hba
->task_ctx
[task_idx
];
356 task
= &(task_page
[index
]);
357 bnx2fc_init_mp_task(els_req
, task
);
359 spin_lock_bh(&tgt
->tgt_lock
);
361 if (!test_bit(BNX2FC_FLAG_SESSION_READY
, &tgt
->flags
)) {
362 printk(KERN_ERR PFX
"initiate_els.. session not ready\n");
363 els_req
->cb_func
= NULL
;
364 els_req
->cb_arg
= NULL
;
365 kref_put(&els_req
->refcount
, bnx2fc_cmd_release
);
366 spin_unlock_bh(&tgt
->tgt_lock
);
371 bnx2fc_cmd_timer_set(els_req
, timer_msec
);
372 bnx2fc_add_2_sq(tgt
, xid
);
374 els_req
->on_active_queue
= 1;
375 list_add_tail(&els_req
->link
, &tgt
->els_queue
);
378 bnx2fc_ring_doorbell(tgt
);
379 spin_unlock_bh(&tgt
->tgt_lock
);
385 void bnx2fc_process_els_compl(struct bnx2fc_cmd
*els_req
,
386 struct fcoe_task_ctx_entry
*task
, u8 num_rq
)
388 struct bnx2fc_mp_req
*mp_req
;
389 struct fc_frame_header
*fc_hdr
;
393 BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x"
394 "cmd_type = %d\n", els_req
->xid
, els_req
->cmd_type
);
396 if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE
,
397 &els_req
->req_flags
)) {
398 BNX2FC_ELS_DBG("Timer context finished processing this "
399 "els - 0x%x\n", els_req
->xid
);
400 /* This IO doesn't receive cleanup completion */
401 kref_put(&els_req
->refcount
, bnx2fc_cmd_release
);
405 /* Cancel the timeout_work, as we received the response */
406 if (cancel_delayed_work(&els_req
->timeout_work
))
407 kref_put(&els_req
->refcount
,
408 bnx2fc_cmd_release
); /* drop timer hold */
410 if (els_req
->on_active_queue
) {
411 list_del_init(&els_req
->link
);
412 els_req
->on_active_queue
= 0;
415 mp_req
= &(els_req
->mp_req
);
416 fc_hdr
= &(mp_req
->resp_fc_hdr
);
420 &task
->cmn
.general
.cmd_info
.mp_fc_frame
.fc_hdr
;
421 hdr
[0] = cpu_to_be64(temp_hdr
[0]);
422 hdr
[1] = cpu_to_be64(temp_hdr
[1]);
423 hdr
[2] = cpu_to_be64(temp_hdr
[2]);
425 mp_req
->resp_len
= task
->rx_wr_only
.sgl_ctx
.mul_sges
.cur_sge_off
;
427 /* Parse ELS response */
428 if ((els_req
->cb_func
) && (els_req
->cb_arg
)) {
429 els_req
->cb_func(els_req
->cb_arg
);
430 els_req
->cb_arg
= NULL
;
433 kref_put(&els_req
->refcount
, bnx2fc_cmd_release
);
436 static void bnx2fc_flogi_resp(struct fc_seq
*seq
, struct fc_frame
*fp
,
439 struct fcoe_ctlr
*fip
= arg
;
440 struct fc_exch
*exch
= fc_seq_exch(seq
);
441 struct fc_lport
*lport
= exch
->lp
;
443 struct fc_frame_header
*fh
;
449 mac
= fr_cb(fp
)->granted_mac
;
450 if (is_zero_ether_addr(mac
)) {
451 fh
= fc_frame_header_get(fp
);
452 if (fh
->fh_type
!= FC_TYPE_ELS
) {
453 printk(KERN_ERR PFX
"bnx2fc_flogi_resp:"
454 "fh_type != FC_TYPE_ELS\n");
458 op
= fc_frame_payload_op(fp
);
460 if (op
== ELS_LS_RJT
) {
461 printk(KERN_ERR PFX
"bnx2fc_flogi_resp is LS_RJT\n");
462 fc_vport_terminate(lport
->vport
);
467 if (fcoe_ctlr_recv_flogi(fip
, lport
, fp
)) {
472 fip
->update_mac(lport
, mac
);
474 fc_lport_flogi_resp(seq
, fp
, lport
);
477 static void bnx2fc_logo_resp(struct fc_seq
*seq
, struct fc_frame
*fp
,
480 struct fcoe_ctlr
*fip
= arg
;
481 struct fc_exch
*exch
= fc_seq_exch(seq
);
482 struct fc_lport
*lport
= exch
->lp
;
483 static u8 zero_mac
[ETH_ALEN
] = { 0 };
486 fip
->update_mac(lport
, zero_mac
);
487 fc_lport_logo_resp(seq
, fp
, lport
);
490 struct fc_seq
*bnx2fc_elsct_send(struct fc_lport
*lport
, u32 did
,
491 struct fc_frame
*fp
, unsigned int op
,
492 void (*resp
)(struct fc_seq
*,
495 void *arg
, u32 timeout
)
497 struct fcoe_port
*port
= lport_priv(lport
);
498 struct bnx2fc_hba
*hba
= port
->priv
;
499 struct fcoe_ctlr
*fip
= &hba
->ctlr
;
500 struct fc_frame_header
*fh
= fc_frame_header_get(fp
);
505 return fc_elsct_send(lport
, did
, fp
, op
, bnx2fc_flogi_resp
,
508 /* only hook onto fabric logouts, not port logouts */
509 if (ntoh24(fh
->fh_d_id
) != FC_FID_FLOGI
)
511 return fc_elsct_send(lport
, did
, fp
, op
, bnx2fc_logo_resp
,
514 return fc_elsct_send(lport
, did
, fp
, op
, resp
, arg
, timeout
);