]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blame - drivers/scsi/bfa/bfa_fcs_lport.c
[SCSI] bfa: RPORT state machine: direct attach mode fix.
[mirror_ubuntu-kernels.git] / drivers / scsi / bfa / bfa_fcs_lport.c
CommitLineData
7725ccfd
JH
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
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:
e641de37 117 bfa_sm_fault(port->fcs, event);
7725ccfd
JH
118 }
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
138 default:
e641de37 139 bfa_sm_fault(port->fcs, event);
7725ccfd
JH
140 }
141}
142
143static void
144bfa_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:
e641de37 179 bfa_sm_fault(port->fcs, event);
7725ccfd
JH
180 }
181}
182
183static void
184bfa_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:
e641de37 217 bfa_sm_fault(port->fcs, event);
7725ccfd
JH
218 }
219}
220
221static void
222bfa_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:
e641de37 237 bfa_sm_fault(port->fcs, event);
7725ccfd
JH
238 }
239}
240
241
242
243/**
244 * fcs_port_pvt
245 */
246
247/**
248 * Send AEN notification
249 */
250static void
251bfa_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 */
301static void
302bfa_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 */
328static void
329bfa_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 */
437static void
438bfa_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 */
477static void
478bfa_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 */
534static void
535bfa_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
547static void
548bfa_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
561static void
562bfa_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
f8ceafde 571 if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
7725ccfd 572 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
f8ceafde 573 else
7725ccfd 574 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE);
7725ccfd
JH
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
585static void
586bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port)
587{
588 bfa_assert(0);
589}
590
591static void
592bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port)
593{
594 bfa_assert(0);
595}
596
597static void
598bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port)
599{
600 bfa_assert(0);
601}
602
603static void
604bfa_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 */
629void
630bfa_fcs_port_modinit(struct bfa_fcs_s *fcs)
631{
632
633}
634
635/**
636 * Module cleanup
637 */
638void
639bfa_fcs_port_modexit(struct bfa_fcs_s *fcs)
640{
641 bfa_fcs_modexit_comp(fcs);
642}
643
644/**
645 * Unsolicited frame receive handling.
646 */
647void
648bfa_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 */
747struct bfa_fcs_rport_s *
748bfa_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 */
766struct bfa_fcs_rport_s *
767bfa_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);
f8ceafde 779 return NULL;
7725ccfd
JH
780}
781
782/**
783 * NWWN based Lookup for a R-Port in the Port R-Port Queue
784 */
785struct bfa_fcs_rport_s *
786bfa_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);
f8ceafde 798 return NULL;
7725ccfd
JH
799}
800
801/**
802 * Called by rport module when new rports are discovered.
803 */
804void
805bfa_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 */
815void
816bfa_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 */
830void
831bfa_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 */
840void
841bfa_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 */
852void
853bfa_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 */
861void
862bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
863{
864}
865
866/**
867 * Return TRUE if port is online, else return FALSE
868 */
869bfa_boolean_t
870bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
871{
f8ceafde 872 return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online);
7725ccfd
JH
873}
874
875/**
e6714324 876 * Attach time initialization of logical ports.
7725ccfd
JH
877 */
878void
e6714324
KG
879bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
880 uint16_t vf_id, struct bfa_fcs_vport_s *vport)
7725ccfd
JH
881{
882 lport->fcs = fcs;
883 lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
7725ccfd
JH
884 lport->vport = vport;
885 lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
886 bfa_lps_get_tag(lport->fabric->lps);
887
888 INIT_LIST_HEAD(&lport->rport_q);
889 lport->num_rports = 0;
e6714324
KG
890}
891
892/**
893 * Logical port initialization of base or virtual port.
894 * Called by fabric for base port or by vport for virtual ports.
895 */
7725ccfd 896
e6714324
KG
897void
898bfa_fcs_lport_init(struct bfa_fcs_port_s *lport,
899 struct bfa_port_cfg_s *port_cfg)
900{
901 struct bfa_fcs_vport_s *vport = lport->vport;
902
903 bfa_os_assign(lport->port_cfg, *port_cfg);
904
905 lport->bfad_port = bfa_fcb_port_new(lport->fcs->bfad, lport,
906 lport->port_cfg.roles,
7725ccfd
JH
907 lport->fabric->vf_drv,
908 vport ? vport->vport_drv : NULL);
e6714324 909
7725ccfd
JH
910 bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW);
911
912 bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit);
913 bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
914}
915
7725ccfd
JH
916/**
917 * fcs_lport_api
918 */
919
920void
921bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
922 struct bfa_port_attr_s *port_attr)
923{
924 if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online))
925 port_attr->pid = port->pid;
926 else
927 port_attr->pid = 0;
928
929 port_attr->port_cfg = port->port_cfg;
930
931 if (port->fabric) {
932 port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
933 port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
934 port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port);
935 memcpy(port_attr->fabric_ip_addr,
936 bfa_fcs_port_get_fabric_ipaddr(port),
937 BFA_FCS_FABRIC_IPADDR_SZ);
938
939 if (port->vport != NULL)
940 port_attr->port_type = BFA_PPORT_TYPE_VPORT;
941
942 } else {
943 port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
944 port_attr->state = BFA_PORT_UNINIT;
945 }
946
947}
948
949