Linux-libre 2.6.32.42-gnu1
[librecmc/linux-libre.git] / drivers / scsi / bfa / ms.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 #include <bfa.h>
20 #include <bfa_svc.h>
21 #include "fcs_lport.h"
22 #include "fcs_rport.h"
23 #include "fcs_trcmod.h"
24 #include "fcs_fcxp.h"
25 #include "lport_priv.h"
26
27 BFA_TRC_FILE(FCS, MS);
28
29 #define BFA_FCS_MS_CMD_MAX_RETRIES  2
30 /*
31  * forward declarations
32  */
33 static void     bfa_fcs_port_ms_send_plogi(void *ms_cbarg,
34                                            struct bfa_fcxp_s *fcxp_alloced);
35 static void     bfa_fcs_port_ms_timeout(void *arg);
36 static void     bfa_fcs_port_ms_plogi_response(void *fcsarg,
37                                                struct bfa_fcxp_s *fcxp,
38                                                void *cbarg,
39                                                bfa_status_t req_status,
40                                                u32 rsp_len,
41                                                u32 resid_len,
42                                                struct fchs_s *rsp_fchs);
43
44 static void     bfa_fcs_port_ms_send_gmal(void *ms_cbarg,
45                                           struct bfa_fcxp_s *fcxp_alloced);
46 static void     bfa_fcs_port_ms_gmal_response(void *fcsarg,
47                                               struct bfa_fcxp_s *fcxp,
48                                               void *cbarg,
49                                               bfa_status_t req_status,
50                                               u32 rsp_len,
51                                               u32 resid_len,
52                                               struct fchs_s *rsp_fchs);
53 static void     bfa_fcs_port_ms_send_gfn(void *ms_cbarg,
54                                          struct bfa_fcxp_s *fcxp_alloced);
55 static void     bfa_fcs_port_ms_gfn_response(void *fcsarg,
56                                              struct bfa_fcxp_s *fcxp,
57                                              void *cbarg,
58                                              bfa_status_t req_status,
59                                              u32 rsp_len,
60                                              u32 resid_len,
61                                              struct fchs_s *rsp_fchs);
62 /**
63  *  fcs_ms_sm FCS MS state machine
64  */
65
66 /**
67  *  MS State Machine events
68  */
69 enum port_ms_event {
70         MSSM_EVENT_PORT_ONLINE = 1,
71         MSSM_EVENT_PORT_OFFLINE = 2,
72         MSSM_EVENT_RSP_OK = 3,
73         MSSM_EVENT_RSP_ERROR = 4,
74         MSSM_EVENT_TIMEOUT = 5,
75         MSSM_EVENT_FCXP_SENT = 6,
76         MSSM_EVENT_PORT_FABRIC_RSCN = 7
77 };
78
79 static void     bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms,
80                                            enum port_ms_event event);
81 static void     bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms,
82                                                  enum port_ms_event event);
83 static void     bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms,
84                                          enum port_ms_event event);
85 static void     bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms,
86                                                enum port_ms_event event);
87 static void     bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms,
88                                                 enum port_ms_event event);
89 static void     bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms,
90                                         enum port_ms_event event);
91 static void     bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms,
92                                               enum port_ms_event event);
93 static void     bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms,
94                                                enum port_ms_event event);
95 static void     bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms,
96                                        enum port_ms_event event);
97 static void     bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms,
98                                              enum port_ms_event event);
99 static void     bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms,
100                                           enum port_ms_event event);
101 /**
102  *              Start in offline state - awaiting NS to send start.
103  */
104 static void
105 bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms,
106                            enum port_ms_event event)
107 {
108         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
109         bfa_trc(ms->port->fcs, event);
110
111         switch (event) {
112         case MSSM_EVENT_PORT_ONLINE:
113                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending);
114                 bfa_fcs_port_ms_send_plogi(ms, NULL);
115                 break;
116
117         case MSSM_EVENT_PORT_OFFLINE:
118                 break;
119
120         default:
121                 bfa_assert(0);
122         }
123 }
124
125 static void
126 bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms,
127                                  enum port_ms_event event)
128 {
129         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
130         bfa_trc(ms->port->fcs, event);
131
132         switch (event) {
133         case MSSM_EVENT_FCXP_SENT:
134                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi);
135                 break;
136
137         case MSSM_EVENT_PORT_OFFLINE:
138                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
139                 bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
140                                        &ms->fcxp_wqe);
141                 break;
142
143         default:
144                 bfa_assert(0);
145         }
146 }
147
148 static void
149 bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
150 {
151         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
152         bfa_trc(ms->port->fcs, event);
153
154         switch (event) {
155         case MSSM_EVENT_RSP_ERROR:
156                 /*
157                  * Start timer for a delayed retry
158                  */
159                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_retry);
160                 bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer,
161                                 bfa_fcs_port_ms_timeout, ms,
162                                 BFA_FCS_RETRY_TIMEOUT);
163                 break;
164
165         case MSSM_EVENT_RSP_OK:
166                 /*
167                  * since plogi is done, now invoke MS related sub-modules
168                  */
169                 bfa_fcs_port_fdmi_online(ms);
170
171                 /**
172                  * if this is a Vport, go to online state.
173                  */
174                 if (ms->port->vport) {
175                         bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
176                         break;
177                 }
178
179                 /*
180                  * For a base port we need to get the
181                  * switch's IP address.
182                  */
183                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending);
184                 bfa_fcs_port_ms_send_gmal(ms, NULL);
185                 break;
186
187         case MSSM_EVENT_PORT_OFFLINE:
188                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
189                 bfa_fcxp_discard(ms->fcxp);
190                 break;
191
192         default:
193                 bfa_assert(0);
194         }
195 }
196
197 static void
198 bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms,
199                                enum port_ms_event event)
200 {
201         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
202         bfa_trc(ms->port->fcs, event);
203
204         switch (event) {
205         case MSSM_EVENT_TIMEOUT:
206                 /*
207                  * Retry Timer Expired. Re-send
208                  */
209                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending);
210                 bfa_fcs_port_ms_send_plogi(ms, NULL);
211                 break;
212
213         case MSSM_EVENT_PORT_OFFLINE:
214                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
215                 bfa_timer_stop(&ms->timer);
216                 break;
217
218         default:
219                 bfa_assert(0);
220         }
221 }
222
223 static void
224 bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms,
225                           enum port_ms_event event)
226 {
227         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
228         bfa_trc(ms->port->fcs, event);
229
230         switch (event) {
231         case MSSM_EVENT_PORT_OFFLINE:
232                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
233                 /*
234                  * now invoke MS related sub-modules
235                  */
236                 bfa_fcs_port_fdmi_offline(ms);
237                 break;
238
239         case MSSM_EVENT_PORT_FABRIC_RSCN:
240                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
241                 ms->retry_cnt = 0;
242                 bfa_fcs_port_ms_send_gfn(ms, NULL);
243                 break;
244
245         default:
246                 bfa_assert(0);
247         }
248 }
249
250 static void
251 bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms,
252                                 enum port_ms_event event)
253 {
254         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
255         bfa_trc(ms->port->fcs, event);
256
257         switch (event) {
258         case MSSM_EVENT_FCXP_SENT:
259                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal);
260                 break;
261
262         case MSSM_EVENT_PORT_OFFLINE:
263                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
264                 bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
265                                        &ms->fcxp_wqe);
266                 break;
267
268         default:
269                 bfa_assert(0);
270         }
271 }
272
273 static void
274 bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
275 {
276         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
277         bfa_trc(ms->port->fcs, event);
278
279         switch (event) {
280         case MSSM_EVENT_RSP_ERROR:
281                 /*
282                  * Start timer for a delayed retry
283                  */
284                 if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
285                         bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_retry);
286                         bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
287                                         &ms->timer, bfa_fcs_port_ms_timeout, ms,
288                                         BFA_FCS_RETRY_TIMEOUT);
289                 } else {
290                         bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
291                         bfa_fcs_port_ms_send_gfn(ms, NULL);
292                         ms->retry_cnt = 0;
293                 }
294                 break;
295
296         case MSSM_EVENT_RSP_OK:
297                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
298                 bfa_fcs_port_ms_send_gfn(ms, NULL);
299                 break;
300
301         case MSSM_EVENT_PORT_OFFLINE:
302                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
303                 bfa_fcxp_discard(ms->fcxp);
304                 break;
305
306         default:
307                 bfa_assert(0);
308         }
309 }
310
311 static void
312 bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms,
313                               enum port_ms_event event)
314 {
315         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
316         bfa_trc(ms->port->fcs, event);
317
318         switch (event) {
319         case MSSM_EVENT_TIMEOUT:
320                 /*
321                  * Retry Timer Expired. Re-send
322                  */
323                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending);
324                 bfa_fcs_port_ms_send_gmal(ms, NULL);
325                 break;
326
327         case MSSM_EVENT_PORT_OFFLINE:
328                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
329                 bfa_timer_stop(&ms->timer);
330                 break;
331
332         default:
333                 bfa_assert(0);
334         }
335 }
336
337 /**
338  *  ms_pvt MS local functions
339  */
340
341 static void
342 bfa_fcs_port_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
343 {
344         struct bfa_fcs_port_ms_s *ms = ms_cbarg;
345         struct bfa_fcs_port_s *port = ms->port;
346         struct fchs_s          fchs;
347         int             len;
348         struct bfa_fcxp_s *fcxp;
349
350         bfa_trc(port->fcs, port->pid);
351
352         fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
353         if (!fcxp) {
354                 bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
355                                     bfa_fcs_port_ms_send_gmal, ms);
356                 return;
357         }
358         ms->fcxp = fcxp;
359
360         len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
361                                 bfa_fcs_port_get_fcid(port),
362                                 bfa_lps_get_peer_nwwn(port->fabric->lps));
363
364         bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
365                       FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response,
366                       (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
367
368         bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
369 }
370
371 static void
372 bfa_fcs_port_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
373                               void *cbarg, bfa_status_t req_status,
374                               u32 rsp_len, u32 resid_len,
375                               struct fchs_s *rsp_fchs)
376 {
377         struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
378         struct bfa_fcs_port_s *port = ms->port;
379         struct ct_hdr_s       *cthdr = NULL;
380         struct fcgs_gmal_resp_s *gmal_resp;
381         struct fc_gmal_entry_s *gmal_entry;
382         u32        num_entries;
383         u8        *rsp_str;
384
385         bfa_trc(port->fcs, req_status);
386         bfa_trc(port->fcs, port->port_cfg.pwwn);
387
388         /*
389          * Sanity Checks
390          */
391         if (req_status != BFA_STATUS_OK) {
392                 bfa_trc(port->fcs, req_status);
393                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
394                 return;
395         }
396
397         cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
398         cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
399
400         if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
401                 gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1);
402                 num_entries = bfa_os_ntohl(gmal_resp->ms_len);
403                 if (num_entries == 0) {
404                         bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
405                         return;
406                 }
407                 /*
408                  * The response could contain multiple Entries.
409                  * Entries for SNMP interface, etc.
410                  * We look for the entry with a telnet prefix.
411                  * First "http://" entry refers to IP addr
412                  */
413
414                 gmal_entry = (struct fc_gmal_entry_s *)gmal_resp->ms_ma;
415                 while (num_entries > 0) {
416                         if (strncmp
417                             (gmal_entry->prefix, CT_GMAL_RESP_PREFIX_HTTP,
418                              sizeof(gmal_entry->prefix)) == 0) {
419
420                                 /*
421                                  * if the IP address is terminating with a '/',
422                                  * remove it. *Byte 0 consists of the length
423                                  * of the string.
424                                  */
425                                 rsp_str = &(gmal_entry->prefix[0]);
426                                 if (rsp_str[gmal_entry->len - 1] == '/')
427                                         rsp_str[gmal_entry->len - 1] = 0;
428                                 /*
429                                  * copy IP Address to fabric
430                                  */
431                                 strncpy(bfa_fcs_port_get_fabric_ipaddr(port),
432                                         gmal_entry->ip_addr,
433                                         BFA_FCS_FABRIC_IPADDR_SZ);
434                                 break;
435                         } else {
436                                 --num_entries;
437                                 ++gmal_entry;
438                         }
439                 }
440
441                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
442                 return;
443         }
444
445         bfa_trc(port->fcs, cthdr->reason_code);
446         bfa_trc(port->fcs, cthdr->exp_code);
447         bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
448 }
449
450 static void
451 bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms,
452                                enum port_ms_event event)
453 {
454         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
455         bfa_trc(ms->port->fcs, event);
456
457         switch (event) {
458         case MSSM_EVENT_FCXP_SENT:
459                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn);
460                 break;
461
462         case MSSM_EVENT_PORT_OFFLINE:
463                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
464                 bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
465                                        &ms->fcxp_wqe);
466                 break;
467
468         default:
469                 bfa_assert(0);
470         }
471 }
472
473 static void
474 bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
475 {
476         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
477         bfa_trc(ms->port->fcs, event);
478
479         switch (event) {
480         case MSSM_EVENT_RSP_ERROR:
481                 /*
482                  * Start timer for a delayed retry
483                  */
484                 if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
485                         bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_retry);
486                         bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
487                                         &ms->timer, bfa_fcs_port_ms_timeout, ms,
488                                         BFA_FCS_RETRY_TIMEOUT);
489                 } else {
490                         bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
491                         ms->retry_cnt = 0;
492                 }
493                 break;
494
495         case MSSM_EVENT_RSP_OK:
496                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
497                 break;
498
499         case MSSM_EVENT_PORT_OFFLINE:
500                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
501                 bfa_fcxp_discard(ms->fcxp);
502                 break;
503
504         default:
505                 bfa_assert(0);
506         }
507 }
508
509 static void
510 bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms,
511                              enum port_ms_event event)
512 {
513         bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
514         bfa_trc(ms->port->fcs, event);
515
516         switch (event) {
517         case MSSM_EVENT_TIMEOUT:
518                 /*
519                  * Retry Timer Expired. Re-send
520                  */
521                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
522                 bfa_fcs_port_ms_send_gfn(ms, NULL);
523                 break;
524
525         case MSSM_EVENT_PORT_OFFLINE:
526                 bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
527                 bfa_timer_stop(&ms->timer);
528                 break;
529
530         default:
531                 bfa_assert(0);
532         }
533 }
534
535 /**
536  *  ms_pvt MS local functions
537  */
538
539 static void
540 bfa_fcs_port_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
541 {
542         struct bfa_fcs_port_ms_s *ms = ms_cbarg;
543         struct bfa_fcs_port_s *port = ms->port;
544         struct fchs_s          fchs;
545         int             len;
546         struct bfa_fcxp_s *fcxp;
547
548         bfa_trc(port->fcs, port->pid);
549
550         fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
551         if (!fcxp) {
552                 bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
553                                     bfa_fcs_port_ms_send_gfn, ms);
554                 return;
555         }
556         ms->fcxp = fcxp;
557
558         len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
559                                bfa_fcs_port_get_fcid(port),
560                                bfa_lps_get_peer_nwwn(port->fabric->lps));
561
562         bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
563                       FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response,
564                       (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
565
566         bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
567 }
568
569 static void
570 bfa_fcs_port_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
571                              bfa_status_t req_status, u32 rsp_len,
572                                u32 resid_len, struct fchs_s *rsp_fchs)
573 {
574         struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
575         struct bfa_fcs_port_s *port = ms->port;
576         struct ct_hdr_s       *cthdr = NULL;
577         wwn_t          *gfn_resp;
578
579         bfa_trc(port->fcs, req_status);
580         bfa_trc(port->fcs, port->port_cfg.pwwn);
581
582         /*
583          * Sanity Checks
584          */
585         if (req_status != BFA_STATUS_OK) {
586                 bfa_trc(port->fcs, req_status);
587                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
588                 return;
589         }
590
591         cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
592         cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
593
594         if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
595                 gfn_resp = (wwn_t *) (cthdr + 1);
596                 /*
597                  * check if it has actually changed
598                  */
599                 if ((memcmp
600                      ((void *)&bfa_fcs_port_get_fabric_name(port), gfn_resp,
601                       sizeof(wwn_t)) != 0))
602                         bfa_fcs_fabric_set_fabric_name(port->fabric, *gfn_resp);
603                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
604                 return;
605         }
606
607         bfa_trc(port->fcs, cthdr->reason_code);
608         bfa_trc(port->fcs, cthdr->exp_code);
609         bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
610 }
611
612 /**
613  *  ms_pvt MS local functions
614  */
615
616 static void
617 bfa_fcs_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
618 {
619         struct bfa_fcs_port_ms_s *ms = ms_cbarg;
620         struct bfa_fcs_port_s *port = ms->port;
621         struct fchs_s          fchs;
622         int             len;
623         struct bfa_fcxp_s *fcxp;
624
625         bfa_trc(port->fcs, port->pid);
626
627         fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
628         if (!fcxp) {
629                 port->stats.ms_plogi_alloc_wait++;
630                 bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
631                                     bfa_fcs_port_ms_send_plogi, ms);
632                 return;
633         }
634         ms->fcxp = fcxp;
635
636         len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
637                              bfa_os_hton3b(FC_MGMT_SERVER),
638                              bfa_fcs_port_get_fcid(port), 0,
639                              port->port_cfg.pwwn, port->port_cfg.nwwn,
640                              bfa_pport_get_maxfrsize(port->fcs->bfa));
641
642         bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
643                       FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response,
644                       (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
645
646         port->stats.ms_plogi_sent++;
647         bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
648 }
649
650 static void
651 bfa_fcs_port_ms_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
652                                void *cbarg, bfa_status_t req_status,
653                                u32 rsp_len, u32 resid_len,
654                                struct fchs_s *rsp_fchs)
655 {
656         struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
657
658         struct bfa_fcs_port_s *port = ms->port;
659         struct fc_els_cmd_s   *els_cmd;
660         struct fc_ls_rjt_s    *ls_rjt;
661
662         bfa_trc(port->fcs, req_status);
663         bfa_trc(port->fcs, port->port_cfg.pwwn);
664
665         /*
666          * Sanity Checks
667          */
668         if (req_status != BFA_STATUS_OK) {
669                 port->stats.ms_plogi_rsp_err++;
670                 bfa_trc(port->fcs, req_status);
671                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
672                 return;
673         }
674
675         els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
676
677         switch (els_cmd->els_code) {
678
679         case FC_ELS_ACC:
680                 if (rsp_len < sizeof(struct fc_logi_s)) {
681                         bfa_trc(port->fcs, rsp_len);
682                         port->stats.ms_plogi_acc_err++;
683                         bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
684                         break;
685                 }
686                 port->stats.ms_plogi_accepts++;
687                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
688                 break;
689
690         case FC_ELS_LS_RJT:
691                 ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
692
693                 bfa_trc(port->fcs, ls_rjt->reason_code);
694                 bfa_trc(port->fcs, ls_rjt->reason_code_expl);
695
696                 port->stats.ms_rejects++;
697                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
698                 break;
699
700         default:
701                 port->stats.ms_plogi_unknown_rsp++;
702                 bfa_trc(port->fcs, els_cmd->els_code);
703                 bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
704         }
705 }
706
707 static void
708 bfa_fcs_port_ms_timeout(void *arg)
709 {
710         struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)arg;
711
712         ms->port->stats.ms_timeouts++;
713         bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT);
714 }
715
716
717 void
718 bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port)
719 {
720         struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
721
722         ms->port = port;
723         bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
724
725         /*
726          * Invoke init routines of sub modules.
727          */
728         bfa_fcs_port_fdmi_init(ms);
729 }
730
731 void
732 bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port)
733 {
734         struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
735
736         ms->port = port;
737         bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE);
738 }
739
740 void
741 bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port)
742 {
743         struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
744
745         ms->port = port;
746         bfa_sm_send_event(ms, MSSM_EVENT_PORT_ONLINE);
747 }
748
749 void
750 bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port)
751 {
752         struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
753
754         /*
755          * @todo.  Handle this only when in Online state
756          */
757         if (bfa_sm_cmp_state(ms, bfa_fcs_port_ms_sm_online))
758                 bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN);
759 }