Merge tag 'drm-intel-fixes-2014-02-14' of ssh://git.freedesktop.org/git/drm-intel...
[linux-2.6-block.git] / drivers / scsi / bfa / bfa_fcs_fcpim.c
CommitLineData
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
27BFA_TRC_FILE(FCS, FCPIM);
28
29/*
30 * forward declarations
31 */
a36c61f9
KG
32static void bfa_fcs_itnim_timeout(void *arg);
33static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
34static void bfa_fcs_itnim_send_prli(void *itnim_cbarg,
7725ccfd 35 struct bfa_fcxp_s *fcxp_alloced);
a36c61f9
KG
36static 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
40static void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
41 enum bfa_itnim_aen_event event);
7725ccfd 42
a36c61f9 43static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
7725ccfd 44 enum bfa_fcs_itnim_event event);
a36c61f9 45static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
7725ccfd 46 enum bfa_fcs_itnim_event event);
a36c61f9 47static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
7725ccfd 48 enum bfa_fcs_itnim_event event);
a36c61f9 49static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
7725ccfd 50 enum bfa_fcs_itnim_event event);
a36c61f9 51static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
7725ccfd 52 enum bfa_fcs_itnim_event event);
61ba4394
KG
53static void bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
54 enum bfa_fcs_itnim_event event);
a36c61f9 55static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
7725ccfd 56 enum bfa_fcs_itnim_event event);
a36c61f9 57static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
7725ccfd 58 enum bfa_fcs_itnim_event event);
a36c61f9 59static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
7725ccfd
JH
60 enum bfa_fcs_itnim_event event);
61
62static 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
77static void
78bfa_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
109static void
110bfa_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
144static void
145bfa_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
196static void
197bfa_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
234static void
235bfa_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
279static void
280bfa_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
317static void
318bfa_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
358static void
359bfa_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 */
386static void
387bfa_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
420static void
421bfa_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
447static void
448bfa_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
481static void
482bfa_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
553static void
554bfa_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
562static void
563bfa_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 */
584struct bfa_fcs_itnim_s *
585bfa_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 */
626void
627bfa_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 */
636void
61ba4394 637bfa_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 */
648void
649bfa_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 */
659void
660bfa_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 */
670bfa_status_t
671bfa_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 */
687void
688bfa_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 */
699void
700bfa_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 */
712void
713bfa_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 */
723void
724bfa_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 */
740void
741bfa_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
750struct bfa_fcs_itnim_s *
a36c61f9 751bfa_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
763bfa_status_t
a36c61f9 764bfa_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
782bfa_status_t
a36c61f9 783bfa_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
800bfa_status_t
a36c61f9 801bfa_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
816void
a36c61f9
KG
817bfa_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}