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 } 834