2 * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License (GPL) Version 2 as
10 * published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
19 #include <bfi/bfi_lps.h>
20 #include <cs/bfa_debug.h>
22 BFA_TRC_FILE(HAL
, LPS
);
25 #define BFA_LPS_MIN_LPORTS (1)
26 #define BFA_LPS_MAX_LPORTS (256)
29 * forward declarations
31 static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s
*cfg
, u32
*ndm_len
,
33 static void bfa_lps_attach(struct bfa_s
*bfa
, void *bfad
,
34 struct bfa_iocfc_cfg_s
*cfg
,
35 struct bfa_meminfo_s
*meminfo
,
36 struct bfa_pcidev_s
*pcidev
);
37 static void bfa_lps_initdone(struct bfa_s
*bfa
);
38 static void bfa_lps_detach(struct bfa_s
*bfa
);
39 static void bfa_lps_start(struct bfa_s
*bfa
);
40 static void bfa_lps_stop(struct bfa_s
*bfa
);
41 static void bfa_lps_iocdisable(struct bfa_s
*bfa
);
42 static void bfa_lps_login_rsp(struct bfa_s
*bfa
,
43 struct bfi_lps_login_rsp_s
*rsp
);
44 static void bfa_lps_logout_rsp(struct bfa_s
*bfa
,
45 struct bfi_lps_logout_rsp_s
*rsp
);
46 static void bfa_lps_reqq_resume(void *lps_arg
);
47 static void bfa_lps_free(struct bfa_lps_s
*lps
);
48 static void bfa_lps_send_login(struct bfa_lps_s
*lps
);
49 static void bfa_lps_send_logout(struct bfa_lps_s
*lps
);
50 static void bfa_lps_login_comp(struct bfa_lps_s
*lps
);
51 static void bfa_lps_logout_comp(struct bfa_lps_s
*lps
);
55 * lps_pvt BFA LPS private functions
59 BFA_LPS_SM_LOGIN
= 1, /* login request from user */
60 BFA_LPS_SM_LOGOUT
= 2, /* logout request from user */
61 BFA_LPS_SM_FWRSP
= 3, /* f/w response to login/logout */
62 BFA_LPS_SM_RESUME
= 4, /* space present in reqq queue */
63 BFA_LPS_SM_DELETE
= 5, /* lps delete from user */
64 BFA_LPS_SM_OFFLINE
= 6, /* Link is offline */
67 static void bfa_lps_sm_init(struct bfa_lps_s
*lps
, enum bfa_lps_event event
);
68 static void bfa_lps_sm_login(struct bfa_lps_s
*lps
, enum bfa_lps_event event
);
69 static void bfa_lps_sm_loginwait(struct bfa_lps_s
*lps
,
70 enum bfa_lps_event event
);
71 static void bfa_lps_sm_online(struct bfa_lps_s
*lps
, enum bfa_lps_event event
);
72 static void bfa_lps_sm_logout(struct bfa_lps_s
*lps
, enum bfa_lps_event event
);
73 static void bfa_lps_sm_logowait(struct bfa_lps_s
*lps
,
74 enum bfa_lps_event event
);
77 * Init state -- no login
80 bfa_lps_sm_init(struct bfa_lps_s
*lps
, enum bfa_lps_event event
)
82 bfa_trc(lps
->bfa
, lps
->lp_tag
);
83 bfa_trc(lps
->bfa
, event
);
86 case BFA_LPS_SM_LOGIN
:
87 if (bfa_reqq_full(lps
->bfa
, lps
->reqq
)) {
88 bfa_sm_set_state(lps
, bfa_lps_sm_loginwait
);
89 bfa_reqq_wait(lps
->bfa
, lps
->reqq
, &lps
->wqe
);
91 bfa_sm_set_state(lps
, bfa_lps_sm_login
);
92 bfa_lps_send_login(lps
);
96 case BFA_LPS_SM_LOGOUT
:
97 bfa_lps_logout_comp(lps
);
100 case BFA_LPS_SM_DELETE
:
104 case BFA_LPS_SM_OFFLINE
:
107 case BFA_LPS_SM_FWRSP
:
108 /* Could happen when fabric detects loopback and discards
109 * the lps request. Fw will eventually sent out the timeout
120 * login is in progress -- awaiting response from firmware
123 bfa_lps_sm_login(struct bfa_lps_s
*lps
, enum bfa_lps_event event
)
125 bfa_trc(lps
->bfa
, lps
->lp_tag
);
126 bfa_trc(lps
->bfa
, event
);
129 case BFA_LPS_SM_FWRSP
:
130 if (lps
->status
== BFA_STATUS_OK
)
131 bfa_sm_set_state(lps
, bfa_lps_sm_online
);
133 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
134 bfa_lps_login_comp(lps
);
137 case BFA_LPS_SM_OFFLINE
:
138 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
147 * login pending - awaiting space in request queue
150 bfa_lps_sm_loginwait(struct bfa_lps_s
*lps
, enum bfa_lps_event event
)
152 bfa_trc(lps
->bfa
, lps
->lp_tag
);
153 bfa_trc(lps
->bfa
, event
);
156 case BFA_LPS_SM_RESUME
:
157 bfa_sm_set_state(lps
, bfa_lps_sm_login
);
160 case BFA_LPS_SM_OFFLINE
:
161 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
162 bfa_reqq_wcancel(&lps
->wqe
);
174 bfa_lps_sm_online(struct bfa_lps_s
*lps
, enum bfa_lps_event event
)
176 bfa_trc(lps
->bfa
, lps
->lp_tag
);
177 bfa_trc(lps
->bfa
, event
);
180 case BFA_LPS_SM_LOGOUT
:
181 if (bfa_reqq_full(lps
->bfa
, lps
->reqq
)) {
182 bfa_sm_set_state(lps
, bfa_lps_sm_logowait
);
183 bfa_reqq_wait(lps
->bfa
, lps
->reqq
, &lps
->wqe
);
185 bfa_sm_set_state(lps
, bfa_lps_sm_logout
);
186 bfa_lps_send_logout(lps
);
190 case BFA_LPS_SM_OFFLINE
:
191 case BFA_LPS_SM_DELETE
:
192 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
201 * logout in progress - awaiting firmware response
204 bfa_lps_sm_logout(struct bfa_lps_s
*lps
, enum bfa_lps_event event
)
206 bfa_trc(lps
->bfa
, lps
->lp_tag
);
207 bfa_trc(lps
->bfa
, event
);
210 case BFA_LPS_SM_FWRSP
:
211 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
212 bfa_lps_logout_comp(lps
);
215 case BFA_LPS_SM_OFFLINE
:
216 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
225 * logout pending -- awaiting space in request queue
228 bfa_lps_sm_logowait(struct bfa_lps_s
*lps
, enum bfa_lps_event event
)
230 bfa_trc(lps
->bfa
, lps
->lp_tag
);
231 bfa_trc(lps
->bfa
, event
);
234 case BFA_LPS_SM_RESUME
:
235 bfa_sm_set_state(lps
, bfa_lps_sm_logout
);
236 bfa_lps_send_logout(lps
);
239 case BFA_LPS_SM_OFFLINE
:
240 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
241 bfa_reqq_wcancel(&lps
->wqe
);
252 * lps_pvt BFA LPS private functions
256 * return memory requirement
259 bfa_lps_meminfo(struct bfa_iocfc_cfg_s
*cfg
, u32
*ndm_len
, u32
*dm_len
)
261 if (cfg
->drvcfg
.min_cfg
)
262 *ndm_len
+= sizeof(struct bfa_lps_s
) * BFA_LPS_MIN_LPORTS
;
264 *ndm_len
+= sizeof(struct bfa_lps_s
) * BFA_LPS_MAX_LPORTS
;
268 * bfa module attach at initialization time
271 bfa_lps_attach(struct bfa_s
*bfa
, void *bfad
, struct bfa_iocfc_cfg_s
*cfg
,
272 struct bfa_meminfo_s
*meminfo
, struct bfa_pcidev_s
*pcidev
)
274 struct bfa_lps_mod_s
*mod
= BFA_LPS_MOD(bfa
);
275 struct bfa_lps_s
*lps
;
278 bfa_os_memset(mod
, 0, sizeof(struct bfa_lps_mod_s
));
279 mod
->num_lps
= BFA_LPS_MAX_LPORTS
;
280 if (cfg
->drvcfg
.min_cfg
)
281 mod
->num_lps
= BFA_LPS_MIN_LPORTS
;
283 mod
->num_lps
= BFA_LPS_MAX_LPORTS
;
284 mod
->lps_arr
= lps
= (struct bfa_lps_s
*) bfa_meminfo_kva(meminfo
);
286 bfa_meminfo_kva(meminfo
) += mod
->num_lps
* sizeof(struct bfa_lps_s
);
288 INIT_LIST_HEAD(&mod
->lps_free_q
);
289 INIT_LIST_HEAD(&mod
->lps_active_q
);
291 for (i
= 0; i
< mod
->num_lps
; i
++, lps
++) {
293 lps
->lp_tag
= (u8
) i
;
294 lps
->reqq
= BFA_REQQ_LPS
;
295 bfa_reqq_winit(&lps
->wqe
, bfa_lps_reqq_resume
, lps
);
296 list_add_tail(&lps
->qe
, &mod
->lps_free_q
);
301 bfa_lps_initdone(struct bfa_s
*bfa
)
306 bfa_lps_detach(struct bfa_s
*bfa
)
311 bfa_lps_start(struct bfa_s
*bfa
)
316 bfa_lps_stop(struct bfa_s
*bfa
)
321 * IOC in disabled state -- consider all lps offline
324 bfa_lps_iocdisable(struct bfa_s
*bfa
)
326 struct bfa_lps_mod_s
*mod
= BFA_LPS_MOD(bfa
);
327 struct bfa_lps_s
*lps
;
328 struct list_head
*qe
, *qen
;
330 list_for_each_safe(qe
, qen
, &mod
->lps_active_q
) {
331 lps
= (struct bfa_lps_s
*) qe
;
332 bfa_sm_send_event(lps
, BFA_LPS_SM_OFFLINE
);
337 * Firmware login response
340 bfa_lps_login_rsp(struct bfa_s
*bfa
, struct bfi_lps_login_rsp_s
*rsp
)
342 struct bfa_lps_mod_s
*mod
= BFA_LPS_MOD(bfa
);
343 struct bfa_lps_s
*lps
;
345 bfa_assert(rsp
->lp_tag
< mod
->num_lps
);
346 lps
= BFA_LPS_FROM_TAG(mod
, rsp
->lp_tag
);
348 lps
->status
= rsp
->status
;
349 switch (rsp
->status
) {
351 lps
->fport
= rsp
->f_port
;
352 lps
->npiv_en
= rsp
->npiv_en
;
353 lps
->lp_pid
= rsp
->lp_pid
;
354 lps
->pr_bbcred
= bfa_os_ntohs(rsp
->bb_credit
);
355 lps
->pr_pwwn
= rsp
->port_name
;
356 lps
->pr_nwwn
= rsp
->node_name
;
357 lps
->auth_req
= rsp
->auth_req
;
358 lps
->lp_mac
= rsp
->lp_mac
;
359 lps
->brcd_switch
= rsp
->brcd_switch
;
360 lps
->fcf_mac
= rsp
->fcf_mac
;
364 case BFA_STATUS_FABRIC_RJT
:
365 lps
->lsrjt_rsn
= rsp
->lsrjt_rsn
;
366 lps
->lsrjt_expl
= rsp
->lsrjt_expl
;
370 case BFA_STATUS_EPROTOCOL
:
371 lps
->ext_status
= rsp
->ext_status
;
376 /* Nothing to do with other status */
380 bfa_sm_send_event(lps
, BFA_LPS_SM_FWRSP
);
384 * Firmware logout response
387 bfa_lps_logout_rsp(struct bfa_s
*bfa
, struct bfi_lps_logout_rsp_s
*rsp
)
389 struct bfa_lps_mod_s
*mod
= BFA_LPS_MOD(bfa
);
390 struct bfa_lps_s
*lps
;
392 bfa_assert(rsp
->lp_tag
< mod
->num_lps
);
393 lps
= BFA_LPS_FROM_TAG(mod
, rsp
->lp_tag
);
395 bfa_sm_send_event(lps
, BFA_LPS_SM_FWRSP
);
399 * Space is available in request queue, resume queueing request to firmware.
402 bfa_lps_reqq_resume(void *lps_arg
)
404 struct bfa_lps_s
*lps
= lps_arg
;
406 bfa_sm_send_event(lps
, BFA_LPS_SM_RESUME
);
410 * lps is freed -- triggered by vport delete
413 bfa_lps_free(struct bfa_lps_s
*lps
)
415 struct bfa_lps_mod_s
*mod
= BFA_LPS_MOD(lps
->bfa
);
418 list_add_tail(&lps
->qe
, &mod
->lps_free_q
);
422 * send login request to firmware
425 bfa_lps_send_login(struct bfa_lps_s
*lps
)
427 struct bfi_lps_login_req_s
*m
;
429 m
= bfa_reqq_next(lps
->bfa
, lps
->reqq
);
432 bfi_h2i_set(m
->mh
, BFI_MC_LPS
, BFI_LPS_H2I_LOGIN_REQ
,
433 bfa_lpuid(lps
->bfa
));
435 m
->lp_tag
= lps
->lp_tag
;
437 m
->pdu_size
= bfa_os_htons(lps
->pdusz
);
440 m
->fdisc
= lps
->fdisc
;
441 m
->auth_en
= lps
->auth_en
;
443 bfa_reqq_produce(lps
->bfa
, lps
->reqq
);
447 * send logout request to firmware
450 bfa_lps_send_logout(struct bfa_lps_s
*lps
)
452 struct bfi_lps_logout_req_s
*m
;
454 m
= bfa_reqq_next(lps
->bfa
, lps
->reqq
);
457 bfi_h2i_set(m
->mh
, BFI_MC_LPS
, BFI_LPS_H2I_LOGOUT_REQ
,
458 bfa_lpuid(lps
->bfa
));
460 m
->lp_tag
= lps
->lp_tag
;
461 m
->port_name
= lps
->pwwn
;
462 bfa_reqq_produce(lps
->bfa
, lps
->reqq
);
466 * Indirect login completion handler for non-fcs
469 bfa_lps_login_comp_cb(void *arg
, bfa_boolean_t complete
)
471 struct bfa_lps_s
*lps
= arg
;
477 bfa_cb_lps_fdisc_comp(lps
->bfa
->bfad
, lps
->uarg
, lps
->status
);
479 bfa_cb_lps_flogi_comp(lps
->bfa
->bfad
, lps
->uarg
, lps
->status
);
483 * Login completion handler -- direct call for fcs, queue for others
486 bfa_lps_login_comp(struct bfa_lps_s
*lps
)
488 if (!lps
->bfa
->fcs
) {
489 bfa_cb_queue(lps
->bfa
, &lps
->hcb_qe
,
490 bfa_lps_login_comp_cb
, lps
);
495 bfa_cb_lps_fdisc_comp(lps
->bfa
->bfad
, lps
->uarg
, lps
->status
);
497 bfa_cb_lps_flogi_comp(lps
->bfa
->bfad
, lps
->uarg
, lps
->status
);
501 * Indirect logout completion handler for non-fcs
504 bfa_lps_logout_comp_cb(void *arg
, bfa_boolean_t complete
)
506 struct bfa_lps_s
*lps
= arg
;
512 bfa_cb_lps_fdisclogo_comp(lps
->bfa
->bfad
, lps
->uarg
);
514 bfa_cb_lps_flogo_comp(lps
->bfa
->bfad
, lps
->uarg
);
518 * Logout completion handler -- direct call for fcs, queue for others
521 bfa_lps_logout_comp(struct bfa_lps_s
*lps
)
523 if (!lps
->bfa
->fcs
) {
524 bfa_cb_queue(lps
->bfa
, &lps
->hcb_qe
,
525 bfa_lps_logout_comp_cb
, lps
);
529 bfa_cb_lps_fdisclogo_comp(lps
->bfa
->bfad
, lps
->uarg
);
531 bfa_cb_lps_flogo_comp(lps
->bfa
->bfad
, lps
->uarg
);
537 * lps_public BFA LPS public functions
541 * Allocate a lport srvice tag.
544 bfa_lps_alloc(struct bfa_s
*bfa
)
546 struct bfa_lps_mod_s
*mod
= BFA_LPS_MOD(bfa
);
547 struct bfa_lps_s
*lps
= NULL
;
549 bfa_q_deq(&mod
->lps_free_q
, &lps
);
554 list_add_tail(&lps
->qe
, &mod
->lps_active_q
);
556 bfa_sm_set_state(lps
, bfa_lps_sm_init
);
561 * Free lport service tag. This can be called anytime after an alloc.
562 * No need to wait for any pending login/logout completions.
565 bfa_lps_delete(struct bfa_lps_s
*lps
)
567 bfa_sm_send_event(lps
, BFA_LPS_SM_DELETE
);
571 * Initiate a lport login.
574 bfa_lps_flogi(struct bfa_lps_s
*lps
, void *uarg
, u8 alpa
, u16 pdusz
,
575 wwn_t pwwn
, wwn_t nwwn
, bfa_boolean_t auth_en
)
582 lps
->fdisc
= BFA_FALSE
;
583 lps
->auth_en
= auth_en
;
584 bfa_sm_send_event(lps
, BFA_LPS_SM_LOGIN
);
588 * Initiate a lport fdisc login.
591 bfa_lps_fdisc(struct bfa_lps_s
*lps
, void *uarg
, u16 pdusz
, wwn_t pwwn
,
599 lps
->fdisc
= BFA_TRUE
;
600 lps
->auth_en
= BFA_FALSE
;
601 bfa_sm_send_event(lps
, BFA_LPS_SM_LOGIN
);
605 * Initiate a lport logout (flogi).
608 bfa_lps_flogo(struct bfa_lps_s
*lps
)
610 bfa_sm_send_event(lps
, BFA_LPS_SM_LOGOUT
);
614 * Initiate a lport FDSIC logout.
617 bfa_lps_fdisclogo(struct bfa_lps_s
*lps
)
619 bfa_sm_send_event(lps
, BFA_LPS_SM_LOGOUT
);
623 * Discard a pending login request -- should be called only for
624 * link down handling.
627 bfa_lps_discard(struct bfa_lps_s
*lps
)
629 bfa_sm_send_event(lps
, BFA_LPS_SM_OFFLINE
);
633 * Return lport services tag
636 bfa_lps_get_tag(struct bfa_lps_s
*lps
)
642 * Return lport services tag given the pid
645 bfa_lps_get_tag_from_pid(struct bfa_s
*bfa
, u32 pid
)
647 struct bfa_lps_mod_s
*mod
= BFA_LPS_MOD(bfa
);
648 struct bfa_lps_s
*lps
;
651 for (i
= 0, lps
= mod
->lps_arr
; i
< mod
->num_lps
; i
++, lps
++) {
652 if (lps
->lp_pid
== pid
)
656 /* Return base port tag anyway */
661 * return if fabric login indicates support for NPIV
664 bfa_lps_is_npiv_en(struct bfa_lps_s
*lps
)
670 * Return TRUE if attached to F-Port, else return FALSE
673 bfa_lps_is_fport(struct bfa_lps_s
*lps
)
679 * Return TRUE if attached to a Brocade Fabric
682 bfa_lps_is_brcd_fabric(struct bfa_lps_s
*lps
)
684 return lps
->brcd_switch
;
687 * return TRUE if authentication is required
690 bfa_lps_is_authreq(struct bfa_lps_s
*lps
)
692 return lps
->auth_req
;
696 bfa_lps_get_extstatus(struct bfa_lps_s
*lps
)
698 return lps
->ext_status
;
702 * return port id assigned to the lport
705 bfa_lps_get_pid(struct bfa_lps_s
*lps
)
711 * Return bb_credit assigned in FLOGI response
714 bfa_lps_get_peer_bbcredit(struct bfa_lps_s
*lps
)
716 return lps
->pr_bbcred
;
720 * Return peer port name
723 bfa_lps_get_peer_pwwn(struct bfa_lps_s
*lps
)
729 * Return peer node name
732 bfa_lps_get_peer_nwwn(struct bfa_lps_s
*lps
)
738 * return reason code if login request is rejected
741 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s
*lps
)
743 return lps
->lsrjt_rsn
;
747 * return explanation code if login request is rejected
750 bfa_lps_get_lsrjt_expl(struct bfa_lps_s
*lps
)
752 return lps
->lsrjt_expl
;
757 * LPS firmware message class handler.
760 bfa_lps_isr(struct bfa_s
*bfa
, struct bfi_msg_s
*m
)
762 union bfi_lps_i2h_msg_u msg
;
764 bfa_trc(bfa
, m
->mhdr
.msg_id
);
767 switch (m
->mhdr
.msg_id
) {
768 case BFI_LPS_H2I_LOGIN_RSP
:
769 bfa_lps_login_rsp(bfa
, msg
.login_rsp
);
772 case BFI_LPS_H2I_LOGOUT_RSP
:
773 bfa_lps_logout_rsp(bfa
, msg
.logout_rsp
);
777 bfa_trc(bfa
, m
->mhdr
.msg_id
);