Commit | Line | Data |
---|---|---|
7725ccfd JH |
1 | /* |
2 | * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. | |
3 | * All rights reserved | |
4 | * www.brocade.com | |
5 | * | |
6 | * Linux driver for Brocade Fibre Channel Host Bus Adapter. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License (GPL) Version 2 as | |
10 | * published by the Free Software Foundation | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | */ | |
17 | ||
18 | #include <bfa.h> | |
19 | #include <bfi/bfi_lps.h> | |
20 | #include <cs/bfa_debug.h> | |
a046bf05 | 21 | #include <defs/bfa_defs_pci.h> |
7725ccfd JH |
22 | |
23 | BFA_TRC_FILE(HAL, LPS); | |
24 | BFA_MODULE(lps); | |
25 | ||
26 | #define BFA_LPS_MIN_LPORTS (1) | |
27 | #define BFA_LPS_MAX_LPORTS (256) | |
28 | ||
a046bf05 KG |
29 | /* |
30 | * Maximum Vports supported per physical port or vf. | |
31 | */ | |
32 | #define BFA_LPS_MAX_VPORTS_SUPP_CB 255 | |
33 | #define BFA_LPS_MAX_VPORTS_SUPP_CT 190 | |
34 | ||
7725ccfd JH |
35 | /** |
36 | * forward declarations | |
37 | */ | |
38 | static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, | |
39 | u32 *dm_len); | |
40 | static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, | |
41 | struct bfa_iocfc_cfg_s *cfg, | |
42 | struct bfa_meminfo_s *meminfo, | |
43 | struct bfa_pcidev_s *pcidev); | |
7725ccfd JH |
44 | static void bfa_lps_detach(struct bfa_s *bfa); |
45 | static void bfa_lps_start(struct bfa_s *bfa); | |
46 | static void bfa_lps_stop(struct bfa_s *bfa); | |
47 | static void bfa_lps_iocdisable(struct bfa_s *bfa); | |
48 | static void bfa_lps_login_rsp(struct bfa_s *bfa, | |
49 | struct bfi_lps_login_rsp_s *rsp); | |
50 | static void bfa_lps_logout_rsp(struct bfa_s *bfa, | |
51 | struct bfi_lps_logout_rsp_s *rsp); | |
52 | static void bfa_lps_reqq_resume(void *lps_arg); | |
53 | static void bfa_lps_free(struct bfa_lps_s *lps); | |
54 | static void bfa_lps_send_login(struct bfa_lps_s *lps); | |
55 | static void bfa_lps_send_logout(struct bfa_lps_s *lps); | |
56 | static void bfa_lps_login_comp(struct bfa_lps_s *lps); | |
57 | static void bfa_lps_logout_comp(struct bfa_lps_s *lps); | |
5c1fb1d5 | 58 | static void bfa_lps_cvl_event(struct bfa_lps_s *lps); |
7725ccfd JH |
59 | |
60 | /** | |
61 | * lps_pvt BFA LPS private functions | |
62 | */ | |
63 | ||
64 | enum bfa_lps_event { | |
65 | BFA_LPS_SM_LOGIN = 1, /* login request from user */ | |
66 | BFA_LPS_SM_LOGOUT = 2, /* logout request from user */ | |
67 | BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */ | |
68 | BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */ | |
69 | BFA_LPS_SM_DELETE = 5, /* lps delete from user */ | |
70 | BFA_LPS_SM_OFFLINE = 6, /* Link is offline */ | |
5c1fb1d5 | 71 | BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */ |
7725ccfd JH |
72 | }; |
73 | ||
74 | static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event); | |
75 | static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event); | |
76 | static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, | |
77 | enum bfa_lps_event event); | |
78 | static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event); | |
79 | static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event); | |
80 | static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, | |
81 | enum bfa_lps_event event); | |
82 | ||
83 | /** | |
84 | * Init state -- no login | |
85 | */ | |
86 | static void | |
87 | bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) | |
88 | { | |
89 | bfa_trc(lps->bfa, lps->lp_tag); | |
90 | bfa_trc(lps->bfa, event); | |
91 | ||
92 | switch (event) { | |
93 | case BFA_LPS_SM_LOGIN: | |
94 | if (bfa_reqq_full(lps->bfa, lps->reqq)) { | |
95 | bfa_sm_set_state(lps, bfa_lps_sm_loginwait); | |
96 | bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); | |
97 | } else { | |
98 | bfa_sm_set_state(lps, bfa_lps_sm_login); | |
99 | bfa_lps_send_login(lps); | |
100 | } | |
f58e9ebb KG |
101 | if (lps->fdisc) |
102 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, | |
103 | BFA_PL_EID_LOGIN, 0, "FDISC Request"); | |
104 | else | |
105 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, | |
106 | BFA_PL_EID_LOGIN, 0, "FLOGI Request"); | |
7725ccfd JH |
107 | break; |
108 | ||
109 | case BFA_LPS_SM_LOGOUT: | |
110 | bfa_lps_logout_comp(lps); | |
111 | break; | |
112 | ||
113 | case BFA_LPS_SM_DELETE: | |
114 | bfa_lps_free(lps); | |
115 | break; | |
116 | ||
5c1fb1d5 | 117 | case BFA_LPS_SM_RX_CVL: |
7725ccfd JH |
118 | case BFA_LPS_SM_OFFLINE: |
119 | break; | |
120 | ||
121 | case BFA_LPS_SM_FWRSP: | |
122 | /* Could happen when fabric detects loopback and discards | |
123 | * the lps request. Fw will eventually sent out the timeout | |
124 | * Just ignore | |
125 | */ | |
126 | break; | |
127 | ||
128 | default: | |
e641de37 | 129 | bfa_sm_fault(lps->bfa, event); |
7725ccfd JH |
130 | } |
131 | } | |
132 | ||
133 | /** | |
134 | * login is in progress -- awaiting response from firmware | |
135 | */ | |
136 | static void | |
137 | bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) | |
138 | { | |
139 | bfa_trc(lps->bfa, lps->lp_tag); | |
140 | bfa_trc(lps->bfa, event); | |
141 | ||
142 | switch (event) { | |
143 | case BFA_LPS_SM_FWRSP: | |
f58e9ebb | 144 | if (lps->status == BFA_STATUS_OK) { |
7725ccfd | 145 | bfa_sm_set_state(lps, bfa_lps_sm_online); |
f58e9ebb KG |
146 | if (lps->fdisc) |
147 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, | |
148 | BFA_PL_EID_LOGIN, 0, "FDISC Accept"); | |
149 | else | |
150 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, | |
151 | BFA_PL_EID_LOGIN, 0, "FLOGI Accept"); | |
152 | } else { | |
7725ccfd | 153 | bfa_sm_set_state(lps, bfa_lps_sm_init); |
f58e9ebb KG |
154 | if (lps->fdisc) |
155 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, | |
156 | BFA_PL_EID_LOGIN, 0, | |
157 | "FDISC Fail (RJT or timeout)"); | |
158 | else | |
159 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, | |
160 | BFA_PL_EID_LOGIN, 0, | |
161 | "FLOGI Fail (RJT or timeout)"); | |
162 | } | |
7725ccfd JH |
163 | bfa_lps_login_comp(lps); |
164 | break; | |
165 | ||
166 | case BFA_LPS_SM_OFFLINE: | |
167 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
168 | break; | |
169 | ||
170 | default: | |
e641de37 | 171 | bfa_sm_fault(lps->bfa, event); |
7725ccfd JH |
172 | } |
173 | } | |
174 | ||
175 | /** | |
176 | * login pending - awaiting space in request queue | |
177 | */ | |
178 | static void | |
179 | bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) | |
180 | { | |
181 | bfa_trc(lps->bfa, lps->lp_tag); | |
182 | bfa_trc(lps->bfa, event); | |
183 | ||
184 | switch (event) { | |
185 | case BFA_LPS_SM_RESUME: | |
186 | bfa_sm_set_state(lps, bfa_lps_sm_login); | |
187 | break; | |
188 | ||
189 | case BFA_LPS_SM_OFFLINE: | |
190 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
191 | bfa_reqq_wcancel(&lps->wqe); | |
192 | break; | |
193 | ||
5c1fb1d5 KG |
194 | case BFA_LPS_SM_RX_CVL: |
195 | /* | |
196 | * Login was not even sent out; so when getting out | |
197 | * of this state, it will appear like a login retry | |
198 | * after Clear virtual link | |
199 | */ | |
200 | break; | |
201 | ||
7725ccfd | 202 | default: |
e641de37 | 203 | bfa_sm_fault(lps->bfa, event); |
7725ccfd JH |
204 | } |
205 | } | |
206 | ||
207 | /** | |
208 | * login complete | |
209 | */ | |
210 | static void | |
211 | bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) | |
212 | { | |
213 | bfa_trc(lps->bfa, lps->lp_tag); | |
214 | bfa_trc(lps->bfa, event); | |
215 | ||
216 | switch (event) { | |
217 | case BFA_LPS_SM_LOGOUT: | |
218 | if (bfa_reqq_full(lps->bfa, lps->reqq)) { | |
219 | bfa_sm_set_state(lps, bfa_lps_sm_logowait); | |
220 | bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); | |
221 | } else { | |
222 | bfa_sm_set_state(lps, bfa_lps_sm_logout); | |
223 | bfa_lps_send_logout(lps); | |
224 | } | |
f58e9ebb KG |
225 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, |
226 | BFA_PL_EID_LOGO, 0, "Logout"); | |
7725ccfd JH |
227 | break; |
228 | ||
5c1fb1d5 KG |
229 | case BFA_LPS_SM_RX_CVL: |
230 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
231 | ||
232 | /* Let the vport module know about this event */ | |
233 | bfa_lps_cvl_event(lps); | |
234 | bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, | |
235 | BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx"); | |
236 | break; | |
237 | ||
7725ccfd JH |
238 | case BFA_LPS_SM_OFFLINE: |
239 | case BFA_LPS_SM_DELETE: | |
240 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
241 | break; | |
242 | ||
243 | default: | |
e641de37 | 244 | bfa_sm_fault(lps->bfa, event); |
7725ccfd JH |
245 | } |
246 | } | |
247 | ||
248 | /** | |
249 | * logout in progress - awaiting firmware response | |
250 | */ | |
251 | static void | |
252 | bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) | |
253 | { | |
254 | bfa_trc(lps->bfa, lps->lp_tag); | |
255 | bfa_trc(lps->bfa, event); | |
256 | ||
257 | switch (event) { | |
258 | case BFA_LPS_SM_FWRSP: | |
259 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
260 | bfa_lps_logout_comp(lps); | |
261 | break; | |
262 | ||
263 | case BFA_LPS_SM_OFFLINE: | |
264 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
265 | break; | |
266 | ||
267 | default: | |
e641de37 | 268 | bfa_sm_fault(lps->bfa, event); |
7725ccfd JH |
269 | } |
270 | } | |
271 | ||
272 | /** | |
273 | * logout pending -- awaiting space in request queue | |
274 | */ | |
275 | static void | |
276 | bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) | |
277 | { | |
278 | bfa_trc(lps->bfa, lps->lp_tag); | |
279 | bfa_trc(lps->bfa, event); | |
280 | ||
281 | switch (event) { | |
282 | case BFA_LPS_SM_RESUME: | |
283 | bfa_sm_set_state(lps, bfa_lps_sm_logout); | |
284 | bfa_lps_send_logout(lps); | |
285 | break; | |
286 | ||
287 | case BFA_LPS_SM_OFFLINE: | |
288 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
289 | bfa_reqq_wcancel(&lps->wqe); | |
290 | break; | |
291 | ||
292 | default: | |
e641de37 | 293 | bfa_sm_fault(lps->bfa, event); |
7725ccfd JH |
294 | } |
295 | } | |
296 | ||
297 | ||
298 | ||
299 | /** | |
300 | * lps_pvt BFA LPS private functions | |
301 | */ | |
302 | ||
303 | /** | |
304 | * return memory requirement | |
305 | */ | |
306 | static void | |
307 | bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) | |
308 | { | |
309 | if (cfg->drvcfg.min_cfg) | |
310 | *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS; | |
311 | else | |
312 | *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS; | |
313 | } | |
314 | ||
315 | /** | |
316 | * bfa module attach at initialization time | |
317 | */ | |
318 | static void | |
319 | bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, | |
320 | struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) | |
321 | { | |
322 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); | |
323 | struct bfa_lps_s *lps; | |
324 | int i; | |
325 | ||
326 | bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s)); | |
327 | mod->num_lps = BFA_LPS_MAX_LPORTS; | |
328 | if (cfg->drvcfg.min_cfg) | |
329 | mod->num_lps = BFA_LPS_MIN_LPORTS; | |
330 | else | |
331 | mod->num_lps = BFA_LPS_MAX_LPORTS; | |
332 | mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo); | |
333 | ||
334 | bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s); | |
335 | ||
336 | INIT_LIST_HEAD(&mod->lps_free_q); | |
337 | INIT_LIST_HEAD(&mod->lps_active_q); | |
338 | ||
339 | for (i = 0; i < mod->num_lps; i++, lps++) { | |
340 | lps->bfa = bfa; | |
341 | lps->lp_tag = (u8) i; | |
342 | lps->reqq = BFA_REQQ_LPS; | |
343 | bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); | |
344 | list_add_tail(&lps->qe, &mod->lps_free_q); | |
345 | } | |
346 | } | |
347 | ||
7725ccfd JH |
348 | static void |
349 | bfa_lps_detach(struct bfa_s *bfa) | |
350 | { | |
351 | } | |
352 | ||
353 | static void | |
354 | bfa_lps_start(struct bfa_s *bfa) | |
355 | { | |
356 | } | |
357 | ||
358 | static void | |
359 | bfa_lps_stop(struct bfa_s *bfa) | |
360 | { | |
361 | } | |
362 | ||
363 | /** | |
364 | * IOC in disabled state -- consider all lps offline | |
365 | */ | |
366 | static void | |
367 | bfa_lps_iocdisable(struct bfa_s *bfa) | |
368 | { | |
369 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); | |
370 | struct bfa_lps_s *lps; | |
371 | struct list_head *qe, *qen; | |
372 | ||
373 | list_for_each_safe(qe, qen, &mod->lps_active_q) { | |
374 | lps = (struct bfa_lps_s *) qe; | |
375 | bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); | |
376 | } | |
377 | } | |
378 | ||
379 | /** | |
380 | * Firmware login response | |
381 | */ | |
382 | static void | |
383 | bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) | |
384 | { | |
385 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); | |
386 | struct bfa_lps_s *lps; | |
387 | ||
388 | bfa_assert(rsp->lp_tag < mod->num_lps); | |
389 | lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); | |
390 | ||
391 | lps->status = rsp->status; | |
392 | switch (rsp->status) { | |
393 | case BFA_STATUS_OK: | |
394 | lps->fport = rsp->f_port; | |
395 | lps->npiv_en = rsp->npiv_en; | |
396 | lps->lp_pid = rsp->lp_pid; | |
397 | lps->pr_bbcred = bfa_os_ntohs(rsp->bb_credit); | |
398 | lps->pr_pwwn = rsp->port_name; | |
399 | lps->pr_nwwn = rsp->node_name; | |
400 | lps->auth_req = rsp->auth_req; | |
401 | lps->lp_mac = rsp->lp_mac; | |
402 | lps->brcd_switch = rsp->brcd_switch; | |
403 | lps->fcf_mac = rsp->fcf_mac; | |
404 | ||
405 | break; | |
406 | ||
407 | case BFA_STATUS_FABRIC_RJT: | |
408 | lps->lsrjt_rsn = rsp->lsrjt_rsn; | |
409 | lps->lsrjt_expl = rsp->lsrjt_expl; | |
410 | ||
411 | break; | |
412 | ||
413 | case BFA_STATUS_EPROTOCOL: | |
414 | lps->ext_status = rsp->ext_status; | |
415 | ||
416 | break; | |
417 | ||
418 | default: | |
419 | /* Nothing to do with other status */ | |
420 | break; | |
421 | } | |
422 | ||
423 | bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); | |
424 | } | |
425 | ||
426 | /** | |
427 | * Firmware logout response | |
428 | */ | |
429 | static void | |
430 | bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) | |
431 | { | |
432 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); | |
433 | struct bfa_lps_s *lps; | |
434 | ||
435 | bfa_assert(rsp->lp_tag < mod->num_lps); | |
436 | lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); | |
437 | ||
438 | bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); | |
439 | } | |
440 | ||
5c1fb1d5 KG |
441 | /** |
442 | * Firmware received a Clear virtual link request (for FCoE) | |
443 | */ | |
444 | static void | |
445 | bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl) | |
446 | { | |
447 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); | |
448 | struct bfa_lps_s *lps; | |
449 | ||
450 | lps = BFA_LPS_FROM_TAG(mod, cvl->lp_tag); | |
451 | ||
452 | bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL); | |
453 | } | |
454 | ||
7725ccfd JH |
455 | /** |
456 | * Space is available in request queue, resume queueing request to firmware. | |
457 | */ | |
458 | static void | |
459 | bfa_lps_reqq_resume(void *lps_arg) | |
460 | { | |
461 | struct bfa_lps_s *lps = lps_arg; | |
462 | ||
463 | bfa_sm_send_event(lps, BFA_LPS_SM_RESUME); | |
464 | } | |
465 | ||
466 | /** | |
467 | * lps is freed -- triggered by vport delete | |
468 | */ | |
469 | static void | |
470 | bfa_lps_free(struct bfa_lps_s *lps) | |
471 | { | |
472 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa); | |
473 | ||
474 | list_del(&lps->qe); | |
475 | list_add_tail(&lps->qe, &mod->lps_free_q); | |
476 | } | |
477 | ||
478 | /** | |
479 | * send login request to firmware | |
480 | */ | |
481 | static void | |
482 | bfa_lps_send_login(struct bfa_lps_s *lps) | |
483 | { | |
484 | struct bfi_lps_login_req_s *m; | |
485 | ||
486 | m = bfa_reqq_next(lps->bfa, lps->reqq); | |
487 | bfa_assert(m); | |
488 | ||
489 | bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, | |
490 | bfa_lpuid(lps->bfa)); | |
491 | ||
492 | m->lp_tag = lps->lp_tag; | |
493 | m->alpa = lps->alpa; | |
494 | m->pdu_size = bfa_os_htons(lps->pdusz); | |
495 | m->pwwn = lps->pwwn; | |
496 | m->nwwn = lps->nwwn; | |
497 | m->fdisc = lps->fdisc; | |
498 | m->auth_en = lps->auth_en; | |
499 | ||
500 | bfa_reqq_produce(lps->bfa, lps->reqq); | |
501 | } | |
502 | ||
503 | /** | |
504 | * send logout request to firmware | |
505 | */ | |
506 | static void | |
507 | bfa_lps_send_logout(struct bfa_lps_s *lps) | |
508 | { | |
509 | struct bfi_lps_logout_req_s *m; | |
510 | ||
511 | m = bfa_reqq_next(lps->bfa, lps->reqq); | |
512 | bfa_assert(m); | |
513 | ||
514 | bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, | |
515 | bfa_lpuid(lps->bfa)); | |
516 | ||
517 | m->lp_tag = lps->lp_tag; | |
518 | m->port_name = lps->pwwn; | |
519 | bfa_reqq_produce(lps->bfa, lps->reqq); | |
520 | } | |
521 | ||
522 | /** | |
523 | * Indirect login completion handler for non-fcs | |
524 | */ | |
525 | static void | |
526 | bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete) | |
527 | { | |
528 | struct bfa_lps_s *lps = arg; | |
529 | ||
530 | if (!complete) | |
531 | return; | |
532 | ||
533 | if (lps->fdisc) | |
534 | bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); | |
535 | else | |
536 | bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); | |
537 | } | |
538 | ||
539 | /** | |
540 | * Login completion handler -- direct call for fcs, queue for others | |
541 | */ | |
542 | static void | |
543 | bfa_lps_login_comp(struct bfa_lps_s *lps) | |
544 | { | |
545 | if (!lps->bfa->fcs) { | |
546 | bfa_cb_queue(lps->bfa, &lps->hcb_qe, | |
547 | bfa_lps_login_comp_cb, lps); | |
548 | return; | |
549 | } | |
550 | ||
551 | if (lps->fdisc) | |
552 | bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); | |
553 | else | |
554 | bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); | |
555 | } | |
556 | ||
557 | /** | |
558 | * Indirect logout completion handler for non-fcs | |
559 | */ | |
560 | static void | |
561 | bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete) | |
562 | { | |
563 | struct bfa_lps_s *lps = arg; | |
564 | ||
565 | if (!complete) | |
566 | return; | |
567 | ||
568 | if (lps->fdisc) | |
569 | bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); | |
570 | else | |
571 | bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); | |
572 | } | |
573 | ||
574 | /** | |
575 | * Logout completion handler -- direct call for fcs, queue for others | |
576 | */ | |
577 | static void | |
578 | bfa_lps_logout_comp(struct bfa_lps_s *lps) | |
579 | { | |
580 | if (!lps->bfa->fcs) { | |
581 | bfa_cb_queue(lps->bfa, &lps->hcb_qe, | |
582 | bfa_lps_logout_comp_cb, lps); | |
583 | return; | |
584 | } | |
585 | if (lps->fdisc) | |
586 | bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); | |
587 | else | |
588 | bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); | |
589 | } | |
590 | ||
5c1fb1d5 KG |
591 | /** |
592 | * Clear virtual link completion handler for non-fcs | |
593 | */ | |
594 | static void | |
595 | bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete) | |
596 | { | |
597 | struct bfa_lps_s *lps = arg; | |
598 | ||
599 | if (!complete) | |
600 | return; | |
601 | ||
602 | /* Clear virtual link to base port will result in link down */ | |
603 | if (lps->fdisc) | |
604 | bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); | |
605 | } | |
606 | ||
607 | /** | |
608 | * Received Clear virtual link event --direct call for fcs, | |
609 | * queue for others | |
610 | */ | |
611 | static void | |
612 | bfa_lps_cvl_event(struct bfa_lps_s *lps) | |
613 | { | |
614 | if (!lps->bfa->fcs) { | |
615 | bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_cvl_event_cb, | |
616 | lps); | |
617 | return; | |
618 | } | |
7725ccfd | 619 | |
5c1fb1d5 KG |
620 | /* Clear virtual link to base port will result in link down */ |
621 | if (lps->fdisc) | |
622 | bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); | |
623 | } | |
7725ccfd | 624 | |
a046bf05 KG |
625 | u32 |
626 | bfa_lps_get_max_vport(struct bfa_s *bfa) | |
627 | { | |
0a4b1fc0 | 628 | if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) |
86e32dab | 629 | return BFA_LPS_MAX_VPORTS_SUPP_CT; |
a046bf05 | 630 | else |
86e32dab | 631 | return BFA_LPS_MAX_VPORTS_SUPP_CB; |
a046bf05 KG |
632 | } |
633 | ||
7725ccfd JH |
634 | /** |
635 | * lps_public BFA LPS public functions | |
636 | */ | |
637 | ||
638 | /** | |
639 | * Allocate a lport srvice tag. | |
640 | */ | |
641 | struct bfa_lps_s * | |
642 | bfa_lps_alloc(struct bfa_s *bfa) | |
643 | { | |
644 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); | |
645 | struct bfa_lps_s *lps = NULL; | |
646 | ||
647 | bfa_q_deq(&mod->lps_free_q, &lps); | |
648 | ||
649 | if (lps == NULL) | |
650 | return NULL; | |
651 | ||
652 | list_add_tail(&lps->qe, &mod->lps_active_q); | |
653 | ||
654 | bfa_sm_set_state(lps, bfa_lps_sm_init); | |
655 | return lps; | |
656 | } | |
657 | ||
658 | /** | |
659 | * Free lport service tag. This can be called anytime after an alloc. | |
660 | * No need to wait for any pending login/logout completions. | |
661 | */ | |
662 | void | |
663 | bfa_lps_delete(struct bfa_lps_s *lps) | |
664 | { | |
665 | bfa_sm_send_event(lps, BFA_LPS_SM_DELETE); | |
666 | } | |
667 | ||
668 | /** | |
669 | * Initiate a lport login. | |
670 | */ | |
671 | void | |
672 | bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, | |
673 | wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en) | |
674 | { | |
675 | lps->uarg = uarg; | |
676 | lps->alpa = alpa; | |
677 | lps->pdusz = pdusz; | |
678 | lps->pwwn = pwwn; | |
679 | lps->nwwn = nwwn; | |
680 | lps->fdisc = BFA_FALSE; | |
681 | lps->auth_en = auth_en; | |
682 | bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); | |
683 | } | |
684 | ||
685 | /** | |
686 | * Initiate a lport fdisc login. | |
687 | */ | |
688 | void | |
689 | bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, | |
690 | wwn_t nwwn) | |
691 | { | |
692 | lps->uarg = uarg; | |
693 | lps->alpa = 0; | |
694 | lps->pdusz = pdusz; | |
695 | lps->pwwn = pwwn; | |
696 | lps->nwwn = nwwn; | |
697 | lps->fdisc = BFA_TRUE; | |
698 | lps->auth_en = BFA_FALSE; | |
699 | bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); | |
700 | } | |
701 | ||
702 | /** | |
703 | * Initiate a lport logout (flogi). | |
704 | */ | |
705 | void | |
706 | bfa_lps_flogo(struct bfa_lps_s *lps) | |
707 | { | |
708 | bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); | |
709 | } | |
710 | ||
711 | /** | |
712 | * Initiate a lport FDSIC logout. | |
713 | */ | |
714 | void | |
715 | bfa_lps_fdisclogo(struct bfa_lps_s *lps) | |
716 | { | |
717 | bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); | |
718 | } | |
719 | ||
720 | /** | |
721 | * Discard a pending login request -- should be called only for | |
722 | * link down handling. | |
723 | */ | |
724 | void | |
725 | bfa_lps_discard(struct bfa_lps_s *lps) | |
726 | { | |
727 | bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); | |
728 | } | |
729 | ||
730 | /** | |
731 | * Return lport services tag | |
732 | */ | |
733 | u8 | |
734 | bfa_lps_get_tag(struct bfa_lps_s *lps) | |
735 | { | |
736 | return lps->lp_tag; | |
737 | } | |
738 | ||
739 | /** | |
740 | * Return lport services tag given the pid | |
741 | */ | |
742 | u8 | |
743 | bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) | |
744 | { | |
745 | struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); | |
746 | struct bfa_lps_s *lps; | |
747 | int i; | |
748 | ||
749 | for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { | |
750 | if (lps->lp_pid == pid) | |
751 | return lps->lp_tag; | |
752 | } | |
753 | ||
754 | /* Return base port tag anyway */ | |
755 | return 0; | |
756 | } | |
757 | ||
758 | /** | |
759 | * return if fabric login indicates support for NPIV | |
760 | */ | |
761 | bfa_boolean_t | |
762 | bfa_lps_is_npiv_en(struct bfa_lps_s *lps) | |
763 | { | |
764 | return lps->npiv_en; | |
765 | } | |
766 | ||
767 | /** | |
768 | * Return TRUE if attached to F-Port, else return FALSE | |
769 | */ | |
770 | bfa_boolean_t | |
771 | bfa_lps_is_fport(struct bfa_lps_s *lps) | |
772 | { | |
773 | return lps->fport; | |
774 | } | |
775 | ||
776 | /** | |
777 | * Return TRUE if attached to a Brocade Fabric | |
778 | */ | |
779 | bfa_boolean_t | |
780 | bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps) | |
781 | { | |
782 | return lps->brcd_switch; | |
783 | } | |
784 | /** | |
785 | * return TRUE if authentication is required | |
786 | */ | |
787 | bfa_boolean_t | |
788 | bfa_lps_is_authreq(struct bfa_lps_s *lps) | |
789 | { | |
790 | return lps->auth_req; | |
791 | } | |
792 | ||
793 | bfa_eproto_status_t | |
794 | bfa_lps_get_extstatus(struct bfa_lps_s *lps) | |
795 | { | |
796 | return lps->ext_status; | |
797 | } | |
798 | ||
799 | /** | |
800 | * return port id assigned to the lport | |
801 | */ | |
802 | u32 | |
803 | bfa_lps_get_pid(struct bfa_lps_s *lps) | |
804 | { | |
805 | return lps->lp_pid; | |
806 | } | |
807 | ||
808 | /** | |
809 | * Return bb_credit assigned in FLOGI response | |
810 | */ | |
811 | u16 | |
812 | bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps) | |
813 | { | |
814 | return lps->pr_bbcred; | |
815 | } | |
816 | ||
817 | /** | |
818 | * Return peer port name | |
819 | */ | |
820 | wwn_t | |
821 | bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps) | |
822 | { | |
823 | return lps->pr_pwwn; | |
824 | } | |
825 | ||
826 | /** | |
827 | * Return peer node name | |
828 | */ | |
829 | wwn_t | |
830 | bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps) | |
831 | { | |
832 | return lps->pr_nwwn; | |
833 | } | |
834 | ||
835 | /** | |
836 | * return reason code if login request is rejected | |
837 | */ | |
838 | u8 | |
839 | bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps) | |
840 | { | |
841 | return lps->lsrjt_rsn; | |
842 | } | |
843 | ||
844 | /** | |
845 | * return explanation code if login request is rejected | |
846 | */ | |
847 | u8 | |
848 | bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps) | |
849 | { | |
850 | return lps->lsrjt_expl; | |
851 | } | |
852 | ||
86e32dab KG |
853 | /** |
854 | * Return fpma/spma MAC for lport | |
855 | */ | |
856 | struct mac_s | |
857 | bfa_lps_get_lp_mac(struct bfa_lps_s *lps) | |
858 | { | |
859 | return lps->lp_mac; | |
860 | } | |
7725ccfd JH |
861 | |
862 | /** | |
863 | * LPS firmware message class handler. | |
864 | */ | |
865 | void | |
866 | bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) | |
867 | { | |
868 | union bfi_lps_i2h_msg_u msg; | |
869 | ||
870 | bfa_trc(bfa, m->mhdr.msg_id); | |
871 | msg.msg = m; | |
872 | ||
873 | switch (m->mhdr.msg_id) { | |
874 | case BFI_LPS_H2I_LOGIN_RSP: | |
875 | bfa_lps_login_rsp(bfa, msg.login_rsp); | |
876 | break; | |
877 | ||
878 | case BFI_LPS_H2I_LOGOUT_RSP: | |
879 | bfa_lps_logout_rsp(bfa, msg.logout_rsp); | |
880 | break; | |
881 | ||
5c1fb1d5 KG |
882 | case BFI_LPS_H2I_CVL_EVENT: |
883 | bfa_lps_rx_cvl_event(bfa, msg.cvl_event); | |
884 | break; | |
885 | ||
7725ccfd JH |
886 | default: |
887 | bfa_trc(bfa, m->mhdr.msg_id); | |
888 | bfa_assert(0); | |
889 | } | |
890 | } | |
891 | ||
892 |