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