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