2 * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License (GPL) Version 2 as
10 * published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
20 #include "fcs_lport.h"
21 #include "fcs_rport.h"
23 #include "fcs_trcmod.h"
26 #include "lport_priv.h"
28 BFA_TRC_FILE(FCS
, SCN
);
30 #define FC_QOS_RSCN_EVENT 0x0c
31 #define FC_FABRIC_NAME_RSCN_EVENT 0x0d
34 * forward declarations
36 static void bfa_fcs_port_scn_send_scr(void *scn_cbarg
,
37 struct bfa_fcxp_s
*fcxp_alloced
);
38 static void bfa_fcs_port_scn_scr_response(void *fcsarg
,
39 struct bfa_fcxp_s
*fcxp
,
41 bfa_status_t req_status
,
44 struct fchs_s
*rsp_fchs
);
45 static void bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s
*port
,
46 struct fchs_s
*rx_fchs
);
47 static void bfa_fcs_port_scn_timeout(void *arg
);
50 * fcs_scm_sm FCS SCN state machine
54 * VPort SCN State Machine events
57 SCNSM_EVENT_PORT_ONLINE
= 1,
58 SCNSM_EVENT_PORT_OFFLINE
= 2,
59 SCNSM_EVENT_RSP_OK
= 3,
60 SCNSM_EVENT_RSP_ERROR
= 4,
61 SCNSM_EVENT_TIMEOUT
= 5,
62 SCNSM_EVENT_SCR_SENT
= 6,
65 static void bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s
*scn
,
66 enum port_scn_event event
);
67 static void bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s
*scn
,
68 enum port_scn_event event
);
69 static void bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s
*scn
,
70 enum port_scn_event event
);
71 static void bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s
*scn
,
72 enum port_scn_event event
);
73 static void bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s
*scn
,
74 enum port_scn_event event
);
77 * Starting state - awaiting link up.
80 bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s
*scn
,
81 enum port_scn_event event
)
84 case SCNSM_EVENT_PORT_ONLINE
:
85 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_sending_scr
);
86 bfa_fcs_port_scn_send_scr(scn
, NULL
);
89 case SCNSM_EVENT_PORT_OFFLINE
:
93 bfa_sm_fault(scn
->port
->fcs
, event
);
98 bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s
*scn
,
99 enum port_scn_event event
)
102 case SCNSM_EVENT_SCR_SENT
:
103 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_scr
);
106 case SCNSM_EVENT_PORT_OFFLINE
:
107 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_offline
);
108 bfa_fcxp_walloc_cancel(scn
->port
->fcs
->bfa
, &scn
->fcxp_wqe
);
112 bfa_sm_fault(scn
->port
->fcs
, event
);
117 bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s
*scn
,
118 enum port_scn_event event
)
120 struct bfa_fcs_port_s
*port
= scn
->port
;
123 case SCNSM_EVENT_RSP_OK
:
124 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_online
);
127 case SCNSM_EVENT_RSP_ERROR
:
128 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_scr_retry
);
129 bfa_timer_start(port
->fcs
->bfa
, &scn
->timer
,
130 bfa_fcs_port_scn_timeout
, scn
,
131 BFA_FCS_RETRY_TIMEOUT
);
134 case SCNSM_EVENT_PORT_OFFLINE
:
135 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_offline
);
136 bfa_fcxp_discard(scn
->fcxp
);
140 bfa_sm_fault(scn
->port
->fcs
, event
);
145 bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s
*scn
,
146 enum port_scn_event event
)
149 case SCNSM_EVENT_TIMEOUT
:
150 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_sending_scr
);
151 bfa_fcs_port_scn_send_scr(scn
, NULL
);
154 case SCNSM_EVENT_PORT_OFFLINE
:
155 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_offline
);
156 bfa_timer_stop(&scn
->timer
);
160 bfa_sm_fault(scn
->port
->fcs
, event
);
165 bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s
*scn
,
166 enum port_scn_event event
)
169 case SCNSM_EVENT_PORT_OFFLINE
:
170 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_offline
);
174 bfa_sm_fault(scn
->port
->fcs
, event
);
181 * fcs_scn_private FCS SCN private functions
185 * This routine will be called to send a SCR command.
188 bfa_fcs_port_scn_send_scr(void *scn_cbarg
, struct bfa_fcxp_s
*fcxp_alloced
)
190 struct bfa_fcs_port_scn_s
*scn
= scn_cbarg
;
191 struct bfa_fcs_port_s
*port
= scn
->port
;
194 struct bfa_fcxp_s
*fcxp
;
196 bfa_trc(port
->fcs
, port
->pid
);
197 bfa_trc(port
->fcs
, port
->port_cfg
.pwwn
);
199 fcxp
= fcxp_alloced
? fcxp_alloced
: bfa_fcs_fcxp_alloc(port
->fcs
);
201 bfa_fcxp_alloc_wait(port
->fcs
->bfa
, &scn
->fcxp_wqe
,
202 bfa_fcs_port_scn_send_scr
, scn
);
208 * Handle VU registrations for Base port only
210 if ((!port
->vport
) && bfa_ioc_get_fcmode(&port
->fcs
->bfa
->ioc
)) {
211 len
= fc_scr_build(&fchs
, bfa_fcxp_get_reqbuf(fcxp
),
212 bfa_lps_is_brcd_fabric(port
->fabric
->lps
),
215 len
= fc_scr_build(&fchs
, bfa_fcxp_get_reqbuf(fcxp
), BFA_FALSE
,
219 bfa_fcxp_send(fcxp
, NULL
, port
->fabric
->vf_id
, port
->lp_tag
, BFA_FALSE
,
220 FC_CLASS_3
, len
, &fchs
, bfa_fcs_port_scn_scr_response
,
221 (void *)scn
, FC_MAX_PDUSZ
, FC_RA_TOV
);
223 bfa_sm_send_event(scn
, SCNSM_EVENT_SCR_SENT
);
227 bfa_fcs_port_scn_scr_response(void *fcsarg
, struct bfa_fcxp_s
*fcxp
,
228 void *cbarg
, bfa_status_t req_status
,
229 u32 rsp_len
, u32 resid_len
,
230 struct fchs_s
*rsp_fchs
)
232 struct bfa_fcs_port_scn_s
*scn
= (struct bfa_fcs_port_scn_s
*)cbarg
;
233 struct bfa_fcs_port_s
*port
= scn
->port
;
234 struct fc_els_cmd_s
*els_cmd
;
235 struct fc_ls_rjt_s
*ls_rjt
;
237 bfa_trc(port
->fcs
, port
->port_cfg
.pwwn
);
242 if (req_status
!= BFA_STATUS_OK
) {
243 bfa_trc(port
->fcs
, req_status
);
244 bfa_sm_send_event(scn
, SCNSM_EVENT_RSP_ERROR
);
248 els_cmd
= (struct fc_els_cmd_s
*) BFA_FCXP_RSP_PLD(fcxp
);
250 switch (els_cmd
->els_code
) {
253 bfa_sm_send_event(scn
, SCNSM_EVENT_RSP_OK
);
258 ls_rjt
= (struct fc_ls_rjt_s
*) BFA_FCXP_RSP_PLD(fcxp
);
260 bfa_trc(port
->fcs
, ls_rjt
->reason_code
);
261 bfa_trc(port
->fcs
, ls_rjt
->reason_code_expl
);
263 bfa_sm_send_event(scn
, SCNSM_EVENT_RSP_ERROR
);
267 bfa_sm_send_event(scn
, SCNSM_EVENT_RSP_ERROR
);
275 bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s
*port
,
276 struct fchs_s
*rx_fchs
)
279 struct bfa_fcxp_s
*fcxp
;
280 struct bfa_rport_s
*bfa_rport
= NULL
;
283 bfa_trc(port
->fcs
, rx_fchs
->s_id
);
285 fcxp
= bfa_fcs_fcxp_alloc(port
->fcs
);
289 len
= fc_ls_acc_build(&fchs
, bfa_fcxp_get_reqbuf(fcxp
), rx_fchs
->s_id
,
290 bfa_fcs_port_get_fcid(port
), rx_fchs
->ox_id
);
292 bfa_fcxp_send(fcxp
, bfa_rport
, port
->fabric
->vf_id
, port
->lp_tag
,
293 BFA_FALSE
, FC_CLASS_3
, len
, &fchs
, NULL
, NULL
,
298 * This routine will be called by bfa_timer on timer timeouts.
300 * param[in] vport - pointer to bfa_fcs_port_t.
301 * param[out] vport_status - pointer to return vport status in
306 * Special Considerations:
311 bfa_fcs_port_scn_timeout(void *arg
)
313 struct bfa_fcs_port_scn_s
*scn
= (struct bfa_fcs_port_scn_s
*)arg
;
315 bfa_sm_send_event(scn
, SCNSM_EVENT_TIMEOUT
);
321 * fcs_scn_public FCS state change notification public interfaces
325 * Functions called by port/fab
328 bfa_fcs_port_scn_init(struct bfa_fcs_port_s
*port
)
330 struct bfa_fcs_port_scn_s
*scn
= BFA_FCS_GET_SCN_FROM_PORT(port
);
333 bfa_sm_set_state(scn
, bfa_fcs_port_scn_sm_offline
);
337 bfa_fcs_port_scn_offline(struct bfa_fcs_port_s
*port
)
339 struct bfa_fcs_port_scn_s
*scn
= BFA_FCS_GET_SCN_FROM_PORT(port
);
342 bfa_sm_send_event(scn
, SCNSM_EVENT_PORT_OFFLINE
);
346 bfa_fcs_port_scn_online(struct bfa_fcs_port_s
*port
)
348 struct bfa_fcs_port_scn_s
*scn
= BFA_FCS_GET_SCN_FROM_PORT(port
);
351 bfa_sm_send_event(scn
, SCNSM_EVENT_PORT_ONLINE
);
355 bfa_fcs_port_scn_portid_rscn(struct bfa_fcs_port_s
*port
, u32 rpid
)
357 struct bfa_fcs_rport_s
*rport
;
359 bfa_trc(port
->fcs
, rpid
);
362 * If this is an unknown device, then it just came online.
363 * Otherwise let rport handle the RSCN event.
365 rport
= bfa_fcs_port_get_rport_by_pid(port
, rpid
);
368 * If min cfg mode is enabled, we donot need to
369 * discover any new rports.
371 if (!__fcs_min_cfg(port
->fcs
))
372 rport
= bfa_fcs_rport_create(port
, rpid
);
374 bfa_fcs_rport_scn(rport
);
379 * rscn format based PID comparison
381 #define __fc_pid_match(__c0, __c1, __fmt) \
382 (((__fmt) == FC_RSCN_FORMAT_FABRIC) || \
383 (((__fmt) == FC_RSCN_FORMAT_DOMAIN) && \
384 ((__c0)[0] == (__c1)[0])) || \
385 (((__fmt) == FC_RSCN_FORMAT_AREA) && \
386 ((__c0)[0] == (__c1)[0]) && \
387 ((__c0)[1] == (__c1)[1])))
390 bfa_fcs_port_scn_multiport_rscn(struct bfa_fcs_port_s
*port
,
391 enum fc_rscn_format format
, u32 rscn_pid
)
393 struct bfa_fcs_rport_s
*rport
;
394 struct list_head
*qe
, *qe_next
;
397 bfa_trc(port
->fcs
, format
);
398 bfa_trc(port
->fcs
, rscn_pid
);
400 c0
= (u8
*) &rscn_pid
;
402 list_for_each_safe(qe
, qe_next
, &port
->rport_q
) {
403 rport
= (struct bfa_fcs_rport_s
*)qe
;
404 c1
= (u8
*) &rport
->pid
;
405 if (__fc_pid_match(c0
, c1
, format
))
406 bfa_fcs_rport_scn(rport
);
411 bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s
*port
, struct fchs_s
*fchs
,
414 struct fc_rscn_pl_s
*rscn
= (struct fc_rscn_pl_s
*) (fchs
+ 1);
417 bfa_boolean_t nsquery
= BFA_FALSE
;
421 (bfa_os_ntohs(rscn
->payldlen
) -
422 sizeof(u32
)) / sizeof(rscn
->event
[0]);
424 bfa_trc(port
->fcs
, num_entries
);
426 port
->stats
.num_rscn
++;
428 bfa_fcs_port_scn_send_ls_acc(port
, fchs
);
430 for (i
= 0; i
< num_entries
; i
++) {
431 rscn_pid
= rscn
->event
[i
].portid
;
433 bfa_trc(port
->fcs
, rscn
->event
[i
].format
);
434 bfa_trc(port
->fcs
, rscn_pid
);
436 switch (rscn
->event
[i
].format
) {
437 case FC_RSCN_FORMAT_PORTID
:
438 if (rscn
->event
[i
].qualifier
== FC_QOS_RSCN_EVENT
) {
440 * Ignore this event. f/w would have processed
443 bfa_trc(port
->fcs
, rscn_pid
);
445 port
->stats
.num_portid_rscn
++;
446 bfa_fcs_port_scn_portid_rscn(port
, rscn_pid
);
450 case FC_RSCN_FORMAT_FABRIC
:
451 if (rscn
->event
[i
].qualifier
==
452 FC_FABRIC_NAME_RSCN_EVENT
) {
453 bfa_fcs_port_ms_fabric_rscn(port
);
457 * !!!!!!!!! Fall Through !!!!!!!!!!!!!
460 case FC_RSCN_FORMAT_AREA
:
461 case FC_RSCN_FORMAT_DOMAIN
:
463 bfa_fcs_port_scn_multiport_rscn(port
,
464 rscn
->event
[i
].format
,
475 * If any of area, domain or fabric RSCN is received, do a fresh discovery
476 * to find new devices.
479 bfa_fcs_port_ns_query(port
);