PM / sleep: Asynchronous threads for suspend_noirq
[linux/fpc-iii.git] / drivers / scsi / bfa / bfa_fcs_fcpim.c
blob6dc7926a3edd4d9927199530b57af61554a492d3
1 /*
2 * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
3 * All rights reserved
4 * www.brocade.com
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
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
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.
19 * fcpim.c - FCP initiator mode i-t nexus state machine
22 #include "bfad_drv.h"
23 #include "bfa_fcs.h"
24 #include "bfa_fcbuild.h"
25 #include "bfad_im.h"
27 BFA_TRC_FILE(FCS, FCPIM);
30 * forward declarations
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,
35 struct bfa_fcxp_s *fcxp_alloced);
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);
40 static void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
41 enum bfa_itnim_aen_event event);
43 static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
44 enum bfa_fcs_itnim_event event);
45 static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
46 enum bfa_fcs_itnim_event event);
47 static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
48 enum bfa_fcs_itnim_event event);
49 static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
50 enum bfa_fcs_itnim_event event);
51 static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
52 enum bfa_fcs_itnim_event event);
53 static void bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
54 enum bfa_fcs_itnim_event event);
55 static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
56 enum bfa_fcs_itnim_event event);
57 static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
58 enum bfa_fcs_itnim_event event);
59 static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
60 enum bfa_fcs_itnim_event event);
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},
74 * fcs_itnim_sm FCS itnim state machine
77 static void
78 bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
79 enum bfa_fcs_itnim_event event)
81 bfa_trc(itnim->fcs, itnim->rport->pwwn);
82 bfa_trc(itnim->fcs, event);
84 switch (event) {
85 case BFA_FCS_ITNIM_SM_FCS_ONLINE:
86 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
87 itnim->prli_retries = 0;
88 bfa_fcs_itnim_send_prli(itnim, NULL);
89 break;
91 case BFA_FCS_ITNIM_SM_OFFLINE:
92 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
93 break;
95 case BFA_FCS_ITNIM_SM_INITIATOR:
96 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
97 break;
99 case BFA_FCS_ITNIM_SM_DELETE:
100 bfa_fcs_itnim_free(itnim);
101 break;
103 default:
104 bfa_sm_fault(itnim->fcs, event);
109 static void
110 bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
111 enum bfa_fcs_itnim_event event)
113 bfa_trc(itnim->fcs, itnim->rport->pwwn);
114 bfa_trc(itnim->fcs, event);
116 switch (event) {
117 case BFA_FCS_ITNIM_SM_FRMSENT:
118 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli);
119 break;
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);
124 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
125 break;
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);
130 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
131 break;
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;
139 default:
140 bfa_sm_fault(itnim->fcs, event);
144 static void
145 bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
146 enum bfa_fcs_itnim_event event)
148 bfa_trc(itnim->fcs, itnim->rport->pwwn);
149 bfa_trc(itnim->fcs, event);
151 switch (event) {
152 case BFA_FCS_ITNIM_SM_RSP_OK:
153 if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR)
154 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
155 else
156 bfa_sm_set_state(itnim,
157 bfa_fcs_itnim_sm_hal_rport_online);
159 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
160 break;
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;
169 case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP:
170 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
171 break;
173 case BFA_FCS_ITNIM_SM_OFFLINE:
174 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
175 bfa_fcxp_discard(itnim->fcxp);
176 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
177 break;
179 case BFA_FCS_ITNIM_SM_INITIATOR:
180 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
181 bfa_fcxp_discard(itnim->fcxp);
182 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
183 break;
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;
191 default:
192 bfa_sm_fault(itnim->fcs, event);
196 static void
197 bfa_fcs_itnim_sm_hal_rport_online(struct bfa_fcs_itnim_s *itnim,
198 enum bfa_fcs_itnim_event event)
200 bfa_trc(itnim->fcs, itnim->rport->pwwn);
201 bfa_trc(itnim->fcs, event);
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);
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);
217 break;
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;
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;
229 default:
230 bfa_sm_fault(itnim->fcs, event);
234 static void
235 bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
236 enum bfa_fcs_itnim_event event)
238 bfa_trc(itnim->fcs, itnim->rport->pwwn);
239 bfa_trc(itnim->fcs, event);
241 switch (event) {
242 case BFA_FCS_ITNIM_SM_TIMEOUT:
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);
251 bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
253 break;
256 case BFA_FCS_ITNIM_SM_OFFLINE:
257 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
258 bfa_timer_stop(&itnim->timer);
259 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
260 break;
262 case BFA_FCS_ITNIM_SM_INITIATOR:
263 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
264 bfa_timer_stop(&itnim->timer);
265 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
266 break;
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;
274 default:
275 bfa_sm_fault(itnim->fcs, event);
279 static void
280 bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
281 enum bfa_fcs_itnim_event event)
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];
287 bfa_trc(itnim->fcs, itnim->rport->pwwn);
288 bfa_trc(itnim->fcs, event);
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);
294 wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
295 wwn2str(rpwwn_buf, itnim->rport->pwwn);
296 BFA_LOG(KERN_INFO, bfad, bfa_log_level,
297 "Target (WWN = %s) is online for initiator (WWN = %s)\n",
298 rpwwn_buf, lpwwn_buf);
299 bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
300 break;
302 case BFA_FCS_ITNIM_SM_OFFLINE:
303 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
304 bfa_itnim_offline(itnim->bfa_itnim);
305 break;
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;
312 default:
313 bfa_sm_fault(itnim->fcs, event);
317 static void
318 bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
319 enum bfa_fcs_itnim_event event)
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];
325 bfa_trc(itnim->fcs, itnim->rport->pwwn);
326 bfa_trc(itnim->fcs, event);
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);
333 wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
334 wwn2str(rpwwn_buf, itnim->rport->pwwn);
335 if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) {
336 BFA_LOG(KERN_ERR, bfad, bfa_log_level,
337 "Target (WWN = %s) connectivity lost for "
338 "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
339 bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
340 } else {
341 BFA_LOG(KERN_INFO, bfad, bfa_log_level,
342 "Target (WWN = %s) offlined by initiator (WWN = %s)\n",
343 rpwwn_buf, lpwwn_buf);
344 bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
346 break;
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;
353 default:
354 bfa_sm_fault(itnim->fcs, event);
358 static void
359 bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
360 enum bfa_fcs_itnim_event event)
362 bfa_trc(itnim->fcs, itnim->rport->pwwn);
363 bfa_trc(itnim->fcs, event);
365 switch (event) {
366 case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
367 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
368 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
369 break;
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;
376 default:
377 bfa_sm_fault(itnim->fcs, event);
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.
386 static void
387 bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
388 enum bfa_fcs_itnim_event event)
390 bfa_trc(itnim->fcs, itnim->rport->pwwn);
391 bfa_trc(itnim->fcs, event);
393 switch (event) {
394 case BFA_FCS_ITNIM_SM_OFFLINE:
395 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
396 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE);
397 break;
400 * fcs_online is expected here for well known initiator ports
402 case BFA_FCS_ITNIM_SM_FCS_ONLINE:
403 bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_FCS_ONLINE);
404 break;
406 case BFA_FCS_ITNIM_SM_RSP_ERROR:
407 case BFA_FCS_ITNIM_SM_INITIATOR:
408 break;
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;
415 default:
416 bfa_sm_fault(itnim->fcs, event);
420 static void
421 bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
422 enum bfa_itnim_aen_event event)
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;
428 /* Don't post events for well known addresses */
429 if (BFA_FCS_PID_IS_WKA(rport->pid))
430 return;
432 bfad_get_aen_entry(bfad, aen_entry);
433 if (!aen_entry)
434 return;
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;
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);
447 static void
448 bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
450 struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
451 struct bfa_fcs_rport_s *rport = itnim->rport;
452 struct bfa_fcs_lport_s *port = rport->port;
453 struct fchs_s fchs;
454 struct bfa_fcxp_s *fcxp;
455 int len;
457 bfa_trc(itnim->fcs, itnim->rport->pwwn);
459 fcxp = fcxp_alloced ? fcxp_alloced :
460 bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
461 if (!fcxp) {
462 itnim->stats.fcxp_alloc_wait++;
463 bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
464 bfa_fcs_itnim_send_prli, itnim, BFA_TRUE);
465 return;
467 itnim->fcxp = fcxp;
469 len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
470 itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0);
472 bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
473 BFA_FALSE, FC_CLASS_3, len, &fchs,
474 bfa_fcs_itnim_prli_response, (void *)itnim,
475 FC_MAX_PDUSZ, FC_ELS_TOV);
477 itnim->stats.prli_sent++;
478 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
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)
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;
490 struct fc_prli_params_s *sparams;
492 bfa_trc(itnim->fcs, req_status);
495 * Sanity Checks
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;
503 els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
505 if (els_cmd->els_code == FC_ELS_ACC) {
506 prli_resp = (struct fc_prli_s *) els_cmd;
508 if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
509 bfa_trc(itnim->fcs, rsp_len);
511 * Check if this r-port is also in Initiator mode.
512 * If so, we need to set this ITN as a no-op.
514 if (prli_resp->parampage.servparams.initiator) {
515 bfa_trc(itnim->fcs, prli_resp->parampage.type);
516 itnim->rport->scsi_function =
517 BFA_RPORT_INITIATOR;
518 itnim->stats.prli_rsp_acc++;
519 itnim->stats.initiator++;
520 bfa_sm_send_event(itnim,
521 BFA_FCS_ITNIM_SM_RSP_OK);
522 return;
525 itnim->stats.prli_rsp_parse_err++;
526 return;
528 itnim->rport->scsi_function = BFA_RPORT_TARGET;
530 sparams = &prli_resp->parampage.servparams;
531 itnim->seq_rec = sparams->retry;
532 itnim->rec_support = sparams->rec_support;
533 itnim->task_retry_id = sparams->task_retry_id;
534 itnim->conf_comp = sparams->confirm;
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);
541 bfa_trc(itnim->fcs, ls_rjt->reason_code);
542 bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
544 itnim->stats.prli_rsp_rjt++;
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;
549 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
553 static void
554 bfa_fcs_itnim_timeout(void *arg)
556 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg;
558 itnim->stats.timeout++;
559 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
562 static void
563 bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
565 if (itnim->bfa_itnim) {
566 bfa_itnim_delete(itnim->bfa_itnim);
567 itnim->bfa_itnim = NULL;
570 bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
576 * itnim_public FCS ITNIM public interfaces
580 * Called by rport when a new rport is created.
582 * @param[in] rport - remote port.
584 struct bfa_fcs_itnim_s *
585 bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
587 struct bfa_fcs_lport_s *port = rport->port;
588 struct bfa_fcs_itnim_s *itnim;
589 struct bfad_itnim_s *itnim_drv;
592 * call bfad to allocate the itnim
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;
601 * Initialize itnim
603 itnim->rport = rport;
604 itnim->fcs = rport->fcs;
605 itnim->itnim_drv = itnim_drv;
607 itnim->bfa_itnim = NULL;
608 itnim->seq_rec = BFA_FALSE;
609 itnim->rec_support = BFA_FALSE;
610 itnim->conf_comp = BFA_FALSE;
611 itnim->task_retry_id = BFA_FALSE;
614 * Set State machine
616 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
618 return itnim;
622 * Called by rport to delete the instance of FCPIM.
624 * @param[in] rport - remote port.
626 void
627 bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
629 bfa_trc(itnim->fcs, itnim->rport->pid);
630 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
634 * Notification from rport that PLOGI is complete to initiate FC-4 session.
636 void
637 bfa_fcs_itnim_brp_online(struct bfa_fcs_itnim_s *itnim)
639 itnim->stats.onlines++;
641 if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid))
642 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HAL_ONLINE);
646 * Called by rport to handle a remote device offline.
648 void
649 bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
651 itnim->stats.offlines++;
652 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
656 * Called by rport when remote port is known to be an initiator from
657 * PRLI received.
659 void
660 bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
662 bfa_trc(itnim->fcs, itnim->rport->pid);
663 itnim->stats.initiator++;
664 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
668 * Called by rport to check if the itnim is online.
670 bfa_status_t
671 bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
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;
679 default:
680 return BFA_STATUS_NO_FCPIM_NEXUS;
685 * BFA completion callback for bfa_itnim_online().
687 void
688 bfa_cb_itnim_online(void *cbarg)
690 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg;
692 bfa_trc(itnim->fcs, itnim->rport->pwwn);
693 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
697 * BFA completion callback for bfa_itnim_offline().
699 void
700 bfa_cb_itnim_offline(void *cb_arg)
702 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
704 bfa_trc(itnim->fcs, itnim->rport->pwwn);
705 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
709 * Mark the beginning of PATH TOV handling. IO completion callbacks
710 * are still pending.
712 void
713 bfa_cb_itnim_tov_begin(void *cb_arg)
715 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
717 bfa_trc(itnim->fcs, itnim->rport->pwwn);
721 * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
723 void
724 bfa_cb_itnim_tov(void *cb_arg)
726 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
727 struct bfad_itnim_s *itnim_drv = itnim->itnim_drv;
729 bfa_trc(itnim->fcs, itnim->rport->pwwn);
730 itnim_drv->state = ITNIM_STATE_TIMEOUT;
734 * BFA notification to FCS/driver for second level error recovery.
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.
740 void
741 bfa_cb_itnim_sler(void *cb_arg)
743 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg;
745 itnim->stats.sler++;
746 bfa_trc(itnim->fcs, itnim->rport->pwwn);
747 bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP);
750 struct bfa_fcs_itnim_s *
751 bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
753 struct bfa_fcs_rport_s *rport;
754 rport = bfa_fcs_rport_lookup(port, rpwwn);
756 if (!rport)
757 return NULL;
759 WARN_ON(rport->itnim == NULL);
760 return rport->itnim;
763 bfa_status_t
764 bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
765 struct bfa_itnim_attr_s *attr)
767 struct bfa_fcs_itnim_s *itnim = NULL;
769 itnim = bfa_fcs_itnim_lookup(port, rpwwn);
771 if (itnim == NULL)
772 return BFA_STATUS_NO_FCPIM_NEXUS;
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;
778 attr->task_retry_id = itnim->task_retry_id;
779 return BFA_STATUS_OK;
782 bfa_status_t
783 bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn,
784 struct bfa_itnim_stats_s *stats)
786 struct bfa_fcs_itnim_s *itnim = NULL;
788 WARN_ON(port == NULL);
790 itnim = bfa_fcs_itnim_lookup(port, rpwwn);
792 if (itnim == NULL)
793 return BFA_STATUS_NO_FCPIM_NEXUS;
795 memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
797 return BFA_STATUS_OK;
800 bfa_status_t
801 bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn)
803 struct bfa_fcs_itnim_s *itnim = NULL;
805 WARN_ON(port == NULL);
807 itnim = bfa_fcs_itnim_lookup(port, rpwwn);
809 if (itnim == NULL)
810 return BFA_STATUS_NO_FCPIM_NEXUS;
812 memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
813 return BFA_STATUS_OK;
816 void
817 bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
818 struct fchs_s *fchs, u16 len)
820 struct fc_els_cmd_s *els_cmd;
822 bfa_trc(itnim->fcs, fchs->type);
824 if (fchs->type != FC_TYPE_ELS)
825 return;
827 els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
829 bfa_trc(itnim->fcs, els_cmd->els_code);
831 switch (els_cmd->els_code) {
832 case FC_ELS_PRLO:
833 bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id);
834 break;
836 default:
837 WARN_ON(1);