123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- /*
- * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
- * All rights reserved
- * www.brocade.com
- *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License (GPL) Version 2 as
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
- #include <bfa.h>
- #include <bfa_svc.h>
- #include "fcs_lport.h"
- #include "fcs_rport.h"
- #include "fcs_ms.h"
- #include "fcs_trcmod.h"
- #include "fcs_fcxp.h"
- #include "fcs.h"
- #include "lport_priv.h"
- BFA_TRC_FILE(FCS, SCN);
- #define FC_QOS_RSCN_EVENT 0x0c
- #define FC_FABRIC_NAME_RSCN_EVENT 0x0d
- /*
- * forward declarations
- */
- static void bfa_fcs_port_scn_send_scr(void *scn_cbarg,
- struct bfa_fcxp_s *fcxp_alloced);
- static void bfa_fcs_port_scn_scr_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
- static void bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
- struct fchs_s *rx_fchs);
- static void bfa_fcs_port_scn_timeout(void *arg);
- /**
- * fcs_scm_sm FCS SCN state machine
- */
- /**
- * VPort SCN State Machine events
- */
- enum port_scn_event {
- SCNSM_EVENT_PORT_ONLINE = 1,
- SCNSM_EVENT_PORT_OFFLINE = 2,
- SCNSM_EVENT_RSP_OK = 3,
- SCNSM_EVENT_RSP_ERROR = 4,
- SCNSM_EVENT_TIMEOUT = 5,
- SCNSM_EVENT_SCR_SENT = 6,
- };
- static void bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event);
- static void bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event);
- static void bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event);
- static void bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event);
- static void bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event);
- /**
- * Starting state - awaiting link up.
- */
- static void
- bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event)
- {
- switch (event) {
- case SCNSM_EVENT_PORT_ONLINE:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
- bfa_fcs_port_scn_send_scr(scn, NULL);
- break;
- case SCNSM_EVENT_PORT_OFFLINE:
- break;
- default:
- bfa_assert(0);
- }
- }
- static void
- bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event)
- {
- switch (event) {
- case SCNSM_EVENT_SCR_SENT:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr);
- break;
- case SCNSM_EVENT_PORT_OFFLINE:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
- bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe);
- break;
- default:
- bfa_assert(0);
- }
- }
- static void
- bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event)
- {
- struct bfa_fcs_port_s *port = scn->port;
- switch (event) {
- case SCNSM_EVENT_RSP_OK:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_online);
- break;
- case SCNSM_EVENT_RSP_ERROR:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr_retry);
- bfa_timer_start(port->fcs->bfa, &scn->timer,
- bfa_fcs_port_scn_timeout, scn,
- BFA_FCS_RETRY_TIMEOUT);
- break;
- case SCNSM_EVENT_PORT_OFFLINE:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
- bfa_fcxp_discard(scn->fcxp);
- break;
- default:
- bfa_assert(0);
- }
- }
- static void
- bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event)
- {
- switch (event) {
- case SCNSM_EVENT_TIMEOUT:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
- bfa_fcs_port_scn_send_scr(scn, NULL);
- break;
- case SCNSM_EVENT_PORT_OFFLINE:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
- bfa_timer_stop(&scn->timer);
- break;
- default:
- bfa_assert(0);
- }
- }
- static void
- bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
- enum port_scn_event event)
- {
- switch (event) {
- case SCNSM_EVENT_PORT_OFFLINE:
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
- break;
- default:
- bfa_assert(0);
- }
- }
- /**
- * fcs_scn_private FCS SCN private functions
- */
- /**
- * This routine will be called to send a SCR command.
- */
- static void
- bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced)
- {
- struct bfa_fcs_port_scn_s *scn = scn_cbarg;
- struct bfa_fcs_port_s *port = scn->port;
- struct fchs_s fchs;
- int len;
- struct bfa_fcxp_s *fcxp;
- bfa_trc(port->fcs, port->pid);
- bfa_trc(port->fcs, port->port_cfg.pwwn);
- fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
- if (!fcxp) {
- bfa_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe,
- bfa_fcs_port_scn_send_scr, scn);
- return;
- }
- scn->fcxp = fcxp;
- /*
- * Handle VU registrations for Base port only
- */
- if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) {
- len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
- bfa_lps_is_brcd_fabric(port->fabric->lps),
- port->pid, 0);
- } else {
- len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), BFA_FALSE,
- port->pid, 0);
- }
- bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
- FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response,
- (void *)scn, FC_MAX_PDUSZ, FC_RA_TOV);
- bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
- }
- static void
- bfa_fcs_port_scn_scr_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
- void *cbarg, bfa_status_t req_status,
- u32 rsp_len, u32 resid_len,
- struct fchs_s *rsp_fchs)
- {
- struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)cbarg;
- struct bfa_fcs_port_s *port = scn->port;
- struct fc_els_cmd_s *els_cmd;
- struct fc_ls_rjt_s *ls_rjt;
- bfa_trc(port->fcs, port->port_cfg.pwwn);
- /*
- * Sanity Checks
- */
- if (req_status != BFA_STATUS_OK) {
- bfa_trc(port->fcs, req_status);
- bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
- return;
- }
- els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
- switch (els_cmd->els_code) {
- case FC_ELS_ACC:
- bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK);
- break;
- case FC_ELS_LS_RJT:
- ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
- bfa_trc(port->fcs, ls_rjt->reason_code);
- bfa_trc(port->fcs, ls_rjt->reason_code_expl);
- bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
- break;
- default:
- bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
- }
- }
- /*
- * Send a LS Accept
- */
- static void
- bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
- struct fchs_s *rx_fchs)
- {
- 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_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
- bfa_fcs_port_get_fcid(port), rx_fchs->ox_id);
- 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);
- }
- /**
- * This routine will be called by bfa_timer on timer timeouts.
- *
- * param[in] vport - pointer to bfa_fcs_port_t.
- * param[out] vport_status - pointer to return vport status in
- *
- * return
- * void
- *
- * Special Considerations:
- *
- * note
- */
- static void
- bfa_fcs_port_scn_timeout(void *arg)
- {
- struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)arg;
- bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT);
- }
- /**
- * fcs_scn_public FCS state change notification public interfaces
- */
- /*
- * Functions called by port/fab
- */
- void
- bfa_fcs_port_scn_init(struct bfa_fcs_port_s *port)
- {
- struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
- scn->port = port;
- bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
- }
- void
- bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *port)
- {
- struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
- scn->port = port;
- bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE);
- }
- void
- bfa_fcs_port_scn_online(struct bfa_fcs_port_s *port)
- {
- struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
- scn->port = port;
- bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE);
- }
- static void
- bfa_fcs_port_scn_portid_rscn(struct bfa_fcs_port_s *port, u32 rpid)
- {
- struct bfa_fcs_rport_s *rport;
- bfa_trc(port->fcs, rpid);
- /**
- * If this is an unknown device, then it just came online.
- * Otherwise let rport handle the RSCN event.
- */
- rport = bfa_fcs_port_get_rport_by_pid(port, rpid);
- if (rport == NULL) {
- /*
- * If min cfg mode is enabled, we donot need to
- * discover any new rports.
- */
- if (!__fcs_min_cfg(port->fcs))
- rport = bfa_fcs_rport_create(port, rpid);
- } else {
- bfa_fcs_rport_scn(rport);
- }
- }
- /**
- * rscn format based PID comparison
- */
- #define __fc_pid_match(__c0, __c1, __fmt) \
- (((__fmt) == FC_RSCN_FORMAT_FABRIC) || \
- (((__fmt) == FC_RSCN_FORMAT_DOMAIN) && \
- ((__c0)[0] == (__c1)[0])) || \
- (((__fmt) == FC_RSCN_FORMAT_AREA) && \
- ((__c0)[0] == (__c1)[0]) && \
- ((__c0)[1] == (__c1)[1])))
- static void
- bfa_fcs_port_scn_multiport_rscn(struct bfa_fcs_port_s *port,
- enum fc_rscn_format format, u32 rscn_pid)
- {
- struct bfa_fcs_rport_s *rport;
- struct list_head *qe, *qe_next;
- u8 *c0, *c1;
- bfa_trc(port->fcs, format);
- bfa_trc(port->fcs, rscn_pid);
- c0 = (u8 *) &rscn_pid;
- list_for_each_safe(qe, qe_next, &port->rport_q) {
- rport = (struct bfa_fcs_rport_s *)qe;
- c1 = (u8 *) &rport->pid;
- if (__fc_pid_match(c0, c1, format))
- bfa_fcs_rport_scn(rport);
- }
- }
- void
- bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port, struct fchs_s *fchs,
- u32 len)
- {
- struct fc_rscn_pl_s *rscn = (struct fc_rscn_pl_s *) (fchs + 1);
- int num_entries;
- u32 rscn_pid;
- bfa_boolean_t nsquery = BFA_FALSE;
- int i = 0;
- num_entries =
- (bfa_os_ntohs(rscn->payldlen) -
- sizeof(u32)) / sizeof(rscn->event[0]);
- bfa_trc(port->fcs, num_entries);
- port->stats.num_rscn++;
- bfa_fcs_port_scn_send_ls_acc(port, fchs);
- for (i = 0; i < num_entries; i++) {
- rscn_pid = rscn->event[i].portid;
- bfa_trc(port->fcs, rscn->event[i].format);
- bfa_trc(port->fcs, rscn_pid);
- switch (rscn->event[i].format) {
- case FC_RSCN_FORMAT_PORTID:
- if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) {
- /*
- * Ignore this event. f/w would have processed
- * it
- */
- bfa_trc(port->fcs, rscn_pid);
- } else {
- port->stats.num_portid_rscn++;
- bfa_fcs_port_scn_portid_rscn(port, rscn_pid);
- }
- break;
- case FC_RSCN_FORMAT_FABRIC:
- if (rscn->event[i].qualifier ==
- FC_FABRIC_NAME_RSCN_EVENT) {
- bfa_fcs_port_ms_fabric_rscn(port);
- break;
- }
- /*
- * !!!!!!!!! Fall Through !!!!!!!!!!!!!
- */
- case FC_RSCN_FORMAT_AREA:
- case FC_RSCN_FORMAT_DOMAIN:
- nsquery = BFA_TRUE;
- bfa_fcs_port_scn_multiport_rscn(port,
- rscn->event[i].format,
- rscn_pid);
- break;
- default:
- bfa_assert(0);
- nsquery = BFA_TRUE;
- }
- }
- /**
- * If any of area, domain or fabric RSCN is received, do a fresh discovery
- * to find new devices.
- */
- if (nsquery)
- bfa_fcs_port_ns_query(port);
- }
|