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