/* * 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. */ /** * bfa_fcs_port.c BFA FCS port */ #include #include #include #include #include #include #include "fcs.h" #include "fcs_lport.h" #include "fcs_vport.h" #include "fcs_rport.h" #include "fcs_fcxp.h" #include "fcs_trcmod.h" #include "lport_priv.h" #include BFA_TRC_FILE(FCS, PORT); /** * Forward declarations */ static void bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, enum bfa_lport_aen_event event); static void bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl); static void bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, struct fc_logi_s *plogi); static void bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port); static void bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port); static void bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port); static void bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port); static void bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port); static void bfa_fcs_port_deleted(struct bfa_fcs_port_s *port); static void bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, struct fc_echo_s *echo, u16 len); static void bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, struct fc_rnid_cmd_s *rnid, u16 len); static void bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, struct fc_rnid_general_topology_data_s *gen_topo_data); static struct { void (*init) (struct bfa_fcs_port_s *port); void (*online) (struct bfa_fcs_port_s *port); void (*offline) (struct bfa_fcs_port_s *port); } __port_action[] = { { bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online, bfa_fcs_port_unknown_offline}, { bfa_fcs_port_fab_init, bfa_fcs_port_fab_online, bfa_fcs_port_fab_offline}, { bfa_fcs_port_loop_init, bfa_fcs_port_loop_online, bfa_fcs_port_loop_offline}, { bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online, bfa_fcs_port_n2n_offline},}; /** * fcs_port_sm FCS logical port state machine */ enum bfa_fcs_port_event { BFA_FCS_PORT_SM_CREATE = 1, BFA_FCS_PORT_SM_ONLINE = 2, BFA_FCS_PORT_SM_OFFLINE = 3, BFA_FCS_PORT_SM_DELETE = 4, BFA_FCS_PORT_SM_DELRPORT = 5, }; static void bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event); static void bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event); static void bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event); static void bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event); static void bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event); static void bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) { bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_CREATE: bfa_sm_set_state(port, bfa_fcs_port_sm_init); break; default: bfa_sm_fault(port->fcs, event); } } static void bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) { bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_ONLINE: bfa_sm_set_state(port, bfa_fcs_port_sm_online); bfa_fcs_port_online_actions(port); break; case BFA_FCS_PORT_SM_DELETE: bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); bfa_fcs_port_deleted(port); break; default: bfa_sm_fault(port->fcs, event); } } static void bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) { struct bfa_fcs_rport_s *rport; struct list_head *qe, *qen; bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_OFFLINE: bfa_sm_set_state(port, bfa_fcs_port_sm_offline); bfa_fcs_port_offline_actions(port); break; case BFA_FCS_PORT_SM_DELETE: __port_action[port->fabric->fab_type].offline(port); if (port->num_rports == 0) { bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); bfa_fcs_port_deleted(port); } else { bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); list_for_each_safe(qe, qen, &port->rport_q) { rport = (struct bfa_fcs_rport_s *)qe; bfa_fcs_rport_delete(rport); } } break; case BFA_FCS_PORT_SM_DELRPORT: break; default: bfa_sm_fault(port->fcs, event); } } static void bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) { struct bfa_fcs_rport_s *rport; struct list_head *qe, *qen; bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_ONLINE: bfa_sm_set_state(port, bfa_fcs_port_sm_online); bfa_fcs_port_online_actions(port); break; case BFA_FCS_PORT_SM_DELETE: if (port->num_rports == 0) { bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); bfa_fcs_port_deleted(port); } else { bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); list_for_each_safe(qe, qen, &port->rport_q) { rport = (struct bfa_fcs_rport_s *)qe; bfa_fcs_rport_delete(rport); } } break; case BFA_FCS_PORT_SM_DELRPORT: case BFA_FCS_PORT_SM_OFFLINE: break; default: bfa_sm_fault(port->fcs, event); } } static void bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) { bfa_trc(port->fcs, port->port_cfg.pwwn); bfa_trc(port->fcs, event); switch (event) { case BFA_FCS_PORT_SM_DELRPORT: if (port->num_rports == 0) { bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); bfa_fcs_port_deleted(port); } break; default: bfa_sm_fault(port->fcs, event); } } /** * fcs_port_pvt */ /** * Send AEN notification */ static void bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, enum bfa_lport_aen_event event) { union bfa_aen_data_u aen_data; struct bfa_log_mod_s *logmod = port->fcs->logm; enum bfa_port_role role = port->port_cfg.roles; wwn_t lpwwn = bfa_fcs_port_get_pwwn(port); char lpwwn_ptr[BFA_STRING_32]; char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] = { "Initiator", "Target", "IPFC" }; wwn2str(lpwwn_ptr, lpwwn); bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX); bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, event), lpwwn_ptr, role_str[role/2]); aen_data.lport.vf_id = port->fabric->vf_id; aen_data.lport.roles = role; aen_data.lport.ppwwn = bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); aen_data.lport.lpwwn = lpwwn; } /* * Send a LS reject */ static void bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl) { struct fchs_s fchs; struct bfa_fcxp_s *fcxp; struct bfa_rport_s *bfa_rport = NULL; int len; bfa_trc(port->fcs, rx_fchs->s_id); fcxp = bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) return; len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, reason_code, reason_code_expl); bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); } /** * Process incoming plogi from a remote port. */ static void bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, struct fc_logi_s *plogi) { struct bfa_fcs_rport_s *rport; bfa_trc(port->fcs, rx_fchs->d_id); bfa_trc(port->fcs, rx_fchs->s_id); /* * If min cfg mode is enabled, drop any incoming PLOGIs */ if (__fcs_min_cfg(port->fcs)) { bfa_trc(port->fcs, rx_fchs->s_id); return; } if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) { bfa_trc(port->fcs, rx_fchs->s_id); /* * send a LS reject */ bfa_fcs_port_send_ls_rjt(port, rx_fchs, FC_LS_RJT_RSN_PROTOCOL_ERROR, FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS); return; } /** * Direct Attach P2P mode : verify address assigned by the r-port. */ if ((!bfa_fcs_fabric_is_switched(port->fabric)) && (memcmp ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) { /* * Address assigned to us cannot be a WKA */ bfa_fcs_port_send_ls_rjt(port, rx_fchs, FC_LS_RJT_RSN_PROTOCOL_ERROR, FC_LS_RJT_EXP_INVALID_NPORT_ID); return; } port->pid = rx_fchs->d_id; } /** * First, check if we know the device by pwwn. */ rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name); if (rport) { /** * Direct Attach P2P mode: handle address assigned by the rport. */ if ((!bfa_fcs_fabric_is_switched(port->fabric)) && (memcmp ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { port->pid = rx_fchs->d_id; rport->pid = rx_fchs->s_id; } bfa_fcs_rport_plogi(rport, rx_fchs, plogi); return; } /** * Next, lookup rport by PID. */ rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id); if (!rport) { /** * Inbound PLOGI from a new device. */ bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); return; } /** * Rport is known only by PID. */ if (rport->pwwn) { /** * This is a different device with the same pid. Old device * disappeared. Send implicit LOGO to old device. */ bfa_assert(rport->pwwn != plogi->port_name); bfa_fcs_rport_logo_imp(rport); /** * Inbound PLOGI from a new device (with old PID). */ bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); return; } /** * PLOGI crossing each other. */ bfa_assert(rport->pwwn == WWN_NULL); bfa_fcs_rport_plogi(rport, rx_fchs, plogi); } /* * Process incoming ECHO. * Since it does not require a login, it is processed here. */ static void bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, struct fc_echo_s *echo, u16 rx_len) { struct fchs_s fchs; struct bfa_fcxp_s *fcxp; struct bfa_rport_s *bfa_rport = NULL; int len, pyld_len; bfa_trc(port->fcs, rx_fchs->s_id); bfa_trc(port->fcs, rx_fchs->d_id); bfa_trc(port->fcs, rx_len); fcxp = bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) return; len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, bfa_fcs_port_get_fcid(port), rx_fchs->ox_id); /* * Copy the payload (if any) from the echo frame */ pyld_len = rx_len - sizeof(struct fchs_s); bfa_trc(port->fcs, pyld_len); if (pyld_len > len) memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) + sizeof(struct fc_echo_s), (echo + 1), (pyld_len - sizeof(struct fc_echo_s))); bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); } /* * Process incoming RNID. * Since it does not require a login, it is processed here. */ static void bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, struct fc_rnid_cmd_s *rnid, u16 rx_len) { struct fc_rnid_common_id_data_s common_id_data; struct fc_rnid_general_topology_data_s gen_topo_data; struct fchs_s fchs; struct bfa_fcxp_s *fcxp; struct bfa_rport_s *bfa_rport = NULL; u16 len; u32 data_format; bfa_trc(port->fcs, rx_fchs->s_id); bfa_trc(port->fcs, rx_fchs->d_id); bfa_trc(port->fcs, rx_len); fcxp = bfa_fcs_fcxp_alloc(port->fcs); if (!fcxp) return; /* * Check Node Indentification Data Format * We only support General Topology Discovery Format. * For any other requested Data Formats, we return Common Node Id Data * only, as per FC-LS. */ bfa_trc(port->fcs, rnid->node_id_data_format); if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) { data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY; /* * Get General topology data for this port */ bfa_fs_port_get_gen_topo_data(port, &gen_topo_data); } else { data_format = RNID_NODEID_DATA_FORMAT_COMMON; } /* * Copy the Node Id Info */ common_id_data.port_name = bfa_fcs_port_get_pwwn(port); common_id_data.node_name = bfa_fcs_port_get_nwwn(port); len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, data_format, &common_id_data, &gen_topo_data); bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); return; } /* * Fill out General Topolpgy Discovery Data for RNID ELS. */ static void bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, struct fc_rnid_general_topology_data_s *gen_topo_data) { bfa_os_memset(gen_topo_data, 0, sizeof(struct fc_rnid_general_topology_data_s)); gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST); gen_topo_data->phy_port_num = 0; /* @todo */ gen_topo_data->num_attached_nodes = bfa_os_htonl(1); } static void bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port) { bfa_trc(port->fcs, port->fabric->oper_type); __port_action[port->fabric->fab_type].init(port); __port_action[port->fabric->fab_type].online(port); bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE); bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles, port->fabric->vf_drv, (port->vport == NULL) ? NULL : port->vport->vport_drv); } static void bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port) { struct list_head *qe, *qen; struct bfa_fcs_rport_s *rport; bfa_trc(port->fcs, port->fabric->oper_type); __port_action[port->fabric->fab_type].offline(port); if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT); else bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE); bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles, port->fabric->vf_drv, (port->vport == NULL) ? NULL : port->vport->vport_drv); list_for_each_safe(qe, qen, &port->rport_q) { rport = (struct bfa_fcs_rport_s *)qe; bfa_fcs_rport_offline(rport); } } static void bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port) { bfa_assert(0); } static void bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port) { bfa_assert(0); } static void bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port) { bfa_assert(0); } static void bfa_fcs_port_deleted(struct bfa_fcs_port_s *port) { bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE); /* * Base port will be deleted by the OS driver */ if (port->vport) { bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles, port->fabric->vf_drv, port->vport ? port->vport->vport_drv : NULL); bfa_fcs_vport_delete_comp(port->vport); } else { bfa_fcs_fabric_port_delete_comp(port->fabric); } } /** * fcs_lport_api BFA FCS port API */ /** * Module initialization */ void bfa_fcs_port_modinit(struct bfa_fcs_s *fcs) { } /** * Module cleanup */ void bfa_fcs_port_modexit(struct bfa_fcs_s *fcs) { bfa_fcs_modexit_comp(fcs); } /** * Unsolicited frame receive handling. */ void bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, u16 len) { u32 pid = fchs->s_id; struct bfa_fcs_rport_s *rport = NULL; struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); bfa_stats(lport, uf_recvs); if (!bfa_fcs_port_is_online(lport)) { bfa_stats(lport, uf_recv_drops); return; } /** * First, handle ELSs that donot require a login. */ /* * Handle PLOGI first */ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_PLOGI)) { bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd); return; } /* * Handle ECHO separately. */ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) { bfa_fcs_port_echo(lport, fchs, (struct fc_echo_s *) els_cmd, len); return; } /* * Handle RNID separately. */ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) { bfa_fcs_port_rnid(lport, fchs, (struct fc_rnid_cmd_s *) els_cmd, len); return; } /** * look for a matching remote port ID */ rport = bfa_fcs_port_get_rport_by_pid(lport, pid); if (rport) { bfa_trc(rport->fcs, fchs->s_id); bfa_trc(rport->fcs, fchs->d_id); bfa_trc(rport->fcs, fchs->type); bfa_fcs_rport_uf_recv(rport, fchs, len); return; } /** * Only handles ELS frames for now. */ if (fchs->type != FC_TYPE_ELS) { bfa_trc(lport->fcs, fchs->type); bfa_assert(0); return; } bfa_trc(lport->fcs, els_cmd->els_code); if (els_cmd->els_code == FC_ELS_RSCN) { bfa_fcs_port_scn_process_rscn(lport, fchs, len); return; } if (els_cmd->els_code == FC_ELS_LOGO) { /** * @todo Handle LOGO frames received. */ bfa_trc(lport->fcs, els_cmd->els_code); return; } if (els_cmd->els_code == FC_ELS_PRLI) { /** * @todo Handle PRLI frames received. */ bfa_trc(lport->fcs, els_cmd->els_code); return; } /** * Unhandled ELS frames. Send a LS_RJT. */ bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, FC_LS_RJT_EXP_NO_ADDL_INFO); } /** * PID based Lookup for a R-Port in the Port R-Port Queue */ struct bfa_fcs_rport_s * bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid) { struct bfa_fcs_rport_s *rport; struct list_head *qe; list_for_each(qe, &port->rport_q) { rport = (struct bfa_fcs_rport_s *)qe; if (rport->pid == pid) return rport; } bfa_trc(port->fcs, pid); return NULL; } /** * PWWN based Lookup for a R-Port in the Port R-Port Queue */ struct bfa_fcs_rport_s * bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn) { struct bfa_fcs_rport_s *rport; struct list_head *qe; list_for_each(qe, &port->rport_q) { rport = (struct bfa_fcs_rport_s *)qe; if (wwn_is_equal(rport->pwwn, pwwn)) return rport; } bfa_trc(port->fcs, pwwn); return NULL; } /** * NWWN based Lookup for a R-Port in the Port R-Port Queue */ struct bfa_fcs_rport_s * bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn) { struct bfa_fcs_rport_s *rport; struct list_head *qe; list_for_each(qe, &port->rport_q) { rport = (struct bfa_fcs_rport_s *)qe; if (wwn_is_equal(rport->nwwn, nwwn)) return rport; } bfa_trc(port->fcs, nwwn); return NULL; } /** * Called by rport module when new rports are discovered. */ void bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, struct bfa_fcs_rport_s *rport) { list_add_tail(&rport->qe, &port->rport_q); port->num_rports++; } /** * Called by rport module to when rports are deleted. */ void bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, struct bfa_fcs_rport_s *rport) { bfa_assert(bfa_q_is_on_q(&port->rport_q, rport)); list_del(&rport->qe); port->num_rports--; bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT); } /** * Called by fabric for base port when fabric login is complete. * Called by vport for virtual ports when FDISC is complete. */ void bfa_fcs_port_online(struct bfa_fcs_port_s *port) { bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE); } /** * Called by fabric for base port when fabric goes offline. * Called by vport for virtual ports when virtual port becomes offline. */ void bfa_fcs_port_offline(struct bfa_fcs_port_s *port) { bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE); } /** * Called by fabric to delete base lport and associated resources. * * Called by vport to delete lport and associated resources. Should call * bfa_fcs_vport_delete_comp() for vports on completion. */ void bfa_fcs_port_delete(struct bfa_fcs_port_s *port) { bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE); } /** * Called by fabric in private loop topology to process LIP event. */ void bfa_fcs_port_lip(struct bfa_fcs_port_s *port) { } /** * Return TRUE if port is online, else return FALSE */ bfa_boolean_t bfa_fcs_port_is_online(struct bfa_fcs_port_s *port) { return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online); } /** * Attach time initialization of logical ports. */ void bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, uint16_t vf_id, struct bfa_fcs_vport_s *vport) { lport->fcs = fcs; lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); lport->vport = vport; lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) : bfa_lps_get_tag(lport->fabric->lps); INIT_LIST_HEAD(&lport->rport_q); lport->num_rports = 0; } /** * Logical port initialization of base or virtual port. * Called by fabric for base port or by vport for virtual ports. */ void bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_port_cfg_s *port_cfg) { struct bfa_fcs_vport_s *vport = lport->vport; bfa_os_assign(lport->port_cfg, *port_cfg); lport->bfad_port = bfa_fcb_port_new(lport->fcs->bfad, lport, lport->port_cfg.roles, lport->fabric->vf_drv, vport ? vport->vport_drv : NULL); bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW); bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit); bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE); } /** * fcs_lport_api */ void bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, struct bfa_port_attr_s *port_attr) { if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online)) port_attr->pid = port->pid; else port_attr->pid = 0; port_attr->port_cfg = port->port_cfg; if (port->fabric) { port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric); port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric); port_attr->authfail = bfa_fcs_fabric_is_auth_failed(port->fabric); port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port); memcpy(port_attr->fabric_ip_addr, bfa_fcs_port_get_fabric_ipaddr(port), BFA_FCS_FABRIC_IPADDR_SZ); if (port->vport != NULL) { port_attr->port_type = BFA_PPORT_TYPE_VPORT; port_attr->fpma_mac = bfa_lps_get_lp_mac(port->vport->lps); } else port_attr->fpma_mac = bfa_lps_get_lp_mac(port->fabric->lps); } else { port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN; port_attr->state = BFA_PORT_UNINIT; } }