xref: /openbmc/linux/drivers/scsi/bfa/bfa_fcs_lport.c (revision 86e32dab)
17725ccfdSJing Huang /*
27725ccfdSJing Huang  * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
37725ccfdSJing Huang  * All rights reserved
47725ccfdSJing Huang  * www.brocade.com
57725ccfdSJing Huang  *
67725ccfdSJing Huang  * Linux driver for Brocade Fibre Channel Host Bus Adapter.
77725ccfdSJing Huang  *
87725ccfdSJing Huang  * This program is free software; you can redistribute it and/or modify it
97725ccfdSJing Huang  * under the terms of the GNU General Public License (GPL) Version 2 as
107725ccfdSJing Huang  * published by the Free Software Foundation
117725ccfdSJing Huang  *
127725ccfdSJing Huang  * This program is distributed in the hope that it will be useful, but
137725ccfdSJing Huang  * WITHOUT ANY WARRANTY; without even the implied warranty of
147725ccfdSJing Huang  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
157725ccfdSJing Huang  * General Public License for more details.
167725ccfdSJing Huang  */
177725ccfdSJing Huang 
187725ccfdSJing Huang /**
197725ccfdSJing Huang  *  bfa_fcs_port.c BFA FCS port
207725ccfdSJing Huang  */
217725ccfdSJing Huang 
227725ccfdSJing Huang #include <fcs/bfa_fcs.h>
237725ccfdSJing Huang #include <fcs/bfa_fcs_lport.h>
247725ccfdSJing Huang #include <fcs/bfa_fcs_rport.h>
257725ccfdSJing Huang #include <fcb/bfa_fcb_port.h>
267725ccfdSJing Huang #include <bfa_svc.h>
277725ccfdSJing Huang #include <log/bfa_log_fcs.h>
287725ccfdSJing Huang #include "fcs.h"
297725ccfdSJing Huang #include "fcs_lport.h"
307725ccfdSJing Huang #include "fcs_vport.h"
317725ccfdSJing Huang #include "fcs_rport.h"
327725ccfdSJing Huang #include "fcs_fcxp.h"
337725ccfdSJing Huang #include "fcs_trcmod.h"
347725ccfdSJing Huang #include "lport_priv.h"
357725ccfdSJing Huang #include <aen/bfa_aen_lport.h>
367725ccfdSJing Huang 
377725ccfdSJing Huang BFA_TRC_FILE(FCS, PORT);
387725ccfdSJing Huang 
397725ccfdSJing Huang /**
407725ccfdSJing Huang  * Forward declarations
417725ccfdSJing Huang  */
427725ccfdSJing Huang 
437725ccfdSJing Huang static void     bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
447725ccfdSJing Huang 				      enum bfa_lport_aen_event event);
457725ccfdSJing Huang static void     bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port,
467725ccfdSJing Huang 			struct fchs_s *rx_fchs, u8 reason_code,
477725ccfdSJing Huang 			u8 reason_code_expl);
487725ccfdSJing Huang static void     bfa_fcs_port_plogi(struct bfa_fcs_port_s *port,
497725ccfdSJing Huang 			struct fchs_s *rx_fchs,
507725ccfdSJing Huang 			struct fc_logi_s *plogi);
517725ccfdSJing Huang static void     bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port);
527725ccfdSJing Huang static void     bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port);
537725ccfdSJing Huang static void     bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port);
547725ccfdSJing Huang static void     bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port);
557725ccfdSJing Huang static void     bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port);
567725ccfdSJing Huang static void     bfa_fcs_port_deleted(struct bfa_fcs_port_s *port);
577725ccfdSJing Huang static void     bfa_fcs_port_echo(struct bfa_fcs_port_s *port,
587725ccfdSJing Huang 			struct fchs_s *rx_fchs,
597725ccfdSJing Huang 			struct fc_echo_s *echo, u16 len);
607725ccfdSJing Huang static void     bfa_fcs_port_rnid(struct bfa_fcs_port_s *port,
617725ccfdSJing Huang 			struct fchs_s *rx_fchs,
627725ccfdSJing Huang 			struct fc_rnid_cmd_s *rnid, u16 len);
637725ccfdSJing Huang static void     bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
647725ccfdSJing Huang 			struct fc_rnid_general_topology_data_s *gen_topo_data);
657725ccfdSJing Huang 
667725ccfdSJing Huang static struct {
677725ccfdSJing Huang 	void            (*init) (struct bfa_fcs_port_s *port);
687725ccfdSJing Huang 	void            (*online) (struct bfa_fcs_port_s *port);
697725ccfdSJing Huang 	void            (*offline) (struct bfa_fcs_port_s *port);
707725ccfdSJing Huang } __port_action[] = {
717725ccfdSJing Huang 	{
727725ccfdSJing Huang 	bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online,
737725ccfdSJing Huang 			bfa_fcs_port_unknown_offline}, {
747725ccfdSJing Huang 	bfa_fcs_port_fab_init, bfa_fcs_port_fab_online,
757725ccfdSJing Huang 			bfa_fcs_port_fab_offline}, {
767725ccfdSJing Huang 	bfa_fcs_port_loop_init, bfa_fcs_port_loop_online,
777725ccfdSJing Huang 			bfa_fcs_port_loop_offline}, {
787725ccfdSJing Huang bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online,
797725ccfdSJing Huang 			bfa_fcs_port_n2n_offline},};
807725ccfdSJing Huang 
817725ccfdSJing Huang /**
827725ccfdSJing Huang  *  fcs_port_sm FCS logical port state machine
837725ccfdSJing Huang  */
847725ccfdSJing Huang 
857725ccfdSJing Huang enum bfa_fcs_port_event {
867725ccfdSJing Huang 	BFA_FCS_PORT_SM_CREATE = 1,
877725ccfdSJing Huang 	BFA_FCS_PORT_SM_ONLINE = 2,
887725ccfdSJing Huang 	BFA_FCS_PORT_SM_OFFLINE = 3,
897725ccfdSJing Huang 	BFA_FCS_PORT_SM_DELETE = 4,
907725ccfdSJing Huang 	BFA_FCS_PORT_SM_DELRPORT = 5,
917725ccfdSJing Huang };
927725ccfdSJing Huang 
937725ccfdSJing Huang static void     bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
947725ccfdSJing Huang 				       enum bfa_fcs_port_event event);
957725ccfdSJing Huang static void     bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port,
967725ccfdSJing Huang 				     enum bfa_fcs_port_event event);
977725ccfdSJing Huang static void     bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
987725ccfdSJing Huang 				       enum bfa_fcs_port_event event);
997725ccfdSJing Huang static void     bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
1007725ccfdSJing Huang 					enum bfa_fcs_port_event event);
1017725ccfdSJing Huang static void     bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
1027725ccfdSJing Huang 					 enum bfa_fcs_port_event event);
1037725ccfdSJing Huang 
1047725ccfdSJing Huang static void
1057725ccfdSJing Huang bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
1067725ccfdSJing Huang 			enum bfa_fcs_port_event event)
1077725ccfdSJing Huang {
1087725ccfdSJing Huang 	bfa_trc(port->fcs, port->port_cfg.pwwn);
1097725ccfdSJing Huang 	bfa_trc(port->fcs, event);
1107725ccfdSJing Huang 
1117725ccfdSJing Huang 	switch (event) {
1127725ccfdSJing Huang 	case BFA_FCS_PORT_SM_CREATE:
1137725ccfdSJing Huang 		bfa_sm_set_state(port, bfa_fcs_port_sm_init);
1147725ccfdSJing Huang 		break;
1157725ccfdSJing Huang 
1167725ccfdSJing Huang 	default:
117e641de37SKrishna Gudipati 		bfa_sm_fault(port->fcs, event);
1187725ccfdSJing Huang 	}
1197725ccfdSJing Huang }
1207725ccfdSJing Huang 
1217725ccfdSJing Huang static void
1227725ccfdSJing Huang bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event)
1237725ccfdSJing Huang {
1247725ccfdSJing Huang 	bfa_trc(port->fcs, port->port_cfg.pwwn);
1257725ccfdSJing Huang 	bfa_trc(port->fcs, event);
1267725ccfdSJing Huang 
1277725ccfdSJing Huang 	switch (event) {
1287725ccfdSJing Huang 	case BFA_FCS_PORT_SM_ONLINE:
1297725ccfdSJing Huang 		bfa_sm_set_state(port, bfa_fcs_port_sm_online);
1307725ccfdSJing Huang 		bfa_fcs_port_online_actions(port);
1317725ccfdSJing Huang 		break;
1327725ccfdSJing Huang 
1337725ccfdSJing Huang 	case BFA_FCS_PORT_SM_DELETE:
1347725ccfdSJing Huang 		bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
1357725ccfdSJing Huang 		bfa_fcs_port_deleted(port);
1367725ccfdSJing Huang 		break;
1377725ccfdSJing Huang 
1387725ccfdSJing Huang 	default:
139e641de37SKrishna Gudipati 		bfa_sm_fault(port->fcs, event);
1407725ccfdSJing Huang 	}
1417725ccfdSJing Huang }
1427725ccfdSJing Huang 
1437725ccfdSJing Huang static void
1447725ccfdSJing Huang bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
1457725ccfdSJing Huang 			enum bfa_fcs_port_event event)
1467725ccfdSJing Huang {
1477725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport;
1487725ccfdSJing Huang 	struct list_head *qe, *qen;
1497725ccfdSJing Huang 
1507725ccfdSJing Huang 	bfa_trc(port->fcs, port->port_cfg.pwwn);
1517725ccfdSJing Huang 	bfa_trc(port->fcs, event);
1527725ccfdSJing Huang 
1537725ccfdSJing Huang 	switch (event) {
1547725ccfdSJing Huang 	case BFA_FCS_PORT_SM_OFFLINE:
1557725ccfdSJing Huang 		bfa_sm_set_state(port, bfa_fcs_port_sm_offline);
1567725ccfdSJing Huang 		bfa_fcs_port_offline_actions(port);
1577725ccfdSJing Huang 		break;
1587725ccfdSJing Huang 
1597725ccfdSJing Huang 	case BFA_FCS_PORT_SM_DELETE:
1607725ccfdSJing Huang 
1617725ccfdSJing Huang 		__port_action[port->fabric->fab_type].offline(port);
1627725ccfdSJing Huang 
1637725ccfdSJing Huang 		if (port->num_rports == 0) {
1647725ccfdSJing Huang 			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
1657725ccfdSJing Huang 			bfa_fcs_port_deleted(port);
1667725ccfdSJing Huang 		} else {
1677725ccfdSJing Huang 			bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
1687725ccfdSJing Huang 			list_for_each_safe(qe, qen, &port->rport_q) {
1697725ccfdSJing Huang 				rport = (struct bfa_fcs_rport_s *)qe;
1707725ccfdSJing Huang 				bfa_fcs_rport_delete(rport);
1717725ccfdSJing Huang 			}
1727725ccfdSJing Huang 		}
1737725ccfdSJing Huang 		break;
1747725ccfdSJing Huang 
1757725ccfdSJing Huang 	case BFA_FCS_PORT_SM_DELRPORT:
1767725ccfdSJing Huang 		break;
1777725ccfdSJing Huang 
1787725ccfdSJing Huang 	default:
179e641de37SKrishna Gudipati 		bfa_sm_fault(port->fcs, event);
1807725ccfdSJing Huang 	}
1817725ccfdSJing Huang }
1827725ccfdSJing Huang 
1837725ccfdSJing Huang static void
1847725ccfdSJing Huang bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
1857725ccfdSJing Huang 			enum bfa_fcs_port_event event)
1867725ccfdSJing Huang {
1877725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport;
1887725ccfdSJing Huang 	struct list_head *qe, *qen;
1897725ccfdSJing Huang 
1907725ccfdSJing Huang 	bfa_trc(port->fcs, port->port_cfg.pwwn);
1917725ccfdSJing Huang 	bfa_trc(port->fcs, event);
1927725ccfdSJing Huang 
1937725ccfdSJing Huang 	switch (event) {
1947725ccfdSJing Huang 	case BFA_FCS_PORT_SM_ONLINE:
1957725ccfdSJing Huang 		bfa_sm_set_state(port, bfa_fcs_port_sm_online);
1967725ccfdSJing Huang 		bfa_fcs_port_online_actions(port);
1977725ccfdSJing Huang 		break;
1987725ccfdSJing Huang 
1997725ccfdSJing Huang 	case BFA_FCS_PORT_SM_DELETE:
2007725ccfdSJing Huang 		if (port->num_rports == 0) {
2017725ccfdSJing Huang 			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
2027725ccfdSJing Huang 			bfa_fcs_port_deleted(port);
2037725ccfdSJing Huang 		} else {
2047725ccfdSJing Huang 			bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
2057725ccfdSJing Huang 			list_for_each_safe(qe, qen, &port->rport_q) {
2067725ccfdSJing Huang 				rport = (struct bfa_fcs_rport_s *)qe;
2077725ccfdSJing Huang 				bfa_fcs_rport_delete(rport);
2087725ccfdSJing Huang 			}
2097725ccfdSJing Huang 		}
2107725ccfdSJing Huang 		break;
2117725ccfdSJing Huang 
2127725ccfdSJing Huang 	case BFA_FCS_PORT_SM_DELRPORT:
2137725ccfdSJing Huang 	case BFA_FCS_PORT_SM_OFFLINE:
2147725ccfdSJing Huang 		break;
2157725ccfdSJing Huang 
2167725ccfdSJing Huang 	default:
217e641de37SKrishna Gudipati 		bfa_sm_fault(port->fcs, event);
2187725ccfdSJing Huang 	}
2197725ccfdSJing Huang }
2207725ccfdSJing Huang 
2217725ccfdSJing Huang static void
2227725ccfdSJing Huang bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
2237725ccfdSJing Huang 			 enum bfa_fcs_port_event event)
2247725ccfdSJing Huang {
2257725ccfdSJing Huang 	bfa_trc(port->fcs, port->port_cfg.pwwn);
2267725ccfdSJing Huang 	bfa_trc(port->fcs, event);
2277725ccfdSJing Huang 
2287725ccfdSJing Huang 	switch (event) {
2297725ccfdSJing Huang 	case BFA_FCS_PORT_SM_DELRPORT:
2307725ccfdSJing Huang 		if (port->num_rports == 0) {
2317725ccfdSJing Huang 			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
2327725ccfdSJing Huang 			bfa_fcs_port_deleted(port);
2337725ccfdSJing Huang 		}
2347725ccfdSJing Huang 		break;
2357725ccfdSJing Huang 
2367725ccfdSJing Huang 	default:
237e641de37SKrishna Gudipati 		bfa_sm_fault(port->fcs, event);
2387725ccfdSJing Huang 	}
2397725ccfdSJing Huang }
2407725ccfdSJing Huang 
2417725ccfdSJing Huang 
2427725ccfdSJing Huang 
2437725ccfdSJing Huang /**
2447725ccfdSJing Huang  *  fcs_port_pvt
2457725ccfdSJing Huang  */
2467725ccfdSJing Huang 
2477725ccfdSJing Huang /**
2487725ccfdSJing Huang  * Send AEN notification
2497725ccfdSJing Huang  */
2507725ccfdSJing Huang static void
2517725ccfdSJing Huang bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
2527725ccfdSJing Huang 		      enum bfa_lport_aen_event event)
2537725ccfdSJing Huang {
2547725ccfdSJing Huang 	union bfa_aen_data_u aen_data;
2557725ccfdSJing Huang 	struct bfa_log_mod_s *logmod = port->fcs->logm;
2567725ccfdSJing Huang 	enum bfa_port_role role = port->port_cfg.roles;
2577725ccfdSJing Huang 	wwn_t           lpwwn = bfa_fcs_port_get_pwwn(port);
2587725ccfdSJing Huang 	char            lpwwn_ptr[BFA_STRING_32];
2597725ccfdSJing Huang 	char           *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] =
2607725ccfdSJing Huang 		{ "Initiator", "Target", "IPFC" };
2617725ccfdSJing Huang 
2627725ccfdSJing Huang 	wwn2str(lpwwn_ptr, lpwwn);
2637725ccfdSJing Huang 
2647725ccfdSJing Huang 	bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
2657725ccfdSJing Huang 
2667725ccfdSJing Huang 	switch (event) {
2677725ccfdSJing Huang 	case BFA_LPORT_AEN_ONLINE:
2687725ccfdSJing Huang 		bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr,
2697725ccfdSJing Huang 			role_str[role / 2]);
2707725ccfdSJing Huang 		break;
2717725ccfdSJing Huang 	case BFA_LPORT_AEN_OFFLINE:
2727725ccfdSJing Huang 		bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr,
2737725ccfdSJing Huang 			role_str[role / 2]);
2747725ccfdSJing Huang 		break;
2757725ccfdSJing Huang 	case BFA_LPORT_AEN_NEW:
2767725ccfdSJing Huang 		bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr,
2777725ccfdSJing Huang 			role_str[role / 2]);
2787725ccfdSJing Huang 		break;
2797725ccfdSJing Huang 	case BFA_LPORT_AEN_DELETE:
2807725ccfdSJing Huang 		bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr,
2817725ccfdSJing Huang 			role_str[role / 2]);
2827725ccfdSJing Huang 		break;
2837725ccfdSJing Huang 	case BFA_LPORT_AEN_DISCONNECT:
2847725ccfdSJing Huang 		bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr,
2857725ccfdSJing Huang 			role_str[role / 2]);
2867725ccfdSJing Huang 		break;
2877725ccfdSJing Huang 	default:
2887725ccfdSJing Huang 		break;
2897725ccfdSJing Huang 	}
2907725ccfdSJing Huang 
2917725ccfdSJing Huang 	aen_data.lport.vf_id = port->fabric->vf_id;
2927725ccfdSJing Huang 	aen_data.lport.roles = role;
2937725ccfdSJing Huang 	aen_data.lport.ppwwn =
2947725ccfdSJing Huang 		bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
2957725ccfdSJing Huang 	aen_data.lport.lpwwn = lpwwn;
2967725ccfdSJing Huang }
2977725ccfdSJing Huang 
2987725ccfdSJing Huang /*
2997725ccfdSJing Huang  * Send a LS reject
3007725ccfdSJing Huang  */
3017725ccfdSJing Huang static void
3027725ccfdSJing Huang bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
3037725ccfdSJing Huang 			 u8 reason_code, u8 reason_code_expl)
3047725ccfdSJing Huang {
3057725ccfdSJing Huang 	struct fchs_s          fchs;
3067725ccfdSJing Huang 	struct bfa_fcxp_s *fcxp;
3077725ccfdSJing Huang 	struct bfa_rport_s *bfa_rport = NULL;
3087725ccfdSJing Huang 	int             len;
3097725ccfdSJing Huang 
3107725ccfdSJing Huang 	bfa_trc(port->fcs, rx_fchs->s_id);
3117725ccfdSJing Huang 
3127725ccfdSJing Huang 	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
3137725ccfdSJing Huang 	if (!fcxp)
3147725ccfdSJing Huang 		return;
3157725ccfdSJing Huang 
3167725ccfdSJing Huang 	len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
3177725ccfdSJing Huang 			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
3187725ccfdSJing Huang 			      reason_code, reason_code_expl);
3197725ccfdSJing Huang 
3207725ccfdSJing Huang 	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
3217725ccfdSJing Huang 		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
3227725ccfdSJing Huang 		      FC_MAX_PDUSZ, 0);
3237725ccfdSJing Huang }
3247725ccfdSJing Huang 
3257725ccfdSJing Huang /**
3267725ccfdSJing Huang  * Process incoming plogi from a remote port.
3277725ccfdSJing Huang  */
3287725ccfdSJing Huang static void
3297725ccfdSJing Huang bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
3307725ccfdSJing Huang 			struct fc_logi_s *plogi)
3317725ccfdSJing Huang {
3327725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport;
3337725ccfdSJing Huang 
3347725ccfdSJing Huang 	bfa_trc(port->fcs, rx_fchs->d_id);
3357725ccfdSJing Huang 	bfa_trc(port->fcs, rx_fchs->s_id);
3367725ccfdSJing Huang 
3377725ccfdSJing Huang 	/*
3387725ccfdSJing Huang 	 * If min cfg mode is enabled, drop any incoming PLOGIs
3397725ccfdSJing Huang 	 */
3407725ccfdSJing Huang 	if (__fcs_min_cfg(port->fcs)) {
3417725ccfdSJing Huang 		bfa_trc(port->fcs, rx_fchs->s_id);
3427725ccfdSJing Huang 		return;
3437725ccfdSJing Huang 	}
3447725ccfdSJing Huang 
3457725ccfdSJing Huang 	if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) {
3467725ccfdSJing Huang 		bfa_trc(port->fcs, rx_fchs->s_id);
3477725ccfdSJing Huang 		/*
3487725ccfdSJing Huang 		 * send a LS reject
3497725ccfdSJing Huang 		 */
3507725ccfdSJing Huang 		bfa_fcs_port_send_ls_rjt(port, rx_fchs,
3517725ccfdSJing Huang 					 FC_LS_RJT_RSN_PROTOCOL_ERROR,
3527725ccfdSJing Huang 					 FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS);
3537725ccfdSJing Huang 		return;
3547725ccfdSJing Huang 	}
3557725ccfdSJing Huang 
3567725ccfdSJing Huang 	/**
3577725ccfdSJing Huang * Direct Attach P2P mode : verify address assigned by the r-port.
3587725ccfdSJing Huang 	 */
3597725ccfdSJing Huang 	if ((!bfa_fcs_fabric_is_switched(port->fabric))
3607725ccfdSJing Huang 	    &&
3617725ccfdSJing Huang 	    (memcmp
3627725ccfdSJing Huang 	     ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name,
3637725ccfdSJing Huang 	      sizeof(wwn_t)) < 0)) {
3647725ccfdSJing Huang 		if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) {
3657725ccfdSJing Huang 			/*
3667725ccfdSJing Huang 			 * Address assigned to us cannot be a WKA
3677725ccfdSJing Huang 			 */
3687725ccfdSJing Huang 			bfa_fcs_port_send_ls_rjt(port, rx_fchs,
3697725ccfdSJing Huang 					FC_LS_RJT_RSN_PROTOCOL_ERROR,
3707725ccfdSJing Huang 					FC_LS_RJT_EXP_INVALID_NPORT_ID);
3717725ccfdSJing Huang 			return;
3727725ccfdSJing Huang 		}
3737725ccfdSJing Huang 		port->pid = rx_fchs->d_id;
3747725ccfdSJing Huang 	}
3757725ccfdSJing Huang 
3767725ccfdSJing Huang 	/**
3777725ccfdSJing Huang 	 * First, check if we know the device by pwwn.
3787725ccfdSJing Huang 	 */
3797725ccfdSJing Huang 	rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name);
3807725ccfdSJing Huang 	if (rport) {
3817725ccfdSJing Huang 		/**
3827725ccfdSJing Huang 		 * Direct Attach P2P mode: handle address assigned by the rport.
3837725ccfdSJing Huang 		 */
3847725ccfdSJing Huang 		if ((!bfa_fcs_fabric_is_switched(port->fabric))
3857725ccfdSJing Huang 		    &&
3867725ccfdSJing Huang 		    (memcmp
3877725ccfdSJing Huang 		     ((void *)&bfa_fcs_port_get_pwwn(port),
3887725ccfdSJing Huang 		      (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
3897725ccfdSJing Huang 			port->pid = rx_fchs->d_id;
3907725ccfdSJing Huang 			rport->pid = rx_fchs->s_id;
3917725ccfdSJing Huang 		}
3927725ccfdSJing Huang 		bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
3937725ccfdSJing Huang 		return;
3947725ccfdSJing Huang 	}
3957725ccfdSJing Huang 
3967725ccfdSJing Huang 	/**
3977725ccfdSJing Huang 	 * Next, lookup rport by PID.
3987725ccfdSJing Huang 	 */
3997725ccfdSJing Huang 	rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id);
4007725ccfdSJing Huang 	if (!rport) {
4017725ccfdSJing Huang 		/**
4027725ccfdSJing Huang 		 * Inbound PLOGI from a new device.
4037725ccfdSJing Huang 		 */
4047725ccfdSJing Huang 		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
4057725ccfdSJing Huang 		return;
4067725ccfdSJing Huang 	}
4077725ccfdSJing Huang 
4087725ccfdSJing Huang 	/**
4097725ccfdSJing Huang 	 * Rport is known only by PID.
4107725ccfdSJing Huang 	 */
4117725ccfdSJing Huang 	if (rport->pwwn) {
4127725ccfdSJing Huang 		/**
4137725ccfdSJing Huang 		 * This is a different device with the same pid. Old device
4147725ccfdSJing Huang 		 * disappeared. Send implicit LOGO to old device.
4157725ccfdSJing Huang 		 */
4167725ccfdSJing Huang 		bfa_assert(rport->pwwn != plogi->port_name);
4177725ccfdSJing Huang 		bfa_fcs_rport_logo_imp(rport);
4187725ccfdSJing Huang 
4197725ccfdSJing Huang 		/**
4207725ccfdSJing Huang 		 * Inbound PLOGI from a new device (with old PID).
4217725ccfdSJing Huang 		 */
4227725ccfdSJing Huang 		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
4237725ccfdSJing Huang 		return;
4247725ccfdSJing Huang 	}
4257725ccfdSJing Huang 
4267725ccfdSJing Huang 	/**
4277725ccfdSJing Huang 	 * PLOGI crossing each other.
4287725ccfdSJing Huang 	 */
4297725ccfdSJing Huang 	bfa_assert(rport->pwwn == WWN_NULL);
4307725ccfdSJing Huang 	bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
4317725ccfdSJing Huang }
4327725ccfdSJing Huang 
4337725ccfdSJing Huang /*
4347725ccfdSJing Huang  * Process incoming ECHO.
4357725ccfdSJing Huang  * Since it does not require a login, it is processed here.
4367725ccfdSJing Huang  */
4377725ccfdSJing Huang static void
4387725ccfdSJing Huang bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
4397725ccfdSJing Huang 			struct fc_echo_s *echo, u16 rx_len)
4407725ccfdSJing Huang {
4417725ccfdSJing Huang 	struct fchs_s          fchs;
4427725ccfdSJing Huang 	struct bfa_fcxp_s *fcxp;
4437725ccfdSJing Huang 	struct bfa_rport_s *bfa_rport = NULL;
4447725ccfdSJing Huang 	int             len, pyld_len;
4457725ccfdSJing Huang 
4467725ccfdSJing Huang 	bfa_trc(port->fcs, rx_fchs->s_id);
4477725ccfdSJing Huang 	bfa_trc(port->fcs, rx_fchs->d_id);
4487725ccfdSJing Huang 	bfa_trc(port->fcs, rx_len);
4497725ccfdSJing Huang 
4507725ccfdSJing Huang 	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
4517725ccfdSJing Huang 	if (!fcxp)
4527725ccfdSJing Huang 		return;
4537725ccfdSJing Huang 
4547725ccfdSJing Huang 	len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
4557725ccfdSJing Huang 			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id);
4567725ccfdSJing Huang 
4577725ccfdSJing Huang 	/*
4587725ccfdSJing Huang 	 * Copy the payload (if any) from the echo frame
4597725ccfdSJing Huang 	 */
4607725ccfdSJing Huang 	pyld_len = rx_len - sizeof(struct fchs_s);
4617725ccfdSJing Huang 	bfa_trc(port->fcs, pyld_len);
4627725ccfdSJing Huang 
4637725ccfdSJing Huang 	if (pyld_len > len)
4647725ccfdSJing Huang 		memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) +
4657725ccfdSJing Huang 		       sizeof(struct fc_echo_s), (echo + 1),
4667725ccfdSJing Huang 		       (pyld_len - sizeof(struct fc_echo_s)));
4677725ccfdSJing Huang 
4687725ccfdSJing Huang 	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
4697725ccfdSJing Huang 		      BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL,
4707725ccfdSJing Huang 		      FC_MAX_PDUSZ, 0);
4717725ccfdSJing Huang }
4727725ccfdSJing Huang 
4737725ccfdSJing Huang /*
4747725ccfdSJing Huang  * Process incoming RNID.
4757725ccfdSJing Huang  * Since it does not require a login, it is processed here.
4767725ccfdSJing Huang  */
4777725ccfdSJing Huang static void
4787725ccfdSJing Huang bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
4797725ccfdSJing Huang 			struct fc_rnid_cmd_s *rnid, u16 rx_len)
4807725ccfdSJing Huang {
4817725ccfdSJing Huang 	struct fc_rnid_common_id_data_s common_id_data;
4827725ccfdSJing Huang 	struct fc_rnid_general_topology_data_s gen_topo_data;
4837725ccfdSJing Huang 	struct fchs_s          fchs;
4847725ccfdSJing Huang 	struct bfa_fcxp_s *fcxp;
4857725ccfdSJing Huang 	struct bfa_rport_s *bfa_rport = NULL;
4867725ccfdSJing Huang 	u16        len;
4877725ccfdSJing Huang 	u32        data_format;
4887725ccfdSJing Huang 
4897725ccfdSJing Huang 	bfa_trc(port->fcs, rx_fchs->s_id);
4907725ccfdSJing Huang 	bfa_trc(port->fcs, rx_fchs->d_id);
4917725ccfdSJing Huang 	bfa_trc(port->fcs, rx_len);
4927725ccfdSJing Huang 
4937725ccfdSJing Huang 	fcxp = bfa_fcs_fcxp_alloc(port->fcs);
4947725ccfdSJing Huang 	if (!fcxp)
4957725ccfdSJing Huang 		return;
4967725ccfdSJing Huang 
4977725ccfdSJing Huang 	/*
4987725ccfdSJing Huang 	 * Check Node Indentification Data Format
4997725ccfdSJing Huang 	 * We only support General Topology Discovery Format.
5007725ccfdSJing Huang 	 * For any other requested Data Formats, we return Common Node Id Data
5017725ccfdSJing Huang 	 * only, as per FC-LS.
5027725ccfdSJing Huang 	 */
5037725ccfdSJing Huang 	bfa_trc(port->fcs, rnid->node_id_data_format);
5047725ccfdSJing Huang 	if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
5057725ccfdSJing Huang 		data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY;
5067725ccfdSJing Huang 		/*
5077725ccfdSJing Huang 		 * Get General topology data for this port
5087725ccfdSJing Huang 		 */
5097725ccfdSJing Huang 		bfa_fs_port_get_gen_topo_data(port, &gen_topo_data);
5107725ccfdSJing Huang 	} else {
5117725ccfdSJing Huang 		data_format = RNID_NODEID_DATA_FORMAT_COMMON;
5127725ccfdSJing Huang 	}
5137725ccfdSJing Huang 
5147725ccfdSJing Huang 	/*
5157725ccfdSJing Huang 	 * Copy the Node Id Info
5167725ccfdSJing Huang 	 */
5177725ccfdSJing Huang 	common_id_data.port_name = bfa_fcs_port_get_pwwn(port);
5187725ccfdSJing Huang 	common_id_data.node_name = bfa_fcs_port_get_nwwn(port);
5197725ccfdSJing Huang 
5207725ccfdSJing Huang 	len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
5217725ccfdSJing Huang 				bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
5227725ccfdSJing Huang 				data_format, &common_id_data, &gen_topo_data);
5237725ccfdSJing Huang 
5247725ccfdSJing Huang 	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
5257725ccfdSJing Huang 		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
5267725ccfdSJing Huang 		      FC_MAX_PDUSZ, 0);
5277725ccfdSJing Huang 
5287725ccfdSJing Huang 	return;
5297725ccfdSJing Huang }
5307725ccfdSJing Huang 
5317725ccfdSJing Huang /*
5327725ccfdSJing Huang  *  Fill out General Topolpgy Discovery Data for RNID ELS.
5337725ccfdSJing Huang  */
5347725ccfdSJing Huang static void
5357725ccfdSJing Huang bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
5367725ccfdSJing Huang 			struct fc_rnid_general_topology_data_s *gen_topo_data)
5377725ccfdSJing Huang {
5387725ccfdSJing Huang 
5397725ccfdSJing Huang 	bfa_os_memset(gen_topo_data, 0,
5407725ccfdSJing Huang 		      sizeof(struct fc_rnid_general_topology_data_s));
5417725ccfdSJing Huang 
5427725ccfdSJing Huang 	gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST);
5437725ccfdSJing Huang 	gen_topo_data->phy_port_num = 0;	/* @todo */
5447725ccfdSJing Huang 	gen_topo_data->num_attached_nodes = bfa_os_htonl(1);
5457725ccfdSJing Huang }
5467725ccfdSJing Huang 
5477725ccfdSJing Huang static void
5487725ccfdSJing Huang bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port)
5497725ccfdSJing Huang {
5507725ccfdSJing Huang 	bfa_trc(port->fcs, port->fabric->oper_type);
5517725ccfdSJing Huang 
5527725ccfdSJing Huang 	__port_action[port->fabric->fab_type].init(port);
5537725ccfdSJing Huang 	__port_action[port->fabric->fab_type].online(port);
5547725ccfdSJing Huang 
5557725ccfdSJing Huang 	bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE);
5567725ccfdSJing Huang 	bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles,
5577725ccfdSJing Huang 			port->fabric->vf_drv, (port->vport == NULL) ?
5587725ccfdSJing Huang 			NULL : port->vport->vport_drv);
5597725ccfdSJing Huang }
5607725ccfdSJing Huang 
5617725ccfdSJing Huang static void
5627725ccfdSJing Huang bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port)
5637725ccfdSJing Huang {
5647725ccfdSJing Huang 	struct list_head *qe, *qen;
5657725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport;
5667725ccfdSJing Huang 
5677725ccfdSJing Huang 	bfa_trc(port->fcs, port->fabric->oper_type);
5687725ccfdSJing Huang 
5697725ccfdSJing Huang 	__port_action[port->fabric->fab_type].offline(port);
5707725ccfdSJing Huang 
571f8ceafdeSJing Huang 	if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
5727725ccfdSJing Huang 		bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
573f8ceafdeSJing Huang 	else
5747725ccfdSJing Huang 		bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE);
5757725ccfdSJing Huang 	bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles,
5767725ccfdSJing Huang 			port->fabric->vf_drv,
5777725ccfdSJing Huang 			(port->vport == NULL) ? NULL : port->vport->vport_drv);
5787725ccfdSJing Huang 
5797725ccfdSJing Huang 	list_for_each_safe(qe, qen, &port->rport_q) {
5807725ccfdSJing Huang 		rport = (struct bfa_fcs_rport_s *)qe;
5817725ccfdSJing Huang 		bfa_fcs_rport_offline(rport);
5827725ccfdSJing Huang 	}
5837725ccfdSJing Huang }
5847725ccfdSJing Huang 
5857725ccfdSJing Huang static void
5867725ccfdSJing Huang bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port)
5877725ccfdSJing Huang {
5887725ccfdSJing Huang 	bfa_assert(0);
5897725ccfdSJing Huang }
5907725ccfdSJing Huang 
5917725ccfdSJing Huang static void
5927725ccfdSJing Huang bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port)
5937725ccfdSJing Huang {
5947725ccfdSJing Huang 	bfa_assert(0);
5957725ccfdSJing Huang }
5967725ccfdSJing Huang 
5977725ccfdSJing Huang static void
5987725ccfdSJing Huang bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port)
5997725ccfdSJing Huang {
6007725ccfdSJing Huang 	bfa_assert(0);
6017725ccfdSJing Huang }
6027725ccfdSJing Huang 
6037725ccfdSJing Huang static void
6047725ccfdSJing Huang bfa_fcs_port_deleted(struct bfa_fcs_port_s *port)
6057725ccfdSJing Huang {
6067725ccfdSJing Huang 	bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE);
6077725ccfdSJing Huang 
6087725ccfdSJing Huang 	/*
6097725ccfdSJing Huang 	 * Base port will be deleted by the OS driver
6107725ccfdSJing Huang 	 */
6117725ccfdSJing Huang 	if (port->vport) {
6127725ccfdSJing Huang 		bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles,
6137725ccfdSJing Huang 			port->fabric->vf_drv,
6147725ccfdSJing Huang 			port->vport ? port->vport->vport_drv : NULL);
6157725ccfdSJing Huang 		bfa_fcs_vport_delete_comp(port->vport);
6167725ccfdSJing Huang 	} else {
6177725ccfdSJing Huang 		bfa_fcs_fabric_port_delete_comp(port->fabric);
6187725ccfdSJing Huang 	}
6197725ccfdSJing Huang }
6207725ccfdSJing Huang 
6217725ccfdSJing Huang 
6227725ccfdSJing Huang 
6237725ccfdSJing Huang /**
6247725ccfdSJing Huang  *  fcs_lport_api BFA FCS port API
6257725ccfdSJing Huang  */
6267725ccfdSJing Huang /**
6277725ccfdSJing Huang  *   Module initialization
6287725ccfdSJing Huang  */
6297725ccfdSJing Huang void
6307725ccfdSJing Huang bfa_fcs_port_modinit(struct bfa_fcs_s *fcs)
6317725ccfdSJing Huang {
6327725ccfdSJing Huang 
6337725ccfdSJing Huang }
6347725ccfdSJing Huang 
6357725ccfdSJing Huang /**
6367725ccfdSJing Huang  *   Module cleanup
6377725ccfdSJing Huang  */
6387725ccfdSJing Huang void
6397725ccfdSJing Huang bfa_fcs_port_modexit(struct bfa_fcs_s *fcs)
6407725ccfdSJing Huang {
6417725ccfdSJing Huang 	bfa_fcs_modexit_comp(fcs);
6427725ccfdSJing Huang }
6437725ccfdSJing Huang 
6447725ccfdSJing Huang /**
6457725ccfdSJing Huang  * 		Unsolicited frame receive handling.
6467725ccfdSJing Huang  */
6477725ccfdSJing Huang void
6487725ccfdSJing Huang bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs,
6497725ccfdSJing Huang 			u16 len)
6507725ccfdSJing Huang {
6517725ccfdSJing Huang 	u32        pid = fchs->s_id;
6527725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport = NULL;
6537725ccfdSJing Huang 	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
6547725ccfdSJing Huang 
6557725ccfdSJing Huang 	bfa_stats(lport, uf_recvs);
6567725ccfdSJing Huang 
6577725ccfdSJing Huang 	if (!bfa_fcs_port_is_online(lport)) {
6587725ccfdSJing Huang 		bfa_stats(lport, uf_recv_drops);
6597725ccfdSJing Huang 		return;
6607725ccfdSJing Huang 	}
6617725ccfdSJing Huang 
6627725ccfdSJing Huang 	/**
6637725ccfdSJing Huang 	 * First, handle ELSs that donot require a login.
6647725ccfdSJing Huang 	 */
6657725ccfdSJing Huang 	/*
6667725ccfdSJing Huang 	 * Handle PLOGI first
6677725ccfdSJing Huang 	 */
6687725ccfdSJing Huang 	if ((fchs->type == FC_TYPE_ELS) &&
6697725ccfdSJing Huang 		(els_cmd->els_code == FC_ELS_PLOGI)) {
6707725ccfdSJing Huang 		bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd);
6717725ccfdSJing Huang 		return;
6727725ccfdSJing Huang 	}
6737725ccfdSJing Huang 
6747725ccfdSJing Huang 	/*
6757725ccfdSJing Huang 	 * Handle ECHO separately.
6767725ccfdSJing Huang 	 */
6777725ccfdSJing Huang 	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) {
6787725ccfdSJing Huang 		bfa_fcs_port_echo(lport, fchs,
6797725ccfdSJing Huang 			(struct fc_echo_s *) els_cmd, len);
6807725ccfdSJing Huang 		return;
6817725ccfdSJing Huang 	}
6827725ccfdSJing Huang 
6837725ccfdSJing Huang 	/*
6847725ccfdSJing Huang 	 * Handle RNID separately.
6857725ccfdSJing Huang 	 */
6867725ccfdSJing Huang 	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) {
6877725ccfdSJing Huang 		bfa_fcs_port_rnid(lport, fchs,
6887725ccfdSJing Huang 			(struct fc_rnid_cmd_s *) els_cmd, len);
6897725ccfdSJing Huang 		return;
6907725ccfdSJing Huang 	}
6917725ccfdSJing Huang 
6927725ccfdSJing Huang 	/**
6937725ccfdSJing Huang 	 * look for a matching remote port ID
6947725ccfdSJing Huang 	 */
6957725ccfdSJing Huang 	rport = bfa_fcs_port_get_rport_by_pid(lport, pid);
6967725ccfdSJing Huang 	if (rport) {
6977725ccfdSJing Huang 		bfa_trc(rport->fcs, fchs->s_id);
6987725ccfdSJing Huang 		bfa_trc(rport->fcs, fchs->d_id);
6997725ccfdSJing Huang 		bfa_trc(rport->fcs, fchs->type);
7007725ccfdSJing Huang 
7017725ccfdSJing Huang 		bfa_fcs_rport_uf_recv(rport, fchs, len);
7027725ccfdSJing Huang 		return;
7037725ccfdSJing Huang 	}
7047725ccfdSJing Huang 
7057725ccfdSJing Huang 	/**
7067725ccfdSJing Huang 	 * Only handles ELS frames for now.
7077725ccfdSJing Huang 	 */
7087725ccfdSJing Huang 	if (fchs->type != FC_TYPE_ELS) {
7097725ccfdSJing Huang 		bfa_trc(lport->fcs, fchs->type);
7107725ccfdSJing Huang 		bfa_assert(0);
7117725ccfdSJing Huang 		return;
7127725ccfdSJing Huang 	}
7137725ccfdSJing Huang 
7147725ccfdSJing Huang 	bfa_trc(lport->fcs, els_cmd->els_code);
7157725ccfdSJing Huang 	if (els_cmd->els_code == FC_ELS_RSCN) {
7167725ccfdSJing Huang 		bfa_fcs_port_scn_process_rscn(lport, fchs, len);
7177725ccfdSJing Huang 		return;
7187725ccfdSJing Huang 	}
7197725ccfdSJing Huang 
7207725ccfdSJing Huang 	if (els_cmd->els_code == FC_ELS_LOGO) {
7217725ccfdSJing Huang 		/**
7227725ccfdSJing Huang 		 * @todo Handle LOGO frames received.
7237725ccfdSJing Huang 		 */
7247725ccfdSJing Huang 		bfa_trc(lport->fcs, els_cmd->els_code);
7257725ccfdSJing Huang 		return;
7267725ccfdSJing Huang 	}
7277725ccfdSJing Huang 
7287725ccfdSJing Huang 	if (els_cmd->els_code == FC_ELS_PRLI) {
7297725ccfdSJing Huang 		/**
7307725ccfdSJing Huang 		 * @todo Handle PRLI frames received.
7317725ccfdSJing Huang 		 */
7327725ccfdSJing Huang 		bfa_trc(lport->fcs, els_cmd->els_code);
7337725ccfdSJing Huang 		return;
7347725ccfdSJing Huang 	}
7357725ccfdSJing Huang 
7367725ccfdSJing Huang 	/**
7377725ccfdSJing Huang 	 * Unhandled ELS frames. Send a LS_RJT.
7387725ccfdSJing Huang 	 */
7397725ccfdSJing Huang 	bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
7407725ccfdSJing Huang 				 FC_LS_RJT_EXP_NO_ADDL_INFO);
7417725ccfdSJing Huang 
7427725ccfdSJing Huang }
7437725ccfdSJing Huang 
7447725ccfdSJing Huang /**
7457725ccfdSJing Huang  *   PID based Lookup for a R-Port in the Port R-Port Queue
7467725ccfdSJing Huang  */
7477725ccfdSJing Huang struct bfa_fcs_rport_s *
7487725ccfdSJing Huang bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid)
7497725ccfdSJing Huang {
7507725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport;
7517725ccfdSJing Huang 	struct list_head *qe;
7527725ccfdSJing Huang 
7537725ccfdSJing Huang 	list_for_each(qe, &port->rport_q) {
7547725ccfdSJing Huang 		rport = (struct bfa_fcs_rport_s *)qe;
7557725ccfdSJing Huang 		if (rport->pid == pid)
7567725ccfdSJing Huang 			return rport;
7577725ccfdSJing Huang 	}
7587725ccfdSJing Huang 
7597725ccfdSJing Huang 	bfa_trc(port->fcs, pid);
7607725ccfdSJing Huang 	return NULL;
7617725ccfdSJing Huang }
7627725ccfdSJing Huang 
7637725ccfdSJing Huang /**
7647725ccfdSJing Huang  *   PWWN based Lookup for a R-Port in the Port R-Port Queue
7657725ccfdSJing Huang  */
7667725ccfdSJing Huang struct bfa_fcs_rport_s *
7677725ccfdSJing Huang bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn)
7687725ccfdSJing Huang {
7697725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport;
7707725ccfdSJing Huang 	struct list_head *qe;
7717725ccfdSJing Huang 
7727725ccfdSJing Huang 	list_for_each(qe, &port->rport_q) {
7737725ccfdSJing Huang 		rport = (struct bfa_fcs_rport_s *)qe;
7747725ccfdSJing Huang 		if (wwn_is_equal(rport->pwwn, pwwn))
7757725ccfdSJing Huang 			return rport;
7767725ccfdSJing Huang 	}
7777725ccfdSJing Huang 
7787725ccfdSJing Huang 	bfa_trc(port->fcs, pwwn);
779f8ceafdeSJing Huang 	return NULL;
7807725ccfdSJing Huang }
7817725ccfdSJing Huang 
7827725ccfdSJing Huang /**
7837725ccfdSJing Huang  *   NWWN based Lookup for a R-Port in the Port R-Port Queue
7847725ccfdSJing Huang  */
7857725ccfdSJing Huang struct bfa_fcs_rport_s *
7867725ccfdSJing Huang bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn)
7877725ccfdSJing Huang {
7887725ccfdSJing Huang 	struct bfa_fcs_rport_s *rport;
7897725ccfdSJing Huang 	struct list_head *qe;
7907725ccfdSJing Huang 
7917725ccfdSJing Huang 	list_for_each(qe, &port->rport_q) {
7927725ccfdSJing Huang 		rport = (struct bfa_fcs_rport_s *)qe;
7937725ccfdSJing Huang 		if (wwn_is_equal(rport->nwwn, nwwn))
7947725ccfdSJing Huang 			return rport;
7957725ccfdSJing Huang 	}
7967725ccfdSJing Huang 
7977725ccfdSJing Huang 	bfa_trc(port->fcs, nwwn);
798f8ceafdeSJing Huang 	return NULL;
7997725ccfdSJing Huang }
8007725ccfdSJing Huang 
8017725ccfdSJing Huang /**
8027725ccfdSJing Huang  * Called by rport module when new rports are discovered.
8037725ccfdSJing Huang  */
8047725ccfdSJing Huang void
8057725ccfdSJing Huang bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port,
8067725ccfdSJing Huang 		       struct bfa_fcs_rport_s *rport)
8077725ccfdSJing Huang {
8087725ccfdSJing Huang 	list_add_tail(&rport->qe, &port->rport_q);
8097725ccfdSJing Huang 	port->num_rports++;
8107725ccfdSJing Huang }
8117725ccfdSJing Huang 
8127725ccfdSJing Huang /**
8137725ccfdSJing Huang  * Called by rport module to when rports are deleted.
8147725ccfdSJing Huang  */
8157725ccfdSJing Huang void
8167725ccfdSJing Huang bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port,
8177725ccfdSJing Huang 		       struct bfa_fcs_rport_s *rport)
8187725ccfdSJing Huang {
8197725ccfdSJing Huang 	bfa_assert(bfa_q_is_on_q(&port->rport_q, rport));
8207725ccfdSJing Huang 	list_del(&rport->qe);
8217725ccfdSJing Huang 	port->num_rports--;
8227725ccfdSJing Huang 
8237725ccfdSJing Huang 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
8247725ccfdSJing Huang }
8257725ccfdSJing Huang 
8267725ccfdSJing Huang /**
8277725ccfdSJing Huang  * Called by fabric for base port when fabric login is complete.
8287725ccfdSJing Huang  * Called by vport for virtual ports when FDISC is complete.
8297725ccfdSJing Huang  */
8307725ccfdSJing Huang void
8317725ccfdSJing Huang bfa_fcs_port_online(struct bfa_fcs_port_s *port)
8327725ccfdSJing Huang {
8337725ccfdSJing Huang 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
8347725ccfdSJing Huang }
8357725ccfdSJing Huang 
8367725ccfdSJing Huang /**
8377725ccfdSJing Huang  * Called by fabric for base port when fabric goes offline.
8387725ccfdSJing Huang  * Called by vport for virtual ports when virtual port becomes offline.
8397725ccfdSJing Huang  */
8407725ccfdSJing Huang void
8417725ccfdSJing Huang bfa_fcs_port_offline(struct bfa_fcs_port_s *port)
8427725ccfdSJing Huang {
8437725ccfdSJing Huang 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
8447725ccfdSJing Huang }
8457725ccfdSJing Huang 
8467725ccfdSJing Huang /**
8477725ccfdSJing Huang  * Called by fabric to delete base lport and associated resources.
8487725ccfdSJing Huang  *
8497725ccfdSJing Huang  * Called by vport to delete lport and associated resources. Should call
8507725ccfdSJing Huang  * bfa_fcs_vport_delete_comp() for vports on completion.
8517725ccfdSJing Huang  */
8527725ccfdSJing Huang void
8537725ccfdSJing Huang bfa_fcs_port_delete(struct bfa_fcs_port_s *port)
8547725ccfdSJing Huang {
8557725ccfdSJing Huang 	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
8567725ccfdSJing Huang }
8577725ccfdSJing Huang 
8587725ccfdSJing Huang /**
8597725ccfdSJing Huang  * Called by fabric in private loop topology to process LIP event.
8607725ccfdSJing Huang  */
8617725ccfdSJing Huang void
8627725ccfdSJing Huang bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
8637725ccfdSJing Huang {
8647725ccfdSJing Huang }
8657725ccfdSJing Huang 
8667725ccfdSJing Huang /**
8677725ccfdSJing Huang  * Return TRUE if port is online, else return FALSE
8687725ccfdSJing Huang  */
8697725ccfdSJing Huang bfa_boolean_t
8707725ccfdSJing Huang bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
8717725ccfdSJing Huang {
872f8ceafdeSJing Huang 	return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online);
8737725ccfdSJing Huang }
8747725ccfdSJing Huang 
8757725ccfdSJing Huang /**
876e6714324SKrishna Gudipati  * Attach time initialization of logical ports.
8777725ccfdSJing Huang  */
8787725ccfdSJing Huang void
879e6714324SKrishna Gudipati bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
880e6714324SKrishna Gudipati 		uint16_t vf_id, struct bfa_fcs_vport_s *vport)
8817725ccfdSJing Huang {
8827725ccfdSJing Huang 	lport->fcs = fcs;
8837725ccfdSJing Huang 	lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
8847725ccfdSJing Huang 	lport->vport = vport;
8857725ccfdSJing Huang 	lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
8867725ccfdSJing Huang 			 bfa_lps_get_tag(lport->fabric->lps);
8877725ccfdSJing Huang 
8887725ccfdSJing Huang 	INIT_LIST_HEAD(&lport->rport_q);
8897725ccfdSJing Huang 	lport->num_rports = 0;
890e6714324SKrishna Gudipati }
8917725ccfdSJing Huang 
892e6714324SKrishna Gudipati /**
893e6714324SKrishna Gudipati  * Logical port initialization of base or virtual port.
894e6714324SKrishna Gudipati  * Called by fabric for base port or by vport for virtual ports.
895e6714324SKrishna Gudipati  */
896e6714324SKrishna Gudipati 
897e6714324SKrishna Gudipati void
898e6714324SKrishna Gudipati bfa_fcs_lport_init(struct bfa_fcs_port_s *lport,
899e6714324SKrishna Gudipati 		struct bfa_port_cfg_s *port_cfg)
900e6714324SKrishna Gudipati {
901e6714324SKrishna Gudipati 	struct bfa_fcs_vport_s *vport = lport->vport;
902e6714324SKrishna Gudipati 
903e6714324SKrishna Gudipati 	bfa_os_assign(lport->port_cfg, *port_cfg);
904e6714324SKrishna Gudipati 
905e6714324SKrishna Gudipati 	lport->bfad_port = bfa_fcb_port_new(lport->fcs->bfad, lport,
906e6714324SKrishna Gudipati 				lport->port_cfg.roles,
9077725ccfdSJing Huang 				lport->fabric->vf_drv,
9087725ccfdSJing Huang 				vport ? vport->vport_drv : NULL);
909e6714324SKrishna Gudipati 
9107725ccfdSJing Huang 	bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW);
9117725ccfdSJing Huang 
9127725ccfdSJing Huang 	bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit);
9137725ccfdSJing Huang 	bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
9147725ccfdSJing Huang }
9157725ccfdSJing Huang 
9167725ccfdSJing Huang /**
9177725ccfdSJing Huang  *  fcs_lport_api
9187725ccfdSJing Huang  */
9197725ccfdSJing Huang 
9207725ccfdSJing Huang void
9217725ccfdSJing Huang bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
9227725ccfdSJing Huang 		      struct bfa_port_attr_s *port_attr)
9237725ccfdSJing Huang {
9247725ccfdSJing Huang 	if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online))
9257725ccfdSJing Huang 		port_attr->pid = port->pid;
9267725ccfdSJing Huang 	else
9277725ccfdSJing Huang 		port_attr->pid = 0;
9287725ccfdSJing Huang 
9297725ccfdSJing Huang 	port_attr->port_cfg = port->port_cfg;
9307725ccfdSJing Huang 
9317725ccfdSJing Huang 	if (port->fabric) {
9327725ccfdSJing Huang 		port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
9337725ccfdSJing Huang 		port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
9347725ccfdSJing Huang 		port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port);
9357725ccfdSJing Huang 		memcpy(port_attr->fabric_ip_addr,
9367725ccfdSJing Huang 		       bfa_fcs_port_get_fabric_ipaddr(port),
9377725ccfdSJing Huang 		       BFA_FCS_FABRIC_IPADDR_SZ);
9387725ccfdSJing Huang 
93986e32dabSKrishna Gudipati 		if (port->vport != NULL) {
9407725ccfdSJing Huang 			port_attr->port_type = BFA_PPORT_TYPE_VPORT;
94186e32dabSKrishna Gudipati 			port_attr->fpma_mac =
94286e32dabSKrishna Gudipati 				bfa_lps_get_lp_mac(port->vport->lps);
94386e32dabSKrishna Gudipati 		} else
94486e32dabSKrishna Gudipati 			port_attr->fpma_mac =
94586e32dabSKrishna Gudipati 				bfa_lps_get_lp_mac(port->fabric->lps);
9467725ccfdSJing Huang 
9477725ccfdSJing Huang 	} else {
9487725ccfdSJing Huang 		port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
9497725ccfdSJing Huang 		port_attr->state = BFA_PORT_UNINIT;
9507725ccfdSJing Huang 	}
9517725ccfdSJing Huang 
9527725ccfdSJing Huang }
9537725ccfdSJing Huang 
9547725ccfdSJing Huang 
955