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