summaryrefslogblamecommitdiffstats
path: root/drivers/scsi/bfa/bfa_fcs_lport.c
blob: 3c9bde9a8080cd490c9b3d38bced2eff6fcfd540 (plain) (tree)
1
2
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
  
                                                               














                                                                          
                     
                    


                        


                        











                                                                                

                                                         
                                                                

                                                             
                                                                           

                                                                               







                                                                        
               


                                                                  

                     






                                                                 
 
  


                                              
                          




                                     
                                 

  









                                                                        

                                                                        

           


                                       





                                                
                                                              


                      
                                               



           

                                                       





                                                

                                                                


                                    

                                                                

                      



                                                             

                                                              

                      


                                     
                
                                               



           


                                       

                                      
                                                  





                                                

                                                                 

                      







                                                                      

                                                                      








                                                                            




                                                                    

                                                                        
                        
                                                                          
                                                                     
                                                                      
                                                                            







                                      
                                               



           


                                       

                                      
                                                  





                                                

                                                                

                      





                                                                      

                                                                      








                                                                            

                                            

                                                                        
                        
                                                                          
                                                                     
                                                                      
                                                                            








                                      
                                               



           












                                                                      

                                                                      








                                               


                                       






                                                

                                                                        



                      
                                               


         
  


                
  
























                                                                            


                   
                                                                               

                                                             
                             

                                             
                            
 
                                          

                                          
                                                        


                       


                                                                             

                                                                         

                                                                        

 
  















                                                                     
                                                        
















                                                                         


                                             

                                                                


















                                                               


                                                                          


                       
          
                                                                          
           


                                                                            
                                                        

                                                                    



                                                                        
                                           
                                                                      

         
          

                                                      
                                                                        
                    
                  





                                                                              
                                                                              





                                                           
          

                                     
                                                                    
                     
                  





                                                                 
          


                                      
                  


                                                                           
                                                         
                                                              
 
                  





                                                                  
          

                                     
                                         







                                                           

                                                                        
 



                                                  


                                          
 
                                                        


                       


                                                                            




                                                        
                                   



                                                           

                                                               

                                                                         

                                                                           






                                                           

                                                                        


                                                             
                             

                                             

                            




                                          
                                                        






















                                                                              

                                                                
 



                                                                             

                                                                         

                                                                      





                                                          
                                                           

                                                                              
                                

                                                                      
                                                                          
                                                           
                                                           


           
                                                          
 


                                                               




                                                           
                                                         
                                                  

                                                            
                                                           

                                             


           
                                                           
 
                                          
                                      

                                                               




                                                            
                                                         
                                          
                                                                
                                                          

                                                                              

                                                                       
                                                          

                                                                   

                                                                    

                                                     
                                                      
                                                              



           
                                                        
 
                   


           
                                                          
 
                   


           
                                                           
 
                   


           
                                                                            
 


                                
 


                                          
                                                        

















                                                                        
                                               

                                                             
                                                           

                                                        
                        
                                                       
            
                                               


 
  
                                      

    

                                                     
 
                                 
                                             
                                                                          

                                   
                                        
 
                                              



                                                
          






                                                         
                                                                               






                                                                                

                                                                  






                                                                                
                                               



                                                               





                                                                









                                                                         
          

                                             
                                                           








                                                        
          


                                           




                                                             




                                               
                                                                 



                                               
                  

                                                     



                                               
                  

                                                     


                       
          

                                               
                                                                          



                                                             
  


                                                           
                                                                     

                                      
                                    

                                           
                                                      







                                      
  


















                                                                         


                                                            
                                                                         

                                      
                                    

                                           
                                                      




                                                    
                    

 
  


                                                            
                                                                         

                                      
                                    

                                           
                                                      




                                                    
                    

 
  



















                                                                         


                                                         


                                      




                                                  
  


                                                     


                                      
 
                                                       





                                                          
  



                                                                
                                                  



                                                        
  



                                                                       
                                                   



                                                         
  









                                                                





                                                                        
                                                  



                                                        
  


                                                   
                                                     
 
                                                               

 
  
                                                

    

                                                                          


                                                      
                             

                                                              


                                        

 
  


                                                                
 
    

                                                 

                                                     

                                                                
 
                                    
 



                                                                         
 
                                                          
                                               

                                                                 
                                                         
 
                                                         


                                                         
  



                 


                                           
 
                                                            






                                             
                                                               

                                                                    
                                     

                                                               
                                                                              
                                                 

                                                              
 
                                          
                                                                   
                                             
                                                         
                        
                                             
                                                          
                 
                




                                                             
  


                                        
  









                                                                   
  








                                                         
  









                                                          
  


                                
  






                                                    
  






















                                                                              
                                                                      
                  







                                                                                
                                                                        








                                                                         
                                               

                                                                
                                                                            





                                                           
  

























































                                                                                

                                                                    
  


                                      
  











































                                                                                
  
























                                                                             
                                                                              














































































































































                                                                              
         























                                                                             
 





















                                                                              

 




                                                                   
 












































































































































                                                                                
  













                                                                 
  













                                                                               

                                                       

                                                                        
                                                                              




                                         
                                      


























                                                                               
                        






                                                     
                                                   















                                                                  
                                                           



                                                                    
                

                                                              




                                               
                                                               




                                                                   
                

                                                              




                                               
                                                            




                                                                   
                

                                                              




                                               
                                                        




                                                                   
                

                                                              




                                               
                                                             




                                                                   
                

                                                              





                                                       
                                                                     




                                                                           
                        

                                                                      





                                               
                                                                 



                                                                   
                       
                

                                                              





                                                       
                                                                      




                                                                           
                        

                                                                      





                                               
                                                             




                                                                   
                

                                                              





                                                       
                                                                  




                                                                           
                        

                                                                      





                                               
                                                         


                                                                 
                

                                                              



                                 
                                                                  
 
                                                           

























                                                                       
                                                               










                                                             
  













                                                                               

                                                       

                                                                        
                                                                              




                                         
                                      
















                                                                               
  











                                                                                
                        
















                                                        
                                                             



                                                                   

                   

                                                          




                                               
                                                              



                                                                   

                   

                                                          




                                               
                                                              



                                                                   
                

                                                              




                                               
                                                              



                                                                   
                

                                                              





                                                       
                                                                    




                                                                           
                        

                                                                      





                                                       
                                                                     




                                                                           
                        

                                                                      




                                 
                                                     
                                                                  











































                                                                                
                                                               










                                                             
  













                                                                              

                                                       

                                                                        
                                                                             




                                         
                                      



                                                                             

                                                                       















































                                                                               
                                                               


















                                                                                
           





                                                                             
                                                                    
































                                                                           
                                                          

 
           






                                                                             
                                                                      













                                                                       























                                                                    



                        

                                                                              



                        
                                                            














                                                                               


































                                                        
































































                                                                            
  


                                  
  

































                                                                                
  






































































                                                                             
                  

































































































































































                                                                              
  













                                                                           

                                                       

                                                                      
                                                                          





                                                                 
                                                             



































                                                                               
                                                               



                                                                   
                                                             



































































































































                                                                              
  













                                                                          

                                                       

                                                                      
                                                                         





                                                                
                                                             































                                                                               
                                                               
















                                                                                
  













                                                                            

                                                       


                                                                      
                                                                           




                                                              
                                                        

                                                                      

                                                                         




















































































































                                                                               
  





























































                                                                              
  


                                                    
  





















































                                                                                
  







































































































































































































































































































































































































































































































                                                                             
  













                                                                            

                                                       


                                                                      
                                                                           




                                                              
                                                        

                                                                      

                                                                         


































































                                                                               
  












                                                                              
                                        


                                                

                                                       


                                                                      
                                                                             







                                                
                  


























































                                                                                
                                                               












                                                         
  












                                                                             

                                                       


                                                                      
                                                                            






































                                                                               
                                                               












                                                         
  













                                                                             

                                                       


                                                                      
                                                                            










































                                                                               
                                                               
















                                                                      
  















                                                                             

                                                       


                                                                      
                                                                            





















































                                                                               
                                                               










































                                                                         
  






























































                                                                               
  










































                                                                       
           











                                                                    
                                


         
























                                                                                

                                                        


                                                                      
                                                                           
































                                                                               
  





















                                                                           
  


                                    
  






















                                                                               
  






































































































                                                                            
  


                                             
  













                                                                            

                                                       

                                                                       
                                                                           






                                                                         

                                                               







































































                                                                               
                                                        











                                                                          
  





















                                                                             
  







































                                                                          
          



                                                                  


                                                                       










                                                                 
  











































                                                                       
                                              




























































                                                                               
                                   



                                           


                                                                        




                                             
  

               
  




























                                                                           
                                                        


























                                                           

                                                                    





                                             
                                                            










                                                      
                                                        






                                                        






                                                  









































                                                                          
                                                          

                                                                                











                                                                             
                                            
                                                



                                    


                                       









                                                                  
                             












































                                                                   
                                                 




























                                                                     
                                                                      

 
  



















                                                                      
  


                                               
  















                                                                            
                                                                     











                                                                             

                                                                              









                                                                          



                                                                             






                                                                          
                                                                                






                                                                    
  



















                                                                      
  










                                                                           

                                                                 



                                                                            
                          














                                                                          
                  









                                                           
  




















                                                                  




                                                                       















                                                                            
  










                                                         
                                                                         



                                                                  
                                                                  


























                                                                      
  
































                                                                  
  


































                                                                   














                                                                   




                                                                       

                                                                  
                                                                  







                                                        
  

























                                                                        



























                                                                    
  






















                                                                  
  















                                                                       



                                                                  







                                                        
  



























                                                                        











                                                                            
                                                                  



















                                                                 
  

                                                        
  
























                                                                            













                                                             

                                                            




                                                               
                                         



                                                                             


                                                                    
                                                                               
                 








                                                                             


                                                                       
                                                                              
                 


                      


                                                                    



                                                                     
  












                                                                    
  



























                                                                             
                                   
 
                                  
                                              

                       
 




                                                                        
                                                                            

 
  


                                                       
  





                                                   



                                                                  

 
  








                                                           
  






                                                            









                                                                   
  







                                                                     
  








                                                            









                                                           
  


                                  
  





























                                                                                
                                     

















                                                               
  




























                                                                                
  
















                                                                    
  













                                                         
  















                                                                            
  




















                                                                        
  













                                                                  
                                                         




                                                                       
 
  




















                                                                   
  












                                                                  
                                               
                   
                                                         











                                                                     
                                                 

























                                                                     
  








                                                          
  










                                                           
/*
 * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
 * All rights reserved
 * www.brocade.com
 *
 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License (GPL) Version 2 as
 * published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

#include "bfad_drv.h"
#include "bfad_im.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
#include "bfa_fc.h"

BFA_TRC_FILE(FCS, PORT);

static void     bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port,
					 struct fchs_s *rx_fchs, u8 reason_code,
					 u8 reason_code_expl);
static void     bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
			struct fchs_s *rx_fchs, struct fc_logi_s *plogi);
static void     bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port,
			struct fchs_s *rx_fchs,
			struct fc_echo_s *echo, u16 len);
static void     bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port,
			struct fchs_s *rx_fchs,
			struct fc_rnid_cmd_s *rnid, u16 len);
static void     bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port,
			struct fc_rnid_general_topology_data_s *gen_topo_data);

static void	bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port);
static void	bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port);
static void	bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port);

static void	bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port);
static void	bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port);
static void	bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port);

static struct {
	void		(*init) (struct bfa_fcs_lport_s *port);
	void		(*online) (struct bfa_fcs_lport_s *port);
	void		(*offline) (struct bfa_fcs_lport_s *port);
} __port_action[] = {
	{
	bfa_fcs_lport_unknown_init, bfa_fcs_lport_unknown_online,
			bfa_fcs_lport_unknown_offline}, {
	bfa_fcs_lport_fab_init, bfa_fcs_lport_fab_online,
			bfa_fcs_lport_fab_offline}, {
	bfa_fcs_lport_n2n_init, bfa_fcs_lport_n2n_online,
			bfa_fcs_lport_n2n_offline},
	};

/*
 *  fcs_port_sm FCS logical port state machine
 */

enum bfa_fcs_lport_event {
	BFA_FCS_PORT_SM_CREATE = 1,
	BFA_FCS_PORT_SM_ONLINE = 2,
	BFA_FCS_PORT_SM_OFFLINE = 3,
	BFA_FCS_PORT_SM_DELETE = 4,
	BFA_FCS_PORT_SM_DELRPORT = 5,
	BFA_FCS_PORT_SM_STOP = 6,
};

static void     bfa_fcs_lport_sm_uninit(struct bfa_fcs_lport_s *port,
					enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port,
					enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_online(struct bfa_fcs_lport_s *port,
					enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_offline(struct bfa_fcs_lport_s *port,
					enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_deleting(struct bfa_fcs_lport_s *port,
					enum bfa_fcs_lport_event event);
static void	bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port,
					enum bfa_fcs_lport_event event);

static void
bfa_fcs_lport_sm_uninit(
	struct bfa_fcs_lport_s *port,
	enum bfa_fcs_lport_event event)
{
	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case BFA_FCS_PORT_SM_CREATE:
		bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port,
			enum bfa_fcs_lport_event event)
{
	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case BFA_FCS_PORT_SM_ONLINE:
		bfa_sm_set_state(port, bfa_fcs_lport_sm_online);
		bfa_fcs_lport_online_actions(port);
		break;

	case BFA_FCS_PORT_SM_DELETE:
		bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
		bfa_fcs_lport_deleted(port);
		break;

	case BFA_FCS_PORT_SM_STOP:
		/* If vport - send completion call back */
		if (port->vport)
			bfa_fcs_vport_stop_comp(port->vport);
		else
			bfa_wc_down(&(port->fabric->stop_wc));
		break;

	case BFA_FCS_PORT_SM_OFFLINE:
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_sm_online(
	struct bfa_fcs_lport_s *port,
	enum bfa_fcs_lport_event event)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head		*qe, *qen;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case BFA_FCS_PORT_SM_OFFLINE:
		bfa_sm_set_state(port, bfa_fcs_lport_sm_offline);
		bfa_fcs_lport_offline_actions(port);
		break;

	case BFA_FCS_PORT_SM_STOP:
		__port_action[port->fabric->fab_type].offline(port);

		if (port->num_rports == 0) {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
			/* If vport - send completion call back */
			if (port->vport)
				bfa_fcs_vport_stop_comp(port->vport);
			else
				bfa_wc_down(&(port->fabric->stop_wc));
		} else {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping);
			list_for_each_safe(qe, qen, &port->rport_q) {
				rport = (struct bfa_fcs_rport_s *) qe;
				bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
			}
		}
		break;

	case BFA_FCS_PORT_SM_DELETE:

		__port_action[port->fabric->fab_type].offline(port);

		if (port->num_rports == 0) {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
			bfa_fcs_lport_deleted(port);
		} else {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
			list_for_each_safe(qe, qen, &port->rport_q) {
				rport = (struct bfa_fcs_rport_s *) qe;
				bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
			}
		}
		break;

	case BFA_FCS_PORT_SM_DELRPORT:
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_sm_offline(
	struct bfa_fcs_lport_s *port,
	enum bfa_fcs_lport_event event)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head		*qe, *qen;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case BFA_FCS_PORT_SM_ONLINE:
		bfa_sm_set_state(port, bfa_fcs_lport_sm_online);
		bfa_fcs_lport_online_actions(port);
		break;

	case BFA_FCS_PORT_SM_STOP:
		if (port->num_rports == 0) {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
			/* If vport - send completion call back */
			if (port->vport)
				bfa_fcs_vport_stop_comp(port->vport);
			else
				bfa_wc_down(&(port->fabric->stop_wc));
		} else {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping);
			list_for_each_safe(qe, qen, &port->rport_q) {
				rport = (struct bfa_fcs_rport_s *) qe;
				bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
			}
		}
		break;

	case BFA_FCS_PORT_SM_DELETE:
		if (port->num_rports == 0) {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
			bfa_fcs_lport_deleted(port);
		} else {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
			list_for_each_safe(qe, qen, &port->rport_q) {
				rport = (struct bfa_fcs_rport_s *) qe;
				bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
			}
		}
		break;

	case BFA_FCS_PORT_SM_DELRPORT:
	case BFA_FCS_PORT_SM_OFFLINE:
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port,
			  enum bfa_fcs_lport_event event)
{
	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case BFA_FCS_PORT_SM_DELRPORT:
		if (port->num_rports == 0) {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
			/* If vport - send completion call back */
			if (port->vport)
				bfa_fcs_vport_stop_comp(port->vport);
			else
				bfa_wc_down(&(port->fabric->stop_wc));
		}
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_sm_deleting(
	struct bfa_fcs_lport_s *port,
	enum bfa_fcs_lport_event event)
{
	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case BFA_FCS_PORT_SM_DELRPORT:
		if (port->num_rports == 0) {
			bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
			bfa_fcs_lport_deleted(port);
		}
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

/*
 *  fcs_port_pvt
 */

/*
 * Send AEN notification
 */
static void
bfa_fcs_lport_aen_post(struct bfa_fcs_lport_s *port,
			enum bfa_lport_aen_event event)
{
	struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
	struct bfa_aen_entry_s  *aen_entry;

	bfad_get_aen_entry(bfad, aen_entry);
	if (!aen_entry)
		return;

	aen_entry->aen_data.lport.vf_id = port->fabric->vf_id;
	aen_entry->aen_data.lport.roles = port->port_cfg.roles;
	aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn(
					bfa_fcs_get_base_port(port->fcs));
	aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port);

	/* Send the AEN notification */
	bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
				  BFA_AEN_CAT_LPORT, event);
}

/*
 * Send a LS reject
 */
static void
bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
			 u8 reason_code, u8 reason_code_expl)
{
	struct fchs_s	fchs;
	struct bfa_fcxp_s *fcxp;
	struct bfa_rport_s *bfa_rport = NULL;
	int		len;

	bfa_trc(port->fcs, rx_fchs->d_id);
	bfa_trc(port->fcs, rx_fchs->s_id);

	fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
	if (!fcxp)
		return;

	len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			      rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
			      rx_fchs->ox_id, reason_code, reason_code_expl);

	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
			  BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
			  FC_MAX_PDUSZ, 0);
}

/*
 * Send a FCCT Reject
 */
static void
bfa_fcs_lport_send_fcgs_rjt(struct bfa_fcs_lport_s *port,
	struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl)
{
	struct fchs_s   fchs;
	struct bfa_fcxp_s *fcxp;
	struct bfa_rport_s *bfa_rport = NULL;
	int             len;
	struct ct_hdr_s *rx_cthdr = (struct ct_hdr_s *)(rx_fchs + 1);
	struct ct_hdr_s *ct_hdr;

	bfa_trc(port->fcs, rx_fchs->d_id);
	bfa_trc(port->fcs, rx_fchs->s_id);

	fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
	if (!fcxp)
		return;

	ct_hdr = bfa_fcxp_get_reqbuf(fcxp);
	ct_hdr->gs_type = rx_cthdr->gs_type;
	ct_hdr->gs_sub_type = rx_cthdr->gs_sub_type;

	len = fc_gs_rjt_build(&fchs, ct_hdr, rx_fchs->s_id,
			bfa_fcs_lport_get_fcid(port),
			rx_fchs->ox_id, reason_code, reason_code_expl);

	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
			BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
			FC_MAX_PDUSZ, 0);
}

/*
 * Process incoming plogi from a remote port.
 */
static void
bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
		struct fchs_s *rx_fchs, struct fc_logi_s *plogi)
{
	struct bfa_fcs_rport_s *rport;

	bfa_trc(port->fcs, rx_fchs->d_id);
	bfa_trc(port->fcs, rx_fchs->s_id);

	/*
	 * If min cfg mode is enabled, drop any incoming PLOGIs
	 */
	if (__fcs_min_cfg(port->fcs)) {
		bfa_trc(port->fcs, rx_fchs->s_id);
		return;
	}

	if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) {
		bfa_trc(port->fcs, rx_fchs->s_id);
		/*
		 * send a LS reject
		 */
		bfa_fcs_lport_send_ls_rjt(port, rx_fchs,
					FC_LS_RJT_RSN_PROTOCOL_ERROR,
					FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS);
		return;
	}

	/*
	 * Direct Attach P2P mode : verify address assigned by the r-port.
	 */
	if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
		(memcmp((void *)&bfa_fcs_lport_get_pwwn(port),
			   (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
		if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) {
			/* Address assigned to us cannot be a WKA */
			bfa_fcs_lport_send_ls_rjt(port, rx_fchs,
					FC_LS_RJT_RSN_PROTOCOL_ERROR,
					FC_LS_RJT_EXP_INVALID_NPORT_ID);
			return;
		}
		port->pid  = rx_fchs->d_id;
		bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
	}

	/*
	 * First, check if we know the device by pwwn.
	 */
	rport = bfa_fcs_lport_get_rport_by_pwwn(port, plogi->port_name);
	if (rport) {
		/*
		 * Direct Attach P2P mode : handle address assigned by r-port.
		 */
		if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
			(memcmp((void *)&bfa_fcs_lport_get_pwwn(port),
			(void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
			port->pid  = rx_fchs->d_id;
			bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
			rport->pid = rx_fchs->s_id;
		}
		bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
		return;
	}

	/*
	 * Next, lookup rport by PID.
	 */
	rport = bfa_fcs_lport_get_rport_by_pid(port, rx_fchs->s_id);
	if (!rport) {
		/*
		 * Inbound PLOGI from a new device.
		 */
		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
		return;
	}

	/*
	 * Rport is known only by PID.
	 */
	if (rport->pwwn) {
		/*
		 * This is a different device with the same pid. Old device
		 * disappeared. Send implicit LOGO to old device.
		 */
		WARN_ON(rport->pwwn == plogi->port_name);
		bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);

		/*
		 * Inbound PLOGI from a new device (with old PID).
		 */
		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
		return;
	}

	/*
	 * PLOGI crossing each other.
	 */
	WARN_ON(rport->pwwn != WWN_NULL);
	bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
}

/*
 * Process incoming ECHO.
 * Since it does not require a login, it is processed here.
 */
static void
bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
		struct fc_echo_s *echo, u16 rx_len)
{
	struct fchs_s		fchs;
	struct bfa_fcxp_s	*fcxp;
	struct bfa_rport_s	*bfa_rport = NULL;
	int			len, pyld_len;

	bfa_trc(port->fcs, rx_fchs->s_id);
	bfa_trc(port->fcs, rx_fchs->d_id);

	fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
	if (!fcxp)
		return;

	len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
				rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
				rx_fchs->ox_id);

	/*
	 * Copy the payload (if any) from the echo frame
	 */
	pyld_len = rx_len - sizeof(struct fchs_s);
	bfa_trc(port->fcs, rx_len);
	bfa_trc(port->fcs, pyld_len);

	if (pyld_len > len)
		memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) +
			sizeof(struct fc_echo_s), (echo + 1),
			(pyld_len - sizeof(struct fc_echo_s)));

	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
			BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL,
			FC_MAX_PDUSZ, 0);
}

/*
 * Process incoming RNID.
 * Since it does not require a login, it is processed here.
 */
static void
bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
		struct fc_rnid_cmd_s *rnid, u16 rx_len)
{
	struct fc_rnid_common_id_data_s common_id_data;
	struct fc_rnid_general_topology_data_s gen_topo_data;
	struct fchs_s	fchs;
	struct bfa_fcxp_s *fcxp;
	struct bfa_rport_s *bfa_rport = NULL;
	u16	len;
	u32	data_format;

	bfa_trc(port->fcs, rx_fchs->s_id);
	bfa_trc(port->fcs, rx_fchs->d_id);
	bfa_trc(port->fcs, rx_len);

	fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
	if (!fcxp)
		return;

	/*
	 * Check Node Indentification Data Format
	 * We only support General Topology Discovery Format.
	 * For any other requested Data Formats, we return Common Node Id Data
	 * only, as per FC-LS.
	 */
	bfa_trc(port->fcs, rnid->node_id_data_format);
	if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
		data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY;
		/*
		 * Get General topology data for this port
		 */
		bfa_fs_port_get_gen_topo_data(port, &gen_topo_data);
	} else {
		data_format = RNID_NODEID_DATA_FORMAT_COMMON;
	}

	/*
	 * Copy the Node Id Info
	 */
	common_id_data.port_name = bfa_fcs_lport_get_pwwn(port);
	common_id_data.node_name = bfa_fcs_lport_get_nwwn(port);

	len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
				rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
				rx_fchs->ox_id, data_format, &common_id_data,
				&gen_topo_data);

	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
			BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
			FC_MAX_PDUSZ, 0);
}

/*
 *  Fill out General Topolpgy Discovery Data for RNID ELS.
 */
static void
bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port,
			struct fc_rnid_general_topology_data_s *gen_topo_data)
{
	memset(gen_topo_data, 0,
		      sizeof(struct fc_rnid_general_topology_data_s));

	gen_topo_data->asso_type = cpu_to_be32(RNID_ASSOCIATED_TYPE_HOST);
	gen_topo_data->phy_port_num = 0;	/* @todo */
	gen_topo_data->num_attached_nodes = cpu_to_be32(1);
}

static void
bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port)
{
	struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
	char	lpwwn_buf[BFA_STRING_32];

	bfa_trc(port->fcs, port->fabric->oper_type);

	__port_action[port->fabric->fab_type].init(port);
	__port_action[port->fabric->fab_type].online(port);

	wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
	BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
		"Logical port online: WWN = %s Role = %s\n",
		lpwwn_buf, "Initiator");
	bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_ONLINE);

	bfad->bfad_flags |= BFAD_PORT_ONLINE;
}

static void
bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port)
{
	struct list_head	*qe, *qen;
	struct bfa_fcs_rport_s *rport;
	struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
	char    lpwwn_buf[BFA_STRING_32];

	bfa_trc(port->fcs, port->fabric->oper_type);

	__port_action[port->fabric->fab_type].offline(port);

	wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
	if (bfa_sm_cmp_state(port->fabric,
			bfa_fcs_fabric_sm_online) == BFA_TRUE) {
		BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
		"Logical port lost fabric connectivity: WWN = %s Role = %s\n",
		lpwwn_buf, "Initiator");
		bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
	} else {
		BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
		"Logical port taken offline: WWN = %s Role = %s\n",
		lpwwn_buf, "Initiator");
		bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_OFFLINE);
	}

	list_for_each_safe(qe, qen, &port->rport_q) {
		rport = (struct bfa_fcs_rport_s *) qe;
		bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
	}
}

static void
bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port)
{
	WARN_ON(1);
}

static void
bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port)
{
	WARN_ON(1);
}

static void
bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port)
{
	WARN_ON(1);
}

static void
bfa_fcs_lport_abts_acc(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs)
{
	struct fchs_s fchs;
	struct bfa_fcxp_s *fcxp;
	int		len;

	bfa_trc(port->fcs, rx_fchs->d_id);
	bfa_trc(port->fcs, rx_fchs->s_id);

	fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
	if (!fcxp)
		return;

	len = fc_ba_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
			rx_fchs->ox_id, 0);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag,
			  BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
			  FC_MAX_PDUSZ, 0);
}
static void
bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
{
	struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
	char    lpwwn_buf[BFA_STRING_32];

	wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
	BFA_LOG(KERN_INFO, bfad, bfa_log_level,
		"Logical port deleted: WWN = %s Role = %s\n",
		lpwwn_buf, "Initiator");
	bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE);

	/* Base port will be deleted by the OS driver */
	if (port->vport)
		bfa_fcs_vport_delete_comp(port->vport);
	else
		bfa_wc_down(&port->fabric->wc);
}


/*
 * Unsolicited frame receive handling.
 */
void
bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
			struct fchs_s *fchs, u16 len)
{
	u32	pid = fchs->s_id;
	struct bfa_fcs_rport_s *rport = NULL;
	struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);

	bfa_stats(lport, uf_recvs);
	bfa_trc(lport->fcs, fchs->type);

	if (!bfa_fcs_lport_is_online(lport)) {
		bfa_stats(lport, uf_recv_drops);
		return;
	}

	/*
	 * First, handle ELSs that donot require a login.
	 */
	/*
	 * Handle PLOGI first
	 */
	if ((fchs->type == FC_TYPE_ELS) &&
		(els_cmd->els_code == FC_ELS_PLOGI)) {
		bfa_fcs_lport_plogi(lport, fchs, (struct fc_logi_s *) els_cmd);
		return;
	}

	/*
	 * Handle ECHO separately.
	 */
	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) {
		bfa_fcs_lport_echo(lport, fchs,
				(struct fc_echo_s *)els_cmd, len);
		return;
	}

	/*
	 * Handle RNID separately.
	 */
	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) {
		bfa_fcs_lport_rnid(lport, fchs,
			(struct fc_rnid_cmd_s *) els_cmd, len);
		return;
	}

	if (fchs->type == FC_TYPE_BLS) {
		if ((fchs->routing == FC_RTG_BASIC_LINK) &&
				(fchs->cat_info == FC_CAT_ABTS))
			bfa_fcs_lport_abts_acc(lport, fchs);
		return;
	}

	if (fchs->type == FC_TYPE_SERVICES) {
		/*
		 * Unhandled FC-GS frames. Send a FC-CT Reject
		 */
		bfa_fcs_lport_send_fcgs_rjt(lport, fchs, CT_RSN_NOT_SUPP,
				CT_NS_EXP_NOADDITIONAL);
		return;
	}

	/*
	 * look for a matching remote port ID
	 */
	rport = bfa_fcs_lport_get_rport_by_pid(lport, pid);
	if (rport) {
		bfa_trc(rport->fcs, fchs->s_id);
		bfa_trc(rport->fcs, fchs->d_id);
		bfa_trc(rport->fcs, fchs->type);

		bfa_fcs_rport_uf_recv(rport, fchs, len);
		return;
	}

	/*
	 * Only handles ELS frames for now.
	 */
	if (fchs->type != FC_TYPE_ELS) {
		bfa_trc(lport->fcs, fchs->s_id);
		bfa_trc(lport->fcs, fchs->d_id);
		/* ignore type FC_TYPE_FC_FSS */
		if (fchs->type != FC_TYPE_FC_FSS)
			bfa_sm_fault(lport->fcs, fchs->type);
		return;
	}

	bfa_trc(lport->fcs, els_cmd->els_code);
	if (els_cmd->els_code == FC_ELS_RSCN) {
		bfa_fcs_lport_scn_process_rscn(lport, fchs, len);
		return;
	}

	if (els_cmd->els_code == FC_ELS_LOGO) {
		/*
		 * @todo Handle LOGO frames received.
		 */
		return;
	}

	if (els_cmd->els_code == FC_ELS_PRLI) {
		/*
		 * @todo Handle PRLI frames received.
		 */
		return;
	}

	/*
	 * Unhandled ELS frames. Send a LS_RJT.
	 */
	bfa_fcs_lport_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
				 FC_LS_RJT_EXP_NO_ADDL_INFO);

}

/*
 *   PID based Lookup for a R-Port in the Port R-Port Queue
 */
struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_pid(struct bfa_fcs_lport_s *port, u32 pid)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head	*qe;

	list_for_each(qe, &port->rport_q) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if (rport->pid == pid)
			return rport;
	}

	bfa_trc(port->fcs, pid);
	return NULL;
}

/*
 * OLD_PID based Lookup for a R-Port in the Port R-Port Queue
 */
struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_old_pid(struct bfa_fcs_lport_s *port, u32 pid)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head	*qe;

	list_for_each(qe, &port->rport_q) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if (rport->old_pid == pid)
			return rport;
	}

	bfa_trc(port->fcs, pid);
	return NULL;
}

/*
 *   PWWN based Lookup for a R-Port in the Port R-Port Queue
 */
struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_pwwn(struct bfa_fcs_lport_s *port, wwn_t pwwn)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head	*qe;

	list_for_each(qe, &port->rport_q) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if (wwn_is_equal(rport->pwwn, pwwn))
			return rport;
	}

	bfa_trc(port->fcs, pwwn);
	return NULL;
}

/*
 *   NWWN based Lookup for a R-Port in the Port R-Port Queue
 */
struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t nwwn)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head	*qe;

	list_for_each(qe, &port->rport_q) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if (wwn_is_equal(rport->nwwn, nwwn))
			return rport;
	}

	bfa_trc(port->fcs, nwwn);
	return NULL;
}

/*
 * PWWN & PID based Lookup for a R-Port in the Port R-Port Queue
 */
struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_qualifier(struct bfa_fcs_lport_s *port,
				     wwn_t pwwn, u32 pid)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head	*qe;

	list_for_each(qe, &port->rport_q) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if (wwn_is_equal(rport->pwwn, pwwn) && rport->pid == pid)
			return rport;
	}

	bfa_trc(port->fcs, pwwn);
	return NULL;
}

/*
 * Called by rport module when new rports are discovered.
 */
void
bfa_fcs_lport_add_rport(
	struct bfa_fcs_lport_s *port,
	struct bfa_fcs_rport_s *rport)
{
	list_add_tail(&rport->qe, &port->rport_q);
	port->num_rports++;
}

/*
 * Called by rport module to when rports are deleted.
 */
void
bfa_fcs_lport_del_rport(
	struct bfa_fcs_lport_s *port,
	struct bfa_fcs_rport_s *rport)
{
	WARN_ON(!bfa_q_is_on_q(&port->rport_q, rport));
	list_del(&rport->qe);
	port->num_rports--;

	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
}

/*
 * Called by fabric for base port when fabric login is complete.
 * Called by vport for virtual ports when FDISC is complete.
 */
void
bfa_fcs_lport_online(struct bfa_fcs_lport_s *port)
{
	bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
}

/*
 * Called by fabric for base port when fabric goes offline.
 * Called by vport for virtual ports when virtual port becomes offline.
 */
void
bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port)
{
	bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
}

/*
 * Called by fabric for base port and by vport for virtual ports
 * when target mode driver is unloaded.
 */
void
bfa_fcs_lport_stop(struct bfa_fcs_lport_s *port)
{
	bfa_sm_send_event(port, BFA_FCS_PORT_SM_STOP);
}

/*
 * Called by fabric to delete base lport and associated resources.
 *
 * Called by vport to delete lport and associated resources. Should call
 * bfa_fcs_vport_delete_comp() for vports on completion.
 */
void
bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port)
{
	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
}

/*
 * Return TRUE if port is online, else return FALSE
 */
bfa_boolean_t
bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port)
{
	return bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online);
}

/*
  * Attach time initialization of logical ports.
 */
void
bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs,
		   u16 vf_id, struct bfa_fcs_vport_s *vport)
{
	lport->fcs = fcs;
	lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
	lport->vport = vport;
	lport->lp_tag = (vport) ? vport->lps->bfa_tag :
				  lport->fabric->lps->bfa_tag;

	INIT_LIST_HEAD(&lport->rport_q);
	lport->num_rports = 0;
}

/*
 * Logical port initialization of base or virtual port.
 * Called by fabric for base port or by vport for virtual ports.
 */

void
bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
	struct bfa_lport_cfg_s *port_cfg)
{
	struct bfa_fcs_vport_s *vport = lport->vport;
	struct bfad_s *bfad = (struct bfad_s *)lport->fcs->bfad;
	char    lpwwn_buf[BFA_STRING_32];

	lport->port_cfg = *port_cfg;

	lport->bfad_port = bfa_fcb_lport_new(lport->fcs->bfad, lport,
					lport->port_cfg.roles,
					lport->fabric->vf_drv,
					vport ? vport->vport_drv : NULL);

	wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport));
	BFA_LOG(KERN_INFO, bfad, bfa_log_level,
		"New logical port created: WWN = %s Role = %s\n",
		lpwwn_buf, "Initiator");
	bfa_fcs_lport_aen_post(lport, BFA_LPORT_AEN_NEW);

	bfa_sm_set_state(lport, bfa_fcs_lport_sm_uninit);
	bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
}

/*
 *  fcs_lport_api
 */

void
bfa_fcs_lport_get_attr(
	struct bfa_fcs_lport_s *port,
	struct bfa_lport_attr_s *port_attr)
{
	if (bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online))
		port_attr->pid = port->pid;
	else
		port_attr->pid = 0;

	port_attr->port_cfg = port->port_cfg;

	if (port->fabric) {
		port_attr->port_type = port->fabric->oper_type;
		port_attr->loopback = bfa_sm_cmp_state(port->fabric,
				bfa_fcs_fabric_sm_loopback);
		port_attr->authfail =
			bfa_sm_cmp_state(port->fabric,
				bfa_fcs_fabric_sm_auth_failed);
		port_attr->fabric_name  = bfa_fcs_lport_get_fabric_name(port);
		memcpy(port_attr->fabric_ip_addr,
			bfa_fcs_lport_get_fabric_ipaddr(port),
			BFA_FCS_FABRIC_IPADDR_SZ);

		if (port->vport != NULL) {
			port_attr->port_type = BFA_PORT_TYPE_VPORT;
			port_attr->fpma_mac =
				port->vport->lps->lp_mac;
		} else {
			port_attr->fpma_mac =
				port->fabric->lps->lp_mac;
		}
	} else {
		port_attr->port_type = BFA_PORT_TYPE_UNKNOWN;
		port_attr->state = BFA_LPORT_UNINIT;
	}
}

/*
 *  bfa_fcs_lport_fab port fab functions
 */

/*
 *   Called by port to initialize fabric services of the base port.
 */
static void
bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port)
{
	bfa_fcs_lport_ns_init(port);
	bfa_fcs_lport_scn_init(port);
	bfa_fcs_lport_ms_init(port);
}

/*
 *   Called by port to notify transition to online state.
 */
static void
bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port)
{
	bfa_fcs_lport_ns_online(port);
	bfa_fcs_lport_scn_online(port);
}

/*
 *   Called by port to notify transition to offline state.
 */
static void
bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port)
{
	bfa_fcs_lport_ns_offline(port);
	bfa_fcs_lport_scn_offline(port);
	bfa_fcs_lport_ms_offline(port);
}

/*
 *  bfa_fcs_lport_n2n  functions
 */

/*
 *   Called by fcs/port to initialize N2N topology.
 */
static void
bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port)
{
}

/*
 *   Called by fcs/port to notify transition to online state.
 */
static void
bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n;
	struct bfa_lport_cfg_s *pcfg = &port->port_cfg;
	struct bfa_fcs_rport_s *rport;

	bfa_trc(port->fcs, pcfg->pwwn);

	/*
	 * If our PWWN is > than that of the r-port, we have to initiate PLOGI
	 * and assign an Address. if not, we need to wait for its PLOGI.
	 *
	 * If our PWWN is < than that of the remote port, it will send a PLOGI
	 * with the PIDs assigned. The rport state machine take care of this
	 * incoming PLOGI.
	 */
	if (memcmp
	    ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn,
	     sizeof(wwn_t)) > 0) {
		port->pid = N2N_LOCAL_PID;
		bfa_lps_set_n2n_pid(port->fabric->lps, N2N_LOCAL_PID);
		/*
		 * First, check if we know the device by pwwn.
		 */
		rport = bfa_fcs_lport_get_rport_by_pwwn(port,
							n2n_port->rem_port_wwn);
		if (rport) {
			bfa_trc(port->fcs, rport->pid);
			bfa_trc(port->fcs, rport->pwwn);
			rport->pid = N2N_REMOTE_PID;
			bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
			return;
		}

		/*
		 * In n2n there can be only one rport. Delete the old one
		 * whose pid should be zero, because it is offline.
		 */
		if (port->num_rports > 0) {
			rport = bfa_fcs_lport_get_rport_by_pid(port, 0);
			WARN_ON(rport == NULL);
			if (rport) {
				bfa_trc(port->fcs, rport->pwwn);
				bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
			}
		}
		bfa_fcs_rport_create(port, N2N_REMOTE_PID);
	}
}

/*
 *   Called by fcs/port to notify transition to offline state.
 */
static void
bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n;

	bfa_trc(port->fcs, port->pid);
	port->pid = 0;
	n2n_port->rem_port_wwn = 0;
	n2n_port->reply_oxid = 0;
}

#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2

/*
 * forward declarations
 */
static void     bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg,
					    struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg,
					    struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg,
					   struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_fdmi_rhba_response(void *fcsarg,
						struct bfa_fcxp_s *fcxp,
						void *cbarg,
						bfa_status_t req_status,
						u32 rsp_len,
						u32 resid_len,
						struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_fdmi_rprt_response(void *fcsarg,
						struct bfa_fcxp_s *fcxp,
						void *cbarg,
						bfa_status_t req_status,
						u32 rsp_len,
						u32 resid_len,
						struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_fdmi_rpa_response(void *fcsarg,
					       struct bfa_fcxp_s *fcxp,
					       void *cbarg,
					       bfa_status_t req_status,
					       u32 rsp_len,
					       u32 resid_len,
					       struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_fdmi_timeout(void *arg);
static u16 bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi,
						  u8 *pyld);
static u16 bfa_fcs_lport_fdmi_build_rprt_pyld(struct bfa_fcs_lport_fdmi_s *fdmi,
						  u8 *pyld);
static u16 bfa_fcs_lport_fdmi_build_rpa_pyld(struct bfa_fcs_lport_fdmi_s *fdmi,
						 u8 *pyld);
static u16 bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *
						       fdmi, u8 *pyld);
static void	bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
				 struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
static void	bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
				  struct bfa_fcs_fdmi_port_attr_s *port_attr);
u32	bfa_fcs_fdmi_convert_speed(enum bfa_port_speed pport_speed);

/*
 *  fcs_fdmi_sm FCS FDMI state machine
 */

/*
 *  FDMI State Machine events
 */
enum port_fdmi_event {
	FDMISM_EVENT_PORT_ONLINE = 1,
	FDMISM_EVENT_PORT_OFFLINE = 2,
	FDMISM_EVENT_RSP_OK = 4,
	FDMISM_EVENT_RSP_ERROR = 5,
	FDMISM_EVENT_TIMEOUT = 6,
	FDMISM_EVENT_RHBA_SENT = 7,
	FDMISM_EVENT_RPRT_SENT = 8,
	FDMISM_EVENT_RPA_SENT = 9,
};

static void     bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi,
					     enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_sending_rhba(
				struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi,
					  enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rhba_retry(
				struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_sending_rprt(
				struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi,
					  enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rprt_retry(
				struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_sending_rpa(
				struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi,
					 enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rpa_retry(
				struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
					    enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_disabled(
				struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event);
/*
 *	Start in offline state - awaiting MS to send start.
 */
static void
bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi,
			     enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	fdmi->retry_cnt = 0;

	switch (event) {
	case FDMISM_EVENT_PORT_ONLINE:
		if (port->vport) {
			/*
			 * For Vports, register a new port.
			 */
			bfa_sm_set_state(fdmi,
					 bfa_fcs_lport_fdmi_sm_sending_rprt);
			bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL);
		} else {
			/*
			 * For a base port, we should first register the HBA
			 * attribute. The HBA attribute also contains the base
			 *  port registration.
			 */
			bfa_sm_set_state(fdmi,
					 bfa_fcs_lport_fdmi_sm_sending_rhba);
			bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL);
		}
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_sending_rhba(struct bfa_fcs_lport_fdmi_s *fdmi,
				  enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_RHBA_SENT:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rhba);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
					   &fdmi->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi,
			enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_RSP_ERROR:
		/*
		 * if max retries have not been reached, start timer for a
		 * delayed retry
		 */
		if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
			bfa_sm_set_state(fdmi,
					bfa_fcs_lport_fdmi_sm_rhba_retry);
			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
					    &fdmi->timer,
					    bfa_fcs_lport_fdmi_timeout, fdmi,
					    BFA_FCS_RETRY_TIMEOUT);
		} else {
			/*
			 * set state to offline
			 */
			bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		}
		break;

	case FDMISM_EVENT_RSP_OK:
		/*
		 * Initiate Register Port Attributes
		 */
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa);
		fdmi->retry_cnt = 0;
		bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_fcxp_discard(fdmi->fcxp);
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_rhba_retry(struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rhba);
		bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		bfa_timer_stop(&fdmi->timer);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

/*
* RPRT : Register Port
 */
static void
bfa_fcs_lport_fdmi_sm_sending_rprt(struct bfa_fcs_lport_fdmi_s *fdmi,
				  enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_RPRT_SENT:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rprt);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
					   &fdmi->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi,
			enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_RSP_ERROR:
		/*
		 * if max retries have not been reached, start timer for a
		 * delayed retry
		 */
		if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
			bfa_sm_set_state(fdmi,
					bfa_fcs_lport_fdmi_sm_rprt_retry);
			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
					    &fdmi->timer,
					    bfa_fcs_lport_fdmi_timeout, fdmi,
					    BFA_FCS_RETRY_TIMEOUT);

		} else {
			/*
			 * set state to offline
			 */
			bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
			fdmi->retry_cnt = 0;
		}
		break;

	case FDMISM_EVENT_RSP_OK:
		fdmi->retry_cnt = 0;
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_fcxp_discard(fdmi->fcxp);
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_rprt_retry(struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rprt);
		bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		bfa_timer_stop(&fdmi->timer);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

/*
 * Register Port Attributes
 */
static void
bfa_fcs_lport_fdmi_sm_sending_rpa(struct bfa_fcs_lport_fdmi_s *fdmi,
				 enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_RPA_SENT:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
					   &fdmi->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi,
			enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_RSP_ERROR:
		/*
		 * if max retries have not been reached, start timer for a
		 * delayed retry
		 */
		if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
			bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa_retry);
			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
					    &fdmi->timer,
					    bfa_fcs_lport_fdmi_timeout, fdmi,
					    BFA_FCS_RETRY_TIMEOUT);
		} else {
			/*
			 * set state to offline
			 */
			bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
			fdmi->retry_cnt = 0;
		}
		break;

	case FDMISM_EVENT_RSP_OK:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online);
		fdmi->retry_cnt = 0;
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_fcxp_discard(fdmi->fcxp);
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_rpa_retry(struct bfa_fcs_lport_fdmi_s *fdmi,
			       enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa);
		bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL);
		break;

	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		bfa_timer_stop(&fdmi->timer);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
				enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	switch (event) {
	case FDMISM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}
/*
 *  FDMI is disabled state.
 */
static void
bfa_fcs_lport_fdmi_sm_disabled(struct bfa_fcs_lport_fdmi_s *fdmi,
			     enum port_fdmi_event event)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;

	bfa_trc(port->fcs, port->port_cfg.pwwn);
	bfa_trc(port->fcs, event);

	/* No op State. It can only be enabled at Driver Init. */
}

/*
*  RHBA : Register HBA Attributes.
 */
static void
bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg;
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct fchs_s fchs;
	int             len, attr_len;
	struct bfa_fcxp_s *fcxp;
	u8        *pyld;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
				bfa_fcs_lport_fdmi_send_rhba, fdmi, BFA_TRUE);
		return;
	}
	fdmi->fcxp = fcxp;

	pyld = bfa_fcxp_get_reqbuf(fcxp);
	memset(pyld, 0, FC_MAX_PDUSZ);

	len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
				   FDMI_RHBA);

	attr_len =
		bfa_fcs_lport_fdmi_build_rhba_pyld(fdmi,
					  (u8 *) ((struct ct_hdr_s *) pyld
						       + 1));

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, (len + attr_len), &fchs,
			  bfa_fcs_lport_fdmi_rhba_response, (void *)fdmi,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT);
}

static          u16
bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct bfa_fcs_fdmi_hba_attr_s hba_attr;
	struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr;
	struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld;
	struct fdmi_attr_s *attr;
	u8        *curr_ptr;
	u16        len, count;
	u16	templen;

	/*
	 * get hba attributes
	 */
	bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr);

	rhba->hba_id = bfa_fcs_lport_get_pwwn(port);
	rhba->port_list.num_ports = cpu_to_be32(1);
	rhba->port_list.port_entry = bfa_fcs_lport_get_pwwn(port);

	len = sizeof(rhba->hba_id) + sizeof(rhba->port_list);

	count = 0;
	len += sizeof(rhba->hba_attr_blk.attr_count);

	/*
	 * fill out the invididual entries of the HBA attrib Block
	 */
	curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr;

	/*
	 * Node Name
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NODENAME);
	templen = sizeof(wwn_t);
	memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), templen);
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * Manufacturer
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MANUFACTURER);
	templen = (u16) strlen(fcs_hba_attr->manufacturer);
	memcpy(attr->value, fcs_hba_attr->manufacturer, templen);
	templen = fc_roundup(templen, sizeof(u32));
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * Serial Number
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_SERIALNUM);
	templen = (u16) strlen(fcs_hba_attr->serial_num);
	memcpy(attr->value, fcs_hba_attr->serial_num, templen);
	templen = fc_roundup(templen, sizeof(u32));
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * Model
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL);
	templen = (u16) strlen(fcs_hba_attr->model);
	memcpy(attr->value, fcs_hba_attr->model, templen);
	templen = fc_roundup(templen, sizeof(u32));
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * Model Desc
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL_DESC);
	templen = (u16) strlen(fcs_hba_attr->model_desc);
	memcpy(attr->value, fcs_hba_attr->model_desc, templen);
	templen = fc_roundup(templen, sizeof(u32));
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * H/W Version
	 */
	if (fcs_hba_attr->hw_version[0] != '\0') {
		attr = (struct fdmi_attr_s *) curr_ptr;
		attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_HW_VERSION);
		templen = (u16) strlen(fcs_hba_attr->hw_version);
		memcpy(attr->value, fcs_hba_attr->hw_version, templen);
		templen = fc_roundup(templen, sizeof(u32));
		curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
		len += templen;
		count++;
		attr->len = cpu_to_be16(templen + sizeof(attr->type) +
					 sizeof(templen));
	}

	/*
	 * Driver Version
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_DRIVER_VERSION);
	templen = (u16) strlen(fcs_hba_attr->driver_version);
	memcpy(attr->value, fcs_hba_attr->driver_version, templen);
	templen = fc_roundup(templen, sizeof(u32));
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * Option Rom Version
	 */
	if (fcs_hba_attr->option_rom_ver[0] != '\0') {
		attr = (struct fdmi_attr_s *) curr_ptr;
		attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_ROM_VERSION);
		templen = (u16) strlen(fcs_hba_attr->option_rom_ver);
		memcpy(attr->value, fcs_hba_attr->option_rom_ver, templen);
		templen = fc_roundup(templen, sizeof(u32));
		curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
		len += templen;
		count++;
		attr->len = cpu_to_be16(templen + sizeof(attr->type) +
					 sizeof(templen));
	}

	/*
	 * f/w Version = driver version
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FW_VERSION);
	templen = (u16) strlen(fcs_hba_attr->driver_version);
	memcpy(attr->value, fcs_hba_attr->driver_version, templen);
	templen = fc_roundup(templen, sizeof(u32));
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * OS Name
	 */
	if (fcs_hba_attr->os_name[0] != '\0') {
		attr = (struct fdmi_attr_s *) curr_ptr;
		attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_OS_NAME);
		templen = (u16) strlen(fcs_hba_attr->os_name);
		memcpy(attr->value, fcs_hba_attr->os_name, templen);
		templen = fc_roundup(templen, sizeof(u32));
		curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
		len += templen;
		count++;
		attr->len = cpu_to_be16(templen + sizeof(attr->type) +
					sizeof(templen));
	}

	/*
	 * MAX_CT_PAYLOAD
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MAX_CT);
	templen = sizeof(fcs_hba_attr->max_ct_pyld);
	memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, templen);
	len += templen;
	count++;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * Update size of payload
	 */
	len += ((sizeof(attr->type) + sizeof(attr->len)) * count);

	rhba->hba_attr_blk.attr_count = cpu_to_be32(count);
	return len;
}

static void
bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
				void *cbarg, bfa_status_t req_status,
				u32 rsp_len, u32 resid_len,
				struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_fdmi_s *fdmi =
				(struct bfa_fcs_lport_fdmi_s *) cbarg;
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct ct_hdr_s *cthdr = NULL;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
		return;
	}

	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);
	bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}

/*
*  RPRT : Register Port
 */
static void
bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg;
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct fchs_s fchs;
	u16        len, attr_len;
	struct bfa_fcxp_s *fcxp;
	u8        *pyld;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
				bfa_fcs_lport_fdmi_send_rprt, fdmi, BFA_TRUE);
		return;
	}
	fdmi->fcxp = fcxp;

	pyld = bfa_fcxp_get_reqbuf(fcxp);
	memset(pyld, 0, FC_MAX_PDUSZ);

	len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
				   FDMI_RPRT);

	attr_len =
		bfa_fcs_lport_fdmi_build_rprt_pyld(fdmi,
					  (u8 *) ((struct ct_hdr_s *) pyld
						       + 1));

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len + attr_len, &fchs,
			  bfa_fcs_lport_fdmi_rprt_response, (void *)fdmi,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
}

/*
 * This routine builds Port Attribute Block that used in RPA, RPRT commands.
 */
static          u16
bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi,
				       u8 *pyld)
{
	struct bfa_fcs_fdmi_port_attr_s fcs_port_attr;
	struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld;
	struct fdmi_attr_s *attr;
	u8        *curr_ptr;
	u16        len;
	u8	count = 0;
	u16	templen;

	/*
	 * get port attributes
	 */
	bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr);

	len = sizeof(port_attrib->attr_count);

	/*
	 * fill out the invididual entries
	 */
	curr_ptr = (u8 *) &port_attrib->port_attr;

	/*
	 * FC4 Types
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FC4_TYPES);
	templen = sizeof(fcs_port_attr.supp_fc4_types);
	memcpy(attr->value, fcs_port_attr.supp_fc4_types, templen);
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	++count;
	attr->len =
		cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * Supported Speed
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_SUPP_SPEED);
	templen = sizeof(fcs_port_attr.supp_speed);
	memcpy(attr->value, &fcs_port_attr.supp_speed, templen);
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	++count;
	attr->len =
		cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * current Port Speed
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_SPEED);
	templen = sizeof(fcs_port_attr.curr_speed);
	memcpy(attr->value, &fcs_port_attr.curr_speed, templen);
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	++count;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * max frame size
	 */
	attr = (struct fdmi_attr_s *) curr_ptr;
	attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FRAME_SIZE);
	templen = sizeof(fcs_port_attr.max_frm_size);
	memcpy(attr->value, &fcs_port_attr.max_frm_size, templen);
	curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
	len += templen;
	++count;
	attr->len = cpu_to_be16(templen + sizeof(attr->type) +
			     sizeof(templen));

	/*
	 * OS Device Name
	 */
	if (fcs_port_attr.os_device_name[0] != '\0') {
		attr = (struct fdmi_attr_s *) curr_ptr;
		attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_DEV_NAME);
		templen = (u16) strlen(fcs_port_attr.os_device_name);
		memcpy(attr->value, fcs_port_attr.os_device_name, templen);
		templen = fc_roundup(templen, sizeof(u32));
		curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
		len += templen;
		++count;
		attr->len = cpu_to_be16(templen + sizeof(attr->type) +
					sizeof(templen));
	}
	/*
	 * Host Name
	 */
	if (fcs_port_attr.host_name[0] != '\0') {
		attr = (struct fdmi_attr_s *) curr_ptr;
		attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_HOST_NAME);
		templen = (u16) strlen(fcs_port_attr.host_name);
		memcpy(attr->value, fcs_port_attr.host_name, templen);
		templen = fc_roundup(templen, sizeof(u32));
		curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
		len += templen;
		++count;
		attr->len = cpu_to_be16(templen + sizeof(attr->type) +
				sizeof(templen));
	}

	/*
	 * Update size of payload
	 */
	port_attrib->attr_count = cpu_to_be32(count);
	len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
	return len;
}

static          u16
bfa_fcs_lport_fdmi_build_rprt_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct fdmi_rprt_s *rprt = (struct fdmi_rprt_s *) pyld;
	u16        len;

	rprt->hba_id = bfa_fcs_lport_get_pwwn(bfa_fcs_get_base_port(port->fcs));
	rprt->port_name = bfa_fcs_lport_get_pwwn(port);

	len = bfa_fcs_lport_fdmi_build_portattr_block(fdmi,
				(u8 *) &rprt->port_attr_blk);

	len += sizeof(rprt->hba_id) + sizeof(rprt->port_name);

	return len;
}

static void
bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
				void *cbarg, bfa_status_t req_status,
				u32 rsp_len, u32 resid_len,
				struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_fdmi_s *fdmi =
			(struct bfa_fcs_lport_fdmi_s *) cbarg;
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct ct_hdr_s *cthdr = NULL;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
		return;
	}

	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);
	bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}

/*
*  RPA : Register Port Attributes.
 */
static void
bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg;
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct fchs_s fchs;
	u16        len, attr_len;
	struct bfa_fcxp_s *fcxp;
	u8        *pyld;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
				bfa_fcs_lport_fdmi_send_rpa, fdmi, BFA_TRUE);
		return;
	}
	fdmi->fcxp = fcxp;

	pyld = bfa_fcxp_get_reqbuf(fcxp);
	memset(pyld, 0, FC_MAX_PDUSZ);

	len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
				   FDMI_RPA);

	attr_len = bfa_fcs_lport_fdmi_build_rpa_pyld(fdmi,
				(u8 *) ((struct ct_hdr_s *) pyld + 1));

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len + attr_len, &fchs,
			  bfa_fcs_lport_fdmi_rpa_response, (void *)fdmi,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT);
}

static          u16
bfa_fcs_lport_fdmi_build_rpa_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct fdmi_rpa_s *rpa = (struct fdmi_rpa_s *) pyld;
	u16        len;

	rpa->port_name = bfa_fcs_lport_get_pwwn(port);

	len = bfa_fcs_lport_fdmi_build_portattr_block(fdmi,
				(u8 *) &rpa->port_attr_blk);

	len += sizeof(rpa->port_name);

	return len;
}

static void
bfa_fcs_lport_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
			void *cbarg, bfa_status_t req_status, u32 rsp_len,
			u32 resid_len, struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_fdmi_s *fdmi =
				(struct bfa_fcs_lport_fdmi_s *) cbarg;
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct ct_hdr_s *cthdr = NULL;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
		return;
	}

	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);
	bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}

static void
bfa_fcs_lport_fdmi_timeout(void *arg)
{
	struct bfa_fcs_lport_fdmi_s *fdmi = (struct bfa_fcs_lport_fdmi_s *) arg;

	bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
}

static void
bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
			 struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct bfa_fcs_driver_info_s  *driver_info = &port->fcs->driver_info;

	memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));

	bfa_ioc_get_adapter_manufacturer(&port->fcs->bfa->ioc,
					hba_attr->manufacturer);
	bfa_ioc_get_adapter_serial_num(&port->fcs->bfa->ioc,
					hba_attr->serial_num);
	bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc,
					hba_attr->model);
	bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc,
					hba_attr->model_desc);
	bfa_ioc_get_pci_chip_rev(&port->fcs->bfa->ioc,
					hba_attr->hw_version);
	bfa_ioc_get_adapter_optrom_ver(&port->fcs->bfa->ioc,
					hba_attr->option_rom_ver);
	bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc,
					hba_attr->fw_version);

	strncpy(hba_attr->driver_version, (char *)driver_info->version,
		sizeof(hba_attr->driver_version));

	strncpy(hba_attr->os_name, driver_info->host_os_name,
		sizeof(hba_attr->os_name));

	/*
	 * If there is a patch level, append it
	 * to the os name along with a separator
	 */
	if (driver_info->host_os_patch[0] != '\0') {
		strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
		strncat(hba_attr->os_name, driver_info->host_os_patch,
				sizeof(driver_info->host_os_patch));
	}

	hba_attr->max_ct_pyld = cpu_to_be32(FC_MAX_PDUSZ);
}

static void
bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
			  struct bfa_fcs_fdmi_port_attr_s *port_attr)
{
	struct bfa_fcs_lport_s *port = fdmi->ms->port;
	struct bfa_fcs_driver_info_s  *driver_info = &port->fcs->driver_info;
	struct bfa_port_attr_s pport_attr;

	memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));

	/*
	 * get pport attributes from hal
	 */
	bfa_fcport_get_attr(port->fcs->bfa, &pport_attr);

	/*
	 * get FC4 type Bitmask
	 */
	fc_get_fc4type_bitmask(FC_TYPE_FCP, port_attr->supp_fc4_types);

	/*
	 * Supported Speeds
	 */
	switch (pport_attr.speed_supported) {
	case BFA_PORT_SPEED_16GBPS:
		port_attr->supp_speed =
			cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_16G);
		break;

	case BFA_PORT_SPEED_10GBPS:
		port_attr->supp_speed =
			cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_10G);
		break;

	case BFA_PORT_SPEED_8GBPS:
		port_attr->supp_speed =
			cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_8G);
		break;

	case BFA_PORT_SPEED_4GBPS:
		port_attr->supp_speed =
			cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_4G);
		break;

	default:
		bfa_sm_fault(port->fcs, pport_attr.speed_supported);
	}

	/*
	 * Current Speed
	 */
	port_attr->curr_speed = cpu_to_be32(
				bfa_fcs_fdmi_convert_speed(pport_attr.speed));

	/*
	 * Max PDU Size.
	 */
	port_attr->max_frm_size = cpu_to_be32(FC_MAX_PDUSZ);

	/*
	 * OS device Name
	 */
	strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name,
		sizeof(port_attr->os_device_name));

	/*
	 * Host name
	 */
	strncpy(port_attr->host_name, (char *)driver_info->host_machine_name,
		sizeof(port_attr->host_name));

}

/*
 * Convert BFA speed to FDMI format.
 */
u32
bfa_fcs_fdmi_convert_speed(bfa_port_speed_t pport_speed)
{
	u32	ret;

	switch (pport_speed) {
	case BFA_PORT_SPEED_1GBPS:
	case BFA_PORT_SPEED_2GBPS:
		ret = pport_speed;
		break;

	case BFA_PORT_SPEED_4GBPS:
		ret = FDMI_TRANS_SPEED_4G;
		break;

	case BFA_PORT_SPEED_8GBPS:
		ret = FDMI_TRANS_SPEED_8G;
		break;

	case BFA_PORT_SPEED_10GBPS:
		ret = FDMI_TRANS_SPEED_10G;
		break;

	case BFA_PORT_SPEED_16GBPS:
		ret = FDMI_TRANS_SPEED_16G;
		break;

	default:
		ret = FDMI_TRANS_SPEED_UNKNOWN;
	}
	return ret;
}

void
bfa_fcs_lport_fdmi_init(struct bfa_fcs_lport_ms_s *ms)
{
	struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi;

	fdmi->ms = ms;
	if (ms->port->fcs->fdmi_enabled)
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
	else
		bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_disabled);
}

void
bfa_fcs_lport_fdmi_offline(struct bfa_fcs_lport_ms_s *ms)
{
	struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi;

	fdmi->ms = ms;
	bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE);
}

void
bfa_fcs_lport_fdmi_online(struct bfa_fcs_lport_ms_s *ms)
{
	struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi;

	fdmi->ms = ms;
	bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE);
}

#define BFA_FCS_MS_CMD_MAX_RETRIES  2

/*
 * forward declarations
 */
static void     bfa_fcs_lport_ms_send_plogi(void *ms_cbarg,
					   struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ms_timeout(void *arg);
static void     bfa_fcs_lport_ms_plogi_response(void *fcsarg,
					       struct bfa_fcxp_s *fcxp,
					       void *cbarg,
					       bfa_status_t req_status,
					       u32 rsp_len,
					       u32 resid_len,
					       struct fchs_s *rsp_fchs);

static void	bfa_fcs_lport_ms_send_gmal(void *ms_cbarg,
					struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ms_gmal_response(void *fcsarg,
					       struct bfa_fcxp_s *fcxp,
					       void *cbarg,
					       bfa_status_t req_status,
					       u32 rsp_len,
					       u32 resid_len,
					       struct fchs_s *rsp_fchs);
static void	bfa_fcs_lport_ms_send_gfn(void *ms_cbarg,
					struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ms_gfn_response(void *fcsarg,
					       struct bfa_fcxp_s *fcxp,
					       void *cbarg,
					       bfa_status_t req_status,
					       u32 rsp_len,
					       u32 resid_len,
					       struct fchs_s *rsp_fchs);
/*
 *  fcs_ms_sm FCS MS state machine
 */

/*
 *  MS State Machine events
 */
enum port_ms_event {
	MSSM_EVENT_PORT_ONLINE = 1,
	MSSM_EVENT_PORT_OFFLINE = 2,
	MSSM_EVENT_RSP_OK = 3,
	MSSM_EVENT_RSP_ERROR = 4,
	MSSM_EVENT_TIMEOUT = 5,
	MSSM_EVENT_FCXP_SENT = 6,
	MSSM_EVENT_PORT_FABRIC_RSCN = 7
};

static void     bfa_fcs_lport_ms_sm_offline(struct bfa_fcs_lport_ms_s *ms,
					   enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_plogi_sending(struct bfa_fcs_lport_ms_s *ms,
						 enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms,
					 enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_plogi_retry(struct bfa_fcs_lport_ms_s *ms,
					       enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_gmal_sending(struct bfa_fcs_lport_ms_s *ms,
						 enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_gmal(struct bfa_fcs_lport_ms_s *ms,
					 enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms,
					       enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_gfn_sending(struct bfa_fcs_lport_ms_s *ms,
						 enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_gfn(struct bfa_fcs_lport_ms_s *ms,
					 enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms,
					       enum port_ms_event event);
static void     bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms,
					  enum port_ms_event event);
/*
 *	Start in offline state - awaiting NS to send start.
 */
static void
bfa_fcs_lport_ms_sm_offline(struct bfa_fcs_lport_ms_s *ms,
				enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_PORT_ONLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_sending);
		bfa_fcs_lport_ms_send_plogi(ms, NULL);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_plogi_sending(struct bfa_fcs_lport_ms_s *ms,
				enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_FCXP_SENT:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
					   &ms->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms,
			enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_RSP_ERROR:
		/*
		 * Start timer for a delayed retry
		 */
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_retry);
		ms->port->stats.ms_retries++;
		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
				    &ms->timer, bfa_fcs_lport_ms_timeout, ms,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case MSSM_EVENT_RSP_OK:
		/*
		 * since plogi is done, now invoke MS related sub-modules
		 */
		bfa_fcs_lport_fdmi_online(ms);

		/*
		 * if this is a Vport, go to online state.
		 */
		if (ms->port->vport) {
			bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online);
			break;
		}

		/*
		 * For a base port we need to get the
		 * switch's IP address.
		 */
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_sending);
		bfa_fcs_lport_ms_send_gmal(ms, NULL);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_fcxp_discard(ms->fcxp);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_plogi_retry(struct bfa_fcs_lport_ms_s *ms,
			enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_sending);
		bfa_fcs_lport_ms_send_plogi(ms, NULL);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_timer_stop(&ms->timer);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms,
			enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		break;

	case MSSM_EVENT_PORT_FABRIC_RSCN:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending);
		ms->retry_cnt = 0;
		bfa_fcs_lport_ms_send_gfn(ms, NULL);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_gmal_sending(struct bfa_fcs_lport_ms_s *ms,
				enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_FCXP_SENT:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
					   &ms->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_gmal(struct bfa_fcs_lport_ms_s *ms,
				enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_RSP_ERROR:
		/*
		 * Start timer for a delayed retry
		 */
		if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
			bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_retry);
			ms->port->stats.ms_retries++;
			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
				&ms->timer, bfa_fcs_lport_ms_timeout, ms,
				BFA_FCS_RETRY_TIMEOUT);
		} else {
			bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending);
			bfa_fcs_lport_ms_send_gfn(ms, NULL);
			ms->retry_cnt = 0;
		}
		break;

	case MSSM_EVENT_RSP_OK:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending);
		bfa_fcs_lport_ms_send_gfn(ms, NULL);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_fcxp_discard(ms->fcxp);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms,
				enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_sending);
		bfa_fcs_lport_ms_send_gmal(ms, NULL);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_timer_stop(&ms->timer);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}
/*
 *  ms_pvt MS local functions
 */

static void
bfa_fcs_lport_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ms_s *ms = ms_cbarg;
	bfa_fcs_lport_t *port = ms->port;
	struct fchs_s	fchs;
	int		len;
	struct bfa_fcxp_s *fcxp;

	bfa_trc(port->fcs, port->pid);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
				bfa_fcs_lport_ms_send_gmal, ms, BFA_TRUE);
		return;
	}
	ms->fcxp = fcxp;

	len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			     bfa_fcs_lport_get_fcid(port),
				 port->fabric->lps->pr_nwwn);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ms_gmal_response, (void *)ms,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
}

static void
bfa_fcs_lport_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
				void *cbarg, bfa_status_t req_status,
				u32 rsp_len, u32 resid_len,
				struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg;
	bfa_fcs_lport_t *port = ms->port;
	struct ct_hdr_s		*cthdr = NULL;
	struct fcgs_gmal_resp_s *gmal_resp;
	struct fcgs_gmal_entry_s *gmal_entry;
	u32		num_entries;
	u8			*rsp_str;

	bfa_trc(port->fcs, req_status);
	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1);

		num_entries = be32_to_cpu(gmal_resp->ms_len);
		if (num_entries == 0) {
			bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
			return;
		}
		/*
		* The response could contain multiple Entries.
		* Entries for SNMP interface, etc.
		* We look for the entry with a telnet prefix.
		* First "http://" entry refers to IP addr
		*/

		gmal_entry = (struct fcgs_gmal_entry_s *)gmal_resp->ms_ma;
		while (num_entries > 0) {
			if (strncmp(gmal_entry->prefix,
				CT_GMAL_RESP_PREFIX_HTTP,
				sizeof(gmal_entry->prefix)) == 0) {

				/*
				* if the IP address is terminating with a '/',
				* remove it.
				* Byte 0 consists of the length of the string.
				*/
				rsp_str = &(gmal_entry->prefix[0]);
				if (rsp_str[gmal_entry->len-1] == '/')
					rsp_str[gmal_entry->len-1] = 0;

				/* copy IP Address to fabric */
				strncpy(bfa_fcs_lport_get_fabric_ipaddr(port),
					gmal_entry->ip_addr,
					BFA_FCS_FABRIC_IPADDR_SZ);
				break;
			} else {
				--num_entries;
				++gmal_entry;
			}
		}

		bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
		return;
	}

	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);
	bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
}

static void
bfa_fcs_lport_ms_sm_gfn_sending(struct bfa_fcs_lport_ms_s *ms,
			enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_FCXP_SENT:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
					   &ms->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_gfn(struct bfa_fcs_lport_ms_s *ms,
			enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_RSP_ERROR:
		/*
		 * Start timer for a delayed retry
		 */
		if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
			bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_retry);
			ms->port->stats.ms_retries++;
			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
				&ms->timer, bfa_fcs_lport_ms_timeout, ms,
				BFA_FCS_RETRY_TIMEOUT);
		} else {
			bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online);
			ms->retry_cnt = 0;
		}
		break;

	case MSSM_EVENT_RSP_OK:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_fcxp_discard(ms->fcxp);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms,
				enum port_ms_event event)
{
	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
	bfa_trc(ms->port->fcs, event);

	switch (event) {
	case MSSM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending);
		bfa_fcs_lport_ms_send_gfn(ms, NULL);
		break;

	case MSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);
		bfa_timer_stop(&ms->timer);
		break;

	default:
		bfa_sm_fault(ms->port->fcs, event);
	}
}
/*
 *  ms_pvt MS local functions
 */

static void
bfa_fcs_lport_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ms_s *ms = ms_cbarg;
	bfa_fcs_lport_t *port = ms->port;
	struct fchs_s		fchs;
	int			len;
	struct bfa_fcxp_s *fcxp;

	bfa_trc(port->fcs, port->pid);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
				bfa_fcs_lport_ms_send_gfn, ms, BFA_TRUE);
		return;
	}
	ms->fcxp = fcxp;

	len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			     bfa_fcs_lport_get_fcid(port),
				 port->fabric->lps->pr_nwwn);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ms_gfn_response, (void *)ms,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
}

static void
bfa_fcs_lport_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
			void *cbarg, bfa_status_t req_status, u32 rsp_len,
			u32 resid_len, struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg;
	bfa_fcs_lport_t *port = ms->port;
	struct ct_hdr_s	*cthdr = NULL;
	wwn_t	       *gfn_resp;

	bfa_trc(port->fcs, req_status);
	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		gfn_resp = (wwn_t *)(cthdr + 1);
		/* check if it has actually changed */
		if ((memcmp((void *)&bfa_fcs_lport_get_fabric_name(port),
				gfn_resp, sizeof(wwn_t)) != 0)) {
			bfa_fcs_fabric_set_fabric_name(port->fabric, *gfn_resp);
		}
		bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
		return;
	}

	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);
	bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
}

/*
 *  ms_pvt MS local functions
 */

static void
bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ms_s *ms = ms_cbarg;
	struct bfa_fcs_lport_s *port = ms->port;
	struct fchs_s	fchs;
	int	len;
	struct bfa_fcxp_s *fcxp;

	bfa_trc(port->fcs, port->pid);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		port->stats.ms_plogi_alloc_wait++;
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
				bfa_fcs_lport_ms_send_plogi, ms, BFA_TRUE);
		return;
	}
	ms->fcxp = fcxp;

	len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			     bfa_hton3b(FC_MGMT_SERVER),
			     bfa_fcs_lport_get_fcid(port), 0,
			     port->port_cfg.pwwn, port->port_cfg.nwwn,
			     bfa_fcport_get_maxfrsize(port->fcs->bfa),
			     bfa_fcport_get_rx_bbcredit(port->fcs->bfa));

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ms_plogi_response, (void *)ms,
			  FC_MAX_PDUSZ, FC_ELS_TOV);

	port->stats.ms_plogi_sent++;
	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
}

static void
bfa_fcs_lport_ms_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
			void *cbarg, bfa_status_t req_status,
			u32 rsp_len, u32 resid_len, struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg;
	struct bfa_fcs_lport_s *port = ms->port;
	struct fc_els_cmd_s *els_cmd;
	struct fc_ls_rjt_s *ls_rjt;

	bfa_trc(port->fcs, req_status);
	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		port->stats.ms_plogi_rsp_err++;
		bfa_trc(port->fcs, req_status);
		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
		return;
	}

	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);

	switch (els_cmd->els_code) {

	case FC_ELS_ACC:
		if (rsp_len < sizeof(struct fc_logi_s)) {
			bfa_trc(port->fcs, rsp_len);
			port->stats.ms_plogi_acc_err++;
			bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
			break;
		}
		port->stats.ms_plogi_accepts++;
		bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
		break;

	case FC_ELS_LS_RJT:
		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);

		bfa_trc(port->fcs, ls_rjt->reason_code);
		bfa_trc(port->fcs, ls_rjt->reason_code_expl);

		port->stats.ms_rejects++;
		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
		break;

	default:
		port->stats.ms_plogi_unknown_rsp++;
		bfa_trc(port->fcs, els_cmd->els_code);
		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
	}
}

static void
bfa_fcs_lport_ms_timeout(void *arg)
{
	struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) arg;

	ms->port->stats.ms_timeouts++;
	bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT);
}


void
bfa_fcs_lport_ms_init(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);

	ms->port = port;
	bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline);

	/*
	 * Invoke init routines of sub modules.
	 */
	bfa_fcs_lport_fdmi_init(ms);
}

void
bfa_fcs_lport_ms_offline(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);

	ms->port = port;
	bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE);
	bfa_fcs_lport_fdmi_offline(ms);
}

void
bfa_fcs_lport_ms_online(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);

	ms->port = port;
	bfa_sm_send_event(ms, MSSM_EVENT_PORT_ONLINE);
}
void
bfa_fcs_lport_ms_fabric_rscn(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);

	/* todo.  Handle this only  when in Online state */
	if (bfa_sm_cmp_state(ms, bfa_fcs_lport_ms_sm_online))
		bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN);
}

/*
 * @page ns_sm_info VPORT NS State Machine
 *
 * @section ns_sm_interactions VPORT NS State Machine Interactions
 *
 * @section ns_sm VPORT NS State Machine
 * img ns_sm.jpg
 */

/*
 * forward declarations
 */
static void     bfa_fcs_lport_ns_send_plogi(void *ns_cbarg,
					   struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg,
					     struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ns_send_rft_id(void *ns_cbarg,
					    struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ns_send_rff_id(void *ns_cbarg,
					    struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ns_send_gid_ft(void *ns_cbarg,
					    struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_ns_timeout(void *arg);
static void     bfa_fcs_lport_ns_plogi_response(void *fcsarg,
					       struct bfa_fcxp_s *fcxp,
					       void *cbarg,
					       bfa_status_t req_status,
					       u32 rsp_len,
					       u32 resid_len,
					       struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_ns_rspn_id_response(void *fcsarg,
						 struct bfa_fcxp_s *fcxp,
						 void *cbarg,
						 bfa_status_t req_status,
						 u32 rsp_len,
						 u32 resid_len,
						 struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_ns_rft_id_response(void *fcsarg,
						struct bfa_fcxp_s *fcxp,
						void *cbarg,
						bfa_status_t req_status,
						u32 rsp_len,
						u32 resid_len,
						struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_ns_rff_id_response(void *fcsarg,
						struct bfa_fcxp_s *fcxp,
						void *cbarg,
						bfa_status_t req_status,
						u32 rsp_len,
						u32 resid_len,
						struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_ns_gid_ft_response(void *fcsarg,
						struct bfa_fcxp_s *fcxp,
						void *cbarg,
						bfa_status_t req_status,
						u32 rsp_len,
						u32 resid_len,
						struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_ns_process_gidft_pids(
				struct bfa_fcs_lport_s *port,
				u32 *pid_buf, u32 n_pids);

static void bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port);
/*
 *  fcs_ns_sm FCS nameserver interface state machine
 */

/*
 * VPort NS State Machine events
 */
enum vport_ns_event {
	NSSM_EVENT_PORT_ONLINE = 1,
	NSSM_EVENT_PORT_OFFLINE = 2,
	NSSM_EVENT_PLOGI_SENT = 3,
	NSSM_EVENT_RSP_OK = 4,
	NSSM_EVENT_RSP_ERROR = 5,
	NSSM_EVENT_TIMEOUT = 6,
	NSSM_EVENT_NS_QUERY = 7,
	NSSM_EVENT_RSPNID_SENT = 8,
	NSSM_EVENT_RFTID_SENT = 9,
	NSSM_EVENT_RFFID_SENT = 10,
	NSSM_EVENT_GIDFT_SENT = 11,
};

static void     bfa_fcs_lport_ns_sm_offline(struct bfa_fcs_lport_ns_s *ns,
					   enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_plogi_sending(struct bfa_fcs_lport_ns_s *ns,
						 enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_plogi(struct bfa_fcs_lport_ns_s *ns,
					 enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_plogi_retry(struct bfa_fcs_lport_ns_s *ns,
					       enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_sending_rspn_id(
					struct bfa_fcs_lport_ns_s *ns,
					enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_rspn_id(struct bfa_fcs_lport_ns_s *ns,
					   enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_rspn_id_retry(struct bfa_fcs_lport_ns_s *ns,
						 enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_sending_rft_id(
					struct bfa_fcs_lport_ns_s *ns,
					enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_rft_id_retry(struct bfa_fcs_lport_ns_s *ns,
						enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_rft_id(struct bfa_fcs_lport_ns_s *ns,
					  enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_sending_rff_id(
					struct bfa_fcs_lport_ns_s *ns,
					enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_rff_id_retry(struct bfa_fcs_lport_ns_s *ns,
						enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_rff_id(struct bfa_fcs_lport_ns_s *ns,
					  enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_sending_gid_ft(
					struct bfa_fcs_lport_ns_s *ns,
					enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_gid_ft(struct bfa_fcs_lport_ns_s *ns,
					  enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns,
						enum vport_ns_event event);
static void     bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns,
					  enum vport_ns_event event);
/*
 *	Start in offline state - awaiting linkup
 */
static void
bfa_fcs_lport_ns_sm_offline(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_PORT_ONLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_sending);
		bfa_fcs_lport_ns_send_plogi(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_plogi_sending(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_PLOGI_SENT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
					   &ns->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_plogi(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RSP_ERROR:
		/*
		 * Start timer for a delayed retry
		 */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_retry);
		ns->port->stats.ns_retries++;
		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
				    &ns->timer, bfa_fcs_lport_ns_timeout, ns,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case NSSM_EVENT_RSP_OK:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rspn_id);
		bfa_fcs_lport_ns_send_rspn_id(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_discard(ns->fcxp);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_plogi_retry(struct bfa_fcs_lport_ns_s *ns,
				enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_sending);
		bfa_fcs_lport_ns_send_plogi(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_timer_stop(&ns->timer);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_sending_rspn_id(struct bfa_fcs_lport_ns_s *ns,
				   enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RSPNID_SENT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rspn_id);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
					   &ns->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_rspn_id(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RSP_ERROR:
		/*
		 * Start timer for a delayed retry
		 */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rspn_id_retry);
		ns->port->stats.ns_retries++;
		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
				    &ns->timer, bfa_fcs_lport_ns_timeout, ns,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case NSSM_EVENT_RSP_OK:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rft_id);
		bfa_fcs_lport_ns_send_rft_id(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_fcxp_discard(ns->fcxp);
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_rspn_id_retry(struct bfa_fcs_lport_ns_s *ns,
				enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_TIMEOUT:
		/*
		 * Retry Timer Expired. Re-send
		 */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rspn_id);
		bfa_fcs_lport_ns_send_rspn_id(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_timer_stop(&ns->timer);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_sending_rft_id(struct bfa_fcs_lport_ns_s *ns,
				  enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RFTID_SENT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rft_id);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
					   &ns->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_rft_id(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RSP_OK:
		/* Now move to register FC4 Features */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rff_id);
		bfa_fcs_lport_ns_send_rff_id(ns, NULL);
		break;

	case NSSM_EVENT_RSP_ERROR:
		/*
		 * Start timer for a delayed retry
		 */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rft_id_retry);
		ns->port->stats.ns_retries++;
		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
				    &ns->timer, bfa_fcs_lport_ns_timeout, ns,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_discard(ns->fcxp);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_rft_id_retry(struct bfa_fcs_lport_ns_s *ns,
				enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_TIMEOUT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rft_id);
		bfa_fcs_lport_ns_send_rft_id(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_timer_stop(&ns->timer);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_sending_rff_id(struct bfa_fcs_lport_ns_s *ns,
				  enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RFFID_SENT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rff_id);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
					   &ns->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_rff_id(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RSP_OK:

		/*
		 * If min cfg mode is enabled, we donot initiate rport
		 * discovery with the fabric. Instead, we will retrieve the
		 * boot targets from HAL/FW.
		 */
		if (__fcs_min_cfg(ns->port->fcs)) {
			bfa_fcs_lport_ns_boot_target_disc(ns->port);
			bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_online);
			return;
		}

		/*
		 * If the port role is Initiator Mode issue NS query.
		 * If it is Target Mode, skip this and go to online.
		 */
		if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) {
			bfa_sm_set_state(ns,
				bfa_fcs_lport_ns_sm_sending_gid_ft);
			bfa_fcs_lport_ns_send_gid_ft(ns, NULL);
		}
		/*
		 * kick off mgmt srvr state machine
		 */
		bfa_fcs_lport_ms_online(ns->port);
		break;

	case NSSM_EVENT_RSP_ERROR:
		/*
		 * Start timer for a delayed retry
		 */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rff_id_retry);
		ns->port->stats.ns_retries++;
		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
				    &ns->timer, bfa_fcs_lport_ns_timeout, ns,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_discard(ns->fcxp);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_rff_id_retry(struct bfa_fcs_lport_ns_s *ns,
				enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_TIMEOUT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rff_id);
		bfa_fcs_lport_ns_send_rff_id(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_timer_stop(&ns->timer);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}
static void
bfa_fcs_lport_ns_sm_sending_gid_ft(struct bfa_fcs_lport_ns_s *ns,
				  enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_GIDFT_SENT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_gid_ft);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
					   &ns->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_gid_ft(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_RSP_OK:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_online);
		break;

	case NSSM_EVENT_RSP_ERROR:
		/*
		 * TBD: for certain reject codes, we don't need to retry
		 */
		/*
		 * Start timer for a delayed retry
		 */
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_gid_ft_retry);
		ns->port->stats.ns_retries++;
		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
				    &ns->timer, bfa_fcs_lport_ns_timeout, ns,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_fcxp_discard(ns->fcxp);
		break;

	case  NSSM_EVENT_NS_QUERY:
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns,
				enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_TIMEOUT:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_gid_ft);
		bfa_fcs_lport_ns_send_gid_ft(ns, NULL);
		break;

	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		bfa_timer_stop(&ns->timer);
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}

static void
bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns,
			enum vport_ns_event event)
{
	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
	bfa_trc(ns->port->fcs, event);

	switch (event) {
	case NSSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
		break;

	case NSSM_EVENT_NS_QUERY:
		/*
		 * If the port role is Initiator Mode issue NS query.
		 * If it is Target Mode, skip this and go to online.
		 */
		if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) {
			bfa_sm_set_state(ns,
				bfa_fcs_lport_ns_sm_sending_gid_ft);
			bfa_fcs_lport_ns_send_gid_ft(ns, NULL);
		};
		break;

	default:
		bfa_sm_fault(ns->port->fcs, event);
	}
}



/*
 *  ns_pvt Nameserver local functions
 */

static void
bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ns_s *ns = ns_cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct fchs_s fchs;
	int             len;
	struct bfa_fcxp_s *fcxp;

	bfa_trc(port->fcs, port->pid);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		port->stats.ns_plogi_alloc_wait++;
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
				bfa_fcs_lport_ns_send_plogi, ns, BFA_TRUE);
		return;
	}
	ns->fcxp = fcxp;

	len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			     bfa_hton3b(FC_NAME_SERVER),
			     bfa_fcs_lport_get_fcid(port), 0,
			     port->port_cfg.pwwn, port->port_cfg.nwwn,
			     bfa_fcport_get_maxfrsize(port->fcs->bfa),
			     bfa_fcport_get_rx_bbcredit(port->fcs->bfa));

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ns_plogi_response, (void *)ns,
			  FC_MAX_PDUSZ, FC_ELS_TOV);
	port->stats.ns_plogi_sent++;

	bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT);
}

static void
bfa_fcs_lport_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
			void *cbarg, bfa_status_t req_status, u32 rsp_len,
		       u32 resid_len, struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	/* struct fc_logi_s *plogi_resp; */
	struct fc_els_cmd_s *els_cmd;
	struct fc_ls_rjt_s *ls_rjt;

	bfa_trc(port->fcs, req_status);
	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		port->stats.ns_plogi_rsp_err++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
		return;
	}

	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);

	switch (els_cmd->els_code) {

	case FC_ELS_ACC:
		if (rsp_len < sizeof(struct fc_logi_s)) {
			bfa_trc(port->fcs, rsp_len);
			port->stats.ns_plogi_acc_err++;
			bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
			break;
		}
		port->stats.ns_plogi_accepts++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
		break;

	case FC_ELS_LS_RJT:
		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);

		bfa_trc(port->fcs, ls_rjt->reason_code);
		bfa_trc(port->fcs, ls_rjt->reason_code_expl);

		port->stats.ns_rejects++;

		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
		break;

	default:
		port->stats.ns_plogi_unknown_rsp++;
		bfa_trc(port->fcs, els_cmd->els_code);
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
	}
}

/*
 * Register the symbolic port name.
 */
static void
bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ns_s *ns = ns_cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct fchs_s fchs;
	int             len;
	struct bfa_fcxp_s *fcxp;
	u8         symbl[256];
	u8         *psymbl = &symbl[0];

	memset(symbl, 0, sizeof(symbl));

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		port->stats.ns_rspnid_alloc_wait++;
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
				bfa_fcs_lport_ns_send_rspn_id, ns, BFA_TRUE);
		return;
	}
	ns->fcxp = fcxp;

	/*
	 * for V-Port, form a Port Symbolic Name
	 */
	if (port->vport) {
		/*
		 * For Vports, we append the vport's port symbolic name
		 * to that of the base port.
		 */

		strncpy((char *)psymbl,
			(char *) &
			(bfa_fcs_lport_get_psym_name
			 (bfa_fcs_get_base_port(port->fcs))),
			strlen((char *) &
			       bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port
							  (port->fcs))));

		/* Ensure we have a null terminating string. */
		((char *)psymbl)[strlen((char *) &
			bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port
						(port->fcs)))] = 0;
		strncat((char *)psymbl,
			(char *) &(bfa_fcs_lport_get_psym_name(port)),
		strlen((char *) &bfa_fcs_lport_get_psym_name(port)));
	} else {
		psymbl = (u8 *) &(bfa_fcs_lport_get_psym_name(port));
	}

	len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			      bfa_fcs_lport_get_fcid(port), 0, psymbl);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ns_rspn_id_response, (void *)ns,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	port->stats.ns_rspnid_sent++;

	bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT);
}

static void
bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
				 void *cbarg, bfa_status_t req_status,
				 u32 rsp_len, u32 resid_len,
				 struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct ct_hdr_s *cthdr = NULL;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		port->stats.ns_rspnid_rsp_err++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		port->stats.ns_rspnid_accepts++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
		return;
	}

	port->stats.ns_rspnid_rejects++;
	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);
	bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
}

/*
 * Register FC4-Types
 */
static void
bfa_fcs_lport_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ns_s *ns = ns_cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct fchs_s fchs;
	int             len;
	struct bfa_fcxp_s *fcxp;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		port->stats.ns_rftid_alloc_wait++;
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
				bfa_fcs_lport_ns_send_rft_id, ns, BFA_TRUE);
		return;
	}
	ns->fcxp = fcxp;

	len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
		     bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.roles);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ns_rft_id_response, (void *)ns,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	port->stats.ns_rftid_sent++;
	bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT);
}

static void
bfa_fcs_lport_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
				void *cbarg, bfa_status_t req_status,
				u32 rsp_len, u32 resid_len,
				struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct ct_hdr_s *cthdr = NULL;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		port->stats.ns_rftid_rsp_err++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		port->stats.ns_rftid_accepts++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
		return;
	}

	port->stats.ns_rftid_rejects++;
	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);
	bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
}

/*
 * Register FC4-Features : Should be done after RFT_ID
 */
static void
bfa_fcs_lport_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ns_s *ns = ns_cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct fchs_s fchs;
	int             len;
	struct bfa_fcxp_s *fcxp;
	u8			fc4_ftrs = 0;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		port->stats.ns_rffid_alloc_wait++;
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
				bfa_fcs_lport_ns_send_rff_id, ns, BFA_TRUE);
		return;
	}
	ns->fcxp = fcxp;

	if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port))
		fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR;

	len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			     bfa_fcs_lport_get_fcid(port), 0,
				 FC_TYPE_FCP, fc4_ftrs);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ns_rff_id_response, (void *)ns,
			  FC_MAX_PDUSZ, FC_FCCT_TOV);

	port->stats.ns_rffid_sent++;
	bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT);
}

static void
bfa_fcs_lport_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
				void *cbarg, bfa_status_t req_status,
				u32 rsp_len, u32 resid_len,
				struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct ct_hdr_s *cthdr = NULL;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		port->stats.ns_rffid_rsp_err++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
		port->stats.ns_rffid_accepts++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
		return;
	}

	port->stats.ns_rffid_rejects++;
	bfa_trc(port->fcs, cthdr->reason_code);
	bfa_trc(port->fcs, cthdr->exp_code);

	if (cthdr->reason_code == CT_RSN_NOT_SUPP) {
		/* if this command is not supported, we don't retry */
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
	} else
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
}
/*
 * Query Fabric for FC4-Types Devices.
 *
* TBD : Need to use a local (FCS private) response buffer, since the response
 * can be larger than 2K.
 */
static void
bfa_fcs_lport_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ns_s *ns = ns_cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct fchs_s fchs;
	int             len;
	struct bfa_fcxp_s *fcxp;

	bfa_trc(port->fcs, port->pid);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		port->stats.ns_gidft_alloc_wait++;
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
				bfa_fcs_lport_ns_send_gid_ft, ns, BFA_TRUE);
		return;
	}
	ns->fcxp = fcxp;

	/*
	 * This query is only initiated for FCP initiator mode.
	 */
	len = fc_gid_ft_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			      ns->port->pid, FC_TYPE_FCP);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_ns_gid_ft_response, (void *)ns,
			  bfa_fcxp_get_maxrsp(port->fcs->bfa), FC_FCCT_TOV);

	port->stats.ns_gidft_sent++;

	bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT);
}

static void
bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
				void *cbarg, bfa_status_t req_status,
				u32 rsp_len, u32 resid_len,
				struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct ct_hdr_s *cthdr = NULL;
	u32        n_pids;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		port->stats.ns_gidft_rsp_err++;
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
		return;
	}

	if (resid_len != 0) {
		/*
		 * TBD : we will need to allocate a larger buffer & retry the
		 * command
		 */
		bfa_trc(port->fcs, rsp_len);
		bfa_trc(port->fcs, resid_len);
		return;
	}

	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
	cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

	switch (cthdr->cmd_rsp_code) {

	case CT_RSP_ACCEPT:

		port->stats.ns_gidft_accepts++;
		n_pids = (fc_get_ctresp_pyld_len(rsp_len) / sizeof(u32));
		bfa_trc(port->fcs, n_pids);
		bfa_fcs_lport_ns_process_gidft_pids(port,
						   (u32 *) (cthdr + 1),
						   n_pids);
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
		break;

	case CT_RSP_REJECT:

		/*
		 * Check the reason code  & explanation.
		 * There may not have been any FC4 devices in the fabric
		 */
		port->stats.ns_gidft_rejects++;
		bfa_trc(port->fcs, cthdr->reason_code);
		bfa_trc(port->fcs, cthdr->exp_code);

		if ((cthdr->reason_code == CT_RSN_UNABLE_TO_PERF)
		    && (cthdr->exp_code == CT_NS_EXP_FT_NOT_REG)) {

			bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
		} else {
			/*
			 * for all other errors, retry
			 */
			bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
		}
		break;

	default:
		port->stats.ns_gidft_unknown_rsp++;
		bfa_trc(port->fcs, cthdr->cmd_rsp_code);
		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
	}
}

/*
 *     This routine will be called by bfa_timer on timer timeouts.
 *
 *	param[in]	port - pointer to bfa_fcs_lport_t.
 *
 *	return
 *		void
 *
 *	Special Considerations:
 *
 *	note
 */
static void
bfa_fcs_lport_ns_timeout(void *arg)
{
	struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) arg;

	ns->port->stats.ns_timeouts++;
	bfa_sm_send_event(ns, NSSM_EVENT_TIMEOUT);
}

/*
 * Process the PID list in GID_FT response
 */
static void
bfa_fcs_lport_ns_process_gidft_pids(struct bfa_fcs_lport_s *port, u32 *pid_buf,
				   u32 n_pids)
{
	struct fcgs_gidft_resp_s *gidft_entry;
	struct bfa_fcs_rport_s *rport;
	u32        ii;

	for (ii = 0; ii < n_pids; ii++) {
		gidft_entry = (struct fcgs_gidft_resp_s *) &pid_buf[ii];

		if (gidft_entry->pid == port->pid)
			continue;

		/*
		 * Check if this rport already exists
		 */
		rport = bfa_fcs_lport_get_rport_by_pid(port, gidft_entry->pid);
		if (rport == NULL) {
			/*
			 * this is a new device. create rport
			 */
			rport = bfa_fcs_rport_create(port, gidft_entry->pid);
		} else {
			/*
			 * this rport already exists
			 */
			bfa_fcs_rport_scn(rport);
		}

		bfa_trc(port->fcs, gidft_entry->pid);

		/*
		 * if the last entry bit is set, bail out.
		 */
		if (gidft_entry->last)
			return;
	}
}

/*
 *  fcs_ns_public FCS nameserver public interfaces
 */

/*
 * Functions called by port/fab.
 * These will send relevant Events to the ns state machine.
 */
void
bfa_fcs_lport_ns_init(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);

	ns->port = port;
	bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline);
}

void
bfa_fcs_lport_ns_offline(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);

	ns->port = port;
	bfa_sm_send_event(ns, NSSM_EVENT_PORT_OFFLINE);
}

void
bfa_fcs_lport_ns_online(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);

	ns->port = port;
	bfa_sm_send_event(ns, NSSM_EVENT_PORT_ONLINE);
}

void
bfa_fcs_lport_ns_query(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);

	bfa_trc(port->fcs, port->pid);
	bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY);
}

static void
bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port)
{

	struct bfa_fcs_rport_s *rport;
	u8 nwwns;
	wwn_t  wwns[BFA_PREBOOT_BOOTLUN_MAX];
	int ii;

	bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, wwns);

	for (ii = 0 ; ii < nwwns; ++ii) {
		rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]);
		WARN_ON(!rport);
	}
}

void
bfa_fcs_lport_ns_util_send_rspn_id(void *cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_ns_s *ns = cbarg;
	struct bfa_fcs_lport_s *port = ns->port;
	struct fchs_s fchs;
	struct bfa_fcxp_s *fcxp;
	u8 symbl[256];
	u8 *psymbl = &symbl[0];
	int len;

	if (!bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online))
		return;

	/* Avoid sending RSPN in the following states. */
	if (bfa_sm_cmp_state(ns, bfa_fcs_lport_ns_sm_offline) ||
	    bfa_sm_cmp_state(ns, bfa_fcs_lport_ns_sm_plogi_sending) ||
	    bfa_sm_cmp_state(ns, bfa_fcs_lport_ns_sm_plogi) ||
	    bfa_sm_cmp_state(ns, bfa_fcs_lport_ns_sm_plogi_retry) ||
	    bfa_sm_cmp_state(ns, bfa_fcs_lport_ns_sm_rspn_id_retry))
		return;

	memset(symbl, 0, sizeof(symbl));
	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
	if (!fcxp) {
		port->stats.ns_rspnid_alloc_wait++;
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
			bfa_fcs_lport_ns_util_send_rspn_id, ns, BFA_FALSE);
		return;
	}

	ns->fcxp = fcxp;

	if (port->vport) {
		/*
		 * For Vports, we append the vport's port symbolic name
		 * to that of the base port.
		 */
		strncpy((char *)psymbl, (char *)&(bfa_fcs_lport_get_psym_name
			(bfa_fcs_get_base_port(port->fcs))),
			strlen((char *)&bfa_fcs_lport_get_psym_name(
			bfa_fcs_get_base_port(port->fcs))));

		/* Ensure we have a null terminating string. */
		((char *)psymbl)[strlen((char *)&bfa_fcs_lport_get_psym_name(
		 bfa_fcs_get_base_port(port->fcs)))] = 0;

		strncat((char *)psymbl,
			(char *)&(bfa_fcs_lport_get_psym_name(port)),
			strlen((char *)&bfa_fcs_lport_get_psym_name(port)));
	}

	len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			      bfa_fcs_lport_get_fcid(port), 0, psymbl);

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
		      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);

	port->stats.ns_rspnid_sent++;
}

/*
 * FCS SCN
 */

#define FC_QOS_RSCN_EVENT		0x0c
#define FC_FABRIC_NAME_RSCN_EVENT	0x0d

/*
 * forward declarations
 */
static void     bfa_fcs_lport_scn_send_scr(void *scn_cbarg,
					  struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_scn_scr_response(void *fcsarg,
					      struct bfa_fcxp_s *fcxp,
					      void *cbarg,
					      bfa_status_t req_status,
					      u32 rsp_len,
					      u32 resid_len,
					      struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port,
					     struct fchs_s *rx_fchs);
static void     bfa_fcs_lport_scn_timeout(void *arg);

/*
 *  fcs_scm_sm FCS SCN state machine
 */

/*
 * VPort SCN State Machine events
 */
enum port_scn_event {
	SCNSM_EVENT_PORT_ONLINE = 1,
	SCNSM_EVENT_PORT_OFFLINE = 2,
	SCNSM_EVENT_RSP_OK = 3,
	SCNSM_EVENT_RSP_ERROR = 4,
	SCNSM_EVENT_TIMEOUT = 5,
	SCNSM_EVENT_SCR_SENT = 6,
};

static void     bfa_fcs_lport_scn_sm_offline(struct bfa_fcs_lport_scn_s *scn,
					    enum port_scn_event event);
static void     bfa_fcs_lport_scn_sm_sending_scr(
					struct bfa_fcs_lport_scn_s *scn,
					enum port_scn_event event);
static void     bfa_fcs_lport_scn_sm_scr(struct bfa_fcs_lport_scn_s *scn,
					enum port_scn_event event);
static void     bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn,
					      enum port_scn_event event);
static void     bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn,
					   enum port_scn_event event);

/*
 *	Starting state - awaiting link up.
 */
static void
bfa_fcs_lport_scn_sm_offline(struct bfa_fcs_lport_scn_s *scn,
			enum port_scn_event event)
{
	switch (event) {
	case SCNSM_EVENT_PORT_ONLINE:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_sending_scr);
		bfa_fcs_lport_scn_send_scr(scn, NULL);
		break;

	case SCNSM_EVENT_PORT_OFFLINE:
		break;

	default:
		bfa_sm_fault(scn->port->fcs, event);
	}
}

static void
bfa_fcs_lport_scn_sm_sending_scr(struct bfa_fcs_lport_scn_s *scn,
				enum port_scn_event event)
{
	switch (event) {
	case SCNSM_EVENT_SCR_SENT:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_scr);
		break;

	case SCNSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline);
		bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe);
		break;

	default:
		bfa_sm_fault(scn->port->fcs, event);
	}
}

static void
bfa_fcs_lport_scn_sm_scr(struct bfa_fcs_lport_scn_s *scn,
			enum port_scn_event event)
{
	struct bfa_fcs_lport_s *port = scn->port;

	switch (event) {
	case SCNSM_EVENT_RSP_OK:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_online);
		break;

	case SCNSM_EVENT_RSP_ERROR:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_scr_retry);
		bfa_timer_start(port->fcs->bfa, &scn->timer,
				    bfa_fcs_lport_scn_timeout, scn,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case SCNSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline);
		bfa_fcxp_discard(scn->fcxp);
		break;

	default:
		bfa_sm_fault(port->fcs, event);
	}
}

static void
bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn,
				enum port_scn_event event)
{
	switch (event) {
	case SCNSM_EVENT_TIMEOUT:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_sending_scr);
		bfa_fcs_lport_scn_send_scr(scn, NULL);
		break;

	case SCNSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline);
		bfa_timer_stop(&scn->timer);
		break;

	default:
		bfa_sm_fault(scn->port->fcs, event);
	}
}

static void
bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn,
			enum port_scn_event event)
{
	switch (event) {
	case SCNSM_EVENT_PORT_OFFLINE:
		bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline);
		break;

	default:
		bfa_sm_fault(scn->port->fcs, event);
	}
}



/*
 *  fcs_scn_private FCS SCN private functions
 */

/*
 * This routine will be called to send a SCR command.
 */
static void
bfa_fcs_lport_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
	struct bfa_fcs_lport_scn_s *scn = scn_cbarg;
	struct bfa_fcs_lport_s *port = scn->port;
	struct fchs_s fchs;
	int             len;
	struct bfa_fcxp_s *fcxp;

	bfa_trc(port->fcs, port->pid);
	bfa_trc(port->fcs, port->port_cfg.pwwn);

	fcxp = fcxp_alloced ? fcxp_alloced :
	       bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
	if (!fcxp) {
		bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe,
				bfa_fcs_lport_scn_send_scr, scn, BFA_TRUE);
		return;
	}
	scn->fcxp = fcxp;

	/* Handle VU registrations for Base port only */
	if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) {
		len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
				port->fabric->lps->brcd_switch,
				port->pid, 0);
	} else {
	    len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
				    BFA_FALSE,
				    port->pid, 0);
	}

	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
			  FC_CLASS_3, len, &fchs,
			  bfa_fcs_lport_scn_scr_response,
			  (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV);

	bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
}

static void
bfa_fcs_lport_scn_scr_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
			void *cbarg, bfa_status_t req_status, u32 rsp_len,
			      u32 resid_len, struct fchs_s *rsp_fchs)
{
	struct bfa_fcs_lport_scn_s *scn = (struct bfa_fcs_lport_scn_s *) cbarg;
	struct bfa_fcs_lport_s *port = scn->port;
	struct fc_els_cmd_s *els_cmd;
	struct fc_ls_rjt_s *ls_rjt;

	bfa_trc(port->fcs, port->port_cfg.pwwn);

	/*
	 * Sanity Checks
	 */
	if (req_status != BFA_STATUS_OK) {
		bfa_trc(port->fcs, req_status);
		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
		return;
	}

	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);

	switch (els_cmd->els_code) {

	case FC_ELS_ACC:
		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK);
		break;

	case FC_ELS_LS_RJT:

		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);

		bfa_trc(port->fcs, ls_rjt->reason_code);
		bfa_trc(port->fcs, ls_rjt->reason_code_expl);

		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
		break;

	default:
		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
	}
}

/*
 * Send a LS Accept
 */
static void
bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port,
				struct fchs_s *rx_fchs)
{
	struct fchs_s fchs;
	struct bfa_fcxp_s *fcxp;
	struct bfa_rport_s *bfa_rport = NULL;
	int             len;

	bfa_trc(port->fcs, rx_fchs->s_id);

	fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
	if (!fcxp)
		return;

	len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
			      rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
			      rx_fchs->ox_id);

	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
			  BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
			  FC_MAX_PDUSZ, 0);
}

/*
 *     This routine will be called by bfa_timer on timer timeouts.
 *
 *	param[in]	vport		- pointer to bfa_fcs_lport_t.
 *	param[out]	vport_status	- pointer to return vport status in
 *
 *	return
 *		void
 *
 *	Special Considerations:
 *
 *	note
 */
static void
bfa_fcs_lport_scn_timeout(void *arg)
{
	struct bfa_fcs_lport_scn_s *scn = (struct bfa_fcs_lport_scn_s *) arg;

	bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT);
}



/*
 *  fcs_scn_public FCS state change notification public interfaces
 */

/*
 * Functions called by port/fab
 */
void
bfa_fcs_lport_scn_init(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);

	scn->port = port;
	bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline);
}

void
bfa_fcs_lport_scn_offline(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);

	scn->port = port;
	bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE);
}

void
bfa_fcs_lport_scn_online(struct bfa_fcs_lport_s *port)
{
	struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);

	scn->port = port;
	bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE);
}

static void
bfa_fcs_lport_scn_portid_rscn(struct bfa_fcs_lport_s *port, u32 rpid)
{
	struct bfa_fcs_rport_s *rport;

	bfa_trc(port->fcs, rpid);

	/*
	 * If this is an unknown device, then it just came online.
	 * Otherwise let rport handle the RSCN event.
	 */
	rport = bfa_fcs_lport_get_rport_by_pid(port, rpid);
	if (!rport)
		rport = bfa_fcs_lport_get_rport_by_old_pid(port, rpid);

	if (rport == NULL) {
		/*
		 * If min cfg mode is enabled, we donot need to
		 * discover any new rports.
		 */
		if (!__fcs_min_cfg(port->fcs))
			rport = bfa_fcs_rport_create(port, rpid);
	} else
		bfa_fcs_rport_scn(rport);
}

/*
 * rscn format based PID comparison
 */
#define __fc_pid_match(__c0, __c1, __fmt)		\
	(((__fmt) == FC_RSCN_FORMAT_FABRIC) ||		\
	 (((__fmt) == FC_RSCN_FORMAT_DOMAIN) &&		\
	  ((__c0)[0] == (__c1)[0])) ||				\
	 (((__fmt) == FC_RSCN_FORMAT_AREA) &&		\
	  ((__c0)[0] == (__c1)[0]) &&				\
	  ((__c0)[1] == (__c1)[1])))

static void
bfa_fcs_lport_scn_multiport_rscn(struct bfa_fcs_lport_s *port,
				enum fc_rscn_format format,
				u32 rscn_pid)
{
	struct bfa_fcs_rport_s *rport;
	struct list_head        *qe, *qe_next;
	u8        *c0, *c1;

	bfa_trc(port->fcs, format);
	bfa_trc(port->fcs, rscn_pid);

	c0 = (u8 *) &rscn_pid;

	list_for_each_safe(qe, qe_next, &port->rport_q) {
		rport = (struct bfa_fcs_rport_s *) qe;
		c1 = (u8 *) &rport->pid;
		if (__fc_pid_match(c0, c1, format))
			bfa_fcs_rport_scn(rport);
	}
}


void
bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port,
			struct fchs_s *fchs, u32 len)
{
	struct fc_rscn_pl_s *rscn = (struct fc_rscn_pl_s *) (fchs + 1);
	int             num_entries;
	u32        rscn_pid;
	bfa_boolean_t   nsquery = BFA_FALSE, found;
	int             i = 0, j;

	num_entries =
		(be16_to_cpu(rscn->payldlen) -
		 sizeof(u32)) / sizeof(rscn->event[0]);

	bfa_trc(port->fcs, num_entries);

	port->stats.num_rscn++;

	bfa_fcs_lport_scn_send_ls_acc(port, fchs);

	for (i = 0; i < num_entries; i++) {
		rscn_pid = rscn->event[i].portid;

		bfa_trc(port->fcs, rscn->event[i].format);
		bfa_trc(port->fcs, rscn_pid);

		/* check for duplicate entries in the list */
		found = BFA_FALSE;
		for (j = 0; j < i; j++) {
			if (rscn->event[j].portid == rscn_pid) {
				found = BFA_TRUE;
				break;
			}
		}

		/* if found in down the list, pid has been already processed */
		if (found) {
			bfa_trc(port->fcs, rscn_pid);
			continue;
		}

		switch (rscn->event[i].format) {
		case FC_RSCN_FORMAT_PORTID:
			if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) {
				/*
				 * Ignore this event.
				 * f/w would have processed it
				 */
				bfa_trc(port->fcs, rscn_pid);
			} else {
				port->stats.num_portid_rscn++;
				bfa_fcs_lport_scn_portid_rscn(port, rscn_pid);
			}
		break;

		case FC_RSCN_FORMAT_FABRIC:
			if (rscn->event[i].qualifier ==
					FC_FABRIC_NAME_RSCN_EVENT) {
				bfa_fcs_lport_ms_fabric_rscn(port);
				break;
			}
			/* !!!!!!!!! Fall Through !!!!!!!!!!!!! */

		case FC_RSCN_FORMAT_AREA:
		case FC_RSCN_FORMAT_DOMAIN:
			nsquery = BFA_TRUE;
			bfa_fcs_lport_scn_multiport_rscn(port,
							rscn->event[i].format,
							rscn_pid);
			break;


		default:
			WARN_ON(1);
			nsquery = BFA_TRUE;
		}
	}

	/*
	 * If any of area, domain or fabric RSCN is received, do a fresh
	 * discovery to find new devices.
	 */
	if (nsquery)
		bfa_fcs_lport_ns_query(port);
}

/*
 * BFA FCS port
 */
/*
 *  fcs_port_api BFA FCS port API
 */
struct bfa_fcs_lport_s *
bfa_fcs_get_base_port(struct bfa_fcs_s *fcs)
{
	return &fcs->fabric.bport;
}

wwn_t
bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, int index,
		int nrports, bfa_boolean_t bwwn)
{
	struct list_head	*qh, *qe;
	struct bfa_fcs_rport_s *rport = NULL;
	int	i;
	struct bfa_fcs_s	*fcs;

	if (port == NULL || nrports == 0)
		return (wwn_t) 0;

	fcs = port->fcs;
	bfa_trc(fcs, (u32) nrports);

	i = 0;
	qh = &port->rport_q;
	qe = bfa_q_first(qh);

	while ((qe != qh) && (i < nrports)) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if (bfa_ntoh3b(rport->pid) > 0xFFF000) {
			qe = bfa_q_next(qe);
			bfa_trc(fcs, (u32) rport->pwwn);
			bfa_trc(fcs, rport->pid);
			bfa_trc(fcs, i);
			continue;
		}

		if (bwwn) {
			if (!memcmp(&wwn, &rport->pwwn, 8))
				break;
		} else {
			if (i == index)
				break;
		}

		i++;
		qe = bfa_q_next(qe);
	}

	bfa_trc(fcs, i);
	if (rport)
		return rport->pwwn;
	else
		return (wwn_t) 0;
}

void
bfa_fcs_lport_get_rport_quals(struct bfa_fcs_lport_s *port,
		struct bfa_rport_qualifier_s rports[], int *nrports)
{
	struct list_head	*qh, *qe;
	struct bfa_fcs_rport_s *rport = NULL;
	int	i;
	struct bfa_fcs_s	*fcs;

	if (port == NULL || rports == NULL || *nrports == 0)
		return;

	fcs = port->fcs;
	bfa_trc(fcs, (u32) *nrports);

	i = 0;
	qh = &port->rport_q;
	qe = bfa_q_first(qh);

	while ((qe != qh) && (i < *nrports)) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if (bfa_ntoh3b(rport->pid) > 0xFFF000) {
			qe = bfa_q_next(qe);
			bfa_trc(fcs, (u32) rport->pwwn);
			bfa_trc(fcs, rport->pid);
			bfa_trc(fcs, i);
			continue;
		}

		if (!rport->pwwn && !rport->pid) {
			qe = bfa_q_next(qe);
			continue;
		}

		rports[i].pwwn = rport->pwwn;
		rports[i].pid = rport->pid;

		i++;
		qe = bfa_q_next(qe);
	}

	bfa_trc(fcs, i);
	*nrports = i;
}

/*
 * Iterate's through all the rport's in the given port to
 * determine the maximum operating speed.
 *
 * !!!! To be used in TRL Functionality only !!!!
 */
bfa_port_speed_t
bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port)
{
	struct list_head *qh, *qe;
	struct bfa_fcs_rport_s *rport = NULL;
	struct bfa_fcs_s	*fcs;
	bfa_port_speed_t max_speed = 0;
	struct bfa_port_attr_s port_attr;
	bfa_port_speed_t port_speed, rport_speed;
	bfa_boolean_t trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa);


	if (port == NULL)
		return 0;

	fcs = port->fcs;

	/* Get Physical port's current speed */
	bfa_fcport_get_attr(port->fcs->bfa, &port_attr);
	port_speed = port_attr.speed;
	bfa_trc(fcs, port_speed);

	qh = &port->rport_q;
	qe = bfa_q_first(qh);

	while (qe != qh) {
		rport = (struct bfa_fcs_rport_s *) qe;
		if ((bfa_ntoh3b(rport->pid) > 0xFFF000) ||
			(bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE) ||
			(rport->scsi_function != BFA_RPORT_TARGET)) {
			qe = bfa_q_next(qe);
			continue;
		}

		rport_speed = rport->rpf.rpsc_speed;
		if ((trl_enabled) && (rport_speed ==
			BFA_PORT_SPEED_UNKNOWN)) {
			/* Use default ratelim speed setting */
			rport_speed =
				bfa_fcport_get_ratelim_speed(port->fcs->bfa);
		}

		if (rport_speed > max_speed)
			max_speed = rport_speed;

		qe = bfa_q_next(qe);
	}

	if (max_speed > port_speed)
		max_speed = port_speed;

	bfa_trc(fcs, max_speed);
	return max_speed;
}

struct bfa_fcs_lport_s *
bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn)
{
	struct bfa_fcs_vport_s *vport;
	bfa_fcs_vf_t   *vf;

	WARN_ON(fcs == NULL);

	vf = bfa_fcs_vf_lookup(fcs, vf_id);
	if (vf == NULL) {
		bfa_trc(fcs, vf_id);
		return NULL;
	}

	if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn))
		return &vf->bport;

	vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn);
	if (vport)
		return &vport->lport;

	return NULL;
}

/*
 *  API corresponding to NPIV_VPORT_GETINFO.
 */
void
bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port,
	 struct bfa_lport_info_s *port_info)
{

	bfa_trc(port->fcs, port->fabric->fabric_name);

	if (port->vport == NULL) {
		/*
		 * This is a Physical port
		 */
		port_info->port_type = BFA_LPORT_TYPE_PHYSICAL;

		/*
		 * @todo : need to fix the state & reason
		 */
		port_info->port_state = 0;
		port_info->offline_reason = 0;

		port_info->port_wwn = bfa_fcs_lport_get_pwwn(port);
		port_info->node_wwn = bfa_fcs_lport_get_nwwn(port);

		port_info->max_vports_supp =
			bfa_lps_get_max_vport(port->fcs->bfa);
		port_info->num_vports_inuse =
			port->fabric->num_vports;
		port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP;
		port_info->num_rports_inuse = port->num_rports;
	} else {
		/*
		 * This is a virtual port
		 */
		port_info->port_type = BFA_LPORT_TYPE_VIRTUAL;

		/*
		 * @todo : need to fix the state & reason
		 */
		port_info->port_state = 0;
		port_info->offline_reason = 0;

		port_info->port_wwn = bfa_fcs_lport_get_pwwn(port);
		port_info->node_wwn = bfa_fcs_lport_get_nwwn(port);
	}
}

void
bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port,
	 struct bfa_lport_stats_s *port_stats)
{
	*port_stats = fcs_port->stats;
}

void
bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port)
{
	memset(&fcs_port->stats, 0, sizeof(struct bfa_lport_stats_s));
}

/*
 * FCS virtual port state machine
 */

#define __vport_fcs(__vp)       ((__vp)->lport.fcs)
#define __vport_pwwn(__vp)      ((__vp)->lport.port_cfg.pwwn)
#define __vport_nwwn(__vp)      ((__vp)->lport.port_cfg.nwwn)
#define __vport_bfa(__vp)       ((__vp)->lport.fcs->bfa)
#define __vport_fcid(__vp)      ((__vp)->lport.pid)
#define __vport_fabric(__vp)    ((__vp)->lport.fabric)
#define __vport_vfid(__vp)      ((__vp)->lport.fabric->vf_id)

#define BFA_FCS_VPORT_MAX_RETRIES  5
/*
 * Forward declarations
 */
static void     bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport);
static void     bfa_fcs_vport_timeout(void *vport_arg);
static void     bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport);
static void     bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport);

/*
 *  fcs_vport_sm FCS virtual port state machine
 */

/*
 * VPort State Machine events
 */
enum bfa_fcs_vport_event {
	BFA_FCS_VPORT_SM_CREATE = 1,	/*  vport create event */
	BFA_FCS_VPORT_SM_DELETE = 2,	/*  vport delete event */
	BFA_FCS_VPORT_SM_START = 3,	/*  vport start request */
	BFA_FCS_VPORT_SM_STOP = 4,	/*  stop: unsupported */
	BFA_FCS_VPORT_SM_ONLINE = 5,	/*  fabric online */
	BFA_FCS_VPORT_SM_OFFLINE = 6,	/*  fabric offline event */
	BFA_FCS_VPORT_SM_FRMSENT = 7,	/*  fdisc/logo sent events */
	BFA_FCS_VPORT_SM_RSP_OK = 8,	/*  good response */
	BFA_FCS_VPORT_SM_RSP_ERROR = 9,	/*  error/bad response */
	BFA_FCS_VPORT_SM_TIMEOUT = 10,	/*  delay timer event */
	BFA_FCS_VPORT_SM_DELCOMP = 11,	/*  lport delete completion */
	BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12,	/*  Dup wnn error*/
	BFA_FCS_VPORT_SM_RSP_FAILED = 13,	/*  non-retryable failure */
	BFA_FCS_VPORT_SM_STOPCOMP = 14,	/* vport delete completion */
};

static void     bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport,
					enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
					 enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport,
					 enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
				       enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport,
					     enum bfa_fcs_vport_event event);
static void	bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport,
					enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
					enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport,
					  enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport,
					 enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
				      enum bfa_fcs_vport_event event);
static void     bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport,
				      enum bfa_fcs_vport_event event);
static void	bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport,
					enum bfa_fcs_vport_event event);
static void	bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport,
					enum bfa_fcs_vport_event event);

static struct bfa_sm_table_s  vport_sm_table[] = {
	{BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT},
	{BFA_SM(bfa_fcs_vport_sm_created), BFA_FCS_VPORT_CREATED},
	{BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE},
	{BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC},
	{BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY},
	{BFA_SM(bfa_fcs_vport_sm_fdisc_rsp_wait), BFA_FCS_VPORT_FDISC_RSP_WAIT},
	{BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE},
	{BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING},
	{BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP},
	{BFA_SM(bfa_fcs_vport_sm_logo), BFA_FCS_VPORT_LOGO},
	{BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR}
};

/*
 * Beginning state.
 */
static void
bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_CREATE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_created);
		bfa_fcs_fabric_addvport(__vport_fabric(vport), vport);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * Created state - a start event is required to start up the state machine.
 */
static void
bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_START:
		if (bfa_sm_cmp_state(__vport_fabric(vport),
					bfa_fcs_fabric_sm_online)
		    && bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) {
			bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
			bfa_fcs_vport_do_fdisc(vport);
		} else {
			/*
			 * Fabric is offline or not NPIV capable, stay in
			 * offline state.
			 */
			vport->vport_stats.fab_no_npiv++;
			bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
		}
		break;

	case BFA_FCS_VPORT_SM_DELETE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		bfa_fcs_lport_delete(&vport->lport);
		break;

	case BFA_FCS_VPORT_SM_ONLINE:
	case BFA_FCS_VPORT_SM_OFFLINE:
		/*
		 * Ignore ONLINE/OFFLINE events from fabric
		 * till vport is started.
		 */
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * Offline state - awaiting ONLINE event from fabric SM.
 */
static void
bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_DELETE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		bfa_fcs_lport_delete(&vport->lport);
		break;

	case BFA_FCS_VPORT_SM_ONLINE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
		vport->fdisc_retries = 0;
		bfa_fcs_vport_do_fdisc(vport);
		break;

	case BFA_FCS_VPORT_SM_STOP:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP);
		break;

	case BFA_FCS_VPORT_SM_OFFLINE:
		/*
		 * This can happen if the vport couldn't be initialzied
		 * due the fact that the npiv was not enabled on the switch.
		 * In that case we will put the vport in offline state.
		 * However, the link can go down and cause the this event to
		 * be sent when we are already offline. Ignore it.
		 */
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}


/*
 * FDISC is sent and awaiting reply from fabric.
 */
static void
bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_DELETE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_rsp_wait);
		break;

	case BFA_FCS_VPORT_SM_OFFLINE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
		bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
		break;

	case BFA_FCS_VPORT_SM_RSP_OK:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_online);
		bfa_fcs_lport_online(&vport->lport);
		break;

	case BFA_FCS_VPORT_SM_RSP_ERROR:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_retry);
		bfa_timer_start(__vport_bfa(vport), &vport->timer,
				    bfa_fcs_vport_timeout, vport,
				    BFA_FCS_RETRY_TIMEOUT);
		break;

	case BFA_FCS_VPORT_SM_RSP_FAILED:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
		break;

	case BFA_FCS_VPORT_SM_RSP_DUP_WWN:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_error);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * FDISC attempt failed - a timer is active to retry FDISC.
 */
static void
bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport,
			     enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_DELETE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		bfa_timer_stop(&vport->timer);
		bfa_fcs_lport_delete(&vport->lport);
		break;

	case BFA_FCS_VPORT_SM_OFFLINE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
		bfa_timer_stop(&vport->timer);
		break;

	case BFA_FCS_VPORT_SM_TIMEOUT:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
		vport->vport_stats.fdisc_retries++;
		vport->fdisc_retries++;
		bfa_fcs_vport_do_fdisc(vport);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * FDISC is in progress and we got a vport delete request -
 * this is a wait state while we wait for fdisc response and
 * we will transition to the appropriate state - on rsp status.
 */
static void
bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport,
				enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_RSP_OK:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting);
		bfa_fcs_lport_delete(&vport->lport);
		break;

	case BFA_FCS_VPORT_SM_DELETE:
		break;

	case BFA_FCS_VPORT_SM_OFFLINE:
	case BFA_FCS_VPORT_SM_RSP_ERROR:
	case BFA_FCS_VPORT_SM_RSP_FAILED:
	case BFA_FCS_VPORT_SM_RSP_DUP_WWN:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
		bfa_fcs_lport_delete(&vport->lport);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * Vport is online (FDISC is complete).
 */
static void
bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_DELETE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting);
		bfa_fcs_lport_delete(&vport->lport);
		break;

	case BFA_FCS_VPORT_SM_STOP:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_stopping);
		bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP);
		break;

	case BFA_FCS_VPORT_SM_OFFLINE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
		bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
		bfa_fcs_lport_offline(&vport->lport);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * Vport is being stopped - awaiting lport stop completion to send
 * LOGO to fabric.
 */
static void
bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport,
			  enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_STOPCOMP:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo_for_stop);
		bfa_fcs_vport_do_logo(vport);
		break;

	case BFA_FCS_VPORT_SM_OFFLINE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * Vport is being deleted - awaiting lport delete completion to send
 * LOGO to fabric.
 */
static void
bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_DELETE:
		break;

	case BFA_FCS_VPORT_SM_DELCOMP:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo);
		bfa_fcs_vport_do_logo(vport);
		break;

	case BFA_FCS_VPORT_SM_OFFLINE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * Error State.
 * This state will be set when the Vport Creation fails due
 * to errors like Dup WWN. In this state only operation allowed
 * is a Vport Delete.
 */
static void
bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_DELETE:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
		bfa_fcs_lport_delete(&vport->lport);
		break;

	default:
		bfa_trc(__vport_fcs(vport), event);
	}
}

/*
 * Lport cleanup is in progress since vport is being deleted. Fabric is
 * offline, so no LOGO is needed to complete vport deletion.
 */
static void
bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_DELCOMP:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
		bfa_fcs_vport_free(vport);
		break;

	case BFA_FCS_VPORT_SM_STOPCOMP:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_created);
		break;

	case BFA_FCS_VPORT_SM_DELETE:
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * LOGO is sent to fabric. Vport stop is in progress. Lport stop cleanup
 * is done.
 */
static void
bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport,
			       enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_OFFLINE:
		bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
		/*
		 * !!! fall through !!!
		 */

	case BFA_FCS_VPORT_SM_RSP_OK:
	case BFA_FCS_VPORT_SM_RSP_ERROR:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_created);
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}

/*
 * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup
 * is done.
 */
static void
bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
			enum bfa_fcs_vport_event event)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), event);

	switch (event) {
	case BFA_FCS_VPORT_SM_OFFLINE:
		bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE);
		/*
		 * !!! fall through !!!
		 */

	case BFA_FCS_VPORT_SM_RSP_OK:
	case BFA_FCS_VPORT_SM_RSP_ERROR:
		bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
		bfa_fcs_vport_free(vport);
		break;

	case BFA_FCS_VPORT_SM_DELETE:
		break;

	default:
		bfa_sm_fault(__vport_fcs(vport), event);
	}
}



/*
 *  fcs_vport_private FCS virtual port private functions
 */
/*
 * Send AEN notification
 */
static void
bfa_fcs_vport_aen_post(struct bfa_fcs_lport_s *port,
		       enum bfa_lport_aen_event event)
{
	struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
	struct bfa_aen_entry_s  *aen_entry;

	bfad_get_aen_entry(bfad, aen_entry);
	if (!aen_entry)
		return;

	aen_entry->aen_data.lport.vf_id = port->fabric->vf_id;
	aen_entry->aen_data.lport.roles = port->port_cfg.roles;
	aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn(
					bfa_fcs_get_base_port(port->fcs));
	aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port);

	/* Send the AEN notification */
	bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
				  BFA_AEN_CAT_LPORT, event);
}

/*
 * This routine will be called to send a FDISC command.
 */
static void
bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport)
{
	bfa_lps_fdisc(vport->lps, vport,
		bfa_fcport_get_maxfrsize(__vport_bfa(vport)),
		__vport_pwwn(vport), __vport_nwwn(vport));
	vport->vport_stats.fdisc_sent++;
}

static void
bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
{
	u8		lsrjt_rsn = vport->lps->lsrjt_rsn;
	u8		lsrjt_expl = vport->lps->lsrjt_expl;

	bfa_trc(__vport_fcs(vport), lsrjt_rsn);
	bfa_trc(__vport_fcs(vport), lsrjt_expl);

	/* For certain reason codes, we don't want to retry. */
	switch (vport->lps->lsrjt_expl) {
	case FC_LS_RJT_EXP_INV_PORT_NAME: /* by brocade */
	case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */
		if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
		else {
			bfa_fcs_vport_aen_post(&vport->lport,
					BFA_LPORT_AEN_NPIV_DUP_WWN);
			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN);
		}
		break;

	case FC_LS_RJT_EXP_INSUFF_RES:
		/*
		 * This means max logins per port/switch setting on the
		 * switch was exceeded.
		 */
		if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
		else {
			bfa_fcs_vport_aen_post(&vport->lport,
					BFA_LPORT_AEN_NPIV_FABRIC_MAX);
			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED);
		}
		break;

	default:
		if (vport->fdisc_retries == 0)
			bfa_fcs_vport_aen_post(&vport->lport,
					BFA_LPORT_AEN_NPIV_UNKNOWN);
		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
	}
}

/*
 *	Called to send a logout to the fabric. Used when a V-Port is
 *	deleted/stopped.
 */
static void
bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport)
{
	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));

	vport->vport_stats.logo_sent++;
	bfa_lps_fdisclogo(vport->lps);
}


/*
 *     This routine will be called by bfa_timer on timer timeouts.
 *
 *	param[in]	vport		- pointer to bfa_fcs_vport_t.
 *	param[out]	vport_status	- pointer to return vport status in
 *
 *	return
 *		void
 *
 *	Special Considerations:
 *
 *	note
 */
static void
bfa_fcs_vport_timeout(void *vport_arg)
{
	struct bfa_fcs_vport_s *vport = (struct bfa_fcs_vport_s *) vport_arg;

	vport->vport_stats.fdisc_timeouts++;
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_TIMEOUT);
}

static void
bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport)
{
	struct bfad_vport_s *vport_drv =
			(struct bfad_vport_s *)vport->vport_drv;

	bfa_fcs_fabric_delvport(__vport_fabric(vport), vport);
	bfa_lps_delete(vport->lps);

	if (vport_drv->comp_del) {
		complete(vport_drv->comp_del);
		return;
	}

	/*
	 * We queue the vport delete work to the IM work_q from here.
	 * The memory for the bfad_vport_s is freed from the FC function
	 * template vport_delete entry point.
	 */
	bfad_im_port_delete(vport_drv->drv_port.bfad, &vport_drv->drv_port);
}

/*
 *  fcs_vport_public FCS virtual port public interfaces
 */

/*
 * Online notification from fabric SM.
 */
void
bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport)
{
	vport->vport_stats.fab_online++;
	if (bfa_fcs_fabric_npiv_capable(__vport_fabric(vport)))
		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE);
	else
		vport->vport_stats.fab_no_npiv++;
}

/*
 * Offline notification from fabric SM.
 */
void
bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport)
{
	vport->vport_stats.fab_offline++;
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE);
}

/*
 * Cleanup notification from fabric SM on link timer expiry.
 */
void
bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport)
{
	vport->vport_stats.fab_cleanup++;
}

/*
 * Stop notification from fabric SM. To be invoked from within FCS.
 */
void
bfa_fcs_vport_fcs_stop(struct bfa_fcs_vport_s *vport)
{
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP);
}

/*
 * delete notification from fabric SM. To be invoked from within FCS.
 */
void
bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport)
{
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
}

/*
 * Stop completion callback from associated lport
 */
void
bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport)
{
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOPCOMP);
}

/*
 * Delete completion callback from associated lport
 */
void
bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport)
{
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELCOMP);
}



/*
 *  fcs_vport_api Virtual port API
 */

/*
 *	Use this function to instantiate a new FCS vport object. This
 *	function will not trigger any HW initialization process (which will be
 *	done in vport_start() call)
 *
 *	param[in] vport	-		pointer to bfa_fcs_vport_t. This space
 *					needs to be allocated by the driver.
 *	param[in] fcs		-	FCS instance
 *	param[in] vport_cfg	-	vport configuration
 *	param[in] vf_id		-	VF_ID if vport is created within a VF.
 *					FC_VF_ID_NULL to specify base fabric.
 *	param[in] vport_drv	-	Opaque handle back to the driver's vport
 *					structure
 *
 *	retval BFA_STATUS_OK - on success.
 *	retval BFA_STATUS_FAILED - on failure.
 */
bfa_status_t
bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
		u16 vf_id, struct bfa_lport_cfg_s *vport_cfg,
		struct bfad_vport_s *vport_drv)
{
	if (vport_cfg->pwwn == 0)
		return BFA_STATUS_INVALID_WWN;

	if (bfa_fcs_lport_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn)
		return BFA_STATUS_VPORT_WWN_BP;

	if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL)
		return BFA_STATUS_VPORT_EXISTS;

	if (fcs->fabric.num_vports ==
			bfa_lps_get_max_vport(fcs->bfa))
		return BFA_STATUS_VPORT_MAX;

	vport->lps = bfa_lps_alloc(fcs->bfa);
	if (!vport->lps)
		return BFA_STATUS_VPORT_MAX;

	vport->vport_drv = vport_drv;
	vport_cfg->preboot_vp = BFA_FALSE;

	bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
	bfa_fcs_lport_attach(&vport->lport, fcs, vf_id, vport);
	bfa_fcs_lport_init(&vport->lport, vport_cfg);
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE);

	return BFA_STATUS_OK;
}

/*
 *	Use this function to instantiate a new FCS PBC vport object. This
 *	function will not trigger any HW initialization process (which will be
 *	done in vport_start() call)
 *
 *	param[in] vport	-	pointer to bfa_fcs_vport_t. This space
 *				needs to be allocated by the driver.
 *	param[in] fcs	-	FCS instance
 *	param[in] vport_cfg	-	vport configuration
 *	param[in] vf_id		-	VF_ID if vport is created within a VF.
 *					FC_VF_ID_NULL to specify base fabric.
 *	param[in] vport_drv	-	Opaque handle back to the driver's vport
 *					structure
 *
 *	retval BFA_STATUS_OK - on success.
 *	retval BFA_STATUS_FAILED - on failure.
 */
bfa_status_t
bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
			u16 vf_id, struct bfa_lport_cfg_s *vport_cfg,
			struct bfad_vport_s *vport_drv)
{
	bfa_status_t rc;

	rc = bfa_fcs_vport_create(vport, fcs, vf_id, vport_cfg, vport_drv);
	vport->lport.port_cfg.preboot_vp = BFA_TRUE;

	return rc;
}

/*
 *	Use this function to findout if this is a pbc vport or not.
 *
 * @param[in] vport - pointer to bfa_fcs_vport_t.
 *
 * @returns None
 */
bfa_boolean_t
bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport)
{

	if (vport && (vport->lport.port_cfg.preboot_vp == BFA_TRUE))
		return BFA_TRUE;
	else
		return BFA_FALSE;

}

/*
 * Use this function initialize the vport.
 *
 * @param[in] vport - pointer to bfa_fcs_vport_t.
 *
 * @returns None
 */
bfa_status_t
bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport)
{
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_START);

	return BFA_STATUS_OK;
}

/*
 *	Use this function quiese the vport object. This function will return
 *	immediately, when the vport is actually stopped, the
 *	bfa_drv_vport_stop_cb() will be called.
 *
 *	param[in] vport - pointer to bfa_fcs_vport_t.
 *
 *	return None
 */
bfa_status_t
bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport)
{
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP);

	return BFA_STATUS_OK;
}

/*
 *	Use this function to delete a vport object. Fabric object should
 *	be stopped before this function call.
 *
 *	!!!!!!! Donot invoke this from within FCS  !!!!!!!
 *
 *	param[in] vport - pointer to bfa_fcs_vport_t.
 *
 *	return     None
 */
bfa_status_t
bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport)
{

	if (vport->lport.port_cfg.preboot_vp)
		return BFA_STATUS_PBC;

	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);

	return BFA_STATUS_OK;
}

/*
 *	Use this function to get vport's current status info.
 *
 *	param[in] vport		pointer to bfa_fcs_vport_t.
 *	param[out] attr		pointer to return vport attributes
 *
 *	return None
 */
void
bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
			struct bfa_vport_attr_s *attr)
{
	if (vport == NULL || attr == NULL)
		return;

	memset(attr, 0, sizeof(struct bfa_vport_attr_s));

	bfa_fcs_lport_get_attr(&vport->lport, &attr->port_attr);
	attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm);
}


/*
 *	Lookup a virtual port. Excludes base port from lookup.
 */
struct bfa_fcs_vport_s *
bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn)
{
	struct bfa_fcs_vport_s *vport;
	struct bfa_fcs_fabric_s *fabric;

	bfa_trc(fcs, vf_id);
	bfa_trc(fcs, vpwwn);

	fabric = bfa_fcs_vf_lookup(fcs, vf_id);
	if (!fabric) {
		bfa_trc(fcs, vf_id);
		return NULL;
	}

	vport = bfa_fcs_fabric_vport_lookup(fabric, vpwwn);
	return vport;
}

/*
 * FDISC Response
 */
void
bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status)
{
	struct bfa_fcs_vport_s *vport = uarg;

	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
	bfa_trc(__vport_fcs(vport), status);

	switch (status) {
	case BFA_STATUS_OK:
		/*
		 * Initialize the V-Port fields
		 */
		__vport_fcid(vport) = vport->lps->lp_pid;
		vport->vport_stats.fdisc_accepts++;
		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
		break;

	case BFA_STATUS_INVALID_MAC:
		/* Only for CNA */
		vport->vport_stats.fdisc_acc_bad++;
		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);

		break;

	case BFA_STATUS_EPROTOCOL:
		switch (vport->lps->ext_status) {
		case BFA_EPROTO_BAD_ACCEPT:
			vport->vport_stats.fdisc_acc_bad++;
			break;

		case BFA_EPROTO_UNKNOWN_RSP:
			vport->vport_stats.fdisc_unknown_rsp++;
			break;

		default:
			break;
		}

		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
		break;

	case BFA_STATUS_FABRIC_RJT:
		vport->vport_stats.fdisc_rejects++;
		bfa_fcs_vport_fdisc_rejected(vport);
		break;

	default:
		vport->vport_stats.fdisc_rsp_err++;
		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
	}
}

/*
 * LOGO response
 */
void
bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg)
{
	struct bfa_fcs_vport_s *vport = uarg;
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
}

/*
 * Received clear virtual link
 */
void
bfa_cb_lps_cvl_event(void *bfad, void *uarg)
{
	struct bfa_fcs_vport_s *vport = uarg;

	/* Send an Offline followed by an ONLINE */
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE);
	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE);
}