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