diff options
Diffstat (limited to 'drivers/scsi/bfa/fcpim.c')
-rw-r--r-- | drivers/scsi/bfa/fcpim.c | 844 |
1 files changed, 844 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c new file mode 100644 index 000000000000..8ce5d8934677 --- /dev/null +++ b/drivers/scsi/bfa/fcpim.c | |||
@@ -0,0 +1,844 @@ | |||
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 | * fcpim.c - FCP initiator mode i-t nexus state machine | ||
20 | */ | ||
21 | |||
22 | #include <bfa.h> | ||
23 | #include <bfa_svc.h> | ||
24 | #include "fcs_fcpim.h" | ||
25 | #include "fcs_rport.h" | ||
26 | #include "fcs_lport.h" | ||
27 | #include "fcs_trcmod.h" | ||
28 | #include "fcs_fcxp.h" | ||
29 | #include "fcs.h" | ||
30 | #include <fcs/bfa_fcs_fcpim.h> | ||
31 | #include <fcb/bfa_fcb_fcpim.h> | ||
32 | #include <aen/bfa_aen_itnim.h> | ||
33 | |||
34 | BFA_TRC_FILE(FCS, FCPIM); | ||
35 | |||
36 | /* | ||
37 | * forward declarations | ||
38 | */ | ||
39 | static void bfa_fcs_itnim_timeout(void *arg); | ||
40 | static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim); | ||
41 | static void bfa_fcs_itnim_send_prli(void *itnim_cbarg, | ||
42 | struct bfa_fcxp_s *fcxp_alloced); | ||
43 | static void bfa_fcs_itnim_prli_response(void *fcsarg, | ||
44 | struct bfa_fcxp_s *fcxp, | ||
45 | void *cbarg, | ||
46 | bfa_status_t req_status, | ||
47 | u32 rsp_len, | ||
48 | u32 resid_len, | ||
49 | struct fchs_s *rsp_fchs); | ||
50 | static void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, | ||
51 | enum bfa_itnim_aen_event event); | ||
52 | |||
53 | /** | ||
54 | * fcs_itnim_sm FCS itnim state machine events | ||
55 | */ | ||
56 | |||
57 | enum bfa_fcs_itnim_event { | ||
58 | BFA_FCS_ITNIM_SM_ONLINE = 1, /* rport online event */ | ||
59 | BFA_FCS_ITNIM_SM_OFFLINE = 2, /* rport offline */ | ||
60 | BFA_FCS_ITNIM_SM_FRMSENT = 3, /* prli frame is sent */ | ||
61 | BFA_FCS_ITNIM_SM_RSP_OK = 4, /* good response */ | ||
62 | BFA_FCS_ITNIM_SM_RSP_ERROR = 5, /* error response */ | ||
63 | BFA_FCS_ITNIM_SM_TIMEOUT = 6, /* delay timeout */ | ||
64 | BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */ | ||
65 | BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */ | ||
66 | BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */ | ||
67 | BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ | ||
68 | BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ | ||
69 | }; | ||
70 | |||
71 | static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, | ||
72 | enum bfa_fcs_itnim_event event); | ||
73 | static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, | ||
74 | enum bfa_fcs_itnim_event event); | ||
75 | static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, | ||
76 | enum bfa_fcs_itnim_event event); | ||
77 | static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, | ||
78 | enum bfa_fcs_itnim_event event); | ||
79 | static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, | ||
80 | enum bfa_fcs_itnim_event event); | ||
81 | static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, | ||
82 | enum bfa_fcs_itnim_event event); | ||
83 | static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, | ||
84 | enum bfa_fcs_itnim_event event); | ||
85 | static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, | ||
86 | enum bfa_fcs_itnim_event event); | ||
87 | |||
88 | static struct bfa_sm_table_s itnim_sm_table[] = { | ||
89 | {BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE}, | ||
90 | {BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND}, | ||
91 | {BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT}, | ||
92 | {BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY}, | ||
93 | {BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE}, | ||
94 | {BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE}, | ||
95 | {BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE}, | ||
96 | {BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR}, | ||
97 | }; | ||
98 | |||
99 | /** | ||
100 | * fcs_itnim_sm FCS itnim state machine | ||
101 | */ | ||
102 | |||
103 | static void | ||
104 | bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, | ||
105 | enum bfa_fcs_itnim_event event) | ||
106 | { | ||
107 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
108 | bfa_trc(itnim->fcs, event); | ||
109 | |||
110 | switch (event) { | ||
111 | case BFA_FCS_ITNIM_SM_ONLINE: | ||
112 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); | ||
113 | bfa_fcs_itnim_send_prli(itnim, NULL); | ||
114 | break; | ||
115 | |||
116 | case BFA_FCS_ITNIM_SM_OFFLINE: | ||
117 | bfa_fcs_rport_itnim_ack(itnim->rport); | ||
118 | break; | ||
119 | |||
120 | case BFA_FCS_ITNIM_SM_INITIATOR: | ||
121 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); | ||
122 | break; | ||
123 | |||
124 | case BFA_FCS_ITNIM_SM_DELETE: | ||
125 | bfa_fcs_itnim_free(itnim); | ||
126 | break; | ||
127 | |||
128 | default: | ||
129 | bfa_assert(0); | ||
130 | } | ||
131 | |||
132 | } | ||
133 | |||
134 | static void | ||
135 | bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, | ||
136 | enum bfa_fcs_itnim_event event) | ||
137 | { | ||
138 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
139 | bfa_trc(itnim->fcs, event); | ||
140 | |||
141 | switch (event) { | ||
142 | case BFA_FCS_ITNIM_SM_FRMSENT: | ||
143 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli); | ||
144 | break; | ||
145 | |||
146 | case BFA_FCS_ITNIM_SM_INITIATOR: | ||
147 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); | ||
148 | bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); | ||
149 | break; | ||
150 | |||
151 | case BFA_FCS_ITNIM_SM_OFFLINE: | ||
152 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
153 | bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); | ||
154 | bfa_fcs_rport_itnim_ack(itnim->rport); | ||
155 | break; | ||
156 | |||
157 | case BFA_FCS_ITNIM_SM_DELETE: | ||
158 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
159 | bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); | ||
160 | bfa_fcs_itnim_free(itnim); | ||
161 | break; | ||
162 | |||
163 | default: | ||
164 | bfa_assert(0); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static void | ||
169 | bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, | ||
170 | enum bfa_fcs_itnim_event event) | ||
171 | { | ||
172 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
173 | bfa_trc(itnim->fcs, event); | ||
174 | |||
175 | switch (event) { | ||
176 | case BFA_FCS_ITNIM_SM_RSP_OK: | ||
177 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online); | ||
178 | bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec); | ||
179 | break; | ||
180 | |||
181 | case BFA_FCS_ITNIM_SM_RSP_ERROR: | ||
182 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry); | ||
183 | bfa_timer_start(itnim->fcs->bfa, &itnim->timer, | ||
184 | bfa_fcs_itnim_timeout, itnim, | ||
185 | BFA_FCS_RETRY_TIMEOUT); | ||
186 | break; | ||
187 | |||
188 | case BFA_FCS_ITNIM_SM_OFFLINE: | ||
189 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
190 | bfa_fcxp_discard(itnim->fcxp); | ||
191 | bfa_fcs_rport_itnim_ack(itnim->rport); | ||
192 | break; | ||
193 | |||
194 | case BFA_FCS_ITNIM_SM_INITIATOR: | ||
195 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); | ||
196 | /* | ||
197 | * dont discard fcxp. accept will reach same state | ||
198 | */ | ||
199 | break; | ||
200 | |||
201 | case BFA_FCS_ITNIM_SM_DELETE: | ||
202 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
203 | bfa_fcxp_discard(itnim->fcxp); | ||
204 | bfa_fcs_itnim_free(itnim); | ||
205 | break; | ||
206 | |||
207 | default: | ||
208 | bfa_assert(0); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | static void | ||
213 | bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, | ||
214 | enum bfa_fcs_itnim_event event) | ||
215 | { | ||
216 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
217 | bfa_trc(itnim->fcs, event); | ||
218 | |||
219 | switch (event) { | ||
220 | case BFA_FCS_ITNIM_SM_TIMEOUT: | ||
221 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); | ||
222 | bfa_fcs_itnim_send_prli(itnim, NULL); | ||
223 | break; | ||
224 | |||
225 | case BFA_FCS_ITNIM_SM_OFFLINE: | ||
226 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
227 | bfa_timer_stop(&itnim->timer); | ||
228 | bfa_fcs_rport_itnim_ack(itnim->rport); | ||
229 | break; | ||
230 | |||
231 | case BFA_FCS_ITNIM_SM_INITIATOR: | ||
232 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); | ||
233 | bfa_timer_stop(&itnim->timer); | ||
234 | break; | ||
235 | |||
236 | case BFA_FCS_ITNIM_SM_DELETE: | ||
237 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
238 | bfa_timer_stop(&itnim->timer); | ||
239 | bfa_fcs_itnim_free(itnim); | ||
240 | break; | ||
241 | |||
242 | default: | ||
243 | bfa_assert(0); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | static void | ||
248 | bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, | ||
249 | enum bfa_fcs_itnim_event event) | ||
250 | { | ||
251 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
252 | bfa_trc(itnim->fcs, event); | ||
253 | |||
254 | switch (event) { | ||
255 | case BFA_FCS_ITNIM_SM_HCB_ONLINE: | ||
256 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online); | ||
257 | bfa_fcb_itnim_online(itnim->itnim_drv); | ||
258 | bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE); | ||
259 | break; | ||
260 | |||
261 | case BFA_FCS_ITNIM_SM_OFFLINE: | ||
262 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
263 | bfa_itnim_offline(itnim->bfa_itnim); | ||
264 | bfa_fcs_rport_itnim_ack(itnim->rport); | ||
265 | break; | ||
266 | |||
267 | case BFA_FCS_ITNIM_SM_DELETE: | ||
268 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
269 | bfa_fcs_itnim_free(itnim); | ||
270 | break; | ||
271 | |||
272 | default: | ||
273 | bfa_assert(0); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static void | ||
278 | bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, | ||
279 | enum bfa_fcs_itnim_event event) | ||
280 | { | ||
281 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
282 | bfa_trc(itnim->fcs, event); | ||
283 | |||
284 | switch (event) { | ||
285 | case BFA_FCS_ITNIM_SM_OFFLINE: | ||
286 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline); | ||
287 | bfa_fcb_itnim_offline(itnim->itnim_drv); | ||
288 | bfa_itnim_offline(itnim->bfa_itnim); | ||
289 | if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE) { | ||
290 | bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT); | ||
291 | } else { | ||
292 | bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE); | ||
293 | } | ||
294 | break; | ||
295 | |||
296 | case BFA_FCS_ITNIM_SM_DELETE: | ||
297 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
298 | bfa_fcs_itnim_free(itnim); | ||
299 | break; | ||
300 | |||
301 | default: | ||
302 | bfa_assert(0); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static void | ||
307 | bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, | ||
308 | enum bfa_fcs_itnim_event event) | ||
309 | { | ||
310 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
311 | bfa_trc(itnim->fcs, event); | ||
312 | |||
313 | switch (event) { | ||
314 | case BFA_FCS_ITNIM_SM_HCB_OFFLINE: | ||
315 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
316 | bfa_fcs_rport_itnim_ack(itnim->rport); | ||
317 | break; | ||
318 | |||
319 | case BFA_FCS_ITNIM_SM_DELETE: | ||
320 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
321 | bfa_fcs_itnim_free(itnim); | ||
322 | break; | ||
323 | |||
324 | default: | ||
325 | bfa_assert(0); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * This state is set when a discovered rport is also in intiator mode. | ||
331 | * This ITN is marked as no_op and is not active and will not be truned into | ||
332 | * online state. | ||
333 | */ | ||
334 | static void | ||
335 | bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, | ||
336 | enum bfa_fcs_itnim_event event) | ||
337 | { | ||
338 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
339 | bfa_trc(itnim->fcs, event); | ||
340 | |||
341 | switch (event) { | ||
342 | case BFA_FCS_ITNIM_SM_OFFLINE: | ||
343 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
344 | bfa_fcs_rport_itnim_ack(itnim->rport); | ||
345 | break; | ||
346 | |||
347 | case BFA_FCS_ITNIM_SM_RSP_ERROR: | ||
348 | case BFA_FCS_ITNIM_SM_ONLINE: | ||
349 | case BFA_FCS_ITNIM_SM_INITIATOR: | ||
350 | break; | ||
351 | |||
352 | case BFA_FCS_ITNIM_SM_DELETE: | ||
353 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
354 | bfa_fcs_itnim_free(itnim); | ||
355 | break; | ||
356 | |||
357 | default: | ||
358 | bfa_assert(0); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | |||
363 | |||
364 | /** | ||
365 | * itnim_private FCS ITNIM private interfaces | ||
366 | */ | ||
367 | |||
368 | static void | ||
369 | bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, | ||
370 | enum bfa_itnim_aen_event event) | ||
371 | { | ||
372 | struct bfa_fcs_rport_s *rport = itnim->rport; | ||
373 | union bfa_aen_data_u aen_data; | ||
374 | struct bfa_log_mod_s *logmod = rport->fcs->logm; | ||
375 | wwn_t lpwwn = bfa_fcs_port_get_pwwn(rport->port); | ||
376 | wwn_t rpwwn = rport->pwwn; | ||
377 | char lpwwn_ptr[BFA_STRING_32]; | ||
378 | char rpwwn_ptr[BFA_STRING_32]; | ||
379 | |||
380 | /* | ||
381 | * Don't post events for well known addresses | ||
382 | */ | ||
383 | if (BFA_FCS_PID_IS_WKA(rport->pid)) | ||
384 | return; | ||
385 | |||
386 | wwn2str(lpwwn_ptr, lpwwn); | ||
387 | wwn2str(rpwwn_ptr, rpwwn); | ||
388 | |||
389 | switch (event) { | ||
390 | case BFA_ITNIM_AEN_ONLINE: | ||
391 | bfa_log(logmod, BFA_AEN_ITNIM_ONLINE, rpwwn_ptr, lpwwn_ptr); | ||
392 | break; | ||
393 | case BFA_ITNIM_AEN_OFFLINE: | ||
394 | bfa_log(logmod, BFA_AEN_ITNIM_OFFLINE, rpwwn_ptr, lpwwn_ptr); | ||
395 | break; | ||
396 | case BFA_ITNIM_AEN_DISCONNECT: | ||
397 | bfa_log(logmod, BFA_AEN_ITNIM_DISCONNECT, rpwwn_ptr, lpwwn_ptr); | ||
398 | break; | ||
399 | default: | ||
400 | break; | ||
401 | } | ||
402 | |||
403 | aen_data.itnim.vf_id = rport->port->fabric->vf_id; | ||
404 | aen_data.itnim.ppwwn = | ||
405 | bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(itnim->fcs)); | ||
406 | aen_data.itnim.lpwwn = lpwwn; | ||
407 | aen_data.itnim.rpwwn = rpwwn; | ||
408 | } | ||
409 | |||
410 | static void | ||
411 | bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced) | ||
412 | { | ||
413 | struct bfa_fcs_itnim_s *itnim = itnim_cbarg; | ||
414 | struct bfa_fcs_rport_s *rport = itnim->rport; | ||
415 | struct bfa_fcs_port_s *port = rport->port; | ||
416 | struct fchs_s fchs; | ||
417 | struct bfa_fcxp_s *fcxp; | ||
418 | int len; | ||
419 | |||
420 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
421 | |||
422 | fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); | ||
423 | if (!fcxp) { | ||
424 | itnim->stats.fcxp_alloc_wait++; | ||
425 | bfa_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe, | ||
426 | bfa_fcs_itnim_send_prli, itnim); | ||
427 | return; | ||
428 | } | ||
429 | itnim->fcxp = fcxp; | ||
430 | |||
431 | len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), itnim->rport->pid, | ||
432 | bfa_fcs_port_get_fcid(port), 0); | ||
433 | |||
434 | bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag, | ||
435 | BFA_FALSE, FC_CLASS_3, len, &fchs, | ||
436 | bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ, | ||
437 | FC_RA_TOV); | ||
438 | |||
439 | itnim->stats.prli_sent++; | ||
440 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT); | ||
441 | } | ||
442 | |||
443 | static void | ||
444 | bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, | ||
445 | bfa_status_t req_status, u32 rsp_len, | ||
446 | u32 resid_len, struct fchs_s *rsp_fchs) | ||
447 | { | ||
448 | struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg; | ||
449 | struct fc_els_cmd_s *els_cmd; | ||
450 | struct fc_prli_s *prli_resp; | ||
451 | struct fc_ls_rjt_s *ls_rjt; | ||
452 | struct fc_prli_params_s *sparams; | ||
453 | |||
454 | bfa_trc(itnim->fcs, req_status); | ||
455 | |||
456 | /* | ||
457 | * Sanity Checks | ||
458 | */ | ||
459 | if (req_status != BFA_STATUS_OK) { | ||
460 | itnim->stats.prli_rsp_err++; | ||
461 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
466 | |||
467 | if (els_cmd->els_code == FC_ELS_ACC) { | ||
468 | prli_resp = (struct fc_prli_s *) els_cmd; | ||
469 | |||
470 | if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) { | ||
471 | bfa_trc(itnim->fcs, rsp_len); | ||
472 | /* | ||
473 | * Check if this r-port is also in Initiator mode. | ||
474 | * If so, we need to set this ITN as a no-op. | ||
475 | */ | ||
476 | if (prli_resp->parampage.servparams.initiator) { | ||
477 | bfa_trc(itnim->fcs, prli_resp->parampage.type); | ||
478 | itnim->rport->scsi_function = | ||
479 | BFA_RPORT_INITIATOR; | ||
480 | itnim->stats.prli_rsp_acc++; | ||
481 | bfa_sm_send_event(itnim, | ||
482 | BFA_FCS_ITNIM_SM_INITIATOR); | ||
483 | return; | ||
484 | } | ||
485 | |||
486 | itnim->stats.prli_rsp_parse_err++; | ||
487 | return; | ||
488 | } | ||
489 | itnim->rport->scsi_function = BFA_RPORT_TARGET; | ||
490 | |||
491 | sparams = &prli_resp->parampage.servparams; | ||
492 | itnim->seq_rec = sparams->retry; | ||
493 | itnim->rec_support = sparams->rec_support; | ||
494 | itnim->task_retry_id = sparams->task_retry_id; | ||
495 | itnim->conf_comp = sparams->confirm; | ||
496 | |||
497 | itnim->stats.prli_rsp_acc++; | ||
498 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK); | ||
499 | } else { | ||
500 | ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); | ||
501 | |||
502 | bfa_trc(itnim->fcs, ls_rjt->reason_code); | ||
503 | bfa_trc(itnim->fcs, ls_rjt->reason_code_expl); | ||
504 | |||
505 | itnim->stats.prli_rsp_rjt++; | ||
506 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); | ||
507 | } | ||
508 | } | ||
509 | |||
510 | static void | ||
511 | bfa_fcs_itnim_timeout(void *arg) | ||
512 | { | ||
513 | struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)arg; | ||
514 | |||
515 | itnim->stats.timeout++; | ||
516 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT); | ||
517 | } | ||
518 | |||
519 | static void | ||
520 | bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim) | ||
521 | { | ||
522 | bfa_itnim_delete(itnim->bfa_itnim); | ||
523 | bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv); | ||
524 | } | ||
525 | |||
526 | |||
527 | |||
528 | /** | ||
529 | * itnim_public FCS ITNIM public interfaces | ||
530 | */ | ||
531 | |||
532 | /** | ||
533 | * Called by rport when a new rport is created. | ||
534 | * | ||
535 | * @param[in] rport - remote port. | ||
536 | */ | ||
537 | struct bfa_fcs_itnim_s * | ||
538 | bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport) | ||
539 | { | ||
540 | struct bfa_fcs_port_s *port = rport->port; | ||
541 | struct bfa_fcs_itnim_s *itnim; | ||
542 | struct bfad_itnim_s *itnim_drv; | ||
543 | struct bfa_itnim_s *bfa_itnim; | ||
544 | |||
545 | /* | ||
546 | * call bfad to allocate the itnim | ||
547 | */ | ||
548 | bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv); | ||
549 | if (itnim == NULL) { | ||
550 | bfa_trc(port->fcs, rport->pwwn); | ||
551 | return NULL; | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * Initialize itnim | ||
556 | */ | ||
557 | itnim->rport = rport; | ||
558 | itnim->fcs = rport->fcs; | ||
559 | itnim->itnim_drv = itnim_drv; | ||
560 | |||
561 | /* | ||
562 | * call BFA to create the itnim | ||
563 | */ | ||
564 | bfa_itnim = bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim); | ||
565 | |||
566 | if (bfa_itnim == NULL) { | ||
567 | bfa_trc(port->fcs, rport->pwwn); | ||
568 | bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv); | ||
569 | bfa_assert(0); | ||
570 | return NULL; | ||
571 | } | ||
572 | |||
573 | itnim->bfa_itnim = bfa_itnim; | ||
574 | itnim->seq_rec = BFA_FALSE; | ||
575 | itnim->rec_support = BFA_FALSE; | ||
576 | itnim->conf_comp = BFA_FALSE; | ||
577 | itnim->task_retry_id = BFA_FALSE; | ||
578 | |||
579 | /* | ||
580 | * Set State machine | ||
581 | */ | ||
582 | bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); | ||
583 | |||
584 | return itnim; | ||
585 | } | ||
586 | |||
587 | /** | ||
588 | * Called by rport to delete the instance of FCPIM. | ||
589 | * | ||
590 | * @param[in] rport - remote port. | ||
591 | */ | ||
592 | void | ||
593 | bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim) | ||
594 | { | ||
595 | bfa_trc(itnim->fcs, itnim->rport->pid); | ||
596 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE); | ||
597 | } | ||
598 | |||
599 | /** | ||
600 | * Notification from rport that PLOGI is complete to initiate FC-4 session. | ||
601 | */ | ||
602 | void | ||
603 | bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim) | ||
604 | { | ||
605 | itnim->stats.onlines++; | ||
606 | |||
607 | if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) { | ||
608 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE); | ||
609 | } else { | ||
610 | /* | ||
611 | * For well known addresses, we set the itnim to initiator | ||
612 | * state | ||
613 | */ | ||
614 | itnim->stats.initiator++; | ||
615 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); | ||
616 | } | ||
617 | } | ||
618 | |||
619 | /** | ||
620 | * Called by rport to handle a remote device offline. | ||
621 | */ | ||
622 | void | ||
623 | bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim) | ||
624 | { | ||
625 | itnim->stats.offlines++; | ||
626 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE); | ||
627 | } | ||
628 | |||
629 | /** | ||
630 | * Called by rport when remote port is known to be an initiator from | ||
631 | * PRLI received. | ||
632 | */ | ||
633 | void | ||
634 | bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim) | ||
635 | { | ||
636 | bfa_trc(itnim->fcs, itnim->rport->pid); | ||
637 | itnim->stats.initiator++; | ||
638 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); | ||
639 | } | ||
640 | |||
641 | /** | ||
642 | * Called by rport to check if the itnim is online. | ||
643 | */ | ||
644 | bfa_status_t | ||
645 | bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim) | ||
646 | { | ||
647 | bfa_trc(itnim->fcs, itnim->rport->pid); | ||
648 | switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) { | ||
649 | case BFA_ITNIM_ONLINE: | ||
650 | case BFA_ITNIM_INITIATIOR: | ||
651 | return BFA_STATUS_OK; | ||
652 | |||
653 | default: | ||
654 | return BFA_STATUS_NO_FCPIM_NEXUS; | ||
655 | |||
656 | } | ||
657 | } | ||
658 | |||
659 | /** | ||
660 | * BFA completion callback for bfa_itnim_online(). | ||
661 | */ | ||
662 | void | ||
663 | bfa_cb_itnim_online(void *cbarg) | ||
664 | { | ||
665 | struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg; | ||
666 | |||
667 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
668 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE); | ||
669 | } | ||
670 | |||
671 | /** | ||
672 | * BFA completion callback for bfa_itnim_offline(). | ||
673 | */ | ||
674 | void | ||
675 | bfa_cb_itnim_offline(void *cb_arg) | ||
676 | { | ||
677 | struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; | ||
678 | |||
679 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
680 | bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE); | ||
681 | } | ||
682 | |||
683 | /** | ||
684 | * Mark the beginning of PATH TOV handling. IO completion callbacks | ||
685 | * are still pending. | ||
686 | */ | ||
687 | void | ||
688 | bfa_cb_itnim_tov_begin(void *cb_arg) | ||
689 | { | ||
690 | struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; | ||
691 | |||
692 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
693 | bfa_fcb_itnim_tov_begin(itnim->itnim_drv); | ||
694 | } | ||
695 | |||
696 | /** | ||
697 | * Mark the end of PATH TOV handling. All pending IOs are already cleaned up. | ||
698 | */ | ||
699 | void | ||
700 | bfa_cb_itnim_tov(void *cb_arg) | ||
701 | { | ||
702 | struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; | ||
703 | |||
704 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
705 | bfa_fcb_itnim_tov(itnim->itnim_drv); | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * BFA notification to FCS/driver for second level error recovery. | ||
710 | * | ||
711 | * Atleast one I/O request has timedout and target is unresponsive to | ||
712 | * repeated abort requests. Second level error recovery should be initiated | ||
713 | * by starting implicit logout and recovery procedures. | ||
714 | */ | ||
715 | void | ||
716 | bfa_cb_itnim_sler(void *cb_arg) | ||
717 | { | ||
718 | struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; | ||
719 | |||
720 | itnim->stats.sler++; | ||
721 | bfa_trc(itnim->fcs, itnim->rport->pwwn); | ||
722 | bfa_fcs_rport_logo_imp(itnim->rport); | ||
723 | } | ||
724 | |||
725 | struct bfa_fcs_itnim_s * | ||
726 | bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn) | ||
727 | { | ||
728 | struct bfa_fcs_rport_s *rport; | ||
729 | rport = bfa_fcs_rport_lookup(port, rpwwn); | ||
730 | |||
731 | if (!rport) | ||
732 | return NULL; | ||
733 | |||
734 | bfa_assert(rport->itnim != NULL); | ||
735 | return (rport->itnim); | ||
736 | } | ||
737 | |||
738 | bfa_status_t | ||
739 | bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, | ||
740 | struct bfa_itnim_attr_s *attr) | ||
741 | { | ||
742 | struct bfa_fcs_itnim_s *itnim = NULL; | ||
743 | |||
744 | itnim = bfa_fcs_itnim_lookup(port, rpwwn); | ||
745 | |||
746 | if (itnim == NULL) | ||
747 | return BFA_STATUS_NO_FCPIM_NEXUS; | ||
748 | |||
749 | attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm); | ||
750 | attr->retry = itnim->seq_rec; | ||
751 | attr->rec_support = itnim->rec_support; | ||
752 | attr->conf_comp = itnim->conf_comp; | ||
753 | attr->task_retry_id = itnim->task_retry_id; | ||
754 | |||
755 | return BFA_STATUS_OK; | ||
756 | } | ||
757 | |||
758 | bfa_status_t | ||
759 | bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, | ||
760 | struct bfa_itnim_stats_s *stats) | ||
761 | { | ||
762 | struct bfa_fcs_itnim_s *itnim = NULL; | ||
763 | |||
764 | bfa_assert(port != NULL); | ||
765 | |||
766 | itnim = bfa_fcs_itnim_lookup(port, rpwwn); | ||
767 | |||
768 | if (itnim == NULL) | ||
769 | return BFA_STATUS_NO_FCPIM_NEXUS; | ||
770 | |||
771 | bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s)); | ||
772 | |||
773 | return BFA_STATUS_OK; | ||
774 | } | ||
775 | |||
776 | bfa_status_t | ||
777 | bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn) | ||
778 | { | ||
779 | struct bfa_fcs_itnim_s *itnim = NULL; | ||
780 | |||
781 | bfa_assert(port != NULL); | ||
782 | |||
783 | itnim = bfa_fcs_itnim_lookup(port, rpwwn); | ||
784 | |||
785 | if (itnim == NULL) | ||
786 | return BFA_STATUS_NO_FCPIM_NEXUS; | ||
787 | |||
788 | bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s)); | ||
789 | return BFA_STATUS_OK; | ||
790 | } | ||
791 | |||
792 | void | ||
793 | bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, | ||
794 | u16 len) | ||
795 | { | ||
796 | struct fc_els_cmd_s *els_cmd; | ||
797 | |||
798 | bfa_trc(itnim->fcs, fchs->type); | ||
799 | |||
800 | if (fchs->type != FC_TYPE_ELS) | ||
801 | return; | ||
802 | |||
803 | els_cmd = (struct fc_els_cmd_s *) (fchs + 1); | ||
804 | |||
805 | bfa_trc(itnim->fcs, els_cmd->els_code); | ||
806 | |||
807 | switch (els_cmd->els_code) { | ||
808 | case FC_ELS_PRLO: | ||
809 | /* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */ | ||
810 | break; | ||
811 | |||
812 | default: | ||
813 | bfa_assert(0); | ||
814 | } | ||
815 | } | ||
816 | |||
817 | void | ||
818 | bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim) | ||
819 | { | ||
820 | } | ||
821 | |||
822 | void | ||
823 | bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim) | ||
824 | { | ||
825 | } | ||
826 | |||
827 | /** | ||
828 | * Module initialization | ||
829 | */ | ||
830 | void | ||
831 | bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs) | ||
832 | { | ||
833 | } | ||
834 | |||
835 | /** | ||
836 | * Module cleanup | ||
837 | */ | ||
838 | void | ||
839 | bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs) | ||
840 | { | ||
841 | bfa_fcs_modexit_comp(fcs); | ||
842 | } | ||
843 | |||
844 | |||