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