1 /* 2 * Copyright (c) 2005-2009 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 * bfa_fcs_port.c BFA FCS port 20 */ 21 22 #include <fcs/bfa_fcs.h> 23 #include <fcs/bfa_fcs_lport.h> 24 #include <fcs/bfa_fcs_rport.h> 25 #include <fcb/bfa_fcb_port.h> 26 #include <bfa_svc.h> 27 #include <log/bfa_log_fcs.h> 28 #include "fcs.h" 29 #include "fcs_lport.h" 30 #include "fcs_vport.h" 31 #include "fcs_rport.h" 32 #include "fcs_fcxp.h" 33 #include "fcs_trcmod.h" 34 #include "lport_priv.h" 35 #include <aen/bfa_aen_lport.h> 36 37 BFA_TRC_FILE(FCS, PORT); 38 39 /** 40 * Forward declarations 41 */ 42 43 static void bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, 44 enum bfa_lport_aen_event event); 45 static void bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, 46 struct fchs_s *rx_fchs, u8 reason_code, 47 u8 reason_code_expl); 48 static void bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, 49 struct fchs_s *rx_fchs, 50 struct fc_logi_s *plogi); 51 static void bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port); 52 static void bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port); 53 static void bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port); 54 static void bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port); 55 static void bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port); 56 static void bfa_fcs_port_deleted(struct bfa_fcs_port_s *port); 57 static void bfa_fcs_port_echo(struct bfa_fcs_port_s *port, 58 struct fchs_s *rx_fchs, 59 struct fc_echo_s *echo, u16 len); 60 static void bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, 61 struct fchs_s *rx_fchs, 62 struct fc_rnid_cmd_s *rnid, u16 len); 63 static void bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, 64 struct fc_rnid_general_topology_data_s *gen_topo_data); 65 66 static struct { 67 void (*init) (struct bfa_fcs_port_s *port); 68 void (*online) (struct bfa_fcs_port_s *port); 69 void (*offline) (struct bfa_fcs_port_s *port); 70 } __port_action[] = { 71 { 72 bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online, 73 bfa_fcs_port_unknown_offline}, { 74 bfa_fcs_port_fab_init, bfa_fcs_port_fab_online, 75 bfa_fcs_port_fab_offline}, { 76 bfa_fcs_port_loop_init, bfa_fcs_port_loop_online, 77 bfa_fcs_port_loop_offline}, { 78 bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online, 79 bfa_fcs_port_n2n_offline},}; 80 81 /** 82 * fcs_port_sm FCS logical port state machine 83 */ 84 85 enum bfa_fcs_port_event { 86 BFA_FCS_PORT_SM_CREATE = 1, 87 BFA_FCS_PORT_SM_ONLINE = 2, 88 BFA_FCS_PORT_SM_OFFLINE = 3, 89 BFA_FCS_PORT_SM_DELETE = 4, 90 BFA_FCS_PORT_SM_DELRPORT = 5, 91 }; 92 93 static void bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, 94 enum bfa_fcs_port_event event); 95 static void bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, 96 enum bfa_fcs_port_event event); 97 static void bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, 98 enum bfa_fcs_port_event event); 99 static void bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, 100 enum bfa_fcs_port_event event); 101 static void bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, 102 enum bfa_fcs_port_event event); 103 104 static void 105 bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, 106 enum bfa_fcs_port_event event) 107 { 108 bfa_trc(port->fcs, port->port_cfg.pwwn); 109 bfa_trc(port->fcs, event); 110 111 switch (event) { 112 case BFA_FCS_PORT_SM_CREATE: 113 bfa_sm_set_state(port, bfa_fcs_port_sm_init); 114 break; 115 116 default: 117 bfa_assert(0); 118 } 119 } 120 121 static void 122 bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) 123 { 124 bfa_trc(port->fcs, port->port_cfg.pwwn); 125 bfa_trc(port->fcs, event); 126 127 switch (event) { 128 case BFA_FCS_PORT_SM_ONLINE: 129 bfa_sm_set_state(port, bfa_fcs_port_sm_online); 130 bfa_fcs_port_online_actions(port); 131 break; 132 133 case BFA_FCS_PORT_SM_DELETE: 134 bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); 135 bfa_fcs_port_deleted(port); 136 break; 137 138 default: 139 bfa_assert(0); 140 } 141 } 142 143 static void 144 bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, 145 enum bfa_fcs_port_event event) 146 { 147 struct bfa_fcs_rport_s *rport; 148 struct list_head *qe, *qen; 149 150 bfa_trc(port->fcs, port->port_cfg.pwwn); 151 bfa_trc(port->fcs, event); 152 153 switch (event) { 154 case BFA_FCS_PORT_SM_OFFLINE: 155 bfa_sm_set_state(port, bfa_fcs_port_sm_offline); 156 bfa_fcs_port_offline_actions(port); 157 break; 158 159 case BFA_FCS_PORT_SM_DELETE: 160 161 __port_action[port->fabric->fab_type].offline(port); 162 163 if (port->num_rports == 0) { 164 bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); 165 bfa_fcs_port_deleted(port); 166 } else { 167 bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); 168 list_for_each_safe(qe, qen, &port->rport_q) { 169 rport = (struct bfa_fcs_rport_s *)qe; 170 bfa_fcs_rport_delete(rport); 171 } 172 } 173 break; 174 175 case BFA_FCS_PORT_SM_DELRPORT: 176 break; 177 178 default: 179 bfa_assert(0); 180 } 181 } 182 183 static void 184 bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, 185 enum bfa_fcs_port_event event) 186 { 187 struct bfa_fcs_rport_s *rport; 188 struct list_head *qe, *qen; 189 190 bfa_trc(port->fcs, port->port_cfg.pwwn); 191 bfa_trc(port->fcs, event); 192 193 switch (event) { 194 case BFA_FCS_PORT_SM_ONLINE: 195 bfa_sm_set_state(port, bfa_fcs_port_sm_online); 196 bfa_fcs_port_online_actions(port); 197 break; 198 199 case BFA_FCS_PORT_SM_DELETE: 200 if (port->num_rports == 0) { 201 bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); 202 bfa_fcs_port_deleted(port); 203 } else { 204 bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); 205 list_for_each_safe(qe, qen, &port->rport_q) { 206 rport = (struct bfa_fcs_rport_s *)qe; 207 bfa_fcs_rport_delete(rport); 208 } 209 } 210 break; 211 212 case BFA_FCS_PORT_SM_DELRPORT: 213 case BFA_FCS_PORT_SM_OFFLINE: 214 break; 215 216 default: 217 bfa_assert(0); 218 } 219 } 220 221 static void 222 bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, 223 enum bfa_fcs_port_event event) 224 { 225 bfa_trc(port->fcs, port->port_cfg.pwwn); 226 bfa_trc(port->fcs, event); 227 228 switch (event) { 229 case BFA_FCS_PORT_SM_DELRPORT: 230 if (port->num_rports == 0) { 231 bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); 232 bfa_fcs_port_deleted(port); 233 } 234 break; 235 236 default: 237 bfa_assert(0); 238 } 239 } 240 241 242 243 /** 244 * fcs_port_pvt 245 */ 246 247 /** 248 * Send AEN notification 249 */ 250 static void 251 bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, 252 enum bfa_lport_aen_event event) 253 { 254 union bfa_aen_data_u aen_data; 255 struct bfa_log_mod_s *logmod = port->fcs->logm; 256 enum bfa_port_role role = port->port_cfg.roles; 257 wwn_t lpwwn = bfa_fcs_port_get_pwwn(port); 258 char lpwwn_ptr[BFA_STRING_32]; 259 char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] = 260 { "Initiator", "Target", "IPFC" }; 261 262 wwn2str(lpwwn_ptr, lpwwn); 263 264 bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX); 265 266 switch (event) { 267 case BFA_LPORT_AEN_ONLINE: 268 bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr, 269 role_str[role / 2]); 270 break; 271 case BFA_LPORT_AEN_OFFLINE: 272 bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr, 273 role_str[role / 2]); 274 break; 275 case BFA_LPORT_AEN_NEW: 276 bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr, 277 role_str[role / 2]); 278 break; 279 case BFA_LPORT_AEN_DELETE: 280 bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr, 281 role_str[role / 2]); 282 break; 283 case BFA_LPORT_AEN_DISCONNECT: 284 bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr, 285 role_str[role / 2]); 286 break; 287 default: 288 break; 289 } 290 291 aen_data.lport.vf_id = port->fabric->vf_id; 292 aen_data.lport.roles = role; 293 aen_data.lport.ppwwn = 294 bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); 295 aen_data.lport.lpwwn = lpwwn; 296 } 297 298 /* 299 * Send a LS reject 300 */ 301 static void 302 bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, 303 u8 reason_code, u8 reason_code_expl) 304 { 305 struct fchs_s fchs; 306 struct bfa_fcxp_s *fcxp; 307 struct bfa_rport_s *bfa_rport = NULL; 308 int len; 309 310 bfa_trc(port->fcs, rx_fchs->s_id); 311 312 fcxp = bfa_fcs_fcxp_alloc(port->fcs); 313 if (!fcxp) 314 return; 315 316 len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, 317 bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, 318 reason_code, reason_code_expl); 319 320 bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, 321 BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, 322 FC_MAX_PDUSZ, 0); 323 } 324 325 /** 326 * Process incoming plogi from a remote port. 327 */ 328 static void 329 bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, 330 struct fc_logi_s *plogi) 331 { 332 struct bfa_fcs_rport_s *rport; 333 334 bfa_trc(port->fcs, rx_fchs->d_id); 335 bfa_trc(port->fcs, rx_fchs->s_id); 336 337 /* 338 * If min cfg mode is enabled, drop any incoming PLOGIs 339 */ 340 if (__fcs_min_cfg(port->fcs)) { 341 bfa_trc(port->fcs, rx_fchs->s_id); 342 return; 343 } 344 345 if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) { 346 bfa_trc(port->fcs, rx_fchs->s_id); 347 /* 348 * send a LS reject 349 */ 350 bfa_fcs_port_send_ls_rjt(port, rx_fchs, 351 FC_LS_RJT_RSN_PROTOCOL_ERROR, 352 FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS); 353 return; 354 } 355 356 /** 357 * Direct Attach P2P mode : verify address assigned by the r-port. 358 */ 359 if ((!bfa_fcs_fabric_is_switched(port->fabric)) 360 && 361 (memcmp 362 ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name, 363 sizeof(wwn_t)) < 0)) { 364 if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) { 365 /* 366 * Address assigned to us cannot be a WKA 367 */ 368 bfa_fcs_port_send_ls_rjt(port, rx_fchs, 369 FC_LS_RJT_RSN_PROTOCOL_ERROR, 370 FC_LS_RJT_EXP_INVALID_NPORT_ID); 371 return; 372 } 373 port->pid = rx_fchs->d_id; 374 } 375 376 /** 377 * First, check if we know the device by pwwn. 378 */ 379 rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name); 380 if (rport) { 381 /** 382 * Direct Attach P2P mode: handle address assigned by the rport. 383 */ 384 if ((!bfa_fcs_fabric_is_switched(port->fabric)) 385 && 386 (memcmp 387 ((void *)&bfa_fcs_port_get_pwwn(port), 388 (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { 389 port->pid = rx_fchs->d_id; 390 rport->pid = rx_fchs->s_id; 391 } 392 bfa_fcs_rport_plogi(rport, rx_fchs, plogi); 393 return; 394 } 395 396 /** 397 * Next, lookup rport by PID. 398 */ 399 rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id); 400 if (!rport) { 401 /** 402 * Inbound PLOGI from a new device. 403 */ 404 bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); 405 return; 406 } 407 408 /** 409 * Rport is known only by PID. 410 */ 411 if (rport->pwwn) { 412 /** 413 * This is a different device with the same pid. Old device 414 * disappeared. Send implicit LOGO to old device. 415 */ 416 bfa_assert(rport->pwwn != plogi->port_name); 417 bfa_fcs_rport_logo_imp(rport); 418 419 /** 420 * Inbound PLOGI from a new device (with old PID). 421 */ 422 bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); 423 return; 424 } 425 426 /** 427 * PLOGI crossing each other. 428 */ 429 bfa_assert(rport->pwwn == WWN_NULL); 430 bfa_fcs_rport_plogi(rport, rx_fchs, plogi); 431 } 432 433 /* 434 * Process incoming ECHO. 435 * Since it does not require a login, it is processed here. 436 */ 437 static void 438 bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, 439 struct fc_echo_s *echo, u16 rx_len) 440 { 441 struct fchs_s fchs; 442 struct bfa_fcxp_s *fcxp; 443 struct bfa_rport_s *bfa_rport = NULL; 444 int len, pyld_len; 445 446 bfa_trc(port->fcs, rx_fchs->s_id); 447 bfa_trc(port->fcs, rx_fchs->d_id); 448 bfa_trc(port->fcs, rx_len); 449 450 fcxp = bfa_fcs_fcxp_alloc(port->fcs); 451 if (!fcxp) 452 return; 453 454 len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, 455 bfa_fcs_port_get_fcid(port), rx_fchs->ox_id); 456 457 /* 458 * Copy the payload (if any) from the echo frame 459 */ 460 pyld_len = rx_len - sizeof(struct fchs_s); 461 bfa_trc(port->fcs, pyld_len); 462 463 if (pyld_len > len) 464 memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) + 465 sizeof(struct fc_echo_s), (echo + 1), 466 (pyld_len - sizeof(struct fc_echo_s))); 467 468 bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, 469 BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL, 470 FC_MAX_PDUSZ, 0); 471 } 472 473 /* 474 * Process incoming RNID. 475 * Since it does not require a login, it is processed here. 476 */ 477 static void 478 bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, 479 struct fc_rnid_cmd_s *rnid, u16 rx_len) 480 { 481 struct fc_rnid_common_id_data_s common_id_data; 482 struct fc_rnid_general_topology_data_s gen_topo_data; 483 struct fchs_s fchs; 484 struct bfa_fcxp_s *fcxp; 485 struct bfa_rport_s *bfa_rport = NULL; 486 u16 len; 487 u32 data_format; 488 489 bfa_trc(port->fcs, rx_fchs->s_id); 490 bfa_trc(port->fcs, rx_fchs->d_id); 491 bfa_trc(port->fcs, rx_len); 492 493 fcxp = bfa_fcs_fcxp_alloc(port->fcs); 494 if (!fcxp) 495 return; 496 497 /* 498 * Check Node Indentification Data Format 499 * We only support General Topology Discovery Format. 500 * For any other requested Data Formats, we return Common Node Id Data 501 * only, as per FC-LS. 502 */ 503 bfa_trc(port->fcs, rnid->node_id_data_format); 504 if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) { 505 data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY; 506 /* 507 * Get General topology data for this port 508 */ 509 bfa_fs_port_get_gen_topo_data(port, &gen_topo_data); 510 } else { 511 data_format = RNID_NODEID_DATA_FORMAT_COMMON; 512 } 513 514 /* 515 * Copy the Node Id Info 516 */ 517 common_id_data.port_name = bfa_fcs_port_get_pwwn(port); 518 common_id_data.node_name = bfa_fcs_port_get_nwwn(port); 519 520 len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, 521 bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, 522 data_format, &common_id_data, &gen_topo_data); 523 524 bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, 525 BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, 526 FC_MAX_PDUSZ, 0); 527 528 return; 529 } 530 531 /* 532 * Fill out General Topolpgy Discovery Data for RNID ELS. 533 */ 534 static void 535 bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, 536 struct fc_rnid_general_topology_data_s *gen_topo_data) 537 { 538 539 bfa_os_memset(gen_topo_data, 0, 540 sizeof(struct fc_rnid_general_topology_data_s)); 541 542 gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST); 543 gen_topo_data->phy_port_num = 0; /* @todo */ 544 gen_topo_data->num_attached_nodes = bfa_os_htonl(1); 545 } 546 547 static void 548 bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port) 549 { 550 bfa_trc(port->fcs, port->fabric->oper_type); 551 552 __port_action[port->fabric->fab_type].init(port); 553 __port_action[port->fabric->fab_type].online(port); 554 555 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE); 556 bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles, 557 port->fabric->vf_drv, (port->vport == NULL) ? 558 NULL : port->vport->vport_drv); 559 } 560 561 static void 562 bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port) 563 { 564 struct list_head *qe, *qen; 565 struct bfa_fcs_rport_s *rport; 566 567 bfa_trc(port->fcs, port->fabric->oper_type); 568 569 __port_action[port->fabric->fab_type].offline(port); 570 571 if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) 572 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT); 573 else 574 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE); 575 bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles, 576 port->fabric->vf_drv, 577 (port->vport == NULL) ? NULL : port->vport->vport_drv); 578 579 list_for_each_safe(qe, qen, &port->rport_q) { 580 rport = (struct bfa_fcs_rport_s *)qe; 581 bfa_fcs_rport_offline(rport); 582 } 583 } 584 585 static void 586 bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port) 587 { 588 bfa_assert(0); 589 } 590 591 static void 592 bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port) 593 { 594 bfa_assert(0); 595 } 596 597 static void 598 bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port) 599 { 600 bfa_assert(0); 601 } 602 603 static void 604 bfa_fcs_port_deleted(struct bfa_fcs_port_s *port) 605 { 606 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE); 607 608 /* 609 * Base port will be deleted by the OS driver 610 */ 611 if (port->vport) { 612 bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles, 613 port->fabric->vf_drv, 614 port->vport ? port->vport->vport_drv : NULL); 615 bfa_fcs_vport_delete_comp(port->vport); 616 } else { 617 bfa_fcs_fabric_port_delete_comp(port->fabric); 618 } 619 } 620 621 622 623 /** 624 * fcs_lport_api BFA FCS port API 625 */ 626 /** 627 * Module initialization 628 */ 629 void 630 bfa_fcs_port_modinit(struct bfa_fcs_s *fcs) 631 { 632 633 } 634 635 /** 636 * Module cleanup 637 */ 638 void 639 bfa_fcs_port_modexit(struct bfa_fcs_s *fcs) 640 { 641 bfa_fcs_modexit_comp(fcs); 642 } 643 644 /** 645 * Unsolicited frame receive handling. 646 */ 647 void 648 bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, 649 u16 len) 650 { 651 u32 pid = fchs->s_id; 652 struct bfa_fcs_rport_s *rport = NULL; 653 struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); 654 655 bfa_stats(lport, uf_recvs); 656 657 if (!bfa_fcs_port_is_online(lport)) { 658 bfa_stats(lport, uf_recv_drops); 659 return; 660 } 661 662 /** 663 * First, handle ELSs that donot require a login. 664 */ 665 /* 666 * Handle PLOGI first 667 */ 668 if ((fchs->type == FC_TYPE_ELS) && 669 (els_cmd->els_code == FC_ELS_PLOGI)) { 670 bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd); 671 return; 672 } 673 674 /* 675 * Handle ECHO separately. 676 */ 677 if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) { 678 bfa_fcs_port_echo(lport, fchs, 679 (struct fc_echo_s *) els_cmd, len); 680 return; 681 } 682 683 /* 684 * Handle RNID separately. 685 */ 686 if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) { 687 bfa_fcs_port_rnid(lport, fchs, 688 (struct fc_rnid_cmd_s *) els_cmd, len); 689 return; 690 } 691 692 /** 693 * look for a matching remote port ID 694 */ 695 rport = bfa_fcs_port_get_rport_by_pid(lport, pid); 696 if (rport) { 697 bfa_trc(rport->fcs, fchs->s_id); 698 bfa_trc(rport->fcs, fchs->d_id); 699 bfa_trc(rport->fcs, fchs->type); 700 701 bfa_fcs_rport_uf_recv(rport, fchs, len); 702 return; 703 } 704 705 /** 706 * Only handles ELS frames for now. 707 */ 708 if (fchs->type != FC_TYPE_ELS) { 709 bfa_trc(lport->fcs, fchs->type); 710 bfa_assert(0); 711 return; 712 } 713 714 bfa_trc(lport->fcs, els_cmd->els_code); 715 if (els_cmd->els_code == FC_ELS_RSCN) { 716 bfa_fcs_port_scn_process_rscn(lport, fchs, len); 717 return; 718 } 719 720 if (els_cmd->els_code == FC_ELS_LOGO) { 721 /** 722 * @todo Handle LOGO frames received. 723 */ 724 bfa_trc(lport->fcs, els_cmd->els_code); 725 return; 726 } 727 728 if (els_cmd->els_code == FC_ELS_PRLI) { 729 /** 730 * @todo Handle PRLI frames received. 731 */ 732 bfa_trc(lport->fcs, els_cmd->els_code); 733 return; 734 } 735 736 /** 737 * Unhandled ELS frames. Send a LS_RJT. 738 */ 739 bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, 740 FC_LS_RJT_EXP_NO_ADDL_INFO); 741 742 } 743 744 /** 745 * PID based Lookup for a R-Port in the Port R-Port Queue 746 */ 747 struct bfa_fcs_rport_s * 748 bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid) 749 { 750 struct bfa_fcs_rport_s *rport; 751 struct list_head *qe; 752 753 list_for_each(qe, &port->rport_q) { 754 rport = (struct bfa_fcs_rport_s *)qe; 755 if (rport->pid == pid) 756 return rport; 757 } 758 759 bfa_trc(port->fcs, pid); 760 return NULL; 761 } 762 763 /** 764 * PWWN based Lookup for a R-Port in the Port R-Port Queue 765 */ 766 struct bfa_fcs_rport_s * 767 bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn) 768 { 769 struct bfa_fcs_rport_s *rport; 770 struct list_head *qe; 771 772 list_for_each(qe, &port->rport_q) { 773 rport = (struct bfa_fcs_rport_s *)qe; 774 if (wwn_is_equal(rport->pwwn, pwwn)) 775 return rport; 776 } 777 778 bfa_trc(port->fcs, pwwn); 779 return NULL; 780 } 781 782 /** 783 * NWWN based Lookup for a R-Port in the Port R-Port Queue 784 */ 785 struct bfa_fcs_rport_s * 786 bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn) 787 { 788 struct bfa_fcs_rport_s *rport; 789 struct list_head *qe; 790 791 list_for_each(qe, &port->rport_q) { 792 rport = (struct bfa_fcs_rport_s *)qe; 793 if (wwn_is_equal(rport->nwwn, nwwn)) 794 return rport; 795 } 796 797 bfa_trc(port->fcs, nwwn); 798 return NULL; 799 } 800 801 /** 802 * Called by rport module when new rports are discovered. 803 */ 804 void 805 bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, 806 struct bfa_fcs_rport_s *rport) 807 { 808 list_add_tail(&rport->qe, &port->rport_q); 809 port->num_rports++; 810 } 811 812 /** 813 * Called by rport module to when rports are deleted. 814 */ 815 void 816 bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, 817 struct bfa_fcs_rport_s *rport) 818 { 819 bfa_assert(bfa_q_is_on_q(&port->rport_q, rport)); 820 list_del(&rport->qe); 821 port->num_rports--; 822 823 bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT); 824 } 825 826 /** 827 * Called by fabric for base port when fabric login is complete. 828 * Called by vport for virtual ports when FDISC is complete. 829 */ 830 void 831 bfa_fcs_port_online(struct bfa_fcs_port_s *port) 832 { 833 bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE); 834 } 835 836 /** 837 * Called by fabric for base port when fabric goes offline. 838 * Called by vport for virtual ports when virtual port becomes offline. 839 */ 840 void 841 bfa_fcs_port_offline(struct bfa_fcs_port_s *port) 842 { 843 bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE); 844 } 845 846 /** 847 * Called by fabric to delete base lport and associated resources. 848 * 849 * Called by vport to delete lport and associated resources. Should call 850 * bfa_fcs_vport_delete_comp() for vports on completion. 851 */ 852 void 853 bfa_fcs_port_delete(struct bfa_fcs_port_s *port) 854 { 855 bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE); 856 } 857 858 /** 859 * Called by fabric in private loop topology to process LIP event. 860 */ 861 void 862 bfa_fcs_port_lip(struct bfa_fcs_port_s *port) 863 { 864 } 865 866 /** 867 * Return TRUE if port is online, else return FALSE 868 */ 869 bfa_boolean_t 870 bfa_fcs_port_is_online(struct bfa_fcs_port_s *port) 871 { 872 return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online); 873 } 874 875 /** 876 * Logical port initialization of base or virtual port. 877 * Called by fabric for base port or by vport for virtual ports. 878 */ 879 void 880 bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, 881 u16 vf_id, struct bfa_port_cfg_s *port_cfg, 882 struct bfa_fcs_vport_s *vport) 883 { 884 lport->fcs = fcs; 885 lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); 886 bfa_os_assign(lport->port_cfg, *port_cfg); 887 lport->vport = vport; 888 lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) : 889 bfa_lps_get_tag(lport->fabric->lps); 890 891 INIT_LIST_HEAD(&lport->rport_q); 892 lport->num_rports = 0; 893 894 lport->bfad_port = 895 bfa_fcb_port_new(fcs->bfad, lport, lport->port_cfg.roles, 896 lport->fabric->vf_drv, 897 vport ? vport->vport_drv : NULL); 898 bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW); 899 900 bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit); 901 bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE); 902 } 903 904 905 906 /** 907 * fcs_lport_api 908 */ 909 910 void 911 bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, 912 struct bfa_port_attr_s *port_attr) 913 { 914 if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online)) 915 port_attr->pid = port->pid; 916 else 917 port_attr->pid = 0; 918 919 port_attr->port_cfg = port->port_cfg; 920 921 if (port->fabric) { 922 port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric); 923 port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric); 924 port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port); 925 memcpy(port_attr->fabric_ip_addr, 926 bfa_fcs_port_get_fabric_ipaddr(port), 927 BFA_FCS_FABRIC_IPADDR_SZ); 928 929 if (port->vport != NULL) 930 port_attr->port_type = BFA_PPORT_TYPE_VPORT; 931 932 } else { 933 port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN; 934 port_attr->state = BFA_PORT_UNINIT; 935 } 936 937 } 938 939 940