1/*
2 * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
3 * All rights reserved
4 * www.brocade.com
5 *
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
7 *
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
11 *
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.
16 */
17
18/*
19 *  bfa_fcs.c BFA FCS main
20 */
21
22#include "bfad_drv.h"
23#include "bfad_im.h"
24#include "bfa_fcs.h"
25#include "bfa_fcbuild.h"
26
27BFA_TRC_FILE(FCS, FCS);
28
29/*
30 * FCS sub-modules
31 */
32struct bfa_fcs_mod_s {
33	void		(*attach) (struct bfa_fcs_s *fcs);
34	void		(*modinit) (struct bfa_fcs_s *fcs);
35	void		(*modexit) (struct bfa_fcs_s *fcs);
36};
37
38#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit }
39
40static struct bfa_fcs_mod_s fcs_modules[] = {
41	{ bfa_fcs_port_attach, NULL, NULL },
42	{ bfa_fcs_uf_attach, NULL, NULL },
43	{ bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit,
44	  bfa_fcs_fabric_modexit },
45};
46
47/*
48 *  fcs_api BFA FCS API
49 */
50
51static void
52bfa_fcs_exit_comp(void *fcs_cbarg)
53{
54	struct bfa_fcs_s      *fcs = fcs_cbarg;
55	struct bfad_s         *bfad = fcs->bfad;
56
57	complete(&bfad->comp);
58}
59
60
61
62/*
63 *  fcs_api BFA FCS API
64 */
65
66/*
67 * fcs attach -- called once to initialize data structures at driver attach time
68 */
69void
70bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
71	       bfa_boolean_t min_cfg)
72{
73	int		i;
74	struct bfa_fcs_mod_s  *mod;
75
76	fcs->bfa = bfa;
77	fcs->bfad = bfad;
78	fcs->min_cfg = min_cfg;
79
80	bfa->fcs = BFA_TRUE;
81	fcbuild_init();
82
83	for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
84		mod = &fcs_modules[i];
85		if (mod->attach)
86			mod->attach(fcs);
87	}
88}
89
90/*
91 * fcs initialization, called once after bfa initialization is complete
92 */
93void
94bfa_fcs_init(struct bfa_fcs_s *fcs)
95{
96	int	i;
97	struct bfa_fcs_mod_s  *mod;
98
99	for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
100		mod = &fcs_modules[i];
101		if (mod->modinit)
102			mod->modinit(fcs);
103	}
104}
105
106/*
107 * FCS update cfg - reset the pwwn/nwwn of fabric base logical port
108 * with values learned during bfa_init firmware GETATTR REQ.
109 */
110void
111bfa_fcs_update_cfg(struct bfa_fcs_s *fcs)
112{
113	struct bfa_fcs_fabric_s *fabric = &fcs->fabric;
114	struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
115	struct bfa_ioc_s *ioc = &fabric->fcs->bfa->ioc;
116
117	port_cfg->nwwn = ioc->attr->nwwn;
118	port_cfg->pwwn = ioc->attr->pwwn;
119}
120
121/*
122 * fcs pbc vport initialization
123 */
124void
125bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs)
126{
127	int i, npbc_vports;
128	struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS];
129
130	/* Initialize pbc vports */
131	if (!fcs->min_cfg) {
132		npbc_vports =
133			bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports);
134		for (i = 0; i < npbc_vports; i++)
135			bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]);
136	}
137}
138
139/*
140 *	brief
141 *		FCS driver details initialization.
142 *
143 *	param[in]		fcs		FCS instance
144 *	param[in]		driver_info	Driver Details
145 *
146 *	return None
147 */
148void
149bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
150			struct bfa_fcs_driver_info_s *driver_info)
151{
152
153	fcs->driver_info = *driver_info;
154
155	bfa_fcs_fabric_psymb_init(&fcs->fabric);
156}
157
158/*
159 *	brief
160 *		FCS instance cleanup and exit.
161 *
162 *	param[in]		fcs			FCS instance
163 *	return None
164 */
165void
166bfa_fcs_exit(struct bfa_fcs_s *fcs)
167{
168	struct bfa_fcs_mod_s  *mod;
169	int		nmods, i;
170
171	bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs);
172
173	nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]);
174
175	for (i = 0; i < nmods; i++) {
176
177		mod = &fcs_modules[i];
178		if (mod->modexit) {
179			bfa_wc_up(&fcs->wc);
180			mod->modexit(fcs);
181		}
182	}
183
184	bfa_wc_wait(&fcs->wc);
185}
186
187
188/*
189 * Fabric module implementation.
190 */
191
192#define BFA_FCS_FABRIC_RETRY_DELAY	(2000)	/* Milliseconds */
193#define BFA_FCS_FABRIC_CLEANUP_DELAY	(10000)	/* Milliseconds */
194
195#define bfa_fcs_fabric_set_opertype(__fabric) do {			\
196	if (bfa_fcport_get_topology((__fabric)->fcs->bfa)		\
197				== BFA_PORT_TOPOLOGY_P2P) {		\
198		if (fabric->fab_type == BFA_FCS_FABRIC_SWITCHED)	\
199			(__fabric)->oper_type = BFA_PORT_TYPE_NPORT;	\
200		else							\
201			(__fabric)->oper_type = BFA_PORT_TYPE_P2P;	\
202	} else								\
203		(__fabric)->oper_type = BFA_PORT_TYPE_NLPORT;		\
204} while (0)
205
206/*
207 * forward declarations
208 */
209static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric);
210static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric);
211static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric);
212static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric);
213static void bfa_fcs_fabric_delay(void *cbarg);
214static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric);
215static void bfa_fcs_fabric_delete_comp(void *cbarg);
216static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric,
217				      struct fchs_s *fchs, u16 len);
218static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
219					 struct fchs_s *fchs, u16 len);
220static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric);
221static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg,
222					 struct bfa_fcxp_s *fcxp, void *cbarg,
223					 bfa_status_t status,
224					 u32 rsp_len,
225					 u32 resid_len,
226					 struct fchs_s *rspfchs);
227static u8 bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric);
228static bfa_boolean_t bfa_fcs_fabric_is_bbscn_enabled(
229				struct bfa_fcs_fabric_s *fabric);
230
231static void	bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
232					 enum bfa_fcs_fabric_event event);
233static void	bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
234					  enum bfa_fcs_fabric_event event);
235static void	bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
236					   enum bfa_fcs_fabric_event event);
237static void	bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
238					enum bfa_fcs_fabric_event event);
239static void	bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
240					      enum bfa_fcs_fabric_event event);
241static void	bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
242				       enum bfa_fcs_fabric_event event);
243static void	bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
244					   enum bfa_fcs_fabric_event event);
245static void	bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
246				       enum bfa_fcs_fabric_event event);
247static void	bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
248					    enum bfa_fcs_fabric_event event);
249static void	bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
250					   enum bfa_fcs_fabric_event event);
251static void	bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
252					   enum bfa_fcs_fabric_event event);
253/*
254 *   Beginning state before fabric creation.
255 */
256static void
257bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
258			 enum bfa_fcs_fabric_event event)
259{
260	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
261	bfa_trc(fabric->fcs, event);
262
263	switch (event) {
264	case BFA_FCS_FABRIC_SM_CREATE:
265		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created);
266		bfa_fcs_fabric_init(fabric);
267		bfa_fcs_lport_init(&fabric->bport, &fabric->bport.port_cfg);
268		break;
269
270	case BFA_FCS_FABRIC_SM_LINK_UP:
271	case BFA_FCS_FABRIC_SM_LINK_DOWN:
272		break;
273
274	default:
275		bfa_sm_fault(fabric->fcs, event);
276	}
277}
278
279/*
280 *   Beginning state before fabric creation.
281 */
282static void
283bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
284			  enum bfa_fcs_fabric_event event)
285{
286	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
287	bfa_trc(fabric->fcs, event);
288
289	switch (event) {
290	case BFA_FCS_FABRIC_SM_START:
291		if (bfa_fcport_is_linkup(fabric->fcs->bfa)) {
292			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
293			bfa_fcs_fabric_login(fabric);
294		} else
295			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
296		break;
297
298	case BFA_FCS_FABRIC_SM_LINK_UP:
299	case BFA_FCS_FABRIC_SM_LINK_DOWN:
300		break;
301
302	case BFA_FCS_FABRIC_SM_DELETE:
303		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
304		bfa_fcs_fabric_delete(fabric);
305		break;
306
307	default:
308		bfa_sm_fault(fabric->fcs, event);
309	}
310}
311
312/*
313 *   Link is down, awaiting LINK UP event from port. This is also the
314 *   first state at fabric creation.
315 */
316static void
317bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
318			   enum bfa_fcs_fabric_event event)
319{
320	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
321	bfa_trc(fabric->fcs, event);
322
323	switch (event) {
324	case BFA_FCS_FABRIC_SM_LINK_UP:
325		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
326		bfa_fcs_fabric_login(fabric);
327		break;
328
329	case BFA_FCS_FABRIC_SM_RETRY_OP:
330		break;
331
332	case BFA_FCS_FABRIC_SM_DELETE:
333		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
334		bfa_fcs_fabric_delete(fabric);
335		break;
336
337	default:
338		bfa_sm_fault(fabric->fcs, event);
339	}
340}
341
342/*
343 *   FLOGI is in progress, awaiting FLOGI reply.
344 */
345static void
346bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
347			enum bfa_fcs_fabric_event event)
348{
349	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
350	bfa_trc(fabric->fcs, event);
351
352	switch (event) {
353	case BFA_FCS_FABRIC_SM_CONT_OP:
354
355		bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa,
356					   fabric->bb_credit,
357					   bfa_fcs_fabric_oper_bbscn(fabric));
358		fabric->fab_type = BFA_FCS_FABRIC_SWITCHED;
359
360		if (fabric->auth_reqd && fabric->is_auth) {
361			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth);
362			bfa_trc(fabric->fcs, event);
363		} else {
364			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
365			bfa_fcs_fabric_notify_online(fabric);
366		}
367		break;
368
369	case BFA_FCS_FABRIC_SM_RETRY_OP:
370		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry);
371		bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer,
372				bfa_fcs_fabric_delay, fabric,
373				BFA_FCS_FABRIC_RETRY_DELAY);
374		break;
375
376	case BFA_FCS_FABRIC_SM_LOOPBACK:
377		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback);
378		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
379		bfa_fcs_fabric_set_opertype(fabric);
380		break;
381
382	case BFA_FCS_FABRIC_SM_NO_FABRIC:
383		fabric->fab_type = BFA_FCS_FABRIC_N2N;
384		bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa,
385					   fabric->bb_credit,
386					   bfa_fcs_fabric_oper_bbscn(fabric));
387		bfa_fcs_fabric_notify_online(fabric);
388		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric);
389		break;
390
391	case BFA_FCS_FABRIC_SM_LINK_DOWN:
392		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
393		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
394		break;
395
396	case BFA_FCS_FABRIC_SM_DELETE:
397		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
398		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
399		bfa_fcs_fabric_delete(fabric);
400		break;
401
402	default:
403		bfa_sm_fault(fabric->fcs, event);
404	}
405}
406
407
408static void
409bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
410			      enum bfa_fcs_fabric_event event)
411{
412	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
413	bfa_trc(fabric->fcs, event);
414
415	switch (event) {
416	case BFA_FCS_FABRIC_SM_DELAYED:
417		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
418		bfa_fcs_fabric_login(fabric);
419		break;
420
421	case BFA_FCS_FABRIC_SM_LINK_DOWN:
422		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
423		bfa_timer_stop(&fabric->delay_timer);
424		break;
425
426	case BFA_FCS_FABRIC_SM_DELETE:
427		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
428		bfa_timer_stop(&fabric->delay_timer);
429		bfa_fcs_fabric_delete(fabric);
430		break;
431
432	default:
433		bfa_sm_fault(fabric->fcs, event);
434	}
435}
436
437/*
438 *   Authentication is in progress, awaiting authentication results.
439 */
440static void
441bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
442		       enum bfa_fcs_fabric_event event)
443{
444	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
445	bfa_trc(fabric->fcs, event);
446
447	switch (event) {
448	case BFA_FCS_FABRIC_SM_AUTH_FAILED:
449		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
450		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
451		break;
452
453	case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
454		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
455		bfa_fcs_fabric_notify_online(fabric);
456		break;
457
458	case BFA_FCS_FABRIC_SM_PERF_EVFP:
459		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp);
460		break;
461
462	case BFA_FCS_FABRIC_SM_LINK_DOWN:
463		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
464		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
465		break;
466
467	case BFA_FCS_FABRIC_SM_DELETE:
468		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
469		bfa_fcs_fabric_delete(fabric);
470		break;
471
472	default:
473		bfa_sm_fault(fabric->fcs, event);
474	}
475}
476
477/*
478 *   Authentication failed
479 */
480void
481bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
482			      enum bfa_fcs_fabric_event event)
483{
484	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
485	bfa_trc(fabric->fcs, event);
486
487	switch (event) {
488	case BFA_FCS_FABRIC_SM_LINK_DOWN:
489		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
490		bfa_fcs_fabric_notify_offline(fabric);
491		break;
492
493	case BFA_FCS_FABRIC_SM_DELETE:
494		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
495		bfa_fcs_fabric_delete(fabric);
496		break;
497
498	default:
499		bfa_sm_fault(fabric->fcs, event);
500	}
501}
502
503/*
504 *   Port is in loopback mode.
505 */
506void
507bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
508			   enum bfa_fcs_fabric_event event)
509{
510	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
511	bfa_trc(fabric->fcs, event);
512
513	switch (event) {
514	case BFA_FCS_FABRIC_SM_LINK_DOWN:
515		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
516		bfa_fcs_fabric_notify_offline(fabric);
517		break;
518
519	case BFA_FCS_FABRIC_SM_DELETE:
520		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
521		bfa_fcs_fabric_delete(fabric);
522		break;
523
524	default:
525		bfa_sm_fault(fabric->fcs, event);
526	}
527}
528
529/*
530 *   There is no attached fabric - private loop or NPort-to-NPort topology.
531 */
532static void
533bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
534			   enum bfa_fcs_fabric_event event)
535{
536	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
537	bfa_trc(fabric->fcs, event);
538
539	switch (event) {
540	case BFA_FCS_FABRIC_SM_LINK_DOWN:
541		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
542		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
543		bfa_fcs_fabric_notify_offline(fabric);
544		break;
545
546	case BFA_FCS_FABRIC_SM_DELETE:
547		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
548		bfa_fcs_fabric_delete(fabric);
549		break;
550
551	case BFA_FCS_FABRIC_SM_NO_FABRIC:
552		bfa_trc(fabric->fcs, fabric->bb_credit);
553		bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa,
554					   fabric->bb_credit,
555					   bfa_fcs_fabric_oper_bbscn(fabric));
556		break;
557
558	case BFA_FCS_FABRIC_SM_RETRY_OP:
559		break;
560
561	default:
562		bfa_sm_fault(fabric->fcs, event);
563	}
564}
565
566/*
567 *   Fabric is online - normal operating state.
568 */
569void
570bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
571			 enum bfa_fcs_fabric_event event)
572{
573	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
574	bfa_trc(fabric->fcs, event);
575
576	switch (event) {
577	case BFA_FCS_FABRIC_SM_LINK_DOWN:
578		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
579		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
580		bfa_fcs_fabric_notify_offline(fabric);
581		break;
582
583	case BFA_FCS_FABRIC_SM_DELETE:
584		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
585		bfa_fcs_fabric_delete(fabric);
586		break;
587
588	case BFA_FCS_FABRIC_SM_AUTH_FAILED:
589		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
590		bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE);
591		break;
592
593	case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
594		break;
595
596	default:
597		bfa_sm_fault(fabric->fcs, event);
598	}
599}
600
601/*
602 *   Exchanging virtual fabric parameters.
603 */
604static void
605bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
606		       enum bfa_fcs_fabric_event event)
607{
608	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
609	bfa_trc(fabric->fcs, event);
610
611	switch (event) {
612	case BFA_FCS_FABRIC_SM_CONT_OP:
613		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done);
614		break;
615
616	case BFA_FCS_FABRIC_SM_ISOLATE:
617		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated);
618		break;
619
620	default:
621		bfa_sm_fault(fabric->fcs, event);
622	}
623}
624
625/*
626 *   EVFP exchange complete and VFT tagging is enabled.
627 */
628static void
629bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
630			    enum bfa_fcs_fabric_event event)
631{
632	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
633	bfa_trc(fabric->fcs, event);
634}
635
636/*
637 *   Port is isolated after EVFP exchange due to VF_ID mismatch (N and F).
638 */
639static void
640bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
641			   enum bfa_fcs_fabric_event event)
642{
643	struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad;
644	char	pwwn_ptr[BFA_STRING_32];
645
646	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
647	bfa_trc(fabric->fcs, event);
648	wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn);
649
650	BFA_LOG(KERN_INFO, bfad, bfa_log_level,
651		"Port is isolated due to VF_ID mismatch. "
652		"PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.",
653		pwwn_ptr, fabric->fcs->port_vfid,
654		fabric->event_arg.swp_vfid);
655}
656
657/*
658 *   Fabric is being deleted, awaiting vport delete completions.
659 */
660static void
661bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
662			   enum bfa_fcs_fabric_event event)
663{
664	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
665	bfa_trc(fabric->fcs, event);
666
667	switch (event) {
668	case BFA_FCS_FABRIC_SM_DELCOMP:
669		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
670		bfa_wc_down(&fabric->fcs->wc);
671		break;
672
673	case BFA_FCS_FABRIC_SM_LINK_UP:
674		break;
675
676	case BFA_FCS_FABRIC_SM_LINK_DOWN:
677		bfa_fcs_fabric_notify_offline(fabric);
678		break;
679
680	default:
681		bfa_sm_fault(fabric->fcs, event);
682	}
683}
684
685
686
687/*
688 *  fcs_fabric_private fabric private functions
689 */
690
691static void
692bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric)
693{
694	struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
695
696	port_cfg->roles = BFA_LPORT_ROLE_FCP_IM;
697	port_cfg->nwwn = fabric->fcs->bfa->ioc.attr->nwwn;
698	port_cfg->pwwn = fabric->fcs->bfa->ioc.attr->pwwn;
699}
700
701/*
702 * Port Symbolic Name Creation for base port.
703 */
704void
705bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
706{
707	struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg;
708	char model[BFA_ADAPTER_MODEL_NAME_LEN] = {0};
709	struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info;
710
711	bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
712
713	/* Model name/number */
714	strncpy((char *)&port_cfg->sym_name, model,
715		BFA_FCS_PORT_SYMBNAME_MODEL_SZ);
716	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
717		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
718
719	/* Driver Version */
720	strncat((char *)&port_cfg->sym_name, (char *)driver_info->version,
721		BFA_FCS_PORT_SYMBNAME_VERSION_SZ);
722	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
723		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
724
725	/* Host machine name */
726	strncat((char *)&port_cfg->sym_name,
727		(char *)driver_info->host_machine_name,
728		BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ);
729	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
730		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
731
732	/*
733	 * Host OS Info :
734	 * If OS Patch Info is not there, do not truncate any bytes from the
735	 * OS name string and instead copy the entire OS info string (64 bytes).
736	 */
737	if (driver_info->host_os_patch[0] == '\0') {
738		strncat((char *)&port_cfg->sym_name,
739			(char *)driver_info->host_os_name,
740			BFA_FCS_OS_STR_LEN);
741		strncat((char *)&port_cfg->sym_name,
742			BFA_FCS_PORT_SYMBNAME_SEPARATOR,
743			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
744	} else {
745		strncat((char *)&port_cfg->sym_name,
746			(char *)driver_info->host_os_name,
747			BFA_FCS_PORT_SYMBNAME_OSINFO_SZ);
748		strncat((char *)&port_cfg->sym_name,
749			BFA_FCS_PORT_SYMBNAME_SEPARATOR,
750			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
751
752		/* Append host OS Patch Info */
753		strncat((char *)&port_cfg->sym_name,
754			(char *)driver_info->host_os_patch,
755			BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ);
756	}
757
758	/* null terminate */
759	port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
760}
761
762/*
763 * bfa lps login completion callback
764 */
765void
766bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
767{
768	struct bfa_fcs_fabric_s *fabric = uarg;
769
770	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
771	bfa_trc(fabric->fcs, status);
772
773	switch (status) {
774	case BFA_STATUS_OK:
775		fabric->stats.flogi_accepts++;
776		break;
777
778	case BFA_STATUS_INVALID_MAC:
779		/* Only for CNA */
780		fabric->stats.flogi_acc_err++;
781		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
782
783		return;
784
785	case BFA_STATUS_EPROTOCOL:
786		switch (fabric->lps->ext_status) {
787		case BFA_EPROTO_BAD_ACCEPT:
788			fabric->stats.flogi_acc_err++;
789			break;
790
791		case BFA_EPROTO_UNKNOWN_RSP:
792			fabric->stats.flogi_unknown_rsp++;
793			break;
794
795		default:
796			break;
797		}
798		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
799
800		return;
801
802	case BFA_STATUS_FABRIC_RJT:
803		fabric->stats.flogi_rejects++;
804		if (fabric->lps->lsrjt_rsn == FC_LS_RJT_RSN_LOGICAL_ERROR &&
805		    fabric->lps->lsrjt_expl == FC_LS_RJT_EXP_NO_ADDL_INFO)
806			fabric->fcs->bbscn_flogi_rjt = BFA_TRUE;
807
808		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
809		return;
810
811	default:
812		fabric->stats.flogi_rsp_err++;
813		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
814		return;
815	}
816
817	fabric->bb_credit = fabric->lps->pr_bbcred;
818	bfa_trc(fabric->fcs, fabric->bb_credit);
819
820	if (!(fabric->lps->brcd_switch))
821		fabric->fabric_name =  fabric->lps->pr_nwwn;
822
823	/*
824	 * Check port type. It should be 1 = F-port.
825	 */
826	if (fabric->lps->fport) {
827		fabric->bport.pid = fabric->lps->lp_pid;
828		fabric->is_npiv = fabric->lps->npiv_en;
829		fabric->is_auth = fabric->lps->auth_req;
830		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP);
831	} else {
832		/*
833		 * Nport-2-Nport direct attached
834		 */
835		fabric->bport.port_topo.pn2n.rem_port_wwn =
836			fabric->lps->pr_pwwn;
837		fabric->fab_type = BFA_FCS_FABRIC_N2N;
838		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
839	}
840
841	bfa_trc(fabric->fcs, fabric->bport.pid);
842	bfa_trc(fabric->fcs, fabric->is_npiv);
843	bfa_trc(fabric->fcs, fabric->is_auth);
844}
845/*
846 *		Allocate and send FLOGI.
847 */
848static void
849bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric)
850{
851	struct bfa_s		*bfa = fabric->fcs->bfa;
852	struct bfa_lport_cfg_s	*pcfg = &fabric->bport.port_cfg;
853	u8			alpa = 0, bb_scn = 0;
854
855	if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP)
856		alpa = bfa_fcport_get_myalpa(bfa);
857
858	if (bfa_fcs_fabric_is_bbscn_enabled(fabric) &&
859	    (!fabric->fcs->bbscn_flogi_rjt))
860		bb_scn = BFA_FCS_PORT_DEF_BB_SCN;
861
862	bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa),
863		      pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd, bb_scn);
864
865	fabric->stats.flogi_sent++;
866}
867
868static void
869bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric)
870{
871	struct bfa_fcs_vport_s *vport;
872	struct list_head	      *qe, *qen;
873
874	bfa_trc(fabric->fcs, fabric->fabric_name);
875
876	bfa_fcs_fabric_set_opertype(fabric);
877	fabric->stats.fabric_onlines++;
878
879	/*
880	 * notify online event to base and then virtual ports
881	 */
882	bfa_fcs_lport_online(&fabric->bport);
883
884	list_for_each_safe(qe, qen, &fabric->vport_q) {
885		vport = (struct bfa_fcs_vport_s *) qe;
886		bfa_fcs_vport_online(vport);
887	}
888}
889
890static void
891bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric)
892{
893	struct bfa_fcs_vport_s *vport;
894	struct list_head	      *qe, *qen;
895
896	bfa_trc(fabric->fcs, fabric->fabric_name);
897	fabric->stats.fabric_offlines++;
898
899	/*
900	 * notify offline event first to vports and then base port.
901	 */
902	list_for_each_safe(qe, qen, &fabric->vport_q) {
903		vport = (struct bfa_fcs_vport_s *) qe;
904		bfa_fcs_vport_offline(vport);
905	}
906
907	bfa_fcs_lport_offline(&fabric->bport);
908
909	fabric->fabric_name = 0;
910	fabric->fabric_ip_addr[0] = 0;
911}
912
913static void
914bfa_fcs_fabric_delay(void *cbarg)
915{
916	struct bfa_fcs_fabric_s *fabric = cbarg;
917
918	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED);
919}
920
921/*
922 * Computes operating BB_SCN value
923 */
924static u8
925bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric)
926{
927	u8	pr_bbscn = fabric->lps->pr_bbscn;
928	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa);
929
930	if (!(fcport->cfg.bb_scn_state && pr_bbscn))
931		return 0;
932
933	/* return max of local/remote bb_scn values */
934	return ((pr_bbscn > BFA_FCS_PORT_DEF_BB_SCN) ?
935		pr_bbscn : BFA_FCS_PORT_DEF_BB_SCN);
936}
937
938/*
939 * Check if BB_SCN can be enabled.
940 */
941static bfa_boolean_t
942bfa_fcs_fabric_is_bbscn_enabled(struct bfa_fcs_fabric_s *fabric)
943{
944	struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa);
945
946	if (bfa_ioc_get_fcmode(&fabric->fcs->bfa->ioc) &&
947			fcport->cfg.bb_scn_state &&
948			!bfa_fcport_is_qos_enabled(fabric->fcs->bfa) &&
949			!bfa_fcport_is_trunk_enabled(fabric->fcs->bfa))
950		return BFA_TRUE;
951	else
952		return BFA_FALSE;
953}
954
955/*
956 * Delete all vports and wait for vport delete completions.
957 */
958static void
959bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric)
960{
961	struct bfa_fcs_vport_s *vport;
962	struct list_head	      *qe, *qen;
963
964	list_for_each_safe(qe, qen, &fabric->vport_q) {
965		vport = (struct bfa_fcs_vport_s *) qe;
966		bfa_fcs_vport_fcs_delete(vport);
967	}
968
969	bfa_fcs_lport_delete(&fabric->bport);
970	bfa_wc_wait(&fabric->wc);
971}
972
973static void
974bfa_fcs_fabric_delete_comp(void *cbarg)
975{
976	struct bfa_fcs_fabric_s *fabric = cbarg;
977
978	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP);
979}
980
981/*
982 *  fcs_fabric_public fabric public functions
983 */
984
985/*
986 * Attach time initialization.
987 */
988void
989bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs)
990{
991	struct bfa_fcs_fabric_s *fabric;
992
993	fabric = &fcs->fabric;
994	memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
995
996	/*
997	 * Initialize base fabric.
998	 */
999	fabric->fcs = fcs;
1000	INIT_LIST_HEAD(&fabric->vport_q);
1001	INIT_LIST_HEAD(&fabric->vf_q);
1002	fabric->lps = bfa_lps_alloc(fcs->bfa);
1003	WARN_ON(!fabric->lps);
1004
1005	/*
1006	 * Initialize fabric delete completion handler. Fabric deletion is
1007	 * complete when the last vport delete is complete.
1008	 */
1009	bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric);
1010	bfa_wc_up(&fabric->wc); /* For the base port */
1011
1012	bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
1013	bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL);
1014}
1015
1016void
1017bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
1018{
1019	bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE);
1020	bfa_trc(fcs, 0);
1021}
1022
1023/*
1024 *   Module cleanup
1025 */
1026void
1027bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
1028{
1029	struct bfa_fcs_fabric_s *fabric;
1030
1031	bfa_trc(fcs, 0);
1032
1033	/*
1034	 * Cleanup base fabric.
1035	 */
1036	fabric = &fcs->fabric;
1037	bfa_lps_delete(fabric->lps);
1038	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE);
1039}
1040
1041/*
1042 * Fabric module start -- kick starts FCS actions
1043 */
1044void
1045bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs)
1046{
1047	struct bfa_fcs_fabric_s *fabric;
1048
1049	bfa_trc(fcs, 0);
1050	fabric = &fcs->fabric;
1051	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START);
1052}
1053
1054
1055/*
1056 *   Link up notification from BFA physical port module.
1057 */
1058void
1059bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric)
1060{
1061	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
1062	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP);
1063}
1064
1065/*
1066 *   Link down notification from BFA physical port module.
1067 */
1068void
1069bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric)
1070{
1071	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
1072	fabric->fcs->bbscn_flogi_rjt = BFA_FALSE;
1073	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN);
1074}
1075
1076/*
1077 *   A child vport is being created in the fabric.
1078 *
1079 *   Call from vport module at vport creation. A list of base port and vports
1080 *   belonging to a fabric is maintained to propagate link events.
1081 *
1082 *   param[in] fabric - Fabric instance. This can be a base fabric or vf.
1083 *   param[in] vport  - Vport being created.
1084 *
1085 *   @return None (always succeeds)
1086 */
1087void
1088bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
1089			struct bfa_fcs_vport_s *vport)
1090{
1091	/*
1092	 * - add vport to fabric's vport_q
1093	 */
1094	bfa_trc(fabric->fcs, fabric->vf_id);
1095
1096	list_add_tail(&vport->qe, &fabric->vport_q);
1097	fabric->num_vports++;
1098	bfa_wc_up(&fabric->wc);
1099}
1100
1101/*
1102 *   A child vport is being deleted from fabric.
1103 *
1104 *   Vport is being deleted.
1105 */
1106void
1107bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
1108			struct bfa_fcs_vport_s *vport)
1109{
1110	list_del(&vport->qe);
1111	fabric->num_vports--;
1112	bfa_wc_down(&fabric->wc);
1113}
1114
1115
1116/*
1117 * Lookup for a vport within a fabric given its pwwn
1118 */
1119struct bfa_fcs_vport_s *
1120bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
1121{
1122	struct bfa_fcs_vport_s *vport;
1123	struct list_head	      *qe;
1124
1125	list_for_each(qe, &fabric->vport_q) {
1126		vport = (struct bfa_fcs_vport_s *) qe;
1127		if (bfa_fcs_lport_get_pwwn(&vport->lport) == pwwn)
1128			return vport;
1129	}
1130
1131	return NULL;
1132}
1133
1134
1135/*
1136 *  Get OUI of the attached switch.
1137 *
1138 *  Note : Use of this function should be avoided as much as possible.
1139 *         This function should be used only if there is any requirement
1140*          to check for FOS version below 6.3.
1141 *         To check if the attached fabric is a brocade fabric, use
1142 *         bfa_lps_is_brcd_fabric() which works for FOS versions 6.3
1143 *         or above only.
1144 */
1145
1146u16
1147bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric)
1148{
1149	wwn_t fab_nwwn;
1150	u8 *tmp;
1151	u16 oui;
1152
1153	fab_nwwn = fabric->lps->pr_nwwn;
1154
1155	tmp = (u8 *)&fab_nwwn;
1156	oui = (tmp[3] << 8) | tmp[4];
1157
1158	return oui;
1159}
1160/*
1161 *		Unsolicited frame receive handling.
1162 */
1163void
1164bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
1165		       u16 len)
1166{
1167	u32	pid = fchs->d_id;
1168	struct bfa_fcs_vport_s *vport;
1169	struct list_head	      *qe;
1170	struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
1171	struct fc_logi_s *flogi = (struct fc_logi_s *) els_cmd;
1172
1173	bfa_trc(fabric->fcs, len);
1174	bfa_trc(fabric->fcs, pid);
1175
1176	/*
1177	 * Look for our own FLOGI frames being looped back. This means an
1178	 * external loopback cable is in place. Our own FLOGI frames are
1179	 * sometimes looped back when switch port gets temporarily bypassed.
1180	 */
1181	if ((pid == bfa_ntoh3b(FC_FABRIC_PORT)) &&
1182	    (els_cmd->els_code == FC_ELS_FLOGI) &&
1183	    (flogi->port_name == bfa_fcs_lport_get_pwwn(&fabric->bport))) {
1184		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK);
1185		return;
1186	}
1187
1188	/*
1189	 * FLOGI/EVFP exchanges should be consumed by base fabric.
1190	 */
1191	if (fchs->d_id == bfa_hton3b(FC_FABRIC_PORT)) {
1192		bfa_trc(fabric->fcs, pid);
1193		bfa_fcs_fabric_process_uf(fabric, fchs, len);
1194		return;
1195	}
1196
1197	if (fabric->bport.pid == pid) {
1198		/*
1199		 * All authentication frames should be routed to auth
1200		 */
1201		bfa_trc(fabric->fcs, els_cmd->els_code);
1202		if (els_cmd->els_code == FC_ELS_AUTH) {
1203			bfa_trc(fabric->fcs, els_cmd->els_code);
1204			return;
1205		}
1206
1207		bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs));
1208		bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len);
1209		return;
1210	}
1211
1212	/*
1213	 * look for a matching local port ID
1214	 */
1215	list_for_each(qe, &fabric->vport_q) {
1216		vport = (struct bfa_fcs_vport_s *) qe;
1217		if (vport->lport.pid == pid) {
1218			bfa_fcs_lport_uf_recv(&vport->lport, fchs, len);
1219			return;
1220		}
1221	}
1222	bfa_trc(fabric->fcs, els_cmd->els_code);
1223	bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len);
1224}
1225
1226/*
1227 *		Unsolicited frames to be processed by fabric.
1228 */
1229static void
1230bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
1231			  u16 len)
1232{
1233	struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
1234
1235	bfa_trc(fabric->fcs, els_cmd->els_code);
1236
1237	switch (els_cmd->els_code) {
1238	case FC_ELS_FLOGI:
1239		bfa_fcs_fabric_process_flogi(fabric, fchs, len);
1240		break;
1241
1242	default:
1243		/*
1244		 * need to generate a LS_RJT
1245		 */
1246		break;
1247	}
1248}
1249
1250/*
1251 *	Process	incoming FLOGI
1252 */
1253static void
1254bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
1255			struct fchs_s *fchs, u16 len)
1256{
1257	struct fc_logi_s *flogi = (struct fc_logi_s *) (fchs + 1);
1258	struct bfa_fcs_lport_s *bport = &fabric->bport;
1259
1260	bfa_trc(fabric->fcs, fchs->s_id);
1261
1262	fabric->stats.flogi_rcvd++;
1263	/*
1264	 * Check port type. It should be 0 = n-port.
1265	 */
1266	if (flogi->csp.port_type) {
1267		/*
1268		 * @todo: may need to send a LS_RJT
1269		 */
1270		bfa_trc(fabric->fcs, flogi->port_name);
1271		fabric->stats.flogi_rejected++;
1272		return;
1273	}
1274
1275	fabric->bb_credit = be16_to_cpu(flogi->csp.bbcred);
1276	fabric->lps->pr_bbscn = (be16_to_cpu(flogi->csp.rxsz) >> 12);
1277	bport->port_topo.pn2n.rem_port_wwn = flogi->port_name;
1278	bport->port_topo.pn2n.reply_oxid = fchs->ox_id;
1279
1280	/*
1281	 * Send a Flogi Acc
1282	 */
1283	bfa_fcs_fabric_send_flogi_acc(fabric);
1284	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
1285}
1286
1287static void
1288bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
1289{
1290	struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg;
1291	struct bfa_fcs_lport_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n;
1292	struct bfa_s	  *bfa = fabric->fcs->bfa;
1293	struct bfa_fcxp_s *fcxp;
1294	u16	reqlen;
1295	struct fchs_s	fchs;
1296
1297	fcxp = bfa_fcs_fcxp_alloc(fabric->fcs);
1298	/*
1299	 * Do not expect this failure -- expect remote node to retry
1300	 */
1301	if (!fcxp)
1302		return;
1303
1304	reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
1305				    bfa_hton3b(FC_FABRIC_PORT),
1306				    n2n_port->reply_oxid, pcfg->pwwn,
1307				    pcfg->nwwn,
1308				    bfa_fcport_get_maxfrsize(bfa),
1309				    bfa_fcport_get_rx_bbcredit(bfa),
1310				    bfa_fcs_fabric_oper_bbscn(fabric));
1311
1312	bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->bfa_tag,
1313		      BFA_FALSE, FC_CLASS_3,
1314		      reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric,
1315		      FC_MAX_PDUSZ, 0);
1316}
1317
1318/*
1319 *   Flogi Acc completion callback.
1320 */
1321static void
1322bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
1323			     bfa_status_t status, u32 rsp_len,
1324			     u32 resid_len, struct fchs_s *rspfchs)
1325{
1326	struct bfa_fcs_fabric_s *fabric = cbarg;
1327
1328	bfa_trc(fabric->fcs, status);
1329}
1330
1331
1332/*
1333 * Send AEN notification
1334 */
1335static void
1336bfa_fcs_fabric_aen_post(struct bfa_fcs_lport_s *port,
1337			enum bfa_port_aen_event event)
1338{
1339	struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
1340	struct bfa_aen_entry_s  *aen_entry;
1341
1342	bfad_get_aen_entry(bfad, aen_entry);
1343	if (!aen_entry)
1344		return;
1345
1346	aen_entry->aen_data.port.pwwn = bfa_fcs_lport_get_pwwn(port);
1347	aen_entry->aen_data.port.fwwn = bfa_fcs_lport_get_fabric_name(port);
1348
1349	/* Send the AEN notification */
1350	bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
1351				  BFA_AEN_CAT_PORT, event);
1352}
1353
1354/*
1355 *
1356 * @param[in] fabric - fabric
1357 * @param[in] wwn_t - new fabric name
1358 *
1359 * @return - none
1360 */
1361void
1362bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
1363			       wwn_t fabric_name)
1364{
1365	struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad;
1366	char	pwwn_ptr[BFA_STRING_32];
1367	char	fwwn_ptr[BFA_STRING_32];
1368
1369	bfa_trc(fabric->fcs, fabric_name);
1370
1371	if (fabric->fabric_name == 0) {
1372		/*
1373		 * With BRCD switches, we don't get Fabric Name in FLOGI.
1374		 * Don't generate a fabric name change event in this case.
1375		 */
1376		fabric->fabric_name = fabric_name;
1377	} else {
1378		fabric->fabric_name = fabric_name;
1379		wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport));
1380		wwn2str(fwwn_ptr,
1381			bfa_fcs_lport_get_fabric_name(&fabric->bport));
1382		BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
1383			"Base port WWN = %s Fabric WWN = %s\n",
1384			pwwn_ptr, fwwn_ptr);
1385		bfa_fcs_fabric_aen_post(&fabric->bport,
1386				BFA_PORT_AEN_FABRIC_NAME_CHANGE);
1387	}
1388}
1389
1390/*
1391 *	Returns FCS vf structure for a given vf_id.
1392 *
1393 *	param[in]	vf_id - VF_ID
1394 *
1395 *	return
1396 *	If lookup succeeds, retuns fcs vf object, otherwise returns NULL
1397 */
1398bfa_fcs_vf_t   *
1399bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id)
1400{
1401	bfa_trc(fcs, vf_id);
1402	if (vf_id == FC_VF_ID_NULL)
1403		return &fcs->fabric;
1404
1405	return NULL;
1406}
1407
1408/*
1409 *	Return the list of local logical ports present in the given VF.
1410 *
1411 *	@param[in]	vf	vf for which logical ports are returned
1412 *	@param[out]	lpwwn	returned logical port wwn list
1413 *	@param[in,out]	nlports in:size of lpwwn list;
1414 *				out:total elements present,
1415 *				actual elements returned is limited by the size
1416 */
1417void
1418bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports)
1419{
1420	struct list_head *qe;
1421	struct bfa_fcs_vport_s *vport;
1422	int	i = 0;
1423	struct bfa_fcs_s	*fcs;
1424
1425	if (vf == NULL || lpwwn == NULL || *nlports == 0)
1426		return;
1427
1428	fcs = vf->fcs;
1429
1430	bfa_trc(fcs, vf->vf_id);
1431	bfa_trc(fcs, (uint32_t) *nlports);
1432
1433	lpwwn[i++] = vf->bport.port_cfg.pwwn;
1434
1435	list_for_each(qe, &vf->vport_q) {
1436		if (i >= *nlports)
1437			break;
1438
1439		vport = (struct bfa_fcs_vport_s *) qe;
1440		lpwwn[i++] = vport->lport.port_cfg.pwwn;
1441	}
1442
1443	bfa_trc(fcs, i);
1444	*nlports = i;
1445}
1446
1447/*
1448 * BFA FCS PPORT ( physical port)
1449 */
1450static void
1451bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event)
1452{
1453	struct bfa_fcs_s      *fcs = cbarg;
1454
1455	bfa_trc(fcs, event);
1456
1457	switch (event) {
1458	case BFA_PORT_LINKUP:
1459		bfa_fcs_fabric_link_up(&fcs->fabric);
1460		break;
1461
1462	case BFA_PORT_LINKDOWN:
1463		bfa_fcs_fabric_link_down(&fcs->fabric);
1464		break;
1465
1466	default:
1467		WARN_ON(1);
1468	}
1469}
1470
1471void
1472bfa_fcs_port_attach(struct bfa_fcs_s *fcs)
1473{
1474	bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs);
1475}
1476
1477/*
1478 * BFA FCS UF ( Unsolicited Frames)
1479 */
1480
1481/*
1482 *		BFA callback for unsolicited frame receive handler.
1483 *
1484 * @param[in]		cbarg		callback arg for receive handler
1485 * @param[in]		uf		unsolicited frame descriptor
1486 *
1487 * @return None
1488 */
1489static void
1490bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
1491{
1492	struct bfa_fcs_s	*fcs = (struct bfa_fcs_s *) cbarg;
1493	struct fchs_s	*fchs = bfa_uf_get_frmbuf(uf);
1494	u16	len = bfa_uf_get_frmlen(uf);
1495	struct fc_vft_s *vft;
1496	struct bfa_fcs_fabric_s *fabric;
1497
1498	/*
1499	 * check for VFT header
1500	 */
1501	if (fchs->routing == FC_RTG_EXT_HDR &&
1502	    fchs->cat_info == FC_CAT_VFT_HDR) {
1503		bfa_stats(fcs, uf.tagged);
1504		vft = bfa_uf_get_frmbuf(uf);
1505		if (fcs->port_vfid == vft->vf_id)
1506			fabric = &fcs->fabric;
1507		else
1508			fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id);
1509
1510		/*
1511		 * drop frame if vfid is unknown
1512		 */
1513		if (!fabric) {
1514			WARN_ON(1);
1515			bfa_stats(fcs, uf.vfid_unknown);
1516			bfa_uf_free(uf);
1517			return;
1518		}
1519
1520		/*
1521		 * skip vft header
1522		 */
1523		fchs = (struct fchs_s *) (vft + 1);
1524		len -= sizeof(struct fc_vft_s);
1525
1526		bfa_trc(fcs, vft->vf_id);
1527	} else {
1528		bfa_stats(fcs, uf.untagged);
1529		fabric = &fcs->fabric;
1530	}
1531
1532	bfa_trc(fcs, ((u32 *) fchs)[0]);
1533	bfa_trc(fcs, ((u32 *) fchs)[1]);
1534	bfa_trc(fcs, ((u32 *) fchs)[2]);
1535	bfa_trc(fcs, ((u32 *) fchs)[3]);
1536	bfa_trc(fcs, ((u32 *) fchs)[4]);
1537	bfa_trc(fcs, ((u32 *) fchs)[5]);
1538	bfa_trc(fcs, len);
1539
1540	bfa_fcs_fabric_uf_recv(fabric, fchs, len);
1541	bfa_uf_free(uf);
1542}
1543
1544void
1545bfa_fcs_uf_attach(struct bfa_fcs_s *fcs)
1546{
1547	bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs);
1548}
1549