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 int ret; 592 593 /* 594 * call bfad to allocate the itnim 595 */ 596 ret = bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv); 597 if (ret) { 598 bfa_trc(port->fcs, rport->pwwn); 599 return NULL; 600 } 601 602 /* 603 * Initialize itnim 604 */ 605 itnim->rport = rport; 606 itnim->fcs = rport->fcs; 607 itnim->itnim_drv = itnim_drv; 608 609 itnim->bfa_itnim = NULL; 610 itnim->seq_rec = BFA_FALSE; 611 itnim->rec_support = BFA_FALSE; 612 itnim->conf_comp = BFA_FALSE; 613 itnim->task_retry_id = BFA_FALSE; 614 615 /* 616 * Set State machine 617 */ 618 bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); 619 620 return itnim; 621 } 622 623 /* 624 * Called by rport to delete the instance of FCPIM. 625 * 626 * @param[in] rport - remote port. 627 */ 628 void 629 bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim) 630 { 631 bfa_trc(itnim->fcs, itnim->rport->pid); 632 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE); 633 } 634 635 /* 636 * Notification from rport that PLOGI is complete to initiate FC-4 session. 637 */ 638 void 639 bfa_fcs_itnim_brp_online(struct bfa_fcs_itnim_s *itnim) 640 { 641 itnim->stats.onlines++; 642 643 if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) 644 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HAL_ONLINE); 645 } 646 647 /* 648 * Called by rport to handle a remote device offline. 649 */ 650 void 651 bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim) 652 { 653 itnim->stats.offlines++; 654 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE); 655 } 656 657 /* 658 * Called by rport when remote port is known to be an initiator from 659 * PRLI received. 660 */ 661 void 662 bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim) 663 { 664 bfa_trc(itnim->fcs, itnim->rport->pid); 665 itnim->stats.initiator++; 666 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); 667 } 668 669 /* 670 * Called by rport to check if the itnim is online. 671 */ 672 bfa_status_t 673 bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim) 674 { 675 bfa_trc(itnim->fcs, itnim->rport->pid); 676 switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) { 677 case BFA_ITNIM_ONLINE: 678 case BFA_ITNIM_INITIATIOR: 679 return BFA_STATUS_OK; 680 681 default: 682 return BFA_STATUS_NO_FCPIM_NEXUS; 683 } 684 } 685 686 /* 687 * BFA completion callback for bfa_itnim_online(). 688 */ 689 void 690 bfa_cb_itnim_online(void *cbarg) 691 { 692 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg; 693 694 bfa_trc(itnim->fcs, itnim->rport->pwwn); 695 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE); 696 } 697 698 /* 699 * BFA completion callback for bfa_itnim_offline(). 700 */ 701 void 702 bfa_cb_itnim_offline(void *cb_arg) 703 { 704 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; 705 706 bfa_trc(itnim->fcs, itnim->rport->pwwn); 707 bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE); 708 } 709 710 /* 711 * Mark the beginning of PATH TOV handling. IO completion callbacks 712 * are still pending. 713 */ 714 void 715 bfa_cb_itnim_tov_begin(void *cb_arg) 716 { 717 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; 718 719 bfa_trc(itnim->fcs, itnim->rport->pwwn); 720 } 721 722 /* 723 * Mark the end of PATH TOV handling. All pending IOs are already cleaned up. 724 */ 725 void 726 bfa_cb_itnim_tov(void *cb_arg) 727 { 728 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; 729 struct bfad_itnim_s *itnim_drv = itnim->itnim_drv; 730 731 bfa_trc(itnim->fcs, itnim->rport->pwwn); 732 itnim_drv->state = ITNIM_STATE_TIMEOUT; 733 } 734 735 /* 736 * BFA notification to FCS/driver for second level error recovery. 737 * 738 * Atleast one I/O request has timedout and target is unresponsive to 739 * repeated abort requests. Second level error recovery should be initiated 740 * by starting implicit logout and recovery procedures. 741 */ 742 void 743 bfa_cb_itnim_sler(void *cb_arg) 744 { 745 struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; 746 747 itnim->stats.sler++; 748 bfa_trc(itnim->fcs, itnim->rport->pwwn); 749 bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP); 750 } 751 752 struct bfa_fcs_itnim_s * 753 bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn) 754 { 755 struct bfa_fcs_rport_s *rport; 756 rport = bfa_fcs_rport_lookup(port, rpwwn); 757 758 if (!rport) 759 return NULL; 760 761 WARN_ON(rport->itnim == NULL); 762 return rport->itnim; 763 } 764 765 bfa_status_t 766 bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, 767 struct bfa_itnim_attr_s *attr) 768 { 769 struct bfa_fcs_itnim_s *itnim = NULL; 770 771 itnim = bfa_fcs_itnim_lookup(port, rpwwn); 772 773 if (itnim == NULL) 774 return BFA_STATUS_NO_FCPIM_NEXUS; 775 776 attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm); 777 attr->retry = itnim->seq_rec; 778 attr->rec_support = itnim->rec_support; 779 attr->conf_comp = itnim->conf_comp; 780 attr->task_retry_id = itnim->task_retry_id; 781 return BFA_STATUS_OK; 782 } 783 784 bfa_status_t 785 bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, 786 struct bfa_itnim_stats_s *stats) 787 { 788 struct bfa_fcs_itnim_s *itnim = NULL; 789 790 WARN_ON(port == NULL); 791 792 itnim = bfa_fcs_itnim_lookup(port, rpwwn); 793 794 if (itnim == NULL) 795 return BFA_STATUS_NO_FCPIM_NEXUS; 796 797 memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s)); 798 799 return BFA_STATUS_OK; 800 } 801 802 bfa_status_t 803 bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn) 804 { 805 struct bfa_fcs_itnim_s *itnim = NULL; 806 807 WARN_ON(port == NULL); 808 809 itnim = bfa_fcs_itnim_lookup(port, rpwwn); 810 811 if (itnim == NULL) 812 return BFA_STATUS_NO_FCPIM_NEXUS; 813 814 memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s)); 815 return BFA_STATUS_OK; 816 } 817 818 void 819 bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, 820 struct fchs_s *fchs, u16 len) 821 { 822 struct fc_els_cmd_s *els_cmd; 823 824 bfa_trc(itnim->fcs, fchs->type); 825 826 if (fchs->type != FC_TYPE_ELS) 827 return; 828 829 els_cmd = (struct fc_els_cmd_s *) (fchs + 1); 830 831 bfa_trc(itnim->fcs, els_cmd->els_code); 832 833 switch (els_cmd->els_code) { 834 case FC_ELS_PRLO: 835 bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id); 836 break; 837 838 default: 839 WARN_ON(1); 840 } 841 } 842