| /* | 
 |  * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. | 
 |  * All rights reserved | 
 |  * www.brocade.com | 
 |  * | 
 |  * Linux driver for Brocade Fibre Channel Host Bus Adapter. | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify it | 
 |  * under the terms of the GNU General Public License (GPL) Version 2 as | 
 |  * published by the Free Software Foundation | 
 |  * | 
 |  * This program is distributed in the hope that it will be useful, but | 
 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * General Public License for more details. | 
 |  */ | 
 |  | 
 | #include <bfa.h> | 
 | #include <bfi/bfi_lps.h> | 
 | #include <cs/bfa_debug.h> | 
 |  | 
 | BFA_TRC_FILE(HAL, LPS); | 
 | BFA_MODULE(lps); | 
 |  | 
 | #define BFA_LPS_MIN_LPORTS	(1) | 
 | #define BFA_LPS_MAX_LPORTS	(256) | 
 |  | 
 | /** | 
 |  * forward declarations | 
 |  */ | 
 | static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, | 
 | 			    u32 *dm_len); | 
 | static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, | 
 | 			   struct bfa_iocfc_cfg_s *cfg, | 
 | 			   struct bfa_meminfo_s *meminfo, | 
 | 			   struct bfa_pcidev_s *pcidev); | 
 | static void bfa_lps_initdone(struct bfa_s *bfa); | 
 | static void bfa_lps_detach(struct bfa_s *bfa); | 
 | static void bfa_lps_start(struct bfa_s *bfa); | 
 | static void bfa_lps_stop(struct bfa_s *bfa); | 
 | static void bfa_lps_iocdisable(struct bfa_s *bfa); | 
 | static void bfa_lps_login_rsp(struct bfa_s *bfa, | 
 | 			      struct bfi_lps_login_rsp_s *rsp); | 
 | static void bfa_lps_logout_rsp(struct bfa_s *bfa, | 
 | 			       struct bfi_lps_logout_rsp_s *rsp); | 
 | static void bfa_lps_reqq_resume(void *lps_arg); | 
 | static void bfa_lps_free(struct bfa_lps_s *lps); | 
 | static void bfa_lps_send_login(struct bfa_lps_s *lps); | 
 | static void bfa_lps_send_logout(struct bfa_lps_s *lps); | 
 | static void bfa_lps_login_comp(struct bfa_lps_s *lps); | 
 | static void bfa_lps_logout_comp(struct bfa_lps_s *lps); | 
 |  | 
 |  | 
 | /** | 
 |  *  lps_pvt BFA LPS private functions | 
 |  */ | 
 |  | 
 | enum bfa_lps_event { | 
 | 	BFA_LPS_SM_LOGIN	= 1,	/* login request from user	*/ | 
 | 	BFA_LPS_SM_LOGOUT	= 2,	/* logout request from user	*/ | 
 | 	BFA_LPS_SM_FWRSP	= 3,	/* f/w response to login/logout	*/ | 
 | 	BFA_LPS_SM_RESUME	= 4,	/* space present in reqq queue	*/ | 
 | 	BFA_LPS_SM_DELETE	= 5,	/* lps delete from user		*/ | 
 | 	BFA_LPS_SM_OFFLINE	= 6,	/* Link is offline		*/ | 
 | }; | 
 |  | 
 | static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event); | 
 | static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event); | 
 | static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, | 
 | 			enum bfa_lps_event event); | 
 | static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event); | 
 | static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event); | 
 | static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, | 
 | 			enum bfa_lps_event event); | 
 |  | 
 | /** | 
 |  * Init state -- no login | 
 |  */ | 
 | static void | 
 | bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) | 
 | { | 
 | 	bfa_trc(lps->bfa, lps->lp_tag); | 
 | 	bfa_trc(lps->bfa, event); | 
 |  | 
 | 	switch (event) { | 
 | 	case BFA_LPS_SM_LOGIN: | 
 | 		if (bfa_reqq_full(lps->bfa, lps->reqq)) { | 
 | 			bfa_sm_set_state(lps, bfa_lps_sm_loginwait); | 
 | 			bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); | 
 | 		} else { | 
 | 			bfa_sm_set_state(lps, bfa_lps_sm_login); | 
 | 			bfa_lps_send_login(lps); | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_LOGOUT: | 
 | 		bfa_lps_logout_comp(lps); | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_DELETE: | 
 | 		bfa_lps_free(lps); | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_OFFLINE: | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_FWRSP: | 
 | 		/* Could happen when fabric detects loopback and discards | 
 | 		 * the lps request. Fw will eventually sent out the timeout | 
 | 		 * Just ignore | 
 | 		 */ | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		bfa_assert(0); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * login is in progress -- awaiting response from firmware | 
 |  */ | 
 | static void | 
 | bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) | 
 | { | 
 | 	bfa_trc(lps->bfa, lps->lp_tag); | 
 | 	bfa_trc(lps->bfa, event); | 
 |  | 
 | 	switch (event) { | 
 | 	case BFA_LPS_SM_FWRSP: | 
 | 		if (lps->status == BFA_STATUS_OK) | 
 | 			bfa_sm_set_state(lps, bfa_lps_sm_online); | 
 | 		else | 
 | 			bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 		bfa_lps_login_comp(lps); | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_OFFLINE: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		bfa_assert(0); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * login pending - awaiting space in request queue | 
 |  */ | 
 | static void | 
 | bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) | 
 | { | 
 | 	bfa_trc(lps->bfa, lps->lp_tag); | 
 | 	bfa_trc(lps->bfa, event); | 
 |  | 
 | 	switch (event) { | 
 | 	case BFA_LPS_SM_RESUME: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_login); | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_OFFLINE: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 		bfa_reqq_wcancel(&lps->wqe); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		bfa_assert(0); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * login complete | 
 |  */ | 
 | static void | 
 | bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) | 
 | { | 
 | 	bfa_trc(lps->bfa, lps->lp_tag); | 
 | 	bfa_trc(lps->bfa, event); | 
 |  | 
 | 	switch (event) { | 
 | 	case BFA_LPS_SM_LOGOUT: | 
 | 		if (bfa_reqq_full(lps->bfa, lps->reqq)) { | 
 | 			bfa_sm_set_state(lps, bfa_lps_sm_logowait); | 
 | 			bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); | 
 | 		} else { | 
 | 			bfa_sm_set_state(lps, bfa_lps_sm_logout); | 
 | 			bfa_lps_send_logout(lps); | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_OFFLINE: | 
 | 	case BFA_LPS_SM_DELETE: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		bfa_assert(0); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * logout in progress - awaiting firmware response | 
 |  */ | 
 | static void | 
 | bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) | 
 | { | 
 | 	bfa_trc(lps->bfa, lps->lp_tag); | 
 | 	bfa_trc(lps->bfa, event); | 
 |  | 
 | 	switch (event) { | 
 | 	case BFA_LPS_SM_FWRSP: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 		bfa_lps_logout_comp(lps); | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_OFFLINE: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		bfa_assert(0); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * logout pending -- awaiting space in request queue | 
 |  */ | 
 | static void | 
 | bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) | 
 | { | 
 | 	bfa_trc(lps->bfa, lps->lp_tag); | 
 | 	bfa_trc(lps->bfa, event); | 
 |  | 
 | 	switch (event) { | 
 | 	case BFA_LPS_SM_RESUME: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_logout); | 
 | 		bfa_lps_send_logout(lps); | 
 | 		break; | 
 |  | 
 | 	case BFA_LPS_SM_OFFLINE: | 
 | 		bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 		bfa_reqq_wcancel(&lps->wqe); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		bfa_assert(0); | 
 | 	} | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  *  lps_pvt BFA LPS private functions | 
 |  */ | 
 |  | 
 | /** | 
 |  * return memory requirement | 
 |  */ | 
 | static void | 
 | bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) | 
 | { | 
 | 	if (cfg->drvcfg.min_cfg) | 
 | 		*ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS; | 
 | 	else | 
 | 		*ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS; | 
 | } | 
 |  | 
 | /** | 
 |  * bfa module attach at initialization time | 
 |  */ | 
 | static void | 
 | bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, | 
 | 		struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) | 
 | { | 
 | 	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); | 
 | 	struct bfa_lps_s	*lps; | 
 | 	int			i; | 
 |  | 
 | 	bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s)); | 
 | 	mod->num_lps = BFA_LPS_MAX_LPORTS; | 
 | 	if (cfg->drvcfg.min_cfg) | 
 | 		mod->num_lps = BFA_LPS_MIN_LPORTS; | 
 | 	else | 
 | 		mod->num_lps = BFA_LPS_MAX_LPORTS; | 
 | 	mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo); | 
 |  | 
 | 	bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s); | 
 |  | 
 | 	INIT_LIST_HEAD(&mod->lps_free_q); | 
 | 	INIT_LIST_HEAD(&mod->lps_active_q); | 
 |  | 
 | 	for (i = 0; i < mod->num_lps; i++, lps++) { | 
 | 		lps->bfa	= bfa; | 
 | 		lps->lp_tag	= (u8) i; | 
 | 		lps->reqq	= BFA_REQQ_LPS; | 
 | 		bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); | 
 | 		list_add_tail(&lps->qe, &mod->lps_free_q); | 
 | 	} | 
 | } | 
 |  | 
 | static void | 
 | bfa_lps_initdone(struct bfa_s *bfa) | 
 | { | 
 | } | 
 |  | 
 | static void | 
 | bfa_lps_detach(struct bfa_s *bfa) | 
 | { | 
 | } | 
 |  | 
 | static void | 
 | bfa_lps_start(struct bfa_s *bfa) | 
 | { | 
 | } | 
 |  | 
 | static void | 
 | bfa_lps_stop(struct bfa_s *bfa) | 
 | { | 
 | } | 
 |  | 
 | /** | 
 |  * IOC in disabled state -- consider all lps offline | 
 |  */ | 
 | static void | 
 | bfa_lps_iocdisable(struct bfa_s *bfa) | 
 | { | 
 | 	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); | 
 | 	struct bfa_lps_s	*lps; | 
 | 	struct list_head		*qe, *qen; | 
 |  | 
 | 	list_for_each_safe(qe, qen, &mod->lps_active_q) { | 
 | 		lps = (struct bfa_lps_s *) qe; | 
 | 		bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * Firmware login response | 
 |  */ | 
 | static void | 
 | bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) | 
 | { | 
 | 	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); | 
 | 	struct bfa_lps_s	*lps; | 
 |  | 
 | 	bfa_assert(rsp->lp_tag < mod->num_lps); | 
 | 	lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); | 
 |  | 
 | 	lps->status = rsp->status; | 
 | 	switch (rsp->status) { | 
 | 	case BFA_STATUS_OK: | 
 | 		lps->fport	= rsp->f_port; | 
 | 		lps->npiv_en	= rsp->npiv_en; | 
 | 		lps->lp_pid	= rsp->lp_pid; | 
 | 		lps->pr_bbcred	= bfa_os_ntohs(rsp->bb_credit); | 
 | 		lps->pr_pwwn	= rsp->port_name; | 
 | 		lps->pr_nwwn	= rsp->node_name; | 
 | 		lps->auth_req	= rsp->auth_req; | 
 | 		lps->lp_mac	= rsp->lp_mac; | 
 | 		lps->brcd_switch = rsp->brcd_switch; | 
 | 		lps->fcf_mac	= rsp->fcf_mac; | 
 |  | 
 | 		break; | 
 |  | 
 | 	case BFA_STATUS_FABRIC_RJT: | 
 | 		lps->lsrjt_rsn = rsp->lsrjt_rsn; | 
 | 		lps->lsrjt_expl = rsp->lsrjt_expl; | 
 |  | 
 | 		break; | 
 |  | 
 | 	case BFA_STATUS_EPROTOCOL: | 
 | 		lps->ext_status = rsp->ext_status; | 
 |  | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		/* Nothing to do with other status */ | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); | 
 | } | 
 |  | 
 | /** | 
 |  * Firmware logout response | 
 |  */ | 
 | static void | 
 | bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) | 
 | { | 
 | 	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); | 
 | 	struct bfa_lps_s	*lps; | 
 |  | 
 | 	bfa_assert(rsp->lp_tag < mod->num_lps); | 
 | 	lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); | 
 |  | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); | 
 | } | 
 |  | 
 | /** | 
 |  * Space is available in request queue, resume queueing request to firmware. | 
 |  */ | 
 | static void | 
 | bfa_lps_reqq_resume(void *lps_arg) | 
 | { | 
 | 	struct bfa_lps_s	*lps = lps_arg; | 
 |  | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_RESUME); | 
 | } | 
 |  | 
 | /** | 
 |  * lps is freed -- triggered by vport delete | 
 |  */ | 
 | static void | 
 | bfa_lps_free(struct bfa_lps_s *lps) | 
 | { | 
 | 	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(lps->bfa); | 
 |  | 
 | 	list_del(&lps->qe); | 
 | 	list_add_tail(&lps->qe, &mod->lps_free_q); | 
 | } | 
 |  | 
 | /** | 
 |  * send login request to firmware | 
 |  */ | 
 | static void | 
 | bfa_lps_send_login(struct bfa_lps_s *lps) | 
 | { | 
 | 	struct bfi_lps_login_req_s	*m; | 
 |  | 
 | 	m = bfa_reqq_next(lps->bfa, lps->reqq); | 
 | 	bfa_assert(m); | 
 |  | 
 | 	bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, | 
 | 			bfa_lpuid(lps->bfa)); | 
 |  | 
 | 	m->lp_tag	= lps->lp_tag; | 
 | 	m->alpa		= lps->alpa; | 
 | 	m->pdu_size	= bfa_os_htons(lps->pdusz); | 
 | 	m->pwwn		= lps->pwwn; | 
 | 	m->nwwn		= lps->nwwn; | 
 | 	m->fdisc	= lps->fdisc; | 
 | 	m->auth_en	= lps->auth_en; | 
 |  | 
 | 	bfa_reqq_produce(lps->bfa, lps->reqq); | 
 | } | 
 |  | 
 | /** | 
 |  * send logout request to firmware | 
 |  */ | 
 | static void | 
 | bfa_lps_send_logout(struct bfa_lps_s *lps) | 
 | { | 
 | 	struct bfi_lps_logout_req_s *m; | 
 |  | 
 | 	m = bfa_reqq_next(lps->bfa, lps->reqq); | 
 | 	bfa_assert(m); | 
 |  | 
 | 	bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, | 
 | 			bfa_lpuid(lps->bfa)); | 
 |  | 
 | 	m->lp_tag    = lps->lp_tag; | 
 | 	m->port_name = lps->pwwn; | 
 | 	bfa_reqq_produce(lps->bfa, lps->reqq); | 
 | } | 
 |  | 
 | /** | 
 |  * Indirect login completion handler for non-fcs | 
 |  */ | 
 | static void | 
 | bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete) | 
 | { | 
 | 	struct bfa_lps_s *lps	= arg; | 
 |  | 
 | 	if (!complete) | 
 | 		return; | 
 |  | 
 | 	if (lps->fdisc) | 
 | 		bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); | 
 | 	else | 
 | 		bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); | 
 | } | 
 |  | 
 | /** | 
 |  * Login completion handler -- direct call for fcs, queue for others | 
 |  */ | 
 | static void | 
 | bfa_lps_login_comp(struct bfa_lps_s *lps) | 
 | { | 
 | 	if (!lps->bfa->fcs) { | 
 | 		bfa_cb_queue(lps->bfa, &lps->hcb_qe, | 
 | 				bfa_lps_login_comp_cb, lps); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	if (lps->fdisc) | 
 | 		bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); | 
 | 	else | 
 | 		bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); | 
 | } | 
 |  | 
 | /** | 
 |  * Indirect logout completion handler for non-fcs | 
 |  */ | 
 | static void | 
 | bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete) | 
 | { | 
 | 	struct bfa_lps_s *lps	= arg; | 
 |  | 
 | 	if (!complete) | 
 | 		return; | 
 |  | 
 | 	if (lps->fdisc) | 
 | 		bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); | 
 | 	else | 
 | 		bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); | 
 | } | 
 |  | 
 | /** | 
 |  * Logout completion handler -- direct call for fcs, queue for others | 
 |  */ | 
 | static void | 
 | bfa_lps_logout_comp(struct bfa_lps_s *lps) | 
 | { | 
 | 	if (!lps->bfa->fcs) { | 
 | 		bfa_cb_queue(lps->bfa, &lps->hcb_qe, | 
 | 				bfa_lps_logout_comp_cb, lps); | 
 | 		return; | 
 | 	} | 
 | 	if (lps->fdisc) | 
 | 		bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); | 
 | 	else | 
 | 		bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  *  lps_public BFA LPS public functions | 
 |  */ | 
 |  | 
 | /** | 
 |  * Allocate a lport srvice tag. | 
 |  */ | 
 | struct bfa_lps_s  * | 
 | bfa_lps_alloc(struct bfa_s *bfa) | 
 | { | 
 | 	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); | 
 | 	struct bfa_lps_s	*lps = NULL; | 
 |  | 
 | 	bfa_q_deq(&mod->lps_free_q, &lps); | 
 |  | 
 | 	if (lps == NULL) | 
 | 		return NULL; | 
 |  | 
 | 	list_add_tail(&lps->qe, &mod->lps_active_q); | 
 |  | 
 | 	bfa_sm_set_state(lps, bfa_lps_sm_init); | 
 | 	return lps; | 
 | } | 
 |  | 
 | /** | 
 |  * Free lport service tag. This can be called anytime after an alloc. | 
 |  * No need to wait for any pending login/logout completions. | 
 |  */ | 
 | void | 
 | bfa_lps_delete(struct bfa_lps_s *lps) | 
 | { | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_DELETE); | 
 | } | 
 |  | 
 | /** | 
 |  * Initiate a lport login. | 
 |  */ | 
 | void | 
 | bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, | 
 | 	wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en) | 
 | { | 
 | 	lps->uarg	= uarg; | 
 | 	lps->alpa	= alpa; | 
 | 	lps->pdusz	= pdusz; | 
 | 	lps->pwwn	= pwwn; | 
 | 	lps->nwwn	= nwwn; | 
 | 	lps->fdisc	= BFA_FALSE; | 
 | 	lps->auth_en	= auth_en; | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); | 
 | } | 
 |  | 
 | /** | 
 |  * Initiate a lport fdisc login. | 
 |  */ | 
 | void | 
 | bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, | 
 | 	wwn_t nwwn) | 
 | { | 
 | 	lps->uarg	= uarg; | 
 | 	lps->alpa	= 0; | 
 | 	lps->pdusz	= pdusz; | 
 | 	lps->pwwn	= pwwn; | 
 | 	lps->nwwn	= nwwn; | 
 | 	lps->fdisc	= BFA_TRUE; | 
 | 	lps->auth_en	= BFA_FALSE; | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); | 
 | } | 
 |  | 
 | /** | 
 |  * Initiate a lport logout (flogi). | 
 |  */ | 
 | void | 
 | bfa_lps_flogo(struct bfa_lps_s *lps) | 
 | { | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); | 
 | } | 
 |  | 
 | /** | 
 |  * Initiate a lport FDSIC logout. | 
 |  */ | 
 | void | 
 | bfa_lps_fdisclogo(struct bfa_lps_s *lps) | 
 | { | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); | 
 | } | 
 |  | 
 | /** | 
 |  * Discard a pending login request -- should be called only for | 
 |  * link down handling. | 
 |  */ | 
 | void | 
 | bfa_lps_discard(struct bfa_lps_s *lps) | 
 | { | 
 | 	bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); | 
 | } | 
 |  | 
 | /** | 
 |  * Return lport services tag | 
 |  */ | 
 | u8 | 
 | bfa_lps_get_tag(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->lp_tag; | 
 | } | 
 |  | 
 | /** | 
 |  * Return lport services tag given the pid | 
 |  */ | 
 | u8 | 
 | bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) | 
 | { | 
 | 	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); | 
 | 	struct bfa_lps_s	*lps; | 
 | 	int			i; | 
 |  | 
 | 	for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { | 
 | 		if (lps->lp_pid == pid) | 
 | 			return lps->lp_tag; | 
 | 	} | 
 |  | 
 | 	/* Return base port tag anyway */ | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * return if fabric login indicates support for NPIV | 
 |  */ | 
 | bfa_boolean_t | 
 | bfa_lps_is_npiv_en(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->npiv_en; | 
 | } | 
 |  | 
 | /** | 
 |  * Return TRUE if attached to F-Port, else return FALSE | 
 |  */ | 
 | bfa_boolean_t | 
 | bfa_lps_is_fport(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->fport; | 
 | } | 
 |  | 
 | /** | 
 |  * Return TRUE if attached to a Brocade Fabric | 
 |  */ | 
 | bfa_boolean_t | 
 | bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->brcd_switch; | 
 | } | 
 | /** | 
 |  * return TRUE if authentication is required | 
 |  */ | 
 | bfa_boolean_t | 
 | bfa_lps_is_authreq(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->auth_req; | 
 | } | 
 |  | 
 | bfa_eproto_status_t | 
 | bfa_lps_get_extstatus(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->ext_status; | 
 | } | 
 |  | 
 | /** | 
 |  * return port id assigned to the lport | 
 |  */ | 
 | u32 | 
 | bfa_lps_get_pid(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->lp_pid; | 
 | } | 
 |  | 
 | /** | 
 |  * Return bb_credit assigned in FLOGI response | 
 |  */ | 
 | u16 | 
 | bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->pr_bbcred; | 
 | } | 
 |  | 
 | /** | 
 |  * Return peer port name | 
 |  */ | 
 | wwn_t | 
 | bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->pr_pwwn; | 
 | } | 
 |  | 
 | /** | 
 |  * Return peer node name | 
 |  */ | 
 | wwn_t | 
 | bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->pr_nwwn; | 
 | } | 
 |  | 
 | /** | 
 |  * return reason code if login request is rejected | 
 |  */ | 
 | u8 | 
 | bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->lsrjt_rsn; | 
 | } | 
 |  | 
 | /** | 
 |  * return explanation code if login request is rejected | 
 |  */ | 
 | u8 | 
 | bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps) | 
 | { | 
 | 	return lps->lsrjt_expl; | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * LPS firmware message class handler. | 
 |  */ | 
 | void | 
 | bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) | 
 | { | 
 | 	union bfi_lps_i2h_msg_u	msg; | 
 |  | 
 | 	bfa_trc(bfa, m->mhdr.msg_id); | 
 | 	msg.msg = m; | 
 |  | 
 | 	switch (m->mhdr.msg_id) { | 
 | 	case BFI_LPS_H2I_LOGIN_RSP: | 
 | 		bfa_lps_login_rsp(bfa, msg.login_rsp); | 
 | 		break; | 
 |  | 
 | 	case BFI_LPS_H2I_LOGOUT_RSP: | 
 | 		bfa_lps_logout_rsp(bfa, msg.logout_rsp); | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		bfa_trc(bfa, m->mhdr.msg_id); | 
 | 		bfa_assert(0); | 
 | 	} | 
 | } | 
 |  | 
 |  |