libata-sff: separate out BMDMA qc_issue
[safe/jmp/linux-2.6] / drivers / scsi / bfa / bfa_fcs_lport.c
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_sm_fault(port->fcs, event);
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_sm_fault(port->fcs, event);
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_sm_fault(port->fcs, event);
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_sm_fault(port->fcs, event);
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_sm_fault(port->fcs, event);
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         bfa_log(logmod, BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, event), lpwwn_ptr,
267                 role_str[role/2]);
268
269         aen_data.lport.vf_id = port->fabric->vf_id;
270         aen_data.lport.roles = role;
271         aen_data.lport.ppwwn =
272                 bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
273         aen_data.lport.lpwwn = lpwwn;
274 }
275
276 /*
277  * Send a LS reject
278  */
279 static void
280 bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
281                          u8 reason_code, u8 reason_code_expl)
282 {
283         struct fchs_s          fchs;
284         struct bfa_fcxp_s *fcxp;
285         struct bfa_rport_s *bfa_rport = NULL;
286         int             len;
287
288         bfa_trc(port->fcs, rx_fchs->s_id);
289
290         fcxp = bfa_fcs_fcxp_alloc(port->fcs);
291         if (!fcxp)
292                 return;
293
294         len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
295                               bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
296                               reason_code, reason_code_expl);
297
298         bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
299                       BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
300                       FC_MAX_PDUSZ, 0);
301 }
302
303 /**
304  * Process incoming plogi from a remote port.
305  */
306 static void
307 bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
308                         struct fc_logi_s *plogi)
309 {
310         struct bfa_fcs_rport_s *rport;
311
312         bfa_trc(port->fcs, rx_fchs->d_id);
313         bfa_trc(port->fcs, rx_fchs->s_id);
314
315         /*
316          * If min cfg mode is enabled, drop any incoming PLOGIs
317          */
318         if (__fcs_min_cfg(port->fcs)) {
319                 bfa_trc(port->fcs, rx_fchs->s_id);
320                 return;
321         }
322
323         if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) {
324                 bfa_trc(port->fcs, rx_fchs->s_id);
325                 /*
326                  * send a LS reject
327                  */
328                 bfa_fcs_port_send_ls_rjt(port, rx_fchs,
329                                          FC_LS_RJT_RSN_PROTOCOL_ERROR,
330                                          FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS);
331                 return;
332         }
333
334         /**
335 * Direct Attach P2P mode : verify address assigned by the r-port.
336          */
337         if ((!bfa_fcs_fabric_is_switched(port->fabric))
338             &&
339             (memcmp
340              ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name,
341               sizeof(wwn_t)) < 0)) {
342                 if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) {
343                         /*
344                          * Address assigned to us cannot be a WKA
345                          */
346                         bfa_fcs_port_send_ls_rjt(port, rx_fchs,
347                                         FC_LS_RJT_RSN_PROTOCOL_ERROR,
348                                         FC_LS_RJT_EXP_INVALID_NPORT_ID);
349                         return;
350                 }
351                 port->pid = rx_fchs->d_id;
352         }
353
354         /**
355          * First, check if we know the device by pwwn.
356          */
357         rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name);
358         if (rport) {
359                 /**
360                  * Direct Attach P2P mode: handle address assigned by the rport.
361                  */
362                 if ((!bfa_fcs_fabric_is_switched(port->fabric))
363                     &&
364                     (memcmp
365                      ((void *)&bfa_fcs_port_get_pwwn(port),
366                       (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
367                         port->pid = rx_fchs->d_id;
368                         rport->pid = rx_fchs->s_id;
369                 }
370                 bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
371                 return;
372         }
373
374         /**
375          * Next, lookup rport by PID.
376          */
377         rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id);
378         if (!rport) {
379                 /**
380                  * Inbound PLOGI from a new device.
381                  */
382                 bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
383                 return;
384         }
385
386         /**
387          * Rport is known only by PID.
388          */
389         if (rport->pwwn) {
390                 /**
391                  * This is a different device with the same pid. Old device
392                  * disappeared. Send implicit LOGO to old device.
393                  */
394                 bfa_assert(rport->pwwn != plogi->port_name);
395                 bfa_fcs_rport_logo_imp(rport);
396
397                 /**
398                  * Inbound PLOGI from a new device (with old PID).
399                  */
400                 bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
401                 return;
402         }
403
404         /**
405          * PLOGI crossing each other.
406          */
407         bfa_assert(rport->pwwn == WWN_NULL);
408         bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
409 }
410
411 /*
412  * Process incoming ECHO.
413  * Since it does not require a login, it is processed here.
414  */
415 static void
416 bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
417                         struct fc_echo_s *echo, u16 rx_len)
418 {
419         struct fchs_s          fchs;
420         struct bfa_fcxp_s *fcxp;
421         struct bfa_rport_s *bfa_rport = NULL;
422         int             len, pyld_len;
423
424         bfa_trc(port->fcs, rx_fchs->s_id);
425         bfa_trc(port->fcs, rx_fchs->d_id);
426         bfa_trc(port->fcs, rx_len);
427
428         fcxp = bfa_fcs_fcxp_alloc(port->fcs);
429         if (!fcxp)
430                 return;
431
432         len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
433                               bfa_fcs_port_get_fcid(port), rx_fchs->ox_id);
434
435         /*
436          * Copy the payload (if any) from the echo frame
437          */
438         pyld_len = rx_len - sizeof(struct fchs_s);
439         bfa_trc(port->fcs, pyld_len);
440
441         if (pyld_len > len)
442                 memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) +
443                        sizeof(struct fc_echo_s), (echo + 1),
444                        (pyld_len - sizeof(struct fc_echo_s)));
445
446         bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
447                       BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL,
448                       FC_MAX_PDUSZ, 0);
449 }
450
451 /*
452  * Process incoming RNID.
453  * Since it does not require a login, it is processed here.
454  */
455 static void
456 bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
457                         struct fc_rnid_cmd_s *rnid, u16 rx_len)
458 {
459         struct fc_rnid_common_id_data_s common_id_data;
460         struct fc_rnid_general_topology_data_s gen_topo_data;
461         struct fchs_s          fchs;
462         struct bfa_fcxp_s *fcxp;
463         struct bfa_rport_s *bfa_rport = NULL;
464         u16        len;
465         u32        data_format;
466
467         bfa_trc(port->fcs, rx_fchs->s_id);
468         bfa_trc(port->fcs, rx_fchs->d_id);
469         bfa_trc(port->fcs, rx_len);
470
471         fcxp = bfa_fcs_fcxp_alloc(port->fcs);
472         if (!fcxp)
473                 return;
474
475         /*
476          * Check Node Indentification Data Format
477          * We only support General Topology Discovery Format.
478          * For any other requested Data Formats, we return Common Node Id Data
479          * only, as per FC-LS.
480          */
481         bfa_trc(port->fcs, rnid->node_id_data_format);
482         if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
483                 data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY;
484                 /*
485                  * Get General topology data for this port
486                  */
487                 bfa_fs_port_get_gen_topo_data(port, &gen_topo_data);
488         } else {
489                 data_format = RNID_NODEID_DATA_FORMAT_COMMON;
490         }
491
492         /*
493          * Copy the Node Id Info
494          */
495         common_id_data.port_name = bfa_fcs_port_get_pwwn(port);
496         common_id_data.node_name = bfa_fcs_port_get_nwwn(port);
497
498         len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
499                                 bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
500                                 data_format, &common_id_data, &gen_topo_data);
501
502         bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
503                       BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
504                       FC_MAX_PDUSZ, 0);
505
506         return;
507 }
508
509 /*
510  *  Fill out General Topolpgy Discovery Data for RNID ELS.
511  */
512 static void
513 bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
514                         struct fc_rnid_general_topology_data_s *gen_topo_data)
515 {
516
517         bfa_os_memset(gen_topo_data, 0,
518                       sizeof(struct fc_rnid_general_topology_data_s));
519
520         gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST);
521         gen_topo_data->phy_port_num = 0;        /* @todo */
522         gen_topo_data->num_attached_nodes = bfa_os_htonl(1);
523 }
524
525 static void
526 bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port)
527 {
528         bfa_trc(port->fcs, port->fabric->oper_type);
529
530         __port_action[port->fabric->fab_type].init(port);
531         __port_action[port->fabric->fab_type].online(port);
532
533         bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE);
534         bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles,
535                         port->fabric->vf_drv, (port->vport == NULL) ?
536                         NULL : port->vport->vport_drv);
537 }
538
539 static void
540 bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port)
541 {
542         struct list_head *qe, *qen;
543         struct bfa_fcs_rport_s *rport;
544
545         bfa_trc(port->fcs, port->fabric->oper_type);
546
547         __port_action[port->fabric->fab_type].offline(port);
548
549         if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
550                 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
551         else
552                 bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE);
553         bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles,
554                         port->fabric->vf_drv,
555                         (port->vport == NULL) ? NULL : port->vport->vport_drv);
556
557         list_for_each_safe(qe, qen, &port->rport_q) {
558                 rport = (struct bfa_fcs_rport_s *)qe;
559                 bfa_fcs_rport_offline(rport);
560         }
561 }
562
563 static void
564 bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port)
565 {
566         bfa_assert(0);
567 }
568
569 static void
570 bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port)
571 {
572         bfa_assert(0);
573 }
574
575 static void
576 bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port)
577 {
578         bfa_assert(0);
579 }
580
581 static void
582 bfa_fcs_port_deleted(struct bfa_fcs_port_s *port)
583 {
584         bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE);
585
586         /*
587          * Base port will be deleted by the OS driver
588          */
589         if (port->vport) {
590                 bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles,
591                         port->fabric->vf_drv,
592                         port->vport ? port->vport->vport_drv : NULL);
593                 bfa_fcs_vport_delete_comp(port->vport);
594         } else {
595                 bfa_fcs_fabric_port_delete_comp(port->fabric);
596         }
597 }
598
599
600
601 /**
602  *  fcs_lport_api BFA FCS port API
603  */
604 /**
605  *   Module initialization
606  */
607 void
608 bfa_fcs_port_modinit(struct bfa_fcs_s *fcs)
609 {
610
611 }
612
613 /**
614  *   Module cleanup
615  */
616 void
617 bfa_fcs_port_modexit(struct bfa_fcs_s *fcs)
618 {
619         bfa_fcs_modexit_comp(fcs);
620 }
621
622 /**
623  *              Unsolicited frame receive handling.
624  */
625 void
626 bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs,
627                         u16 len)
628 {
629         u32        pid = fchs->s_id;
630         struct bfa_fcs_rport_s *rport = NULL;
631         struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
632
633         bfa_stats(lport, uf_recvs);
634
635         if (!bfa_fcs_port_is_online(lport)) {
636                 bfa_stats(lport, uf_recv_drops);
637                 return;
638         }
639
640         /**
641          * First, handle ELSs that donot require a login.
642          */
643         /*
644          * Handle PLOGI first
645          */
646         if ((fchs->type == FC_TYPE_ELS) &&
647                 (els_cmd->els_code == FC_ELS_PLOGI)) {
648                 bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd);
649                 return;
650         }
651
652         /*
653          * Handle ECHO separately.
654          */
655         if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) {
656                 bfa_fcs_port_echo(lport, fchs,
657                         (struct fc_echo_s *) els_cmd, len);
658                 return;
659         }
660
661         /*
662          * Handle RNID separately.
663          */
664         if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) {
665                 bfa_fcs_port_rnid(lport, fchs,
666                         (struct fc_rnid_cmd_s *) els_cmd, len);
667                 return;
668         }
669
670         /**
671          * look for a matching remote port ID
672          */
673         rport = bfa_fcs_port_get_rport_by_pid(lport, pid);
674         if (rport) {
675                 bfa_trc(rport->fcs, fchs->s_id);
676                 bfa_trc(rport->fcs, fchs->d_id);
677                 bfa_trc(rport->fcs, fchs->type);
678
679                 bfa_fcs_rport_uf_recv(rport, fchs, len);
680                 return;
681         }
682
683         /**
684          * Only handles ELS frames for now.
685          */
686         if (fchs->type != FC_TYPE_ELS) {
687                 bfa_trc(lport->fcs, fchs->type);
688                 bfa_assert(0);
689                 return;
690         }
691
692         bfa_trc(lport->fcs, els_cmd->els_code);
693         if (els_cmd->els_code == FC_ELS_RSCN) {
694                 bfa_fcs_port_scn_process_rscn(lport, fchs, len);
695                 return;
696         }
697
698         if (els_cmd->els_code == FC_ELS_LOGO) {
699                 /**
700                  * @todo Handle LOGO frames received.
701                  */
702                 bfa_trc(lport->fcs, els_cmd->els_code);
703                 return;
704         }
705
706         if (els_cmd->els_code == FC_ELS_PRLI) {
707                 /**
708                  * @todo Handle PRLI frames received.
709                  */
710                 bfa_trc(lport->fcs, els_cmd->els_code);
711                 return;
712         }
713
714         /**
715          * Unhandled ELS frames. Send a LS_RJT.
716          */
717         bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
718                                  FC_LS_RJT_EXP_NO_ADDL_INFO);
719
720 }
721
722 /**
723  *   PID based Lookup for a R-Port in the Port R-Port Queue
724  */
725 struct bfa_fcs_rport_s *
726 bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid)
727 {
728         struct bfa_fcs_rport_s *rport;
729         struct list_head *qe;
730
731         list_for_each(qe, &port->rport_q) {
732                 rport = (struct bfa_fcs_rport_s *)qe;
733                 if (rport->pid == pid)
734                         return rport;
735         }
736
737         bfa_trc(port->fcs, pid);
738         return NULL;
739 }
740
741 /**
742  *   PWWN based Lookup for a R-Port in the Port R-Port Queue
743  */
744 struct bfa_fcs_rport_s *
745 bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn)
746 {
747         struct bfa_fcs_rport_s *rport;
748         struct list_head *qe;
749
750         list_for_each(qe, &port->rport_q) {
751                 rport = (struct bfa_fcs_rport_s *)qe;
752                 if (wwn_is_equal(rport->pwwn, pwwn))
753                         return rport;
754         }
755
756         bfa_trc(port->fcs, pwwn);
757         return NULL;
758 }
759
760 /**
761  *   NWWN based Lookup for a R-Port in the Port R-Port Queue
762  */
763 struct bfa_fcs_rport_s *
764 bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn)
765 {
766         struct bfa_fcs_rport_s *rport;
767         struct list_head *qe;
768
769         list_for_each(qe, &port->rport_q) {
770                 rport = (struct bfa_fcs_rport_s *)qe;
771                 if (wwn_is_equal(rport->nwwn, nwwn))
772                         return rport;
773         }
774
775         bfa_trc(port->fcs, nwwn);
776         return NULL;
777 }
778
779 /**
780  * Called by rport module when new rports are discovered.
781  */
782 void
783 bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port,
784                        struct bfa_fcs_rport_s *rport)
785 {
786         list_add_tail(&rport->qe, &port->rport_q);
787         port->num_rports++;
788 }
789
790 /**
791  * Called by rport module to when rports are deleted.
792  */
793 void
794 bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port,
795                        struct bfa_fcs_rport_s *rport)
796 {
797         bfa_assert(bfa_q_is_on_q(&port->rport_q, rport));
798         list_del(&rport->qe);
799         port->num_rports--;
800
801         bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
802 }
803
804 /**
805  * Called by fabric for base port when fabric login is complete.
806  * Called by vport for virtual ports when FDISC is complete.
807  */
808 void
809 bfa_fcs_port_online(struct bfa_fcs_port_s *port)
810 {
811         bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
812 }
813
814 /**
815  * Called by fabric for base port when fabric goes offline.
816  * Called by vport for virtual ports when virtual port becomes offline.
817  */
818 void
819 bfa_fcs_port_offline(struct bfa_fcs_port_s *port)
820 {
821         bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
822 }
823
824 /**
825  * Called by fabric to delete base lport and associated resources.
826  *
827  * Called by vport to delete lport and associated resources. Should call
828  * bfa_fcs_vport_delete_comp() for vports on completion.
829  */
830 void
831 bfa_fcs_port_delete(struct bfa_fcs_port_s *port)
832 {
833         bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
834 }
835
836 /**
837  * Called by fabric in private loop topology to process LIP event.
838  */
839 void
840 bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
841 {
842 }
843
844 /**
845  * Return TRUE if port is online, else return FALSE
846  */
847 bfa_boolean_t
848 bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
849 {
850         return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online);
851 }
852
853 /**
854  * Attach time initialization of logical ports.
855  */
856 void
857 bfa_fcs_lport_attach(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
858                 uint16_t vf_id, struct bfa_fcs_vport_s *vport)
859 {
860         lport->fcs = fcs;
861         lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
862         lport->vport = vport;
863         lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
864                          bfa_lps_get_tag(lport->fabric->lps);
865
866         INIT_LIST_HEAD(&lport->rport_q);
867         lport->num_rports = 0;
868 }
869
870 /**
871  * Logical port initialization of base or virtual port.
872  * Called by fabric for base port or by vport for virtual ports.
873  */
874
875 void
876 bfa_fcs_lport_init(struct bfa_fcs_port_s *lport,
877                 struct bfa_port_cfg_s *port_cfg)
878 {
879         struct bfa_fcs_vport_s *vport = lport->vport;
880
881         bfa_os_assign(lport->port_cfg, *port_cfg);
882
883         lport->bfad_port = bfa_fcb_port_new(lport->fcs->bfad, lport,
884                                 lport->port_cfg.roles,
885                                 lport->fabric->vf_drv,
886                                 vport ? vport->vport_drv : NULL);
887
888         bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW);
889
890         bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit);
891         bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
892 }
893
894 /**
895  *  fcs_lport_api
896  */
897
898 void
899 bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
900                       struct bfa_port_attr_s *port_attr)
901 {
902         if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online))
903                 port_attr->pid = port->pid;
904         else
905                 port_attr->pid = 0;
906
907         port_attr->port_cfg = port->port_cfg;
908
909         if (port->fabric) {
910                 port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
911                 port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
912                 port_attr->authfail =
913                                 bfa_fcs_fabric_is_auth_failed(port->fabric);
914                 port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port);
915                 memcpy(port_attr->fabric_ip_addr,
916                        bfa_fcs_port_get_fabric_ipaddr(port),
917                        BFA_FCS_FABRIC_IPADDR_SZ);
918
919                 if (port->vport != NULL) {
920                         port_attr->port_type = BFA_PPORT_TYPE_VPORT;
921                         port_attr->fpma_mac =
922                                 bfa_lps_get_lp_mac(port->vport->lps);
923                 } else
924                         port_attr->fpma_mac =
925                                 bfa_lps_get_lp_mac(port->fabric->lps);
926
927         } else {
928                 port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
929                 port_attr->state = BFA_PORT_UNINIT;
930         }
931
932 }
933
934