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