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