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 } 576 bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles, 577 port->fabric->vf_drv, 578 (port->vport == NULL) ? NULL : port->vport->vport_drv); 579 580 list_for_each_safe(qe, qen, &port->rport_q) { 581 rport = (struct bfa_fcs_rport_s *)qe; 582 bfa_fcs_rport_offline(rport); 583 } 584 } 585 586 static void 587 bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port) 588 { 589 bfa_assert(0); 590 } 591 592 static void 593 bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port) 594 { 595 bfa_assert(0); 596 } 597 598 static void 599 bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port) 600 { 601 bfa_assert(0); 602 } 603 604 static void 605 bfa_fcs_port_deleted(struct bfa_fcs_port_s *port) 606 { 607 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE); 608 609 /* 610 * Base port will be deleted by the OS driver 611 */ 612 if (port->vport) { 613 bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles, 614 port->fabric->vf_drv, 615 port->vport ? port->vport->vport_drv : NULL); 616 bfa_fcs_vport_delete_comp(port->vport); 617 } else { 618 bfa_fcs_fabric_port_delete_comp(port->fabric); 619 } 620 } 621 622 623 624 /** 625 * fcs_lport_api BFA FCS port API 626 */ 627 /** 628 * Module initialization 629 */ 630 void 631 bfa_fcs_port_modinit(struct bfa_fcs_s *fcs) 632 { 633 634 } 635 636 /** 637 * Module cleanup 638 */ 639 void 640 bfa_fcs_port_modexit(struct bfa_fcs_s *fcs) 641 { 642 bfa_fcs_modexit_comp(fcs); 643 } 644 645 /** 646 * Unsolicited frame receive handling. 647 */ 648 void 649 bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, 650 u16 len) 651 { 652 u32 pid = fchs->s_id; 653 struct bfa_fcs_rport_s *rport = NULL; 654 struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); 655 656 bfa_stats(lport, uf_recvs); 657 658 if (!bfa_fcs_port_is_online(lport)) { 659 bfa_stats(lport, uf_recv_drops); 660 return; 661 } 662 663 /** 664 * First, handle ELSs that donot require a login. 665 */ 666 /* 667 * Handle PLOGI first 668 */ 669 if ((fchs->type == FC_TYPE_ELS) && 670 (els_cmd->els_code == FC_ELS_PLOGI)) { 671 bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd); 672 return; 673 } 674 675 /* 676 * Handle ECHO separately. 677 */ 678 if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) { 679 bfa_fcs_port_echo(lport, fchs, 680 (struct fc_echo_s *) els_cmd, len); 681 return; 682 } 683 684 /* 685 * Handle RNID separately. 686 */ 687 if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) { 688 bfa_fcs_port_rnid(lport, fchs, 689 (struct fc_rnid_cmd_s *) els_cmd, len); 690 return; 691 } 692 693 /** 694 * look for a matching remote port ID 695 */ 696 rport = bfa_fcs_port_get_rport_by_pid(lport, pid); 697 if (rport) { 698 bfa_trc(rport->fcs, fchs->s_id); 699 bfa_trc(rport->fcs, fchs->d_id); 700 bfa_trc(rport->fcs, fchs->type); 701 702 bfa_fcs_rport_uf_recv(rport, fchs, len); 703 return; 704 } 705 706 /** 707 * Only handles ELS frames for now. 708 */ 709 if (fchs->type != FC_TYPE_ELS) { 710 bfa_trc(lport->fcs, fchs->type); 711 bfa_assert(0); 712 return; 713 } 714 715 bfa_trc(lport->fcs, els_cmd->els_code); 716 if (els_cmd->els_code == FC_ELS_RSCN) { 717 bfa_fcs_port_scn_process_rscn(lport, fchs, len); 718 return; 719 } 720 721 if (els_cmd->els_code == FC_ELS_LOGO) { 722 /** 723 * @todo Handle LOGO frames received. 724 */ 725 bfa_trc(lport->fcs, els_cmd->els_code); 726 return; 727 } 728 729 if (els_cmd->els_code == FC_ELS_PRLI) { 730 /** 731 * @todo Handle PRLI frames received. 732 */ 733 bfa_trc(lport->fcs, els_cmd->els_code); 734 return; 735 } 736 737 /** 738 * Unhandled ELS frames. Send a LS_RJT. 739 */ 740 bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, 741 FC_LS_RJT_EXP_NO_ADDL_INFO); 742 743 } 744 745 /** 746 * PID based Lookup for a R-Port in the Port R-Port Queue 747 */ 748 struct bfa_fcs_rport_s * 749 bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid) 750 { 751 struct bfa_fcs_rport_s *rport; 752 struct list_head *qe; 753 754 list_for_each(qe, &port->rport_q) { 755 rport = (struct bfa_fcs_rport_s *)qe; 756 if (rport->pid == pid) 757 return rport; 758 } 759 760 bfa_trc(port->fcs, pid); 761 return NULL; 762 } 763 764 /** 765 * PWWN based Lookup for a R-Port in the Port R-Port Queue 766 */ 767 struct bfa_fcs_rport_s * 768 bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn) 769 { 770 struct bfa_fcs_rport_s *rport; 771 struct list_head *qe; 772 773 list_for_each(qe, &port->rport_q) { 774 rport = (struct bfa_fcs_rport_s *)qe; 775 if (wwn_is_equal(rport->pwwn, pwwn)) 776 return rport; 777 } 778 779 bfa_trc(port->fcs, pwwn); 780 return (NULL); 781 } 782 783 /** 784 * NWWN based Lookup for a R-Port in the Port R-Port Queue 785 */ 786 struct bfa_fcs_rport_s * 787 bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn) 788 { 789 struct bfa_fcs_rport_s *rport; 790 struct list_head *qe; 791 792 list_for_each(qe, &port->rport_q) { 793 rport = (struct bfa_fcs_rport_s *)qe; 794 if (wwn_is_equal(rport->nwwn, nwwn)) 795 return rport; 796 } 797 798 bfa_trc(port->fcs, nwwn); 799 return (NULL); 800 } 801 802 /** 803 * Called by rport module when new rports are discovered. 804 */ 805 void 806 bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, 807 struct bfa_fcs_rport_s *rport) 808 { 809 list_add_tail(&rport->qe, &port->rport_q); 810 port->num_rports++; 811 } 812 813 /** 814 * Called by rport module to when rports are deleted. 815 */ 816 void 817 bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, 818 struct bfa_fcs_rport_s *rport) 819 { 820 bfa_assert(bfa_q_is_on_q(&port->rport_q, rport)); 821 list_del(&rport->qe); 822 port->num_rports--; 823 824 bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT); 825 } 826 827 /** 828 * Called by fabric for base port when fabric login is complete. 829 * Called by vport for virtual ports when FDISC is complete. 830 */ 831 void 832 bfa_fcs_port_online(struct bfa_fcs_port_s *port) 833 { 834 bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE); 835 } 836 837 /** 838 * Called by fabric for base port when fabric goes offline. 839 * Called by vport for virtual ports when virtual port becomes offline. 840 */ 841 void 842 bfa_fcs_port_offline(struct bfa_fcs_port_s *port) 843 { 844 bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE); 845 } 846 847 /** 848 * Called by fabric to delete base lport and associated resources. 849 * 850 * Called by vport to delete lport and associated resources. Should call 851 * bfa_fcs_vport_delete_comp() for vports on completion. 852 */ 853 void 854 bfa_fcs_port_delete(struct bfa_fcs_port_s *port) 855 { 856 bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE); 857 } 858 859 /** 860 * Called by fabric in private loop topology to process LIP event. 861 */ 862 void 863 bfa_fcs_port_lip(struct bfa_fcs_port_s *port) 864 { 865 } 866 867 /** 868 * Return TRUE if port is online, else return FALSE 869 */ 870 bfa_boolean_t 871 bfa_fcs_port_is_online(struct bfa_fcs_port_s *port) 872 { 873 return (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online)); 874 } 875 876 /** 877 * Logical port initialization of base or virtual port. 878 * Called by fabric for base port or by vport for virtual ports. 879 */ 880 void 881 bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, 882 u16 vf_id, struct bfa_port_cfg_s *port_cfg, 883 struct bfa_fcs_vport_s *vport) 884 { 885 lport->fcs = fcs; 886 lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); 887 bfa_os_assign(lport->port_cfg, *port_cfg); 888 lport->vport = vport; 889 lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) : 890 bfa_lps_get_tag(lport->fabric->lps); 891 892 INIT_LIST_HEAD(&lport->rport_q); 893 lport->num_rports = 0; 894 895 lport->bfad_port = 896 bfa_fcb_port_new(fcs->bfad, lport, lport->port_cfg.roles, 897 lport->fabric->vf_drv, 898 vport ? vport->vport_drv : NULL); 899 bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW); 900 901 bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit); 902 bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE); 903 } 904 905 906 907 /** 908 * fcs_lport_api 909 */ 910 911 void 912 bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, 913 struct bfa_port_attr_s *port_attr) 914 { 915 if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online)) 916 port_attr->pid = port->pid; 917 else 918 port_attr->pid = 0; 919 920 port_attr->port_cfg = port->port_cfg; 921 922 if (port->fabric) { 923 port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric); 924 port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric); 925 port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port); 926 memcpy(port_attr->fabric_ip_addr, 927 bfa_fcs_port_get_fabric_ipaddr(port), 928 BFA_FCS_FABRIC_IPADDR_SZ); 929 930 if (port->vport != NULL) 931 port_attr->port_type = BFA_PPORT_TYPE_VPORT; 932 933 } else { 934 port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN; 935 port_attr->state = BFA_PORT_UNINIT; 936 } 937 938 } 939 940 941