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