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