diff options
Diffstat (limited to 'drivers/scsi/bfa/ns.c')
-rw-r--r-- | drivers/scsi/bfa/ns.c | 1243 |
1 files changed, 1243 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c new file mode 100644 index 000000000000..59fea99d67a4 --- /dev/null +++ b/drivers/scsi/bfa/ns.c | |||
@@ -0,0 +1,1243 @@ | |||
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 | /** | ||
19 | * @page ns_sm_info VPORT NS State Machine | ||
20 | * | ||
21 | * @section ns_sm_interactions VPORT NS State Machine Interactions | ||
22 | * | ||
23 | * @section ns_sm VPORT NS State Machine | ||
24 | * img ns_sm.jpg | ||
25 | */ | ||
26 | #include <bfa.h> | ||
27 | #include <bfa_svc.h> | ||
28 | #include <bfa_iocfc.h> | ||
29 | #include "fcs_lport.h" | ||
30 | #include "fcs_rport.h" | ||
31 | #include "fcs_trcmod.h" | ||
32 | #include "fcs_fcxp.h" | ||
33 | #include "fcs.h" | ||
34 | #include "lport_priv.h" | ||
35 | |||
36 | BFA_TRC_FILE(FCS, NS); | ||
37 | |||
38 | /* | ||
39 | * forward declarations | ||
40 | */ | ||
41 | static void bfa_fcs_port_ns_send_plogi(void *ns_cbarg, | ||
42 | struct bfa_fcxp_s *fcxp_alloced); | ||
43 | static void bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, | ||
44 | struct bfa_fcxp_s *fcxp_alloced); | ||
45 | static void bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, | ||
46 | struct bfa_fcxp_s *fcxp_alloced); | ||
47 | static void bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, | ||
48 | struct bfa_fcxp_s *fcxp_alloced); | ||
49 | static void bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, | ||
50 | struct bfa_fcxp_s *fcxp_alloced); | ||
51 | static void bfa_fcs_port_ns_timeout(void *arg); | ||
52 | static void bfa_fcs_port_ns_plogi_response(void *fcsarg, | ||
53 | struct bfa_fcxp_s *fcxp, | ||
54 | void *cbarg, | ||
55 | bfa_status_t req_status, | ||
56 | u32 rsp_len, | ||
57 | u32 resid_len, | ||
58 | struct fchs_s *rsp_fchs); | ||
59 | static void bfa_fcs_port_ns_rspn_id_response(void *fcsarg, | ||
60 | struct bfa_fcxp_s *fcxp, | ||
61 | void *cbarg, | ||
62 | bfa_status_t req_status, | ||
63 | u32 rsp_len, | ||
64 | u32 resid_len, | ||
65 | struct fchs_s *rsp_fchs); | ||
66 | static void bfa_fcs_port_ns_rft_id_response(void *fcsarg, | ||
67 | struct bfa_fcxp_s *fcxp, | ||
68 | void *cbarg, | ||
69 | bfa_status_t req_status, | ||
70 | u32 rsp_len, | ||
71 | u32 resid_len, | ||
72 | struct fchs_s *rsp_fchs); | ||
73 | static void bfa_fcs_port_ns_rff_id_response(void *fcsarg, | ||
74 | struct bfa_fcxp_s *fcxp, | ||
75 | void *cbarg, | ||
76 | bfa_status_t req_status, | ||
77 | u32 rsp_len, | ||
78 | u32 resid_len, | ||
79 | struct fchs_s *rsp_fchs); | ||
80 | static void bfa_fcs_port_ns_gid_ft_response(void *fcsarg, | ||
81 | struct bfa_fcxp_s *fcxp, | ||
82 | void *cbarg, | ||
83 | bfa_status_t req_status, | ||
84 | u32 rsp_len, | ||
85 | u32 resid_len, | ||
86 | struct fchs_s *rsp_fchs); | ||
87 | static void bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port, | ||
88 | u32 *pid_buf, | ||
89 | u32 n_pids); | ||
90 | |||
91 | static void bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port); | ||
92 | /** | ||
93 | * fcs_ns_sm FCS nameserver interface state machine | ||
94 | */ | ||
95 | |||
96 | /** | ||
97 | * VPort NS State Machine events | ||
98 | */ | ||
99 | enum vport_ns_event { | ||
100 | NSSM_EVENT_PORT_ONLINE = 1, | ||
101 | NSSM_EVENT_PORT_OFFLINE = 2, | ||
102 | NSSM_EVENT_PLOGI_SENT = 3, | ||
103 | NSSM_EVENT_RSP_OK = 4, | ||
104 | NSSM_EVENT_RSP_ERROR = 5, | ||
105 | NSSM_EVENT_TIMEOUT = 6, | ||
106 | NSSM_EVENT_NS_QUERY = 7, | ||
107 | NSSM_EVENT_RSPNID_SENT = 8, | ||
108 | NSSM_EVENT_RFTID_SENT = 9, | ||
109 | NSSM_EVENT_RFFID_SENT = 10, | ||
110 | NSSM_EVENT_GIDFT_SENT = 11, | ||
111 | }; | ||
112 | |||
113 | static void bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns, | ||
114 | enum vport_ns_event event); | ||
115 | static void bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns, | ||
116 | enum vport_ns_event event); | ||
117 | static void bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns, | ||
118 | enum vport_ns_event event); | ||
119 | static void bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns, | ||
120 | enum vport_ns_event event); | ||
121 | static void bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns, | ||
122 | enum vport_ns_event event); | ||
123 | static void bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns, | ||
124 | enum vport_ns_event event); | ||
125 | static void bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns, | ||
126 | enum vport_ns_event event); | ||
127 | static void bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns, | ||
128 | enum vport_ns_event event); | ||
129 | static void bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns, | ||
130 | enum vport_ns_event event); | ||
131 | static void bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns, | ||
132 | enum vport_ns_event event); | ||
133 | static void bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns, | ||
134 | enum vport_ns_event event); | ||
135 | static void bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns, | ||
136 | enum vport_ns_event event); | ||
137 | static void bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns, | ||
138 | enum vport_ns_event event); | ||
139 | static void bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns, | ||
140 | enum vport_ns_event event); | ||
141 | static void bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns, | ||
142 | enum vport_ns_event event); | ||
143 | static void bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns, | ||
144 | enum vport_ns_event event); | ||
145 | static void bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns, | ||
146 | enum vport_ns_event event); | ||
147 | /** | ||
148 | * Start in offline state - awaiting linkup | ||
149 | */ | ||
150 | static void | ||
151 | bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns, | ||
152 | enum vport_ns_event event) | ||
153 | { | ||
154 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
155 | bfa_trc(ns->port->fcs, event); | ||
156 | |||
157 | switch (event) { | ||
158 | case NSSM_EVENT_PORT_ONLINE: | ||
159 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending); | ||
160 | bfa_fcs_port_ns_send_plogi(ns, NULL); | ||
161 | break; | ||
162 | |||
163 | case NSSM_EVENT_PORT_OFFLINE: | ||
164 | break; | ||
165 | |||
166 | default: | ||
167 | bfa_assert(0); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | static void | ||
172 | bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns, | ||
173 | enum vport_ns_event event) | ||
174 | { | ||
175 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
176 | bfa_trc(ns->port->fcs, event); | ||
177 | |||
178 | switch (event) { | ||
179 | case NSSM_EVENT_PLOGI_SENT: | ||
180 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi); | ||
181 | break; | ||
182 | |||
183 | case NSSM_EVENT_PORT_OFFLINE: | ||
184 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
185 | bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), | ||
186 | &ns->fcxp_wqe); | ||
187 | break; | ||
188 | |||
189 | default: | ||
190 | bfa_assert(0); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static void | ||
195 | bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns, | ||
196 | enum vport_ns_event event) | ||
197 | { | ||
198 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
199 | bfa_trc(ns->port->fcs, event); | ||
200 | |||
201 | switch (event) { | ||
202 | case NSSM_EVENT_RSP_ERROR: | ||
203 | /* | ||
204 | * Start timer for a delayed retry | ||
205 | */ | ||
206 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_retry); | ||
207 | ns->port->stats.ns_retries++; | ||
208 | bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, | ||
209 | bfa_fcs_port_ns_timeout, ns, | ||
210 | BFA_FCS_RETRY_TIMEOUT); | ||
211 | break; | ||
212 | |||
213 | case NSSM_EVENT_RSP_OK: | ||
214 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id); | ||
215 | bfa_fcs_port_ns_send_rspn_id(ns, NULL); | ||
216 | break; | ||
217 | |||
218 | case NSSM_EVENT_PORT_OFFLINE: | ||
219 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
220 | bfa_fcxp_discard(ns->fcxp); | ||
221 | break; | ||
222 | |||
223 | default: | ||
224 | bfa_assert(0); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static void | ||
229 | bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns, | ||
230 | enum vport_ns_event event) | ||
231 | { | ||
232 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
233 | bfa_trc(ns->port->fcs, event); | ||
234 | |||
235 | switch (event) { | ||
236 | case NSSM_EVENT_TIMEOUT: | ||
237 | /* | ||
238 | * Retry Timer Expired. Re-send | ||
239 | */ | ||
240 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending); | ||
241 | bfa_fcs_port_ns_send_plogi(ns, NULL); | ||
242 | break; | ||
243 | |||
244 | case NSSM_EVENT_PORT_OFFLINE: | ||
245 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
246 | bfa_timer_stop(&ns->timer); | ||
247 | break; | ||
248 | |||
249 | default: | ||
250 | bfa_assert(0); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | static void | ||
255 | bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns, | ||
256 | enum vport_ns_event event) | ||
257 | { | ||
258 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
259 | bfa_trc(ns->port->fcs, event); | ||
260 | |||
261 | switch (event) { | ||
262 | case NSSM_EVENT_RSPNID_SENT: | ||
263 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id); | ||
264 | break; | ||
265 | |||
266 | case NSSM_EVENT_PORT_OFFLINE: | ||
267 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
268 | bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), | ||
269 | &ns->fcxp_wqe); | ||
270 | break; | ||
271 | |||
272 | default: | ||
273 | bfa_assert(0); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static void | ||
278 | bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns, | ||
279 | enum vport_ns_event event) | ||
280 | { | ||
281 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
282 | bfa_trc(ns->port->fcs, event); | ||
283 | |||
284 | switch (event) { | ||
285 | case NSSM_EVENT_RSP_ERROR: | ||
286 | /* | ||
287 | * Start timer for a delayed retry | ||
288 | */ | ||
289 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id_retry); | ||
290 | ns->port->stats.ns_retries++; | ||
291 | bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, | ||
292 | bfa_fcs_port_ns_timeout, ns, | ||
293 | BFA_FCS_RETRY_TIMEOUT); | ||
294 | break; | ||
295 | |||
296 | case NSSM_EVENT_RSP_OK: | ||
297 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id); | ||
298 | bfa_fcs_port_ns_send_rft_id(ns, NULL); | ||
299 | break; | ||
300 | |||
301 | case NSSM_EVENT_PORT_OFFLINE: | ||
302 | bfa_fcxp_discard(ns->fcxp); | ||
303 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
304 | break; | ||
305 | |||
306 | default: | ||
307 | bfa_assert(0); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | static void | ||
312 | bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns, | ||
313 | enum vport_ns_event event) | ||
314 | { | ||
315 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
316 | bfa_trc(ns->port->fcs, event); | ||
317 | |||
318 | switch (event) { | ||
319 | case NSSM_EVENT_TIMEOUT: | ||
320 | /* | ||
321 | * Retry Timer Expired. Re-send | ||
322 | */ | ||
323 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id); | ||
324 | bfa_fcs_port_ns_send_rspn_id(ns, NULL); | ||
325 | break; | ||
326 | |||
327 | case NSSM_EVENT_PORT_OFFLINE: | ||
328 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
329 | bfa_timer_stop(&ns->timer); | ||
330 | break; | ||
331 | |||
332 | default: | ||
333 | bfa_assert(0); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | static void | ||
338 | bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns, | ||
339 | enum vport_ns_event event) | ||
340 | { | ||
341 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
342 | bfa_trc(ns->port->fcs, event); | ||
343 | |||
344 | switch (event) { | ||
345 | case NSSM_EVENT_RFTID_SENT: | ||
346 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id); | ||
347 | break; | ||
348 | |||
349 | case NSSM_EVENT_PORT_OFFLINE: | ||
350 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
351 | bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), | ||
352 | &ns->fcxp_wqe); | ||
353 | break; | ||
354 | |||
355 | default: | ||
356 | bfa_assert(0); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static void | ||
361 | bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns, | ||
362 | enum vport_ns_event event) | ||
363 | { | ||
364 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
365 | bfa_trc(ns->port->fcs, event); | ||
366 | |||
367 | switch (event) { | ||
368 | case NSSM_EVENT_RSP_OK: | ||
369 | /* | ||
370 | * Now move to register FC4 Features | ||
371 | */ | ||
372 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id); | ||
373 | bfa_fcs_port_ns_send_rff_id(ns, NULL); | ||
374 | break; | ||
375 | |||
376 | case NSSM_EVENT_RSP_ERROR: | ||
377 | /* | ||
378 | * Start timer for a delayed retry | ||
379 | */ | ||
380 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id_retry); | ||
381 | ns->port->stats.ns_retries++; | ||
382 | bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, | ||
383 | bfa_fcs_port_ns_timeout, ns, | ||
384 | BFA_FCS_RETRY_TIMEOUT); | ||
385 | break; | ||
386 | |||
387 | case NSSM_EVENT_PORT_OFFLINE: | ||
388 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
389 | bfa_fcxp_discard(ns->fcxp); | ||
390 | break; | ||
391 | |||
392 | default: | ||
393 | bfa_assert(0); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | static void | ||
398 | bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns, | ||
399 | enum vport_ns_event event) | ||
400 | { | ||
401 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
402 | bfa_trc(ns->port->fcs, event); | ||
403 | |||
404 | switch (event) { | ||
405 | case NSSM_EVENT_TIMEOUT: | ||
406 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id); | ||
407 | bfa_fcs_port_ns_send_rft_id(ns, NULL); | ||
408 | break; | ||
409 | |||
410 | case NSSM_EVENT_PORT_OFFLINE: | ||
411 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
412 | bfa_timer_stop(&ns->timer); | ||
413 | break; | ||
414 | |||
415 | default: | ||
416 | bfa_assert(0); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | static void | ||
421 | bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns, | ||
422 | enum vport_ns_event event) | ||
423 | { | ||
424 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
425 | bfa_trc(ns->port->fcs, event); | ||
426 | |||
427 | switch (event) { | ||
428 | case NSSM_EVENT_RFFID_SENT: | ||
429 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id); | ||
430 | break; | ||
431 | |||
432 | case NSSM_EVENT_PORT_OFFLINE: | ||
433 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
434 | bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), | ||
435 | &ns->fcxp_wqe); | ||
436 | break; | ||
437 | |||
438 | default: | ||
439 | bfa_assert(0); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | static void | ||
444 | bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns, | ||
445 | enum vport_ns_event event) | ||
446 | { | ||
447 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
448 | bfa_trc(ns->port->fcs, event); | ||
449 | |||
450 | switch (event) { | ||
451 | case NSSM_EVENT_RSP_OK: | ||
452 | |||
453 | /* | ||
454 | * If min cfg mode is enabled, we donot initiate rport | ||
455 | * discovery with the fabric. Instead, we will retrieve the | ||
456 | * boot targets from HAL/FW. | ||
457 | */ | ||
458 | if (__fcs_min_cfg(ns->port->fcs)) { | ||
459 | bfa_fcs_port_ns_boot_target_disc(ns->port); | ||
460 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); | ||
461 | return; | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * If the port role is Initiator Mode issue NS query. | ||
466 | * If it is Target Mode, skip this and go to online. | ||
467 | */ | ||
468 | if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { | ||
469 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); | ||
470 | bfa_fcs_port_ns_send_gid_ft(ns, NULL); | ||
471 | } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) { | ||
472 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); | ||
473 | } | ||
474 | /* | ||
475 | * kick off mgmt srvr state machine | ||
476 | */ | ||
477 | bfa_fcs_port_ms_online(ns->port); | ||
478 | break; | ||
479 | |||
480 | case NSSM_EVENT_RSP_ERROR: | ||
481 | /* | ||
482 | * Start timer for a delayed retry | ||
483 | */ | ||
484 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id_retry); | ||
485 | ns->port->stats.ns_retries++; | ||
486 | bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, | ||
487 | bfa_fcs_port_ns_timeout, ns, | ||
488 | BFA_FCS_RETRY_TIMEOUT); | ||
489 | break; | ||
490 | |||
491 | case NSSM_EVENT_PORT_OFFLINE: | ||
492 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
493 | bfa_fcxp_discard(ns->fcxp); | ||
494 | break; | ||
495 | |||
496 | default: | ||
497 | bfa_assert(0); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | static void | ||
502 | bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns, | ||
503 | enum vport_ns_event event) | ||
504 | { | ||
505 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
506 | bfa_trc(ns->port->fcs, event); | ||
507 | |||
508 | switch (event) { | ||
509 | case NSSM_EVENT_TIMEOUT: | ||
510 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id); | ||
511 | bfa_fcs_port_ns_send_rff_id(ns, NULL); | ||
512 | break; | ||
513 | |||
514 | case NSSM_EVENT_PORT_OFFLINE: | ||
515 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
516 | bfa_timer_stop(&ns->timer); | ||
517 | break; | ||
518 | |||
519 | default: | ||
520 | bfa_assert(0); | ||
521 | } | ||
522 | } | ||
523 | static void | ||
524 | bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns, | ||
525 | enum vport_ns_event event) | ||
526 | { | ||
527 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
528 | bfa_trc(ns->port->fcs, event); | ||
529 | |||
530 | switch (event) { | ||
531 | case NSSM_EVENT_GIDFT_SENT: | ||
532 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft); | ||
533 | break; | ||
534 | |||
535 | case NSSM_EVENT_PORT_OFFLINE: | ||
536 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
537 | bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), | ||
538 | &ns->fcxp_wqe); | ||
539 | break; | ||
540 | |||
541 | default: | ||
542 | bfa_assert(0); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | static void | ||
547 | bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns, | ||
548 | enum vport_ns_event event) | ||
549 | { | ||
550 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
551 | bfa_trc(ns->port->fcs, event); | ||
552 | |||
553 | switch (event) { | ||
554 | case NSSM_EVENT_RSP_OK: | ||
555 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); | ||
556 | break; | ||
557 | |||
558 | case NSSM_EVENT_RSP_ERROR: | ||
559 | /* | ||
560 | * TBD: for certain reject codes, we don't need to retry | ||
561 | */ | ||
562 | /* | ||
563 | * Start timer for a delayed retry | ||
564 | */ | ||
565 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft_retry); | ||
566 | ns->port->stats.ns_retries++; | ||
567 | bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, | ||
568 | bfa_fcs_port_ns_timeout, ns, | ||
569 | BFA_FCS_RETRY_TIMEOUT); | ||
570 | break; | ||
571 | |||
572 | case NSSM_EVENT_PORT_OFFLINE: | ||
573 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
574 | bfa_fcxp_discard(ns->fcxp); | ||
575 | break; | ||
576 | |||
577 | default: | ||
578 | bfa_assert(0); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | static void | ||
583 | bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns, | ||
584 | enum vport_ns_event event) | ||
585 | { | ||
586 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
587 | bfa_trc(ns->port->fcs, event); | ||
588 | |||
589 | switch (event) { | ||
590 | case NSSM_EVENT_TIMEOUT: | ||
591 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); | ||
592 | bfa_fcs_port_ns_send_gid_ft(ns, NULL); | ||
593 | break; | ||
594 | |||
595 | case NSSM_EVENT_PORT_OFFLINE: | ||
596 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
597 | bfa_timer_stop(&ns->timer); | ||
598 | break; | ||
599 | |||
600 | default: | ||
601 | bfa_assert(0); | ||
602 | } | ||
603 | } | ||
604 | |||
605 | static void | ||
606 | bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns, | ||
607 | enum vport_ns_event event) | ||
608 | { | ||
609 | bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); | ||
610 | bfa_trc(ns->port->fcs, event); | ||
611 | |||
612 | switch (event) { | ||
613 | case NSSM_EVENT_PORT_OFFLINE: | ||
614 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
615 | break; | ||
616 | |||
617 | case NSSM_EVENT_NS_QUERY: | ||
618 | /* | ||
619 | * If the port role is Initiator Mode issue NS query. | ||
620 | * If it is Target Mode, skip this and go to online. | ||
621 | */ | ||
622 | if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { | ||
623 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); | ||
624 | bfa_fcs_port_ns_send_gid_ft(ns, NULL); | ||
625 | }; | ||
626 | break; | ||
627 | |||
628 | default: | ||
629 | bfa_assert(0); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | |||
634 | |||
635 | /** | ||
636 | * ns_pvt Nameserver local functions | ||
637 | */ | ||
638 | |||
639 | static void | ||
640 | bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) | ||
641 | { | ||
642 | struct bfa_fcs_port_ns_s *ns = ns_cbarg; | ||
643 | struct bfa_fcs_port_s *port = ns->port; | ||
644 | struct fchs_s fchs; | ||
645 | int len; | ||
646 | struct bfa_fcxp_s *fcxp; | ||
647 | |||
648 | bfa_trc(port->fcs, port->pid); | ||
649 | |||
650 | fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); | ||
651 | if (!fcxp) { | ||
652 | port->stats.ns_plogi_alloc_wait++; | ||
653 | bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, | ||
654 | bfa_fcs_port_ns_send_plogi, ns); | ||
655 | return; | ||
656 | } | ||
657 | ns->fcxp = fcxp; | ||
658 | |||
659 | len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), | ||
660 | bfa_os_hton3b(FC_NAME_SERVER), | ||
661 | bfa_fcs_port_get_fcid(port), 0, | ||
662 | port->port_cfg.pwwn, port->port_cfg.nwwn, | ||
663 | bfa_pport_get_maxfrsize(port->fcs->bfa)); | ||
664 | |||
665 | bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, | ||
666 | FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response, | ||
667 | (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); | ||
668 | port->stats.ns_plogi_sent++; | ||
669 | |||
670 | bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT); | ||
671 | } | ||
672 | |||
673 | static void | ||
674 | bfa_fcs_port_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, | ||
675 | void *cbarg, bfa_status_t req_status, | ||
676 | u32 rsp_len, u32 resid_len, | ||
677 | struct fchs_s *rsp_fchs) | ||
678 | { | ||
679 | struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; | ||
680 | struct bfa_fcs_port_s *port = ns->port; | ||
681 | /* struct fc_logi_s *plogi_resp; */ | ||
682 | struct fc_els_cmd_s *els_cmd; | ||
683 | struct fc_ls_rjt_s *ls_rjt; | ||
684 | |||
685 | bfa_trc(port->fcs, req_status); | ||
686 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
687 | |||
688 | /* | ||
689 | * Sanity Checks | ||
690 | */ | ||
691 | if (req_status != BFA_STATUS_OK) { | ||
692 | bfa_trc(port->fcs, req_status); | ||
693 | port->stats.ns_plogi_rsp_err++; | ||
694 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
695 | return; | ||
696 | } | ||
697 | |||
698 | els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
699 | |||
700 | switch (els_cmd->els_code) { | ||
701 | |||
702 | case FC_ELS_ACC: | ||
703 | if (rsp_len < sizeof(struct fc_logi_s)) { | ||
704 | bfa_trc(port->fcs, rsp_len); | ||
705 | port->stats.ns_plogi_acc_err++; | ||
706 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
707 | break; | ||
708 | } | ||
709 | port->stats.ns_plogi_accepts++; | ||
710 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); | ||
711 | break; | ||
712 | |||
713 | case FC_ELS_LS_RJT: | ||
714 | ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
715 | |||
716 | bfa_trc(port->fcs, ls_rjt->reason_code); | ||
717 | bfa_trc(port->fcs, ls_rjt->reason_code_expl); | ||
718 | |||
719 | port->stats.ns_rejects++; | ||
720 | |||
721 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
722 | break; | ||
723 | |||
724 | default: | ||
725 | port->stats.ns_plogi_unknown_rsp++; | ||
726 | bfa_trc(port->fcs, els_cmd->els_code); | ||
727 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | /** | ||
732 | * Register the symbolic port name. | ||
733 | */ | ||
734 | static void | ||
735 | bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) | ||
736 | { | ||
737 | struct bfa_fcs_port_ns_s *ns = ns_cbarg; | ||
738 | struct bfa_fcs_port_s *port = ns->port; | ||
739 | struct fchs_s fchs; | ||
740 | int len; | ||
741 | struct bfa_fcxp_s *fcxp; | ||
742 | u8 symbl[256]; | ||
743 | u8 *psymbl = &symbl[0]; | ||
744 | |||
745 | bfa_os_memset(symbl, 0, sizeof(symbl)); | ||
746 | |||
747 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
748 | |||
749 | fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); | ||
750 | if (!fcxp) { | ||
751 | port->stats.ns_rspnid_alloc_wait++; | ||
752 | bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, | ||
753 | bfa_fcs_port_ns_send_rspn_id, ns); | ||
754 | return; | ||
755 | } | ||
756 | ns->fcxp = fcxp; | ||
757 | |||
758 | /* | ||
759 | * for V-Port, form a Port Symbolic Name | ||
760 | */ | ||
761 | if (port->vport) { | ||
762 | /**For Vports, | ||
763 | * we append the vport's port symbolic name to that of the base port. | ||
764 | */ | ||
765 | |||
766 | strncpy((char *)psymbl, | ||
767 | (char *) | ||
768 | &(bfa_fcs_port_get_psym_name | ||
769 | (bfa_fcs_get_base_port(port->fcs))), | ||
770 | strlen((char *) | ||
771 | &bfa_fcs_port_get_psym_name(bfa_fcs_get_base_port | ||
772 | (port->fcs)))); | ||
773 | |||
774 | /* | ||
775 | * Ensure we have a null terminating string. | ||
776 | */ | ||
777 | ((char *) | ||
778 | psymbl)[strlen((char *) | ||
779 | &bfa_fcs_port_get_psym_name | ||
780 | (bfa_fcs_get_base_port(port->fcs)))] = 0; | ||
781 | |||
782 | strncat((char *)psymbl, | ||
783 | (char *)&(bfa_fcs_port_get_psym_name(port)), | ||
784 | strlen((char *)&bfa_fcs_port_get_psym_name(port))); | ||
785 | } else { | ||
786 | psymbl = (u8 *) &(bfa_fcs_port_get_psym_name(port)); | ||
787 | } | ||
788 | |||
789 | len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), | ||
790 | bfa_fcs_port_get_fcid(port), 0, psymbl); | ||
791 | |||
792 | bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, | ||
793 | FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rspn_id_response, | ||
794 | (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); | ||
795 | |||
796 | port->stats.ns_rspnid_sent++; | ||
797 | |||
798 | bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT); | ||
799 | } | ||
800 | |||
801 | static void | ||
802 | bfa_fcs_port_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, | ||
803 | void *cbarg, bfa_status_t req_status, | ||
804 | u32 rsp_len, u32 resid_len, | ||
805 | struct fchs_s *rsp_fchs) | ||
806 | { | ||
807 | struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; | ||
808 | struct bfa_fcs_port_s *port = ns->port; | ||
809 | struct ct_hdr_s *cthdr = NULL; | ||
810 | |||
811 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
812 | |||
813 | /* | ||
814 | * Sanity Checks | ||
815 | */ | ||
816 | if (req_status != BFA_STATUS_OK) { | ||
817 | bfa_trc(port->fcs, req_status); | ||
818 | port->stats.ns_rspnid_rsp_err++; | ||
819 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
820 | return; | ||
821 | } | ||
822 | |||
823 | cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
824 | cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); | ||
825 | |||
826 | if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { | ||
827 | port->stats.ns_rspnid_accepts++; | ||
828 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); | ||
829 | return; | ||
830 | } | ||
831 | |||
832 | port->stats.ns_rspnid_rejects++; | ||
833 | bfa_trc(port->fcs, cthdr->reason_code); | ||
834 | bfa_trc(port->fcs, cthdr->exp_code); | ||
835 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
836 | } | ||
837 | |||
838 | /** | ||
839 | * Register FC4-Types | ||
840 | * TBD, Need to retrieve this from the OS driver, in case IPFC is enabled ? | ||
841 | */ | ||
842 | static void | ||
843 | bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) | ||
844 | { | ||
845 | struct bfa_fcs_port_ns_s *ns = ns_cbarg; | ||
846 | struct bfa_fcs_port_s *port = ns->port; | ||
847 | struct fchs_s fchs; | ||
848 | int len; | ||
849 | struct bfa_fcxp_s *fcxp; | ||
850 | |||
851 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
852 | |||
853 | fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); | ||
854 | if (!fcxp) { | ||
855 | port->stats.ns_rftid_alloc_wait++; | ||
856 | bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, | ||
857 | bfa_fcs_port_ns_send_rft_id, ns); | ||
858 | return; | ||
859 | } | ||
860 | ns->fcxp = fcxp; | ||
861 | |||
862 | len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), | ||
863 | bfa_fcs_port_get_fcid(port), 0, | ||
864 | port->port_cfg.roles); | ||
865 | |||
866 | bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, | ||
867 | FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rft_id_response, | ||
868 | (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); | ||
869 | |||
870 | port->stats.ns_rftid_sent++; | ||
871 | bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT); | ||
872 | } | ||
873 | |||
874 | static void | ||
875 | bfa_fcs_port_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, | ||
876 | void *cbarg, bfa_status_t req_status, | ||
877 | u32 rsp_len, u32 resid_len, | ||
878 | struct fchs_s *rsp_fchs) | ||
879 | { | ||
880 | struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; | ||
881 | struct bfa_fcs_port_s *port = ns->port; | ||
882 | struct ct_hdr_s *cthdr = NULL; | ||
883 | |||
884 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
885 | |||
886 | /* | ||
887 | * Sanity Checks | ||
888 | */ | ||
889 | if (req_status != BFA_STATUS_OK) { | ||
890 | bfa_trc(port->fcs, req_status); | ||
891 | port->stats.ns_rftid_rsp_err++; | ||
892 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
893 | return; | ||
894 | } | ||
895 | |||
896 | cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
897 | cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); | ||
898 | |||
899 | if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { | ||
900 | port->stats.ns_rftid_accepts++; | ||
901 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); | ||
902 | return; | ||
903 | } | ||
904 | |||
905 | port->stats.ns_rftid_rejects++; | ||
906 | bfa_trc(port->fcs, cthdr->reason_code); | ||
907 | bfa_trc(port->fcs, cthdr->exp_code); | ||
908 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
909 | } | ||
910 | |||
911 | /** | ||
912 | * Register FC4-Features : Should be done after RFT_ID | ||
913 | */ | ||
914 | static void | ||
915 | bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) | ||
916 | { | ||
917 | struct bfa_fcs_port_ns_s *ns = ns_cbarg; | ||
918 | struct bfa_fcs_port_s *port = ns->port; | ||
919 | struct fchs_s fchs; | ||
920 | int len; | ||
921 | struct bfa_fcxp_s *fcxp; | ||
922 | u8 fc4_ftrs = 0; | ||
923 | |||
924 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
925 | |||
926 | fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); | ||
927 | if (!fcxp) { | ||
928 | port->stats.ns_rffid_alloc_wait++; | ||
929 | bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, | ||
930 | bfa_fcs_port_ns_send_rff_id, ns); | ||
931 | return; | ||
932 | } | ||
933 | ns->fcxp = fcxp; | ||
934 | |||
935 | if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { | ||
936 | fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR; | ||
937 | } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) { | ||
938 | fc4_ftrs = FC_GS_FCP_FC4_FEATURE_TARGET; | ||
939 | } | ||
940 | |||
941 | len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), | ||
942 | bfa_fcs_port_get_fcid(port), 0, FC_TYPE_FCP, | ||
943 | fc4_ftrs); | ||
944 | |||
945 | bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, | ||
946 | FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rff_id_response, | ||
947 | (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); | ||
948 | |||
949 | port->stats.ns_rffid_sent++; | ||
950 | bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT); | ||
951 | } | ||
952 | |||
953 | static void | ||
954 | bfa_fcs_port_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, | ||
955 | void *cbarg, bfa_status_t req_status, | ||
956 | u32 rsp_len, u32 resid_len, | ||
957 | struct fchs_s *rsp_fchs) | ||
958 | { | ||
959 | struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; | ||
960 | struct bfa_fcs_port_s *port = ns->port; | ||
961 | struct ct_hdr_s *cthdr = NULL; | ||
962 | |||
963 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
964 | |||
965 | /* | ||
966 | * Sanity Checks | ||
967 | */ | ||
968 | if (req_status != BFA_STATUS_OK) { | ||
969 | bfa_trc(port->fcs, req_status); | ||
970 | port->stats.ns_rffid_rsp_err++; | ||
971 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
972 | return; | ||
973 | } | ||
974 | |||
975 | cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
976 | cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); | ||
977 | |||
978 | if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { | ||
979 | port->stats.ns_rffid_accepts++; | ||
980 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); | ||
981 | return; | ||
982 | } | ||
983 | |||
984 | port->stats.ns_rffid_rejects++; | ||
985 | bfa_trc(port->fcs, cthdr->reason_code); | ||
986 | bfa_trc(port->fcs, cthdr->exp_code); | ||
987 | |||
988 | if (cthdr->reason_code == CT_RSN_NOT_SUPP) { | ||
989 | /* | ||
990 | * if this command is not supported, we don't retry | ||
991 | */ | ||
992 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); | ||
993 | } else { | ||
994 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
995 | } | ||
996 | } | ||
997 | |||
998 | /** | ||
999 | * Query Fabric for FC4-Types Devices. | ||
1000 | * | ||
1001 | * TBD : Need to use a local (FCS private) response buffer, since the response | ||
1002 | * can be larger than 2K. | ||
1003 | */ | ||
1004 | static void | ||
1005 | bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) | ||
1006 | { | ||
1007 | struct bfa_fcs_port_ns_s *ns = ns_cbarg; | ||
1008 | struct bfa_fcs_port_s *port = ns->port; | ||
1009 | struct fchs_s fchs; | ||
1010 | int len; | ||
1011 | struct bfa_fcxp_s *fcxp; | ||
1012 | |||
1013 | bfa_trc(port->fcs, port->pid); | ||
1014 | |||
1015 | fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); | ||
1016 | if (!fcxp) { | ||
1017 | port->stats.ns_gidft_alloc_wait++; | ||
1018 | bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, | ||
1019 | bfa_fcs_port_ns_send_gid_ft, ns); | ||
1020 | return; | ||
1021 | } | ||
1022 | ns->fcxp = fcxp; | ||
1023 | |||
1024 | /* | ||
1025 | * This query is only initiated for FCP initiator mode. | ||
1026 | */ | ||
1027 | len = fc_gid_ft_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), ns->port->pid, | ||
1028 | FC_TYPE_FCP); | ||
1029 | |||
1030 | bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, | ||
1031 | FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_gid_ft_response, | ||
1032 | (void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa), | ||
1033 | FC_RA_TOV); | ||
1034 | |||
1035 | port->stats.ns_gidft_sent++; | ||
1036 | |||
1037 | bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT); | ||
1038 | } | ||
1039 | |||
1040 | static void | ||
1041 | bfa_fcs_port_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp, | ||
1042 | void *cbarg, bfa_status_t req_status, | ||
1043 | u32 rsp_len, u32 resid_len, | ||
1044 | struct fchs_s *rsp_fchs) | ||
1045 | { | ||
1046 | struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; | ||
1047 | struct bfa_fcs_port_s *port = ns->port; | ||
1048 | struct ct_hdr_s *cthdr = NULL; | ||
1049 | u32 n_pids; | ||
1050 | |||
1051 | bfa_trc(port->fcs, port->port_cfg.pwwn); | ||
1052 | |||
1053 | /* | ||
1054 | * Sanity Checks | ||
1055 | */ | ||
1056 | if (req_status != BFA_STATUS_OK) { | ||
1057 | bfa_trc(port->fcs, req_status); | ||
1058 | port->stats.ns_gidft_rsp_err++; | ||
1059 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
1060 | return; | ||
1061 | } | ||
1062 | |||
1063 | if (resid_len != 0) { | ||
1064 | /* | ||
1065 | * TBD : we will need to allocate a larger buffer & retry the | ||
1066 | * command | ||
1067 | */ | ||
1068 | bfa_trc(port->fcs, rsp_len); | ||
1069 | bfa_trc(port->fcs, resid_len); | ||
1070 | return; | ||
1071 | } | ||
1072 | |||
1073 | cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
1074 | cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); | ||
1075 | |||
1076 | switch (cthdr->cmd_rsp_code) { | ||
1077 | |||
1078 | case CT_RSP_ACCEPT: | ||
1079 | |||
1080 | port->stats.ns_gidft_accepts++; | ||
1081 | n_pids = (fc_get_ctresp_pyld_len(rsp_len) / sizeof(u32)); | ||
1082 | bfa_trc(port->fcs, n_pids); | ||
1083 | bfa_fcs_port_ns_process_gidft_pids(port, | ||
1084 | (u32 *) (cthdr + 1), | ||
1085 | n_pids); | ||
1086 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); | ||
1087 | break; | ||
1088 | |||
1089 | case CT_RSP_REJECT: | ||
1090 | |||
1091 | /* | ||
1092 | * Check the reason code & explanation. | ||
1093 | * There may not have been any FC4 devices in the fabric | ||
1094 | */ | ||
1095 | port->stats.ns_gidft_rejects++; | ||
1096 | bfa_trc(port->fcs, cthdr->reason_code); | ||
1097 | bfa_trc(port->fcs, cthdr->exp_code); | ||
1098 | |||
1099 | if ((cthdr->reason_code == CT_RSN_UNABLE_TO_PERF) | ||
1100 | && (cthdr->exp_code == CT_NS_EXP_FT_NOT_REG)) { | ||
1101 | |||
1102 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); | ||
1103 | } else { | ||
1104 | /* | ||
1105 | * for all other errors, retry | ||
1106 | */ | ||
1107 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
1108 | } | ||
1109 | break; | ||
1110 | |||
1111 | default: | ||
1112 | port->stats.ns_gidft_unknown_rsp++; | ||
1113 | bfa_trc(port->fcs, cthdr->cmd_rsp_code); | ||
1114 | bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); | ||
1115 | } | ||
1116 | } | ||
1117 | |||
1118 | /** | ||
1119 | * This routine will be called by bfa_timer on timer timeouts. | ||
1120 | * | ||
1121 | * param[in] port - pointer to bfa_fcs_port_t. | ||
1122 | * | ||
1123 | * return | ||
1124 | * void | ||
1125 | * | ||
1126 | * Special Considerations: | ||
1127 | * | ||
1128 | * note | ||
1129 | */ | ||
1130 | static void | ||
1131 | bfa_fcs_port_ns_timeout(void *arg) | ||
1132 | { | ||
1133 | struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)arg; | ||
1134 | |||
1135 | ns->port->stats.ns_timeouts++; | ||
1136 | bfa_sm_send_event(ns, NSSM_EVENT_TIMEOUT); | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Process the PID list in GID_FT response | ||
1141 | */ | ||
1142 | static void | ||
1143 | bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port, | ||
1144 | u32 *pid_buf, u32 n_pids) | ||
1145 | { | ||
1146 | struct fcgs_gidft_resp_s *gidft_entry; | ||
1147 | struct bfa_fcs_rport_s *rport; | ||
1148 | u32 ii; | ||
1149 | |||
1150 | for (ii = 0; ii < n_pids; ii++) { | ||
1151 | gidft_entry = (struct fcgs_gidft_resp_s *) &pid_buf[ii]; | ||
1152 | |||
1153 | if (gidft_entry->pid == port->pid) | ||
1154 | continue; | ||
1155 | |||
1156 | /* | ||
1157 | * Check if this rport already exists | ||
1158 | */ | ||
1159 | rport = bfa_fcs_port_get_rport_by_pid(port, gidft_entry->pid); | ||
1160 | if (rport == NULL) { | ||
1161 | /* | ||
1162 | * this is a new device. create rport | ||
1163 | */ | ||
1164 | rport = bfa_fcs_rport_create(port, gidft_entry->pid); | ||
1165 | } else { | ||
1166 | /* | ||
1167 | * this rport already exists | ||
1168 | */ | ||
1169 | bfa_fcs_rport_scn(rport); | ||
1170 | } | ||
1171 | |||
1172 | bfa_trc(port->fcs, gidft_entry->pid); | ||
1173 | |||
1174 | /* | ||
1175 | * if the last entry bit is set, bail out. | ||
1176 | */ | ||
1177 | if (gidft_entry->last) | ||
1178 | return; | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | /** | ||
1183 | * fcs_ns_public FCS nameserver public interfaces | ||
1184 | */ | ||
1185 | |||
1186 | /* | ||
1187 | * Functions called by port/fab. | ||
1188 | * These will send relevant Events to the ns state machine. | ||
1189 | */ | ||
1190 | void | ||
1191 | bfa_fcs_port_ns_init(struct bfa_fcs_port_s *port) | ||
1192 | { | ||
1193 | struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); | ||
1194 | |||
1195 | ns->port = port; | ||
1196 | bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); | ||
1197 | } | ||
1198 | |||
1199 | void | ||
1200 | bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *port) | ||
1201 | { | ||
1202 | struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); | ||
1203 | |||
1204 | ns->port = port; | ||
1205 | bfa_sm_send_event(ns, NSSM_EVENT_PORT_OFFLINE); | ||
1206 | } | ||
1207 | |||
1208 | void | ||
1209 | bfa_fcs_port_ns_online(struct bfa_fcs_port_s *port) | ||
1210 | { | ||
1211 | struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); | ||
1212 | |||
1213 | ns->port = port; | ||
1214 | bfa_sm_send_event(ns, NSSM_EVENT_PORT_ONLINE); | ||
1215 | } | ||
1216 | |||
1217 | void | ||
1218 | bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port) | ||
1219 | { | ||
1220 | struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); | ||
1221 | |||
1222 | bfa_trc(port->fcs, port->pid); | ||
1223 | bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY); | ||
1224 | } | ||
1225 | |||
1226 | static void | ||
1227 | bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port) | ||
1228 | { | ||
1229 | |||
1230 | struct bfa_fcs_rport_s *rport; | ||
1231 | u8 nwwns; | ||
1232 | wwn_t *wwns; | ||
1233 | int ii; | ||
1234 | |||
1235 | bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, &wwns); | ||
1236 | |||
1237 | for (ii = 0; ii < nwwns; ++ii) { | ||
1238 | rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]); | ||
1239 | bfa_assert(rport); | ||
1240 | } | ||
1241 | } | ||
1242 | |||
1243 | |||