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