123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940 |
- /*
- * 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 <fcs/bfa_fcs.h>
- #include <fcs/bfa_fcs_lport.h>
- #include <fcs/bfa_fcs_rport.h>
- #include <fcb/bfa_fcb_port.h>
- #include <bfa_svc.h>
- #include <log/bfa_log_fcs.h>
- #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 <aen/bfa_aen_lport.h>
- 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_assert(0);
- }
- }
- 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_assert(0);
- }
- }
- 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_assert(0);
- }
- }
- 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_assert(0);
- }
- }
- 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_assert(0);
- }
- }
- /**
- * 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);
- switch (event) {
- case BFA_LPORT_AEN_ONLINE:
- bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr,
- role_str[role / 2]);
- break;
- case BFA_LPORT_AEN_OFFLINE:
- bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr,
- role_str[role / 2]);
- break;
- case BFA_LPORT_AEN_NEW:
- bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr,
- role_str[role / 2]);
- break;
- case BFA_LPORT_AEN_DELETE:
- bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr,
- role_str[role / 2]);
- break;
- case BFA_LPORT_AEN_DISCONNECT:
- bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr,
- role_str[role / 2]);
- break;
- default:
- break;
- }
- 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));
- }
- /**
- * 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_fcs_s *fcs,
- u16 vf_id, struct bfa_port_cfg_s *port_cfg,
- struct bfa_fcs_vport_s *vport)
- {
- lport->fcs = fcs;
- lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
- bfa_os_assign(lport->port_cfg, *port_cfg);
- 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;
- lport->bfad_port =
- bfa_fcb_port_new(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->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;
- } else {
- port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
- port_attr->state = BFA_PORT_UNINIT;
- }
- }
|