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