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