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