summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-11-18 22:19:03 -0800
committerDavid S. Miller <davem@davemloft.net>2009-11-18 22:19:03 -0800
commit3505d1a9fd65e2d3e00827857b6795d9d8983658 (patch)
tree941cfafdb57c427bb6b7ebf6354ee93b2a3693b5 /drivers/scsi
parentdfef948ed2ba69cf041840b5e860d6b4e16fa0b1 (diff)
parent66b00a7c93ec782d118d2c03bd599cfd041e80a1 (diff)
downloadblackbird-op-linux-3505d1a9fd65e2d3e00827857b6795d9d8983658.tar.gz
blackbird-op-linux-3505d1a9fd65e2d3e00827857b6795d9d8983658.zip
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts: drivers/net/sfc/sfe4001.c drivers/net/wireless/libertas/cmd.c drivers/staging/Kconfig drivers/staging/Makefile drivers/staging/rtl8187se/Kconfig drivers/staging/rtl8192e/Kconfig
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/Kconfig11
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/be2iscsi/Kconfig8
-rw-r--r--drivers/scsi/be2iscsi/Makefile8
-rw-r--r--drivers/scsi/be2iscsi/be.h183
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c523
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h877
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c638
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h75
-rw-r--r--drivers/scsi/be2iscsi/be_main.c3390
-rw-r--r--drivers/scsi/be2iscsi/be_main.h837
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c321
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h249
-rw-r--r--drivers/scsi/bfa/Makefile15
-rw-r--r--drivers/scsi/bfa/bfa_callback_priv.h57
-rw-r--r--drivers/scsi/bfa/bfa_cb_ioim_macros.h205
-rw-r--r--drivers/scsi/bfa/bfa_cee.c492
-rw-r--r--drivers/scsi/bfa/bfa_core.c402
-rw-r--r--drivers/scsi/bfa/bfa_csdebug.c58
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c175
-rw-r--r--drivers/scsi/bfa/bfa_fcpim_priv.h188
-rw-r--r--drivers/scsi/bfa/bfa_fcport.c1671
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c182
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c940
-rw-r--r--drivers/scsi/bfa/bfa_fcs_port.c68
-rw-r--r--drivers/scsi/bfa/bfa_fcs_uf.c105
-rw-r--r--drivers/scsi/bfa/bfa_fcxp.c782
-rw-r--r--drivers/scsi/bfa/bfa_fcxp_priv.h138
-rw-r--r--drivers/scsi/bfa/bfa_fwimg_priv.h31
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c142
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c162
-rw-r--r--drivers/scsi/bfa/bfa_intr.c218
-rw-r--r--drivers/scsi/bfa/bfa_intr_priv.h115
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c2382
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h259
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.c872
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.h168
-rw-r--r--drivers/scsi/bfa/bfa_iocfc_q.c44
-rw-r--r--drivers/scsi/bfa/bfa_ioim.c1311
-rw-r--r--drivers/scsi/bfa/bfa_itnim.c1088
-rw-r--r--drivers/scsi/bfa/bfa_log.c346
-rw-r--r--drivers/scsi/bfa/bfa_log_module.c451
-rw-r--r--drivers/scsi/bfa/bfa_lps.c782
-rw-r--r--drivers/scsi/bfa/bfa_lps_priv.h38
-rw-r--r--drivers/scsi/bfa/bfa_module.c90
-rw-r--r--drivers/scsi/bfa/bfa_modules_priv.h43
-rw-r--r--drivers/scsi/bfa/bfa_os_inc.h222
-rw-r--r--drivers/scsi/bfa/bfa_port.c460
-rw-r--r--drivers/scsi/bfa/bfa_port_priv.h90
-rw-r--r--drivers/scsi/bfa/bfa_priv.h113
-rw-r--r--drivers/scsi/bfa/bfa_rport.c911
-rw-r--r--drivers/scsi/bfa/bfa_rport_priv.h45
-rw-r--r--drivers/scsi/bfa/bfa_sgpg.c231
-rw-r--r--drivers/scsi/bfa/bfa_sgpg_priv.h79
-rw-r--r--drivers/scsi/bfa/bfa_sm.c38
-rw-r--r--drivers/scsi/bfa/bfa_timer.c90
-rw-r--r--drivers/scsi/bfa/bfa_trcmod_priv.h66
-rw-r--r--drivers/scsi/bfa/bfa_tskim.c689
-rw-r--r--drivers/scsi/bfa/bfa_uf.c345
-rw-r--r--drivers/scsi/bfa/bfa_uf_priv.h47
-rw-r--r--drivers/scsi/bfa/bfad.c1182
-rw-r--r--drivers/scsi/bfa/bfad_attr.c649
-rw-r--r--drivers/scsi/bfa/bfad_attr.h65
-rw-r--r--drivers/scsi/bfa/bfad_drv.h295
-rw-r--r--drivers/scsi/bfa/bfad_fwimg.c97
-rw-r--r--drivers/scsi/bfa/bfad_im.c1230
-rw-r--r--drivers/scsi/bfa/bfad_im.h150
-rw-r--r--drivers/scsi/bfa/bfad_im_compat.h46
-rw-r--r--drivers/scsi/bfa/bfad_intr.c214
-rw-r--r--drivers/scsi/bfa/bfad_ipfc.h42
-rw-r--r--drivers/scsi/bfa/bfad_os.c50
-rw-r--r--drivers/scsi/bfa/bfad_tm.h59
-rw-r--r--drivers/scsi/bfa/bfad_trcmod.h52
-rw-r--r--drivers/scsi/bfa/fab.c62
-rw-r--r--drivers/scsi/bfa/fabric.c1278
-rw-r--r--drivers/scsi/bfa/fcbuild.c1449
-rw-r--r--drivers/scsi/bfa/fcbuild.h273
-rw-r--r--drivers/scsi/bfa/fcpim.c844
-rw-r--r--drivers/scsi/bfa/fcptm.c68
-rw-r--r--drivers/scsi/bfa/fcs.h30
-rw-r--r--drivers/scsi/bfa/fcs_auth.h37
-rw-r--r--drivers/scsi/bfa/fcs_fabric.h61
-rw-r--r--drivers/scsi/bfa/fcs_fcpim.h44
-rw-r--r--drivers/scsi/bfa/fcs_fcptm.h45
-rw-r--r--drivers/scsi/bfa/fcs_fcxp.h29
-rw-r--r--drivers/scsi/bfa/fcs_lport.h117
-rw-r--r--drivers/scsi/bfa/fcs_ms.h35
-rw-r--r--drivers/scsi/bfa/fcs_port.h32
-rw-r--r--drivers/scsi/bfa/fcs_rport.h61
-rw-r--r--drivers/scsi/bfa/fcs_trcmod.h56
-rw-r--r--drivers/scsi/bfa/fcs_uf.h32
-rw-r--r--drivers/scsi/bfa/fcs_vport.h39
-rw-r--r--drivers/scsi/bfa/fdmi.c1223
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen.h92
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_adapter.h31
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_audit.h31
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_ethport.h35
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_ioc.h37
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_itnim.h33
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_lport.h51
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_port.h57
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_rport.h37
-rw-r--r--drivers/scsi/bfa/include/bfa.h177
-rw-r--r--drivers/scsi/bfa/include/bfa_fcpim.h159
-rw-r--r--drivers/scsi/bfa/include/bfa_fcptm.h47
-rw-r--r--drivers/scsi/bfa/include/bfa_svc.h324
-rw-r--r--drivers/scsi/bfa/include/bfa_timer.h53
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi.h174
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_boot.h34
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_cbreg.h305
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_cee.h119
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ctreg.h611
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fabric.h92
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fcpim.h301
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fcxp.h71
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ioc.h202
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_iocfc.h177
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lport.h89
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lps.h96
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_port.h115
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_pport.h184
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_rport.h104
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_uf.h52
-rw-r--r--drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h36
-rw-r--r--drivers/scsi/bfa/include/cna/cee/bfa_cee.h77
-rw-r--r--drivers/scsi/bfa/include/cna/port/bfa_port.h69
-rw-r--r--drivers/scsi/bfa/include/cna/pstats/ethport_defs.h36
-rw-r--r--drivers/scsi/bfa/include/cna/pstats/phyport_defs.h218
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_checksum.h60
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_debug.h44
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_log.h184
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_perf.h34
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_plog.h162
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_q.h81
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_sm.h69
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_trc.h176
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_wc.h68
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_adapter.h82
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_aen.h73
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_audit.h38
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_auth.h112
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_boot.h71
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_cee.h159
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_driver.h40
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ethport.h98
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h45
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_im_common.h32
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_im_team.h72
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ioc.h152
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h310
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h70
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_itnim.h126
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_led.h35
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_lport.h68
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_mfg.h58
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pci.h41
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pm.h33
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pom.h56
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_port.h245
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pport.h383
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_qos.h99
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_rport.h199
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_status.h255
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_tin.h118
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h43
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_types.h30
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_version.h22
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_vf.h74
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_vport.h91
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb.h33
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h76
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_port.h113
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h80
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h47
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h47
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs.h73
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h82
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h112
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h131
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h63
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h226
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h104
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h63
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_fcs.h28
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_hal.h30
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_linux.h44
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_wdrv.h36
-rw-r--r--drivers/scsi/bfa/include/protocol/ct.h492
-rw-r--r--drivers/scsi/bfa/include/protocol/fc.h1105
-rw-r--r--drivers/scsi/bfa/include/protocol/fc_sp.h224
-rw-r--r--drivers/scsi/bfa/include/protocol/fcp.h186
-rw-r--r--drivers/scsi/bfa/include/protocol/fdmi.h163
-rw-r--r--drivers/scsi/bfa/include/protocol/pcifw.h75
-rw-r--r--drivers/scsi/bfa/include/protocol/scsi.h1648
-rw-r--r--drivers/scsi/bfa/include/protocol/types.h42
-rw-r--r--drivers/scsi/bfa/loop.c422
-rw-r--r--drivers/scsi/bfa/lport_api.c291
-rw-r--r--drivers/scsi/bfa/lport_priv.h82
-rw-r--r--drivers/scsi/bfa/ms.c759
-rw-r--r--drivers/scsi/bfa/n2n.c105
-rw-r--r--drivers/scsi/bfa/ns.c1243
-rw-r--r--drivers/scsi/bfa/plog.c184
-rw-r--r--drivers/scsi/bfa/rport.c2618
-rw-r--r--drivers/scsi/bfa/rport_api.c180
-rw-r--r--drivers/scsi/bfa/rport_ftrs.c375
-rw-r--r--drivers/scsi/bfa/scn.c482
-rw-r--r--drivers/scsi/bfa/vfapi.c292
-rw-r--r--drivers/scsi/bfa/vport.c891
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c2
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_iscsi.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c2
-rw-r--r--drivers/scsi/dpt_i2o.c4
-rw-r--r--drivers/scsi/gdth.c2
-rw-r--r--drivers/scsi/hptiop.c37
-rw-r--r--drivers/scsi/hptiop.h3
-rw-r--r--drivers/scsi/ipr.c42
-rw-r--r--drivers/scsi/ipr.h1
-rw-r--r--drivers/scsi/iscsi_tcp.c2
-rw-r--r--drivers/scsi/libiscsi.c6
-rw-r--r--drivers/scsi/libsas/sas_expander.c1
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c15
-rw-r--r--drivers/scsi/mpt2sas/Kconfig2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h103
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h200
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_history.txt334
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h18
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h65
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h134
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c446
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h106
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c22
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c61
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_debug.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c568
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c26
-rw-r--r--drivers/scsi/mvsas/mv_defs.h4
-rw-r--r--drivers/scsi/mvsas/mv_init.c4
-rw-r--r--drivers/scsi/pmcraid.c68
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c6
-rw-r--r--drivers/scsi/scsi.c11
-rw-r--r--drivers/scsi/scsi_debug.c139
-rw-r--r--drivers/scsi/scsi_error.c3
-rw-r--r--drivers/scsi/scsi_scan.c2
-rw-r--r--drivers/scsi/scsi_sysfs.c7
-rw-r--r--drivers/scsi/scsi_transport_fc.c5
-rw-r--r--drivers/scsi/sd.c140
-rw-r--r--drivers/scsi/sd.h9
-rw-r--r--drivers/scsi/sd_dif.c65
-rw-r--r--drivers/scsi/sg.c10
-rw-r--r--drivers/scsi/sr.c22
-rw-r--r--drivers/scsi/st.c3
254 files changed, 58374 insertions, 631 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 82bb3b2d207a..e11cca4c784c 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -366,6 +366,7 @@ config ISCSI_TCP
source "drivers/scsi/cxgb3i/Kconfig"
source "drivers/scsi/bnx2i/Kconfig"
+source "drivers/scsi/be2iscsi/Kconfig"
config SGIWD93_SCSI
tristate "SGI WD93C93 SCSI Driver"
@@ -1827,6 +1828,16 @@ config SCSI_SRP
To compile this driver as a module, choose M here: the
module will be called libsrp.
+config SCSI_BFA_FC
+ tristate "Brocade BFA Fibre Channel Support"
+ depends on PCI && SCSI
+ select SCSI_FC_ATTRS
+ help
+ This bfa driver supports all Brocade PCIe FC/FCOE host adapters.
+
+ To compile this driver as a module, choose M here. The module will
+ be called bfa.
+
endif # SCSI_LOWLEVEL
source "drivers/scsi/pcmcia/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 61a94af3cee7..3ad61db5e3fa 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
+obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_T128) += t128.o
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
@@ -130,6 +131,7 @@ obj-$(CONFIG_SCSI_MVSAS) += mvsas/
obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
+obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig
new file mode 100644
index 000000000000..2952fcd008ea
--- /dev/null
+++ b/drivers/scsi/be2iscsi/Kconfig
@@ -0,0 +1,8 @@
+config BE2ISCSI
+ tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2"
+ depends on PCI && SCSI
+ select SCSI_ISCSI_ATTRS
+
+ help
+ This driver implements the iSCSI functionality for ServerEngines'
+ 10Gbps Storage adapter - BladeEngine 2.
diff --git a/drivers/scsi/be2iscsi/Makefile b/drivers/scsi/be2iscsi/Makefile
new file mode 100644
index 000000000000..c11f443e3f83
--- /dev/null
+++ b/drivers/scsi/be2iscsi/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile to build the iSCSI driver for ServerEngine's BladeEngine.
+#
+#
+
+obj-$(CONFIG_BE2ISCSI) += be2iscsi.o
+
+be2iscsi-y := be_iscsi.o be_main.o be_mgmt.o be_cmds.o
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
new file mode 100644
index 000000000000..b36020dcf012
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be.h
@@ -0,0 +1,183 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#ifndef BEISCSI_H
+#define BEISCSI_H
+
+#include <linux/pci.h>
+#include <linux/if_vlan.h>
+
+#define FW_VER_LEN 32
+
+struct be_dma_mem {
+ void *va;
+ dma_addr_t dma;
+ u32 size;
+};
+
+struct be_queue_info {
+ struct be_dma_mem dma_mem;
+ u16 len;
+ u16 entry_size; /* Size of an element in the queue */
+ u16 id;
+ u16 tail, head;
+ bool created;
+ atomic_t used; /* Number of valid elements in the queue */
+};
+
+static inline u32 MODULO(u16 val, u16 limit)
+{
+ WARN_ON(limit & (limit - 1));
+ return val & (limit - 1);
+}
+
+static inline void index_inc(u16 *index, u16 limit)
+{
+ *index = MODULO((*index + 1), limit);
+}
+
+static inline void *queue_head_node(struct be_queue_info *q)
+{
+ return q->dma_mem.va + q->head * q->entry_size;
+}
+
+static inline void *queue_tail_node(struct be_queue_info *q)
+{
+ return q->dma_mem.va + q->tail * q->entry_size;
+}
+
+static inline void queue_head_inc(struct be_queue_info *q)
+{
+ index_inc(&q->head, q->len);
+}
+
+static inline void queue_tail_inc(struct be_queue_info *q)
+{
+ index_inc(&q->tail, q->len);
+}
+
+/*ISCSI */
+
+struct be_eq_obj {
+ struct be_queue_info q;
+ char desc[32];
+
+ /* Adaptive interrupt coalescing (AIC) info */
+ bool enable_aic;
+ u16 min_eqd; /* in usecs */
+ u16 max_eqd; /* in usecs */
+ u16 cur_eqd; /* in usecs */
+};
+
+struct be_mcc_obj {
+ struct be_queue_info *q;
+ struct be_queue_info *cq;
+};
+
+struct be_ctrl_info {
+ u8 __iomem *csr;
+ u8 __iomem *db; /* Door Bell */
+ u8 __iomem *pcicfg; /* PCI config space */
+ struct pci_dev *pdev;
+
+ /* Mbox used for cmd request/response */
+ spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */
+ struct be_dma_mem mbox_mem;
+ /* Mbox mem is adjusted to align to 16 bytes. The allocated addr
+ * is stored for freeing purpose */
+ struct be_dma_mem mbox_mem_alloced;
+
+ /* MCC Rings */
+ struct be_mcc_obj mcc_obj;
+ spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
+ spinlock_t mcc_cq_lock;
+
+ /* MCC Async callback */
+ void (*async_cb) (void *adapter, bool link_up);
+ void *adapter_ctxt;
+};
+
+#include "be_cmds.h"
+
+#define PAGE_SHIFT_4K 12
+#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
+
+/* Returns number of pages spanned by the data starting at the given addr */
+#define PAGES_4K_SPANNED(_address, size) \
+ ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
+ (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
+
+/* Byte offset into the page corresponding to given address */
+#define OFFSET_IN_PAGE(addr) \
+ ((size_t)(addr) & (PAGE_SIZE_4K-1))
+
+/* Returns bit offset within a DWORD of a bitfield */
+#define AMAP_BIT_OFFSET(_struct, field) \
+ (((size_t)&(((_struct *)0)->field))%32)
+
+/* Returns the bit mask of the field that is NOT shifted into location. */
+static inline u32 amap_mask(u32 bitsize)
+{
+ return (bitsize == 32 ? 0xFFFFFFFF : (1 << bitsize) - 1);
+}
+
+static inline void amap_set(void *ptr, u32 dw_offset, u32 mask,
+ u32 offset, u32 value)
+{
+ u32 *dw = (u32 *) ptr + dw_offset;
+ *dw &= ~(mask << offset);
+ *dw |= (mask & value) << offset;
+}
+
+#define AMAP_SET_BITS(_struct, field, ptr, val) \
+ amap_set(ptr, \
+ offsetof(_struct, field)/32, \
+ amap_mask(sizeof(((_struct *)0)->field)), \
+ AMAP_BIT_OFFSET(_struct, field), \
+ val)
+
+static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset)
+{
+ u32 *dw = ptr;
+ return mask & (*(dw + dw_offset) >> offset);
+}
+
+#define AMAP_GET_BITS(_struct, field, ptr) \
+ amap_get(ptr, \
+ offsetof(_struct, field)/32, \
+ amap_mask(sizeof(((_struct *)0)->field)), \
+ AMAP_BIT_OFFSET(_struct, field))
+
+#define be_dws_cpu_to_le(wrb, len) swap_dws(wrb, len)
+#define be_dws_le_to_cpu(wrb, len) swap_dws(wrb, len)
+static inline void swap_dws(void *wrb, int len)
+{
+#ifdef __BIG_ENDIAN
+ u32 *dw = wrb;
+ WARN_ON(len % 4);
+ do {
+ *dw = cpu_to_le32(*dw);
+ dw++;
+ len -= 4;
+ } while (len);
+#endif /* __BIG_ENDIAN */
+}
+
+extern void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
+ u16 num_popped);
+
+#endif /* BEISCSI_H */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
new file mode 100644
index 000000000000..08007b6e42df
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -0,0 +1,523 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#include "be.h"
+#include "be_mgmt.h"
+#include "be_main.h"
+
+static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
+{
+ if (compl->flags != 0) {
+ compl->flags = le32_to_cpu(compl->flags);
+ WARN_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0);
+ return true;
+ } else
+ return false;
+}
+
+static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
+{
+ compl->flags = 0;
+}
+
+static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl)
+{
+ u16 compl_status, extd_status;
+
+ be_dws_le_to_cpu(compl, 4);
+
+ compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
+ CQE_STATUS_COMPL_MASK;
+ if (compl_status != MCC_STATUS_SUCCESS) {
+ extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
+ CQE_STATUS_EXTD_MASK;
+ dev_err(&ctrl->pdev->dev,
+ "error in cmd completion: status(compl/extd)=%d/%d\n",
+ compl_status, extd_status);
+ return -1;
+ }
+ return 0;
+}
+
+static inline bool is_link_state_evt(u32 trailer)
+{
+ return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
+ ASYNC_TRAILER_EVENT_CODE_MASK) == ASYNC_EVENT_CODE_LINK_STATE);
+}
+
+void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
+ u16 num_popped)
+{
+ u32 val = 0;
+ val |= qid & DB_CQ_RING_ID_MASK;
+ if (arm)
+ val |= 1 << DB_CQ_REARM_SHIFT;
+ val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
+ iowrite32(val, ctrl->db + DB_CQ_OFFSET);
+}
+
+static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
+{
+#define long_delay 2000
+ void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
+ int cnt = 0, wait = 5; /* in usecs */
+ u32 ready;
+
+ do {
+ ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
+ if (ready)
+ break;
+
+ if (cnt > 6000000) {
+ dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n");
+ return -1;
+ }
+
+ if (cnt > 50) {
+ wait = long_delay;
+ mdelay(long_delay / 1000);
+ } else
+ udelay(wait);
+ cnt += wait;
+ } while (true);
+ return 0;
+}
+
+int be_mbox_notify(struct be_ctrl_info *ctrl)
+{
+ int status;
+ u32 val = 0;
+ void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
+ struct be_dma_mem *mbox_mem = &ctrl->mbox_mem;
+ struct be_mcc_mailbox *mbox = mbox_mem->va;
+ struct be_mcc_compl *compl = &mbox->compl;
+
+ val &= ~MPU_MAILBOX_DB_RDY_MASK;
+ val |= MPU_MAILBOX_DB_HI_MASK;
+ val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
+ iowrite32(val, db);
+
+ status = be_mbox_db_ready_wait(ctrl);
+ if (status != 0) {
+ SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 1\n");
+ return status;
+ }
+ val = 0;
+ val &= ~MPU_MAILBOX_DB_RDY_MASK;
+ val &= ~MPU_MAILBOX_DB_HI_MASK;
+ val |= (u32) (mbox_mem->dma >> 4) << 2;
+ iowrite32(val, db);
+
+ status = be_mbox_db_ready_wait(ctrl);
+ if (status != 0) {
+ SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 2\n");
+ return status;
+ }
+ if (be_mcc_compl_is_new(compl)) {
+ status = be_mcc_compl_process(ctrl, &mbox->compl);
+ be_mcc_compl_use(compl);
+ if (status) {
+ SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process \n");
+ return status;
+ }
+ } else {
+ dev_err(&ctrl->pdev->dev, "invalid mailbox completion\n");
+ return -1;
+ }
+ return 0;
+}
+
+void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
+ bool embedded, u8 sge_cnt)
+{
+ if (embedded)
+ wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
+ else
+ wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) <<
+ MCC_WRB_SGE_CNT_SHIFT;
+ wrb->payload_length = payload_len;
+ be_dws_cpu_to_le(wrb, 8);
+}
+
+void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
+ u8 subsystem, u8 opcode, int cmd_len)
+{
+ req_hdr->opcode = opcode;
+ req_hdr->subsystem = subsystem;
+ req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
+}
+
+static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
+ struct be_dma_mem *mem)
+{
+ int i, buf_pages;
+ u64 dma = (u64) mem->dma;
+
+ buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages);
+ for (i = 0; i < buf_pages; i++) {
+ pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF);
+ pages[i].hi = cpu_to_le32(upper_32_bits(dma));
+ dma += PAGE_SIZE_4K;
+ }
+}
+
+static u32 eq_delay_to_mult(u32 usec_delay)
+{
+#define MAX_INTR_RATE 651042
+ const u32 round = 10;
+ u32 multiplier;
+
+ if (usec_delay == 0)
+ multiplier = 0;
+ else {
+ u32 interrupt_rate = 1000000 / usec_delay;
+ if (interrupt_rate == 0)
+ multiplier = 1023;
+ else {
+ multiplier = (MAX_INTR_RATE - interrupt_rate) * round;
+ multiplier /= interrupt_rate;
+ multiplier = (multiplier + round / 2) / round;
+ multiplier = min(multiplier, (u32) 1023);
+ }
+ }
+ return multiplier;
+}
+
+struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem)
+{
+ return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;
+}
+
+int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *eq, int eq_delay)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_eq_create *req = embedded_payload(wrb);
+ struct be_cmd_resp_eq_create *resp = embedded_payload(wrb);
+ struct be_dma_mem *q_mem = &eq->dma_mem;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_EQ_CREATE, sizeof(*req));
+
+ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+ AMAP_SET_BITS(struct amap_eq_context, func, req->context,
+ PCI_FUNC(ctrl->pdev->devfn));
+ AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
+ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
+ AMAP_SET_BITS(struct amap_eq_context, count, req->context,
+ __ilog2_u32(eq->len / 256));
+ AMAP_SET_BITS(struct amap_eq_context, delaymult, req->context,
+ eq_delay_to_mult(eq_delay));
+ be_dws_cpu_to_le(req->context, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ eq->id = le16_to_cpu(resp->eq_id);
+ eq->created = true;
+ }
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ int status;
+ u8 *endian_check;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ endian_check = (u8 *) wrb;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0x12;
+ *endian_check++ = 0x34;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0x56;
+ *endian_check++ = 0x78;
+ *endian_check++ = 0xFF;
+ be_dws_cpu_to_le(wrb, sizeof(*wrb));
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed \n");
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq, struct be_queue_info *eq,
+ bool sol_evts, bool no_delay, int coalesce_wm)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_cq_create *req = embedded_payload(wrb);
+ struct be_cmd_resp_cq_create *resp = embedded_payload(wrb);
+ struct be_dma_mem *q_mem = &cq->dma_mem;
+ void *ctxt = &req->context;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_CQ_CREATE, sizeof(*req));
+
+ if (!q_mem->va)
+ SE_DEBUG(DBG_LVL_1, "uninitialized q_mem->va\n");
+
+ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+ AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm);
+ AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay);
+ AMAP_SET_BITS(struct amap_cq_context, count, ctxt,
+ __ilog2_u32(cq->len / 256));
+ AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts);
+ AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
+ AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context, func, ctxt,
+ PCI_FUNC(ctrl->pdev->devfn));
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ cq->id = le16_to_cpu(resp->cq_id);
+ cq->created = true;
+ } else
+ SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x \n",
+ status);
+ spin_unlock(&ctrl->mbox_lock);
+
+ return status;
+}
+
+static u32 be_encoded_q_len(int q_len)
+{
+ u32 len_encoded = fls(q_len); /* log2(len) + 1 */
+ if (len_encoded == 16)
+ len_encoded = 0;
+ return len_encoded;
+}
+int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+ int queue_type)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_q_destroy *req = embedded_payload(wrb);
+ u8 subsys = 0, opcode = 0;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ switch (queue_type) {
+ case QTYPE_EQ:
+ subsys = CMD_SUBSYSTEM_COMMON;
+ opcode = OPCODE_COMMON_EQ_DESTROY;
+ break;
+ case QTYPE_CQ:
+ subsys = CMD_SUBSYSTEM_COMMON;
+ opcode = OPCODE_COMMON_CQ_DESTROY;
+ break;
+ case QTYPE_WRBQ:
+ subsys = CMD_SUBSYSTEM_ISCSI;
+ opcode = OPCODE_COMMON_ISCSI_WRBQ_DESTROY;
+ break;
+ case QTYPE_DPDUQ:
+ subsys = CMD_SUBSYSTEM_ISCSI;
+ opcode = OPCODE_COMMON_ISCSI_DEFQ_DESTROY;
+ break;
+ case QTYPE_SGL:
+ subsys = CMD_SUBSYSTEM_ISCSI;
+ opcode = OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES;
+ break;
+ default:
+ spin_unlock(&ctrl->mbox_lock);
+ BUG();
+ return -1;
+ }
+ be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
+ if (queue_type != QTYPE_SGL)
+ req->id = cpu_to_le16(q->id);
+
+ status = be_mbox_notify(ctrl);
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb);
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
+ sizeof(*req));
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb);
+
+ memcpy(mac_addr, resp->mac_address, ETH_ALEN);
+ }
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq,
+ struct be_queue_info *dq, int length,
+ int entry_size)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_defq_create_req *req = embedded_payload(wrb);
+ struct be_dma_mem *q_mem = &dq->dma_mem;
+ void *ctxt = &req->context;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_DEFQ_CREATE, sizeof(*req));
+
+ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid, ctxt, 0);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid_valid, ctxt,
+ 1);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, pci_func_id, ctxt,
+ PCI_FUNC(ctrl->pdev->devfn));
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, ring_size, ctxt,
+ be_encoded_q_len(length / sizeof(struct phys_addr)));
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, default_buffer_size,
+ ctxt, entry_size);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, cq_id_recv, ctxt,
+ cq->id);
+
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_defq_create_resp *resp = embedded_payload(wrb);
+
+ dq->id = le16_to_cpu(resp->id);
+ dq->created = true;
+ }
+ spin_unlock(&ctrl->mbox_lock);
+
+ return status;
+}
+
+int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
+ struct be_queue_info *wrbq)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_wrbq_create_req *req = embedded_payload(wrb);
+ struct be_wrbq_create_resp *resp = embedded_payload(wrb);
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_WRBQ_CREATE, sizeof(*req));
+ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status)
+ wrbq->id = le16_to_cpu(resp->cid);
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
+ struct be_dma_mem *q_mem,
+ u32 page_offset, u32 num_pages)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_post_sgl_pages_req *req = embedded_payload(wrb);
+ int status;
+ unsigned int curr_pages;
+ u32 internal_page_offset = 0;
+ u32 temp_num_pages = num_pages;
+
+ if (num_pages == 0xff)
+ num_pages = 1;
+
+ spin_lock(&ctrl->mbox_lock);
+ do {
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES,
+ sizeof(*req));
+ curr_pages = BE_NUMBER_OF_FIELD(struct be_post_sgl_pages_req,
+ pages);
+ req->num_pages = min(num_pages, curr_pages);
+ req->page_offset = page_offset;
+ be_cmd_page_addrs_prepare(req->pages, req->num_pages, q_mem);
+ q_mem->dma = q_mem->dma + (req->num_pages * PAGE_SIZE);
+ internal_page_offset += req->num_pages;
+ page_offset += req->num_pages;
+ num_pages -= req->num_pages;
+
+ if (temp_num_pages == 0xff)
+ req->num_pages = temp_num_pages;
+
+ status = be_mbox_notify(ctrl);
+ if (status) {
+ SE_DEBUG(DBG_LVL_1,
+ "FW CMD to map iscsi frags failed.\n");
+ goto error;
+ }
+ } while (num_pages > 0);
+error:
+ spin_unlock(&ctrl->mbox_lock);
+ if (status != 0)
+ beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
+ return status;
+}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
new file mode 100644
index 000000000000..c20d686cbb43
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -0,0 +1,877 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#ifndef BEISCSI_CMDS_H
+#define BEISCSI_CMDS_H
+
+/**
+ * The driver sends configuration and managements command requests to the
+ * firmware in the BE. These requests are communicated to the processor
+ * using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one
+ * WRB inside a MAILBOX.
+ * The commands are serviced by the ARM processor in the BladeEngine's MPU.
+ */
+struct be_sge {
+ u32 pa_lo;
+ u32 pa_hi;
+ u32 len;
+};
+
+#define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */
+#define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */
+struct be_mcc_wrb {
+ u32 embedded; /* dword 0 */
+ u32 payload_length; /* dword 1 */
+ u32 tag0; /* dword 2 */
+ u32 tag1; /* dword 3 */
+ u32 rsvd; /* dword 4 */
+ union {
+ u8 embedded_payload[236]; /* used by embedded cmds */
+ struct be_sge sgl[19]; /* used by non-embedded cmds */
+ } payload;
+};
+
+#define CQE_FLAGS_VALID_MASK (1 << 31)
+#define CQE_FLAGS_ASYNC_MASK (1 << 30)
+
+/* Completion Status */
+#define MCC_STATUS_SUCCESS 0x0
+
+#define CQE_STATUS_COMPL_MASK 0xFFFF
+#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
+#define CQE_STATUS_EXTD_MASK 0xFFFF
+#define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */
+
+struct be_mcc_compl {
+ u32 status; /* dword 0 */
+ u32 tag0; /* dword 1 */
+ u32 tag1; /* dword 2 */
+ u32 flags; /* dword 3 */
+};
+
+/********* Mailbox door bell *************/
+/**
+ * Used for driver communication with the FW.
+ * The software must write this register twice to post any command. First,
+ * it writes the register with hi=1 and the upper bits of the physical address
+ * for the MAILBOX structure. Software must poll the ready bit until this
+ * is acknowledged. Then, sotware writes the register with hi=0 with the lower
+ * bits in the address. It must poll the ready bit until the command is
+ * complete. Upon completion, the MAILBOX will contain a valid completion
+ * queue entry.
+ */
+#define MPU_MAILBOX_DB_OFFSET 0x160
+#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */
+#define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */
+
+/********** MPU semphore ******************/
+#define MPU_EP_SEMAPHORE_OFFSET 0xac
+#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
+#define EP_SEMAPHORE_POST_ERR_MASK 0x1
+#define EP_SEMAPHORE_POST_ERR_SHIFT 31
+
+/********** MCC door bell ************/
+#define DB_MCCQ_OFFSET 0x140
+#define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */
+/* Number of entries posted */
+#define DB_MCCQ_NUM_POSTED_SHIFT 16 /* bits 16 - 29 */
+
+/* MPU semphore POST stage values */
+#define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */
+
+/**
+ * When the async bit of mcc_compl is set, the last 4 bytes of
+ * mcc_compl is interpreted as follows:
+ */
+#define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */
+#define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF
+#define ASYNC_EVENT_CODE_LINK_STATE 0x1
+struct be_async_event_trailer {
+ u32 code;
+};
+
+enum {
+ ASYNC_EVENT_LINK_DOWN = 0x0,
+ ASYNC_EVENT_LINK_UP = 0x1
+};
+
+/**
+ * When the event code of an async trailer is link-state, the mcc_compl
+ * must be interpreted as follows
+ */
+struct be_async_event_link_state {
+ u8 physical_port;
+ u8 port_link_status;
+ u8 port_duplex;
+ u8 port_speed;
+ u8 port_fault;
+ u8 rsvd0[7];
+ struct be_async_event_trailer trailer;
+} __packed;
+
+struct be_mcc_mailbox {
+ struct be_mcc_wrb wrb;
+ struct be_mcc_compl compl;
+};
+
+/* Type of subsystems supported by FW */
+#define CMD_SUBSYSTEM_COMMON 0x1
+#define CMD_SUBSYSTEM_ISCSI 0x2
+#define CMD_SUBSYSTEM_ETH 0x3
+#define CMD_SUBSYSTEM_ISCSI_INI 0x6
+#define CMD_COMMON_TCP_UPLOAD 0x1
+
+/**
+ * List of common opcodes subsystem CMD_SUBSYSTEM_COMMON
+ * These opcodes are unique for each subsystem defined above
+ */
+#define OPCODE_COMMON_CQ_CREATE 12
+#define OPCODE_COMMON_EQ_CREATE 13
+#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32
+#define OPCODE_COMMON_GET_FW_VERSION 35
+#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
+#define OPCODE_COMMON_FIRMWARE_CONFIG 42
+#define OPCODE_COMMON_MCC_DESTROY 53
+#define OPCODE_COMMON_CQ_DESTROY 54
+#define OPCODE_COMMON_EQ_DESTROY 55
+#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58
+#define OPCODE_COMMON_FUNCTION_RESET 61
+
+/**
+ * LIST of opcodes that are common between Initiator and Target
+ * used by CMD_SUBSYSTEM_ISCSI
+ * These opcodes are unique for each subsystem defined above
+ */
+#define OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES 2
+#define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3
+#define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7
+#define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61
+#define OPCODE_COMMON_ISCSI_DEFQ_CREATE 64
+#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65
+#define OPCODE_COMMON_ISCSI_WRBQ_CREATE 66
+#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 67
+
+struct be_cmd_req_hdr {
+ u8 opcode; /* dword 0 */
+ u8 subsystem; /* dword 0 */
+ u8 port_number; /* dword 0 */
+ u8 domain; /* dword 0 */
+ u32 timeout; /* dword 1 */
+ u32 request_length; /* dword 2 */
+ u32 rsvd; /* dword 3 */
+};
+
+struct be_cmd_resp_hdr {
+ u32 info; /* dword 0 */
+ u32 status; /* dword 1 */
+ u32 response_length; /* dword 2 */
+ u32 actual_resp_len; /* dword 3 */
+};
+
+struct phys_addr {
+ u32 lo;
+ u32 hi;
+};
+
+/**************************
+ * BE Command definitions *
+ **************************/
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte - used to calculate offset/shift/mask of each field
+ */
+struct amap_eq_context {
+ u8 cidx[13]; /* dword 0 */
+ u8 rsvd0[3]; /* dword 0 */
+ u8 epidx[13]; /* dword 0 */
+ u8 valid; /* dword 0 */
+ u8 rsvd1; /* dword 0 */
+ u8 size; /* dword 0 */
+ u8 pidx[13]; /* dword 1 */
+ u8 rsvd2[3]; /* dword 1 */
+ u8 pd[10]; /* dword 1 */
+ u8 count[3]; /* dword 1 */
+ u8 solevent; /* dword 1 */
+ u8 stalled; /* dword 1 */
+ u8 armed; /* dword 1 */
+ u8 rsvd3[4]; /* dword 2 */
+ u8 func[8]; /* dword 2 */
+ u8 rsvd4; /* dword 2 */
+ u8 delaymult[10]; /* dword 2 */
+ u8 rsvd5[2]; /* dword 2 */
+ u8 phase[2]; /* dword 2 */
+ u8 nodelay; /* dword 2 */
+ u8 rsvd6[4]; /* dword 2 */
+ u8 rsvd7[32]; /* dword 3 */
+} __packed;
+
+struct be_cmd_req_eq_create {
+ struct be_cmd_req_hdr hdr; /* dw[4] */
+ u16 num_pages; /* sword */
+ u16 rsvd0; /* sword */
+ u8 context[sizeof(struct amap_eq_context) / 8]; /* dw[4] */
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_resp_eq_create {
+ struct be_cmd_resp_hdr resp_hdr;
+ u16 eq_id; /* sword */
+ u16 rsvd0; /* sword */
+} __packed;
+
+struct mac_addr {
+ u16 size_of_struct;
+ u8 addr[ETH_ALEN];
+} __packed;
+
+struct be_cmd_req_mac_query {
+ struct be_cmd_req_hdr hdr;
+ u8 type;
+ u8 permanent;
+ u16 if_id;
+} __packed;
+
+struct be_cmd_resp_mac_query {
+ struct be_cmd_resp_hdr hdr;
+ struct mac_addr mac;
+};
+
+/******************** Create CQ ***************************/
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte - used to calculate offset/shift/mask of each field
+ */
+struct amap_cq_context {
+ u8 cidx[11]; /* dword 0 */
+ u8 rsvd0; /* dword 0 */
+ u8 coalescwm[2]; /* dword 0 */
+ u8 nodelay; /* dword 0 */
+ u8 epidx[11]; /* dword 0 */
+ u8 rsvd1; /* dword 0 */
+ u8 count[2]; /* dword 0 */
+ u8 valid; /* dword 0 */
+ u8 solevent; /* dword 0 */
+ u8 eventable; /* dword 0 */
+ u8 pidx[11]; /* dword 1 */
+ u8 rsvd2; /* dword 1 */
+ u8 pd[10]; /* dword 1 */
+ u8 eqid[8]; /* dword 1 */
+ u8 stalled; /* dword 1 */
+ u8 armed; /* dword 1 */
+ u8 rsvd3[4]; /* dword 2 */
+ u8 func[8]; /* dword 2 */
+ u8 rsvd4[20]; /* dword 2 */
+ u8 rsvd5[32]; /* dword 3 */
+} __packed;
+
+struct be_cmd_req_cq_create {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u16 rsvd0;
+ u8 context[sizeof(struct amap_cq_context) / 8];
+ struct phys_addr pages[4];
+} __packed;
+
+struct be_cmd_resp_cq_create {
+ struct be_cmd_resp_hdr hdr;
+ u16 cq_id;
+ u16 rsvd0;
+} __packed;
+
+/******************** Create MCCQ ***************************/
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte - used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_context {
+ u8 con_index[14];
+ u8 rsvd0[2];
+ u8 ring_size[4];
+ u8 fetch_wrb;
+ u8 fetch_r2t;
+ u8 cq_id[10];
+ u8 prod_index[14];
+ u8 fid[8];
+ u8 pdid[9];
+ u8 valid;
+ u8 rsvd1[32];
+ u8 rsvd2[32];
+} __packed;
+
+struct be_cmd_req_mcc_create {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u16 rsvd0;
+ u8 context[sizeof(struct amap_mcc_context) / 8];
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_resp_mcc_create {
+ struct be_cmd_resp_hdr hdr;
+ u16 id;
+ u16 rsvd0;
+} __packed;
+
+/******************** Q Destroy ***************************/
+/* Type of Queue to be destroyed */
+enum {
+ QTYPE_EQ = 1,
+ QTYPE_CQ,
+ QTYPE_MCCQ,
+ QTYPE_WRBQ,
+ QTYPE_DPDUQ,
+ QTYPE_SGL
+};
+
+struct be_cmd_req_q_destroy {
+ struct be_cmd_req_hdr hdr;
+ u16 id;
+ u16 bypass_flush; /* valid only for rx q destroy */
+} __packed;
+
+struct macaddr {
+ u8 byte[ETH_ALEN];
+};
+
+struct be_cmd_req_mcast_mac_config {
+ struct be_cmd_req_hdr hdr;
+ u16 num_mac;
+ u8 promiscuous;
+ u8 interface_id;
+ struct macaddr mac[32];
+} __packed;
+
+static inline void *embedded_payload(struct be_mcc_wrb *wrb)
+{
+ return wrb->payload.embedded_payload;
+}
+
+static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
+{
+ return &wrb->payload.sgl[0];
+}
+
+/******************** Modify EQ Delay *******************/
+struct be_cmd_req_modify_eq_delay {
+ struct be_cmd_req_hdr hdr;
+ u32 num_eq;
+ struct {
+ u32 eq_id;
+ u32 phase;
+ u32 delay_multiplier;
+ } delay[8];
+} __packed;
+
+/******************** Get MAC ADDR *******************/
+
+#define ETH_ALEN 6
+
+
+struct be_cmd_req_get_mac_addr {
+ struct be_cmd_req_hdr hdr;
+ u32 nic_port_count;
+ u32 speed;
+ u32 max_speed;
+ u32 link_state;
+ u32 max_frame_size;
+ u16 size_of_structure;
+ u8 mac_address[ETH_ALEN];
+ u32 rsvd[23];
+};
+
+struct be_cmd_resp_get_mac_addr {
+ struct be_cmd_resp_hdr hdr;
+ u32 nic_port_count;
+ u32 speed;
+ u32 max_speed;
+ u32 link_state;
+ u32 max_frame_size;
+ u16 size_of_structure;
+ u8 mac_address[6];
+ u32 rsvd[23];
+};
+
+int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *eq, int eq_delay);
+
+int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq, struct be_queue_info *eq,
+ bool sol_evts, bool no_delay,
+ int num_cqe_dma_coalesce);
+
+int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+ int type);
+int be_poll_mcc(struct be_ctrl_info *ctrl);
+unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl);
+int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr);
+
+/*ISCSI Functuions */
+int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
+
+struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
+
+int be_mbox_notify(struct be_ctrl_info *ctrl);
+
+int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq,
+ struct be_queue_info *dq, int length,
+ int entry_size);
+
+int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
+ struct be_dma_mem *q_mem, u32 page_offset,
+ u32 num_pages);
+
+int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
+ struct be_queue_info *wrbq);
+
+struct be_default_pdu_context {
+ u32 dw[4];
+} __packed;
+
+struct amap_be_default_pdu_context {
+ u8 dbuf_cindex[13]; /* dword 0 */
+ u8 rsvd0[3]; /* dword 0 */
+ u8 ring_size[4]; /* dword 0 */
+ u8 ring_state[4]; /* dword 0 */
+ u8 rsvd1[8]; /* dword 0 */
+ u8 dbuf_pindex[13]; /* dword 1 */
+ u8 rsvd2; /* dword 1 */
+ u8 pci_func_id[8]; /* dword 1 */
+ u8 rx_pdid[9]; /* dword 1 */
+ u8 rx_pdid_valid; /* dword 1 */
+ u8 default_buffer_size[16]; /* dword 2 */
+ u8 cq_id_recv[10]; /* dword 2 */
+ u8 rx_pdid_not_valid; /* dword 2 */
+ u8 rsvd3[5]; /* dword 2 */
+ u8 rsvd4[32]; /* dword 3 */
+} __packed;
+
+struct be_defq_create_req {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u8 ulp_num;
+ u8 rsvd0;
+ struct be_default_pdu_context context;
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_defq_create_resp {
+ struct be_cmd_req_hdr hdr;
+ u16 id;
+ u16 rsvd0;
+} __packed;
+
+struct be_post_sgl_pages_req {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u16 page_offset;
+ u32 rsvd0;
+ struct phys_addr pages[26];
+ u32 rsvd1;
+} __packed;
+
+struct be_wrbq_create_req {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u8 ulp_num;
+ u8 rsvd0;
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_wrbq_create_resp {
+ struct be_cmd_resp_hdr resp_hdr;
+ u16 cid;
+ u16 rsvd0;
+} __packed;
+
+#define SOL_CID_MASK 0x0000FFC0
+#define SOL_CODE_MASK 0x0000003F
+#define SOL_WRB_INDEX_MASK 0x00FF0000
+#define SOL_CMD_WND_MASK 0xFF000000
+#define SOL_RES_CNT_MASK 0x7FFFFFFF
+#define SOL_EXP_CMD_SN_MASK 0xFFFFFFFF
+#define SOL_HW_STS_MASK 0x000000FF
+#define SOL_STS_MASK 0x0000FF00
+#define SOL_RESP_MASK 0x00FF0000
+#define SOL_FLAGS_MASK 0x7F000000
+#define SOL_S_MASK 0x80000000
+
+struct sol_cqe {
+ u32 dw[4];
+};
+
+struct amap_sol_cqe {
+ u8 hw_sts[8]; /* dword 0 */
+ u8 i_sts[8]; /* dword 0 */
+ u8 i_resp[8]; /* dword 0 */
+ u8 i_flags[7]; /* dword 0 */
+ u8 s; /* dword 0 */
+ u8 i_exp_cmd_sn[32]; /* dword 1 */
+ u8 code[6]; /* dword 2 */
+ u8 cid[10]; /* dword 2 */
+ u8 wrb_index[8]; /* dword 2 */
+ u8 i_cmd_wnd[8]; /* dword 2 */
+ u8 i_res_cnt[31]; /* dword 3 */
+ u8 valid; /* dword 3 */
+} __packed;
+
+
+/**
+ * Post WRB Queue Doorbell Register used by the host Storage
+ * stack to notify the
+ * controller of a posted Work Request Block
+ */
+#define DB_WRB_POST_CID_MASK 0x3FF /* bits 0 - 9 */
+#define DB_DEF_PDU_WRB_INDEX_MASK 0xFF /* bits 0 - 9 */
+
+#define DB_DEF_PDU_WRB_INDEX_SHIFT 16
+#define DB_DEF_PDU_NUM_POSTED_SHIFT 24
+
+struct fragnum_bits_for_sgl_cra_in {
+ struct be_cmd_req_hdr hdr;
+ u32 num_bits;
+} __packed;
+
+struct iscsi_cleanup_req {
+ struct be_cmd_req_hdr hdr;
+ u16 chute;
+ u8 hdr_ring_id;
+ u8 data_ring_id;
+
+} __packed;
+
+struct eq_delay {
+ u32 eq_id;
+ u32 phase;
+ u32 delay_multiplier;
+} __packed;
+
+struct be_eq_delay_params_in {
+ struct be_cmd_req_hdr hdr;
+ u32 num_eq;
+ struct eq_delay delay[8];
+} __packed;
+
+struct ip_address_format {
+ u16 size_of_structure;
+ u8 reserved;
+ u8 ip_type;
+ u8 ip_address[16];
+ u32 rsvd0;
+} __packed;
+
+struct tcp_connect_and_offload_in {
+ struct be_cmd_req_hdr hdr;
+ struct ip_address_format ip_address;
+ u16 tcp_port;
+ u16 cid;
+ u16 cq_id;
+ u16 defq_id;
+ struct phys_addr dataout_template_pa;
+ u16 hdr_ring_id;
+ u16 data_ring_id;
+ u8 do_offload;
+ u8 rsvd0[3];
+} __packed;
+
+struct tcp_connect_and_offload_out {
+ struct be_cmd_resp_hdr hdr;
+ u32 connection_handle;
+ u16 cid;
+ u16 rsvd0;
+
+} __packed;
+
+struct be_mcc_wrb_context {
+ struct MCC_WRB *wrb;
+ int *users_final_status;
+} __packed;
+
+#define DB_DEF_PDU_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+#define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 0 - 9 */
+#define DB_DEF_PDU_REARM_SHIFT 14
+#define DB_DEF_PDU_EVENT_SHIFT 15
+#define DB_DEF_PDU_CQPROC_SHIFT 16
+
+struct dmsg_cqe {
+ u32 dw[4];
+} __packed;
+
+struct tcp_upload_params_in {
+ struct be_cmd_req_hdr hdr;
+ u16 id;
+ u16 upload_type;
+ u32 reset_seq;
+} __packed;
+
+struct tcp_upload_params_out {
+ u32 dw[32];
+} __packed;
+
+union tcp_upload_params {
+ struct tcp_upload_params_in request;
+ struct tcp_upload_params_out response;
+} __packed;
+
+struct be_ulp_fw_cfg {
+ u32 ulp_mode;
+ u32 etx_base;
+ u32 etx_count;
+ u32 sq_base;
+ u32 sq_count;
+ u32 rq_base;
+ u32 rq_count;
+ u32 dq_base;
+ u32 dq_count;
+ u32 lro_base;
+ u32 lro_count;
+ u32 icd_base;
+ u32 icd_count;
+};
+
+struct be_fw_cfg {
+ struct be_cmd_req_hdr hdr;
+ u32 be_config_number;
+ u32 asic_revision;
+ u32 phys_port;
+ u32 function_mode;
+ struct be_ulp_fw_cfg ulp[2];
+ u32 function_caps;
+} __packed;
+
+#define CMD_ISCSI_COMMAND_INVALIDATE 1
+#define ISCSI_OPCODE_SCSI_DATA_OUT 5
+#define OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD 70
+#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41
+#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
+#define OPCODE_COMMON_ISCSI_CLEANUP 59
+#define OPCODE_COMMON_TCP_UPLOAD 56
+#define OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS 1
+/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */
+#define CMD_ISCSI_CONNECTION_INVALIDATE 1
+#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 2
+#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42
+
+#define INI_WR_CMD 1 /* Initiator write command */
+#define INI_TMF_CMD 2 /* Initiator TMF command */
+#define INI_NOPOUT_CMD 3 /* Initiator; Send a NOP-OUT */
+#define INI_RD_CMD 5 /* Initiator requesting to send
+ * a read command
+ */
+#define TGT_CTX_UPDT_CMD 7 /* Target context update */
+#define TGT_STS_CMD 8 /* Target R2T and other BHS
+ * where only the status number
+ * need to be updated
+ */
+#define TGT_DATAIN_CMD 9 /* Target Data-Ins in response
+ * to read command
+ */
+#define TGT_SOS_PDU 10 /* Target:standalone status
+ * response
+ */
+#define TGT_DM_CMD 11 /* Indicates that the bhs
+ * preparedby
+ * driver should not be touched
+ */
+/* --- CMD_CHUTE_TYPE --- */
+#define CMD_CONNECTION_CHUTE_0 1
+#define CMD_CONNECTION_CHUTE_1 2
+#define CMD_CONNECTION_CHUTE_2 3
+
+#define EQ_MAJOR_CODE_COMPLETION 0
+
+#define CMD_ISCSI_SESSION_DEL_CFG_FROM_FLASH 0
+#define CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH 1
+
+/* --- CONNECTION_UPLOAD_PARAMS --- */
+/* These parameters are used to define the type of upload desired. */
+#define CONNECTION_UPLOAD_GRACEFUL 1 /* Graceful upload */
+#define CONNECTION_UPLOAD_ABORT_RESET 2 /* Abortive upload with
+ * reset
+ */
+#define CONNECTION_UPLOAD_ABORT 3 /* Abortive upload without
+ * reset
+ */
+#define CONNECTION_UPLOAD_ABORT_WITH_SEQ 4 /* Abortive upload with reset,
+ * sequence number by driver */
+
+/* Returns byte size of given field with a structure. */
+
+/* Returns the number of items in the field array. */
+#define BE_NUMBER_OF_FIELD(_type_, _field_) \
+ (FIELD_SIZEOF(_type_, _field_)/sizeof((((_type_ *)0)->_field_[0])))\
+
+/**
+ * Different types of iSCSI completions to host driver for both initiator
+ * and taget mode
+ * of operation.
+ */
+#define SOL_CMD_COMPLETE 1 /* Solicited command completed
+ * normally
+ */
+#define SOL_CMD_KILLED_DATA_DIGEST_ERR 2 /* Solicited command got
+ * invalidated internally due
+ * to Data Digest error
+ */
+#define CXN_KILLED_PDU_SIZE_EXCEEDS_DSL 3 /* Connection got invalidated
+ * internally
+ * due to a recieved PDU
+ * size > DSL
+ */
+#define CXN_KILLED_BURST_LEN_MISMATCH 4 /* Connection got invalidated
+ * internally due ti received
+ * PDU sequence size >
+ * FBL/MBL.
+ */
+#define CXN_KILLED_AHS_RCVD 5 /* Connection got invalidated
+ * internally due to a recieved
+ * PDU Hdr that has
+ * AHS */
+#define CXN_KILLED_HDR_DIGEST_ERR 6 /* Connection got invalidated
+ * internally due to Hdr Digest
+ * error
+ */
+#define CXN_KILLED_UNKNOWN_HDR 7 /* Connection got invalidated
+ * internally
+ * due to a bad opcode in the
+ * pdu hdr
+ */
+#define CXN_KILLED_STALE_ITT_TTT_RCVD 8 /* Connection got invalidated
+ * internally due to a recieved
+ * ITT/TTT that does not belong
+ * to this Connection
+ */
+#define CXN_KILLED_INVALID_ITT_TTT_RCVD 9 /* Connection got invalidated
+ * internally due to recieved
+ * ITT/TTT value > Max
+ * Supported ITTs/TTTs
+ */
+#define CXN_KILLED_RST_RCVD 10 /* Connection got invalidated
+ * internally due to an
+ * incoming TCP RST
+ */
+#define CXN_KILLED_TIMED_OUT 11 /* Connection got invalidated
+ * internally due to timeout on
+ * tcp segment 12 retransmit
+ * attempts failed
+ */
+#define CXN_KILLED_RST_SENT 12 /* Connection got invalidated
+ * internally due to TCP RST
+ * sent by the Tx side
+ */
+#define CXN_KILLED_FIN_RCVD 13 /* Connection got invalidated
+ * internally due to an
+ * incoming TCP FIN.
+ */
+#define CXN_KILLED_BAD_UNSOL_PDU_RCVD 14 /* Connection got invalidated
+ * internally due to bad
+ * unsolicited PDU Unsolicited
+ * PDUs are PDUs with
+ * ITT=0xffffffff
+ */
+#define CXN_KILLED_BAD_WRB_INDEX_ERROR 15 /* Connection got invalidated
+ * internally due to bad WRB
+ * index.
+ */
+#define CXN_KILLED_OVER_RUN_RESIDUAL 16 /* Command got invalidated
+ * internally due to recived
+ * command has residual
+ * over run bytes.
+ */
+#define CXN_KILLED_UNDER_RUN_RESIDUAL 17 /* Command got invalidated
+ * internally due to recived
+ * command has residual under
+ * run bytes.
+ */
+#define CMD_KILLED_INVALID_STATSN_RCVD 18 /* Command got invalidated
+ * internally due to a recieved
+ * PDU has an invalid StatusSN
+ */
+#define CMD_KILLED_INVALID_R2T_RCVD 19 /* Command got invalidated
+ * internally due to a recieved
+ * an R2T with some invalid
+ * fields in it
+ */
+#define CMD_CXN_KILLED_LUN_INVALID 20 /* Command got invalidated
+ * internally due to received
+ * PDU has an invalid LUN.
+ */
+#define CMD_CXN_KILLED_ICD_INVALID 21 /* Command got invalidated
+ * internally due to the
+ * corresponding ICD not in a
+ * valid state
+ */
+#define CMD_CXN_KILLED_ITT_INVALID 22 /* Command got invalidated due
+ * to received PDU has an
+ * invalid ITT.
+ */
+#define CMD_CXN_KILLED_SEQ_OUTOFORDER 23 /* Command got invalidated due
+ * to received sequence buffer
+ * offset is out of order.
+ */
+#define CMD_CXN_KILLED_INVALID_DATASN_RCVD 24 /* Command got invalidated
+ * internally due to a
+ * recieved PDU has an invalid
+ * DataSN
+ */
+#define CXN_INVALIDATE_NOTIFY 25 /* Connection invalidation
+ * completion notify.
+ */
+#define CXN_INVALIDATE_INDEX_NOTIFY 26 /* Connection invalidation
+ * completion
+ * with data PDU index.
+ */
+#define CMD_INVALIDATED_NOTIFY 27 /* Command invalidation
+ * completionnotifify.
+ */
+#define UNSOL_HDR_NOTIFY 28 /* Unsolicited header notify.*/
+#define UNSOL_DATA_NOTIFY 29 /* Unsolicited data notify.*/
+#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 30 /* Unsolicited data digest
+ * error notify.
+ */
+#define DRIVERMSG_NOTIFY 31 /* TCP acknowledge based
+ * notification.
+ */
+#define CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN 32 /* Connection got invalidated
+ * internally due to command
+ * and data are not on same
+ * connection.
+ */
+#define SOL_CMD_KILLED_DIF_ERR 33 /* Solicited command got
+ * invalidated internally due
+ * to DIF error
+ */
+#define CXN_KILLED_SYN_RCVD 34 /* Connection got invalidated
+ * internally due to incoming
+ * TCP SYN
+ */
+#define CXN_KILLED_IMM_DATA_RCVD 35 /* Connection got invalidated
+ * internally due to an
+ * incoming Unsolicited PDU
+ * that has immediate data on
+ * the cxn
+ */
+
+void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
+ bool embedded, u8 sge_cnt);
+
+void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
+ u8 subsystem, u8 opcode, int cmd_len);
+
+#endif /* !BEISCSI_CMDS_H */
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
new file mode 100644
index 000000000000..2fd25442cfaf
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -0,0 +1,638 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+
+#include "be_iscsi.h"
+
+extern struct iscsi_transport beiscsi_iscsi_transport;
+
+/**
+ * beiscsi_session_create - creates a new iscsi session
+ * @cmds_max: max commands supported
+ * @qdepth: max queue depth supported
+ * @initial_cmdsn: initial iscsi CMDSN
+ */
+struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
+ u16 cmds_max,
+ u16 qdepth,
+ u32 initial_cmdsn)
+{
+ struct Scsi_Host *shost;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_cls_session *cls_session;
+ struct beiscsi_hba *phba;
+ struct iscsi_session *sess;
+ struct beiscsi_session *beiscsi_sess;
+ struct beiscsi_io_task *io_task;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n");
+
+ if (!ep) {
+ SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n");
+ return NULL;
+ }
+ beiscsi_ep = ep->dd_data;
+ phba = beiscsi_ep->phba;
+ shost = phba->shost;
+ if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) {
+ shost_printk(KERN_ERR, shost, "Cannot handle %d cmds."
+ "Max cmds per session supported is %d. Using %d. "
+ "\n", cmds_max,
+ beiscsi_ep->phba->params.wrbs_per_cxn,
+ beiscsi_ep->phba->params.wrbs_per_cxn);
+ cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn;
+ }
+
+ cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,
+ shost, cmds_max,
+ sizeof(*beiscsi_sess),
+ sizeof(*io_task),
+ initial_cmdsn, ISCSI_MAX_TARGET);
+ if (!cls_session)
+ return NULL;
+ sess = cls_session->dd_data;
+ beiscsi_sess = sess->dd_data;
+ beiscsi_sess->bhs_pool = pci_pool_create("beiscsi_bhs_pool",
+ phba->pcidev,
+ sizeof(struct be_cmd_bhs),
+ 64, 0);
+ if (!beiscsi_sess->bhs_pool)
+ goto destroy_sess;
+
+ return cls_session;
+destroy_sess:
+ iscsi_session_teardown(cls_session);
+ return NULL;
+}
+
+/**
+ * beiscsi_session_destroy - destroys iscsi session
+ * @cls_session: pointer to iscsi cls session
+ *
+ * Destroys iSCSI session instance and releases
+ * resources allocated for it.
+ */
+void beiscsi_session_destroy(struct iscsi_cls_session *cls_session)
+{
+ struct iscsi_session *sess = cls_session->dd_data;
+ struct beiscsi_session *beiscsi_sess = sess->dd_data;
+
+ pci_pool_destroy(beiscsi_sess->bhs_pool);
+ iscsi_session_teardown(cls_session);
+}
+
+/**
+ * beiscsi_conn_create - create an instance of iscsi connection
+ * @cls_session: ptr to iscsi_cls_session
+ * @cid: iscsi cid
+ */
+struct iscsi_cls_conn *
+beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid)
+{
+ struct beiscsi_hba *phba;
+ struct Scsi_Host *shost;
+ struct iscsi_cls_conn *cls_conn;
+ struct beiscsi_conn *beiscsi_conn;
+ struct iscsi_conn *conn;
+ struct iscsi_session *sess;
+ struct beiscsi_session *beiscsi_sess;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid"
+ "from iscsi layer=%d\n", cid);
+ shost = iscsi_session_to_shost(cls_session);
+ phba = iscsi_host_priv(shost);
+
+ cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid);
+ if (!cls_conn)
+ return NULL;
+
+ conn = cls_conn->dd_data;
+ beiscsi_conn = conn->dd_data;
+ beiscsi_conn->ep = NULL;
+ beiscsi_conn->phba = phba;
+ beiscsi_conn->conn = conn;
+ sess = cls_session->dd_data;
+ beiscsi_sess = sess->dd_data;
+ beiscsi_conn->beiscsi_sess = beiscsi_sess;
+ return cls_conn;
+}
+
+/**
+ * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table
+ * @beiscsi_conn: The pointer to beiscsi_conn structure
+ * @phba: The phba instance
+ * @cid: The cid to free
+ */
+static int beiscsi_bindconn_cid(struct beiscsi_hba *phba,
+ struct beiscsi_conn *beiscsi_conn,
+ unsigned int cid)
+{
+ if (phba->conn_table[cid]) {
+ SE_DEBUG(DBG_LVL_1,
+ "Connection table already occupied. Detected clash\n");
+ return -EINVAL;
+ } else {
+ SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n",
+ cid, beiscsi_conn);
+ phba->conn_table[cid] = beiscsi_conn;
+ }
+ return 0;
+}
+
+/**
+ * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection
+ * @cls_session: pointer to iscsi cls session
+ * @cls_conn: pointer to iscsi cls conn
+ * @transport_fd: EP handle(64 bit)
+ *
+ * This function binds the TCP Conn with iSCSI Connection and Session.
+ */
+int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
+ struct iscsi_cls_conn *cls_conn,
+ u64 transport_fd, int is_leading)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct Scsi_Host *shost =
+ (struct Scsi_Host *)iscsi_session_to_shost(cls_session);
+ struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_endpoint *ep;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_bind\n");
+ ep = iscsi_lookup_endpoint(transport_fd);
+ if (!ep)
+ return -EINVAL;
+
+ beiscsi_ep = ep->dd_data;
+
+ if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
+ return -EINVAL;
+
+ if (beiscsi_ep->phba != phba) {
+ SE_DEBUG(DBG_LVL_8,
+ "beiscsi_ep->hba=%p not equal to phba=%p \n",
+ beiscsi_ep->phba, phba);
+ return -EEXIST;
+ }
+
+ beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
+ beiscsi_conn->ep = beiscsi_ep;
+ beiscsi_ep->conn = beiscsi_conn;
+ SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n",
+ beiscsi_conn, conn, beiscsi_ep->ep_cid);
+ return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
+}
+
+/**
+ * beiscsi_conn_get_param - get the iscsi parameter
+ * @cls_conn: pointer to iscsi cls conn
+ * @param: parameter type identifier
+ * @buf: buffer pointer
+ *
+ * returns iscsi parameter
+ */
+int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
+{
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ int len = 0;
+
+ beiscsi_ep = beiscsi_conn->ep;
+ if (!beiscsi_ep) {
+ SE_DEBUG(DBG_LVL_1,
+ "In beiscsi_conn_get_param , no beiscsi_ep\n");
+ return -1;
+ }
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_PORT:
+ len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport);
+ break;
+ case ISCSI_PARAM_CONN_ADDRESS:
+ if (beiscsi_ep->ip_type == BE2_IPV4)
+ len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr);
+ else
+ len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);
+ break;
+ default:
+ return iscsi_conn_get_param(cls_conn, param, buf);
+ }
+ return len;
+}
+
+int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf, int buflen)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_session *session = conn->session;
+ int ret;
+
+ ret = iscsi_set_param(cls_conn, param, buf, buflen);
+ if (ret)
+ return ret;
+ /*
+ * If userspace tried to set the value to higher than we can
+ * support override here.
+ */
+ switch (param) {
+ case ISCSI_PARAM_FIRST_BURST:
+ if (session->first_burst > 8192)
+ session->first_burst = 8192;
+ break;
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ if (conn->max_recv_dlength > 65536)
+ conn->max_recv_dlength = 65536;
+ break;
+ case ISCSI_PARAM_MAX_BURST:
+ if (session->first_burst > 262144)
+ session->first_burst = 262144;
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ * beiscsi_get_host_param - get the iscsi parameter
+ * @shost: pointer to scsi_host structure
+ * @param: parameter type identifier
+ * @buf: buffer pointer
+ *
+ * returns host parameter
+ */
+int beiscsi_get_host_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf)
+{
+ struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
+ int len = 0;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ be_cmd_get_mac_addr(&phba->ctrl, phba->mac_address);
+ len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
+ break;
+ default:
+ return iscsi_host_get_param(shost, param, buf);
+ }
+ return len;
+}
+
+/**
+ * beiscsi_conn_get_stats - get the iscsi stats
+ * @cls_conn: pointer to iscsi cls conn
+ * @stats: pointer to iscsi_stats structure
+ *
+ * returns iscsi stats
+ */
+void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
+ struct iscsi_stats *stats)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_stats\n");
+ stats->txdata_octets = conn->txdata_octets;
+ stats->rxdata_octets = conn->rxdata_octets;
+ stats->dataout_pdus = conn->dataout_pdus_cnt;
+ stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
+ stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
+ stats->datain_pdus = conn->datain_pdus_cnt;
+ stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
+ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
+ stats->r2t_pdus = conn->r2t_pdus_cnt;
+ stats->digest_err = 0;
+ stats->timeout_err = 0;
+ stats->custom_length = 0;
+ strcpy(stats->custom[0].desc, "eh_abort_cnt");
+ stats->custom[0].value = conn->eh_abort_cnt;
+}
+
+/**
+ * beiscsi_set_params_for_offld - get the parameters for offload
+ * @beiscsi_conn: pointer to beiscsi_conn
+ * @params: pointer to offload_params structure
+ */
+static void beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_offload_params *params)
+{
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length,
+ params, session->max_burst);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params,
+ max_send_data_segment_length, params,
+ conn->max_xmit_dlength);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length,
+ params, session->first_burst);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params,
+ session->erl);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params,
+ conn->datadgst_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params,
+ conn->hdrdgst_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params,
+ session->initial_r2t_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params,
+ session->imm_data_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params,
+ (conn->exp_statsn - 1));
+}
+
+/**
+ * beiscsi_conn_start - offload of session to chip
+ * @cls_conn: pointer to beiscsi_conn
+ */
+int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct beiscsi_offload_params params;
+ struct iscsi_session *session = conn->session;
+ struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+
+ memset(&params, 0, sizeof(struct beiscsi_offload_params));
+ beiscsi_ep = beiscsi_conn->ep;
+ if (!beiscsi_ep)
+ SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n");
+
+ free_mgmt_sgl_handle(phba, beiscsi_conn->plogin_sgl_handle);
+ beiscsi_conn->login_in_progress = 0;
+ beiscsi_set_params_for_offld(beiscsi_conn, &params);
+ beiscsi_offload_connection(beiscsi_conn, &params);
+ iscsi_conn_start(cls_conn);
+ return 0;
+}
+
+/**
+ * beiscsi_get_cid - Allocate a cid
+ * @phba: The phba instance
+ */
+static int beiscsi_get_cid(struct beiscsi_hba *phba)
+{
+ unsigned short cid = 0xFFFF;
+
+ if (!phba->avlbl_cids)
+ return cid;
+
+ cid = phba->cid_array[phba->cid_alloc++];
+ if (phba->cid_alloc == phba->params.cxns_per_ctrl)
+ phba->cid_alloc = 0;
+ phba->avlbl_cids--;
+ return cid;
+}
+
+/**
+ * beiscsi_open_conn - Ask FW to open a TCP connection
+ * @ep: endpoint to be used
+ * @src_addr: The source IP address
+ * @dst_addr: The Destination IP address
+ *
+ * Asks the FW to open a TCP connection
+ */
+static int beiscsi_open_conn(struct iscsi_endpoint *ep,
+ struct sockaddr *src_addr,
+ struct sockaddr *dst_addr, int non_blocking)
+{
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+ int ret = -1;
+
+ beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
+ if (beiscsi_ep->ep_cid == 0xFFFF) {
+ SE_DEBUG(DBG_LVL_1, "No free cid available\n");
+ return ret;
+ }
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ",
+ beiscsi_ep->ep_cid);
+ phba->ep_array[beiscsi_ep->ep_cid] = ep;
+ if (beiscsi_ep->ep_cid >
+ (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) {
+ SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
+ return ret;
+ }
+
+ beiscsi_ep->cid_vld = 0;
+ return mgmt_open_connection(phba, dst_addr, beiscsi_ep);
+}
+
+/**
+ * beiscsi_put_cid - Free the cid
+ * @phba: The phba for which the cid is being freed
+ * @cid: The cid to free
+ */
+static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
+{
+ phba->avlbl_cids++;
+ phba->cid_array[phba->cid_free++] = cid;
+ if (phba->cid_free == phba->params.cxns_per_ctrl)
+ phba->cid_free = 0;
+}
+
+/**
+ * beiscsi_free_ep - free endpoint
+ * @ep: pointer to iscsi endpoint structure
+ */
+static void beiscsi_free_ep(struct iscsi_endpoint *ep)
+{
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ beiscsi_ep->phba = NULL;
+ iscsi_destroy_endpoint(ep);
+}
+
+/**
+ * beiscsi_ep_connect - Ask chip to create TCP Conn
+ * @scsi_host: Pointer to scsi_host structure
+ * @dst_addr: The IP address of Target
+ * @non_blocking: blocking or non-blocking call
+ *
+ * This routines first asks chip to create a connection and then allocates an EP
+ */
+struct iscsi_endpoint *
+beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
+ int non_blocking)
+{
+ struct beiscsi_hba *phba;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_endpoint *ep;
+ int ret;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n");
+ if (shost)
+ phba = iscsi_host_priv(shost);
+ else {
+ ret = -ENXIO;
+ SE_DEBUG(DBG_LVL_1, "shost is NULL \n");
+ return ERR_PTR(ret);
+ }
+ ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
+ if (!ep) {
+ ret = -ENOMEM;
+ return ERR_PTR(ret);
+ }
+
+ beiscsi_ep = ep->dd_data;
+ beiscsi_ep->phba = phba;
+
+ if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) {
+ SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
+ ret = -ENOMEM;
+ goto free_ep;
+ }
+
+ return ep;
+
+free_ep:
+ beiscsi_free_ep(ep);
+ return ERR_PTR(ret);
+}
+
+/**
+ * beiscsi_ep_poll - Poll to see if connection is established
+ * @ep: endpoint to be used
+ * @timeout_ms: timeout specified in millisecs
+ *
+ * Poll to see if TCP connection established
+ */
+int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
+{
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_poll\n");
+ if (beiscsi_ep->cid_vld == 1)
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * beiscsi_close_conn - Upload the connection
+ * @ep: The iscsi endpoint
+ * @flag: The type of connection closure
+ */
+static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag)
+{
+ int ret = 0;
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+
+ if (MGMT_STATUS_SUCCESS !=
+ mgmt_upload_connection(phba, beiscsi_ep->ep_cid,
+ CONNECTION_UPLOAD_GRACEFUL)) {
+ SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x",
+ beiscsi_ep->ep_cid);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/**
+ * beiscsi_ep_disconnect - Tears down the TCP connection
+ * @ep: endpoint to be used
+ *
+ * Tears down the TCP connection
+ */
+void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
+{
+ struct beiscsi_conn *beiscsi_conn;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct beiscsi_hba *phba;
+ int flag = 0;
+
+ beiscsi_ep = ep->dd_data;
+ phba = beiscsi_ep->phba;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n");
+
+ if (beiscsi_ep->conn) {
+ beiscsi_conn = beiscsi_ep->conn;
+ iscsi_suspend_queue(beiscsi_conn->conn);
+ beiscsi_close_conn(ep, flag);
+ }
+
+ beiscsi_free_ep(ep);
+}
+
+/**
+ * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
+ * @phba: The phba instance
+ * @cid: The cid to free
+ */
+static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba,
+ unsigned int cid)
+{
+ if (phba->conn_table[cid])
+ phba->conn_table[cid] = NULL;
+ else {
+ SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * beiscsi_conn_stop - Invalidate and stop the connection
+ * @cls_conn: pointer to get iscsi_conn
+ * @flag: The type of connection closure
+ */
+void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_session *session = conn->session;
+ struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ unsigned int status;
+ unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n");
+ beiscsi_ep = beiscsi_conn->ep;
+ if (!beiscsi_ep) {
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n");
+ return;
+ }
+ status = mgmt_invalidate_connection(phba, beiscsi_ep,
+ beiscsi_ep->ep_cid, 1,
+ savecfg_flag);
+ if (status != MGMT_STATUS_SUCCESS) {
+ SE_DEBUG(DBG_LVL_1,
+ "mgmt_invalidate_connection Failed for cid=%d \n",
+ beiscsi_ep->ep_cid);
+ }
+ beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
+ iscsi_conn_stop(cls_conn, flag);
+}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
new file mode 100644
index 000000000000..f92ffc5349fb
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#ifndef _BE_ISCSI_
+#define _BE_ISCSI_
+
+#include "be_main.h"
+#include "be_mgmt.h"
+
+#define BE2_IPV4 0x1
+#define BE2_IPV6 0x10
+
+void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_offload_params *params);
+
+void beiscsi_offload_iscsi(struct beiscsi_hba *phba, struct iscsi_conn *conn,
+ struct beiscsi_conn *beiscsi_conn,
+ unsigned int fw_handle);
+
+struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
+ uint16_t cmds_max,
+ uint16_t qdepth,
+ uint32_t initial_cmdsn);
+
+void beiscsi_session_destroy(struct iscsi_cls_session *cls_session);
+
+struct iscsi_cls_conn *beiscsi_conn_create(struct iscsi_cls_session
+ *cls_session, uint32_t cid);
+
+int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
+ struct iscsi_cls_conn *cls_conn,
+ uint64_t transport_fd, int is_leading);
+
+int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf);
+
+int beiscsi_get_host_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+
+int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf, int buflen);
+
+int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn);
+
+void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag);
+
+struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost,
+ struct sockaddr *dst_addr,
+ int non_blocking);
+
+int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms);
+
+void beiscsi_ep_disconnect(struct iscsi_endpoint *ep);
+
+void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
+ struct iscsi_stats *stats);
+
+#endif
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
new file mode 100644
index 000000000000..4f1aca346e38
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -0,0 +1,3390 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include "be_main.h"
+#include "be_iscsi.h"
+#include "be_mgmt.h"
+
+static unsigned int be_iopoll_budget = 10;
+static unsigned int be_max_phys_size = 64;
+static unsigned int enable_msix;
+
+MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
+MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
+MODULE_AUTHOR("ServerEngines Corporation");
+MODULE_LICENSE("GPL");
+module_param(be_iopoll_budget, int, 0);
+module_param(enable_msix, int, 0);
+module_param(be_max_phys_size, uint, S_IRUGO);
+MODULE_PARM_DESC(be_max_phys_size, "Maximum Size (In Kilobytes) of physically"
+ "contiguous memory that can be allocated."
+ "Range is 16 - 128");
+
+static int beiscsi_slave_configure(struct scsi_device *sdev)
+{
+ blk_queue_max_segment_size(sdev->request_queue, 65536);
+ return 0;
+}
+
+static struct scsi_host_template beiscsi_sht = {
+ .module = THIS_MODULE,
+ .name = "ServerEngines 10Gbe open-iscsi Initiator Driver",
+ .proc_name = DRV_NAME,
+ .queuecommand = iscsi_queuecommand,
+ .eh_abort_handler = iscsi_eh_abort,
+ .change_queue_depth = iscsi_change_queue_depth,
+ .slave_configure = beiscsi_slave_configure,
+ .target_alloc = iscsi_target_alloc,
+ .eh_device_reset_handler = iscsi_eh_device_reset,
+ .eh_target_reset_handler = iscsi_eh_target_reset,
+ .sg_tablesize = BEISCSI_SGLIST_ELEMENTS,
+ .can_queue = BE2_IO_DEPTH,
+ .this_id = -1,
+ .max_sectors = BEISCSI_MAX_SECTORS,
+ .cmd_per_lun = BEISCSI_CMD_PER_LUN,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+static struct scsi_transport_template *beiscsi_scsi_transport;
+
+/*------------------- PCI Driver operations and data ----------------- */
+static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = {
+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
+
+static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
+{
+ struct beiscsi_hba *phba;
+ struct Scsi_Host *shost;
+
+ shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0);
+ if (!shost) {
+ dev_err(&pcidev->dev, "beiscsi_hba_alloc -"
+ "iscsi_host_alloc failed \n");
+ return NULL;
+ }
+ shost->dma_boundary = pcidev->dma_mask;
+ shost->max_id = BE2_MAX_SESSIONS;
+ shost->max_channel = 0;
+ shost->max_cmd_len = BEISCSI_MAX_CMD_LEN;
+ shost->max_lun = BEISCSI_NUM_MAX_LUN;
+ shost->transportt = beiscsi_scsi_transport;
+
+ phba = iscsi_host_priv(shost);
+ memset(phba, 0, sizeof(*phba));
+ phba->shost = shost;
+ phba->pcidev = pci_dev_get(pcidev);
+
+ if (iscsi_host_add(shost, &phba->pcidev->dev))
+ goto free_devices;
+ return phba;
+
+free_devices:
+ pci_dev_put(phba->pcidev);
+ iscsi_host_free(phba->shost);
+ return NULL;
+}
+
+static void beiscsi_unmap_pci_function(struct beiscsi_hba *phba)
+{
+ if (phba->csr_va) {
+ iounmap(phba->csr_va);
+ phba->csr_va = NULL;
+ }
+ if (phba->db_va) {
+ iounmap(phba->db_va);
+ phba->db_va = NULL;
+ }
+ if (phba->pci_va) {
+ iounmap(phba->pci_va);
+ phba->pci_va = NULL;
+ }
+}
+
+static int beiscsi_map_pci_bars(struct beiscsi_hba *phba,
+ struct pci_dev *pcidev)
+{
+ u8 __iomem *addr;
+
+ addr = ioremap_nocache(pci_resource_start(pcidev, 2),
+ pci_resource_len(pcidev, 2));
+ if (addr == NULL)
+ return -ENOMEM;
+ phba->ctrl.csr = addr;
+ phba->csr_va = addr;
+ phba->csr_pa.u.a64.address = pci_resource_start(pcidev, 2);
+
+ addr = ioremap_nocache(pci_resource_start(pcidev, 4), 128 * 1024);
+ if (addr == NULL)
+ goto pci_map_err;
+ phba->ctrl.db = addr;
+ phba->db_va = addr;
+ phba->db_pa.u.a64.address = pci_resource_start(pcidev, 4);
+
+ addr = ioremap_nocache(pci_resource_start(pcidev, 1),
+ pci_resource_len(pcidev, 1));
+ if (addr == NULL)
+ goto pci_map_err;
+ phba->ctrl.pcicfg = addr;
+ phba->pci_va = addr;
+ phba->pci_pa.u.a64.address = pci_resource_start(pcidev, 1);
+ return 0;
+
+pci_map_err:
+ beiscsi_unmap_pci_function(phba);
+ return -ENOMEM;
+}
+
+static int beiscsi_enable_pci(struct pci_dev *pcidev)
+{
+ int ret;
+
+ ret = pci_enable_device(pcidev);
+ if (ret) {
+ dev_err(&pcidev->dev, "beiscsi_enable_pci - enable device "
+ "failed. Returning -ENODEV\n");
+ return ret;
+ }
+
+ if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
+ ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
+ pci_disable_device(pcidev);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced;
+ struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem;
+ int status = 0;
+
+ ctrl->pdev = pdev;
+ status = beiscsi_map_pci_bars(phba, pdev);
+ if (status)
+ return status;
+
+ mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
+ mbox_mem_alloc->va = pci_alloc_consistent(pdev,
+ mbox_mem_alloc->size,
+ &mbox_mem_alloc->dma);
+ if (!mbox_mem_alloc->va) {
+ beiscsi_unmap_pci_function(phba);
+ status = -ENOMEM;
+ return status;
+ }
+
+ mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
+ mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
+ mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
+ memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
+ spin_lock_init(&ctrl->mbox_lock);
+ return status;
+}
+
+static void beiscsi_get_params(struct beiscsi_hba *phba)
+{
+ phba->params.ios_per_ctrl = BE2_IO_DEPTH;
+ phba->params.cxns_per_ctrl = BE2_MAX_SESSIONS;
+ phba->params.asyncpdus_per_ctrl = BE2_ASYNCPDUS;
+ phba->params.icds_per_ctrl = BE2_MAX_ICDS / 2;
+ phba->params.num_sge_per_io = BE2_SGE;
+ phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ;
+ phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ;
+ phba->params.eq_timer = 64;
+ phba->params.num_eq_entries =
+ (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) /
+ 512) + 1) * 512;
+ phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024)
+ ? 1024 : phba->params.num_eq_entries;
+ SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n",
+ phba->params.num_eq_entries);
+ phba->params.num_cq_entries =
+ (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) /
+ 512) + 1) * 512;
+ SE_DEBUG(DBG_LVL_8,
+ "phba->params.num_cq_entries=%d BE2_CMDS_PER_CXN=%d"
+ "BE2_LOGOUTS=%d BE2_TMFS=%d BE2_ASYNCPDUS=%d \n",
+ phba->params.num_cq_entries, BE2_CMDS_PER_CXN,
+ BE2_LOGOUTS, BE2_TMFS, BE2_ASYNCPDUS);
+ phba->params.wrbs_per_cxn = 256;
+}
+
+static void hwi_ring_eq_db(struct beiscsi_hba *phba,
+ unsigned int id, unsigned int clr_interrupt,
+ unsigned int num_processed,
+ unsigned char rearm, unsigned char event)
+{
+ u32 val = 0;
+ val |= id & DB_EQ_RING_ID_MASK;
+ if (rearm)
+ val |= 1 << DB_EQ_REARM_SHIFT;
+ if (clr_interrupt)
+ val |= 1 << DB_EQ_CLR_SHIFT;
+ if (event)
+ val |= 1 << DB_EQ_EVNT_SHIFT;
+ val |= num_processed << DB_EQ_NUM_POPPED_SHIFT;
+ iowrite32(val, phba->db_va + DB_EQ_OFFSET);
+}
+
+/**
+ * be_isr - The isr routine of the driver.
+ * @irq: Not used
+ * @dev_id: Pointer to host adapter structure
+ */
+static irqreturn_t be_isr(int irq, void *dev_id)
+{
+ struct beiscsi_hba *phba;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_eq_entry *eqe = NULL;
+ struct be_queue_info *eq;
+ struct be_queue_info *cq;
+ unsigned long flags, index;
+ unsigned int num_eq_processed;
+ struct be_ctrl_info *ctrl;
+ int isr;
+
+ phba = dev_id;
+ if (!enable_msix) {
+ ctrl = &phba->ctrl;;
+ isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
+ (PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE));
+ if (!isr)
+ return IRQ_NONE;
+ }
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ eq = &phwi_context->be_eq.q;
+ cq = &phwi_context->be_cq;
+ index = 0;
+ eqe = queue_tail_node(eq);
+ if (!eqe)
+ SE_DEBUG(DBG_LVL_1, "eqe is NULL\n");
+
+ num_eq_processed = 0;
+ if (blk_iopoll_enabled) {
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ if (!blk_iopoll_sched_prep(&phba->iopoll))
+ blk_iopoll_sched(&phba->iopoll);
+
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ SE_DEBUG(DBG_LVL_8, "Valid EQE\n");
+ }
+ if (num_eq_processed) {
+ hwi_ring_eq_db(phba, eq->id, 0, num_eq_processed, 0, 1);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+ } else {
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+
+ if (((eqe->dw[offsetof(struct amap_eq_entry,
+ resource_id) / 32] &
+ EQE_RESID_MASK) >> 16) != cq->id) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_mcc_cq = 1;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ } else {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_cq = 1;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ }
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ }
+ if (phba->todo_cq || phba->todo_mcc_cq)
+ queue_work(phba->wq, &phba->work_cqs);
+
+ if (num_eq_processed) {
+ hwi_ring_eq_db(phba, eq->id, 0, num_eq_processed, 1, 1);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+ }
+}
+
+static int beiscsi_init_irqs(struct beiscsi_hba *phba)
+{
+ struct pci_dev *pcidev = phba->pcidev;
+ int ret;
+
+ ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED, "beiscsi", phba);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-"
+ "Failed to register irq\\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void hwi_ring_cq_db(struct beiscsi_hba *phba,
+ unsigned int id, unsigned int num_processed,
+ unsigned char rearm, unsigned char event)
+{
+ u32 val = 0;
+ val |= id & DB_CQ_RING_ID_MASK;
+ if (rearm)
+ val |= 1 << DB_CQ_REARM_SHIFT;
+ val |= num_processed << DB_CQ_NUM_POPPED_SHIFT;
+ iowrite32(val, phba->db_va + DB_CQ_OFFSET);
+}
+
+/*
+ * async pdus include
+ * a. unsolicited NOP-In (target initiated NOP-In)
+ * b. Async Messages
+ * c. Reject PDU
+ * d. Login response
+ * These headers arrive unprocessed by the EP firmware and iSCSI layer
+ * process them
+ */
+static unsigned int
+beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ unsigned short cid,
+ struct pdu_base *ppdu,
+ unsigned long pdu_len,
+ void *pbuffer, unsigned long buf_len)
+{
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ switch (ppdu->dw[offsetof(struct amap_pdu_base, opcode) / 32] &
+ PDUBASE_OPCODE_MASK) {
+ case ISCSI_OP_NOOP_IN:
+ pbuffer = NULL;
+ buf_len = 0;
+ break;
+ case ISCSI_OP_ASYNC_EVENT:
+ break;
+ case ISCSI_OP_REJECT:
+ WARN_ON(!pbuffer);
+ WARN_ON(!(buf_len == 48));
+ SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n");
+ break;
+ case ISCSI_OP_LOGIN_RSP:
+ break;
+ default:
+ shost_printk(KERN_WARNING, phba->shost,
+ "Unrecognized opcode 0x%x in async msg \n",
+ (ppdu->
+ dw[offsetof(struct amap_pdu_base, opcode) / 32]
+ & PDUBASE_OPCODE_MASK));
+ return 1;
+ }
+
+ spin_lock_bh(&session->lock);
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len);
+ spin_unlock_bh(&session->lock);
+ return 0;
+}
+
+static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
+{
+ struct sgl_handle *psgl_handle;
+
+ if (phba->io_sgl_hndl_avbl) {
+ SE_DEBUG(DBG_LVL_8,
+ "In alloc_io_sgl_handle,io_sgl_alloc_index=%d \n",
+ phba->io_sgl_alloc_index);
+ psgl_handle = phba->io_sgl_hndl_base[phba->
+ io_sgl_alloc_index];
+ phba->io_sgl_hndl_base[phba->io_sgl_alloc_index] = NULL;
+ phba->io_sgl_hndl_avbl--;
+ if (phba->io_sgl_alloc_index == (phba->params.ios_per_ctrl - 1))
+ phba->io_sgl_alloc_index = 0;
+ else
+ phba->io_sgl_alloc_index++;
+ } else
+ psgl_handle = NULL;
+ return psgl_handle;
+}
+
+static void
+free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
+{
+ SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d \n",
+ phba->io_sgl_free_index);
+ if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) {
+ /*
+ * this can happen if clean_task is called on a task that
+ * failed in xmit_task or alloc_pdu.
+ */
+ SE_DEBUG(DBG_LVL_8,
+ "Double Free in IO SGL io_sgl_free_index=%d,"
+ "value there=%p \n", phba->io_sgl_free_index,
+ phba->io_sgl_hndl_base[phba->io_sgl_free_index]);
+ return;
+ }
+ phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle;
+ phba->io_sgl_hndl_avbl++;
+ if (phba->io_sgl_free_index == (phba->params.ios_per_ctrl - 1))
+ phba->io_sgl_free_index = 0;
+ else
+ phba->io_sgl_free_index++;
+}
+
+/**
+ * alloc_wrb_handle - To allocate a wrb handle
+ * @phba: The hba pointer
+ * @cid: The cid to use for allocation
+ * @index: index allocation and wrb index
+ *
+ * This happens under session_lock until submission to chip
+ */
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ int index)
+{
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+ struct wrb_handle *pwrb_handle;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[cid];
+ pwrb_handle = pwrb_context->pwrb_handle_base[index];
+ pwrb_handle->wrb_index = index;
+ pwrb_handle->nxt_wrb_index = index;
+ return pwrb_handle;
+}
+
+/**
+ * free_wrb_handle - To free the wrb handle back to pool
+ * @phba: The hba pointer
+ * @pwrb_context: The context to free from
+ * @pwrb_handle: The wrb_handle to free
+ *
+ * This happens under session_lock until submission to chip
+ */
+static void
+free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
+ struct wrb_handle *pwrb_handle)
+{
+ SE_DEBUG(DBG_LVL_8,
+ "FREE WRB: pwrb_handle=%p free_index=%d=0x%x"
+ "wrb_handles_available=%d \n",
+ pwrb_handle, pwrb_context->free_index,
+ pwrb_context->free_index, pwrb_context->wrb_handles_available);
+}
+
+static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
+{
+ struct sgl_handle *psgl_handle;
+
+ if (phba->eh_sgl_hndl_avbl) {
+ psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index];
+ phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL;
+ SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x \n",
+ phba->eh_sgl_alloc_index, phba->eh_sgl_alloc_index);
+ phba->eh_sgl_hndl_avbl--;
+ if (phba->eh_sgl_alloc_index ==
+ (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl -
+ 1))
+ phba->eh_sgl_alloc_index = 0;
+ else
+ phba->eh_sgl_alloc_index++;
+ } else
+ psgl_handle = NULL;
+ return psgl_handle;
+}
+
+void
+free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
+{
+
+ if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) {
+ /*
+ * this can happen if clean_task is called on a task that
+ * failed in xmit_task or alloc_pdu.
+ */
+ SE_DEBUG(DBG_LVL_8,
+ "Double Free in eh SGL ,eh_sgl_free_index=%d \n",
+ phba->eh_sgl_free_index);
+ return;
+ }
+ phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle;
+ phba->eh_sgl_hndl_avbl++;
+ if (phba->eh_sgl_free_index ==
+ (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - 1))
+ phba->eh_sgl_free_index = 0;
+ else
+ phba->eh_sgl_free_index++;
+}
+
+static void
+be_complete_io(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct be_status_bhs *sts_bhs =
+ (struct be_status_bhs *)io_task->cmd_bhs;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ unsigned int sense_len;
+ unsigned char *sense;
+ u32 resid = 0, exp_cmdsn, max_cmdsn;
+ u8 rsp, status, flags;
+
+ exp_cmdsn = be32_to_cpu(psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK);
+ max_cmdsn = be32_to_cpu((psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ rsp = ((psol->dw[offsetof(struct amap_sol_cqe, i_resp) / 32]
+ & SOL_RESP_MASK) >> 16);
+ status = ((psol->dw[offsetof(struct amap_sol_cqe, i_sts) / 32]
+ & SOL_STS_MASK) >> 8);
+ flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+
+ task->sc->result = (DID_OK << 16) | status;
+ if (rsp != ISCSI_STATUS_CMD_COMPLETED) {
+ task->sc->result = DID_ERROR << 16;
+ goto unmap;
+ }
+
+ /* bidi not initially supported */
+ if (flags & (ISCSI_FLAG_CMD_UNDERFLOW | ISCSI_FLAG_CMD_OVERFLOW)) {
+ resid = (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) /
+ 32] & SOL_RES_CNT_MASK);
+
+ if (!status && (flags & ISCSI_FLAG_CMD_OVERFLOW))
+ task->sc->result = DID_ERROR << 16;
+
+ if (flags & ISCSI_FLAG_CMD_UNDERFLOW) {
+ scsi_set_resid(task->sc, resid);
+ if (!status && (scsi_bufflen(task->sc) - resid <
+ task->sc->underflow))
+ task->sc->result = DID_ERROR << 16;
+ }
+ }
+
+ if (status == SAM_STAT_CHECK_CONDITION) {
+ sense = sts_bhs->sense_info + sizeof(unsigned short);
+ sense_len =
+ cpu_to_be16((unsigned short)(sts_bhs->sense_info[0]));
+ memcpy(task->sc->sense_buffer, sense,
+ min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE));
+ }
+ if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) {
+ if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
+ & SOL_RES_CNT_MASK)
+ conn->rxdata_octets += (psol->
+ dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
+ & SOL_RES_CNT_MASK);
+ }
+unmap:
+ scsi_dma_unmap(io_task->scsi_cmnd);
+ iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn);
+}
+
+static void
+be_complete_logout(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct iscsi_logout_rsp *hdr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+
+ hdr = (struct iscsi_logout_rsp *)task->hdr;
+ hdr->t2wait = 5;
+ hdr->t2retain = 0;
+ hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+ hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
+ 32] & SOL_RESP_MASK);
+ hdr->exp_cmdsn = cpu_to_be32(psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK);
+ hdr->max_cmdsn = be32_to_cpu((psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ hdr->hlength = 0;
+
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+}
+
+static void
+be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct iscsi_tm_rsp *hdr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+
+ hdr = (struct iscsi_tm_rsp *)task->hdr;
+ hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+ hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
+ 32] & SOL_RESP_MASK);
+ hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
+ hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+}
+
+static void
+hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba, struct sol_cqe *psol)
+{
+ struct hwi_wrb_context *pwrb_context;
+ struct wrb_handle *pwrb_handle;
+ struct hwi_controller *phwi_ctrlr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[((psol->
+ dw[offsetof(struct amap_sol_cqe, cid) / 32] &
+ SOL_CID_MASK) >> 6)];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ dw[offsetof(struct amap_sol_cqe, wrb_index) /
+ 32] & SOL_WRB_INDEX_MASK) >> 16)];
+ spin_lock_bh(&session->lock);
+ free_wrb_handle(phba, pwrb_context, pwrb_handle);
+ spin_unlock_bh(&session->lock);
+}
+
+static void
+be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct iscsi_nopin *hdr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+
+ hdr = (struct iscsi_nopin *)task->hdr;
+ hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+ hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
+ hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ hdr->opcode = ISCSI_OP_NOOP_IN;
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+}
+
+static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba, struct sol_cqe *psol)
+{
+ struct hwi_wrb_context *pwrb_context;
+ struct wrb_handle *pwrb_handle;
+ struct iscsi_wrb *pwrb = NULL;
+ struct hwi_controller *phwi_ctrlr;
+ struct iscsi_task *task;
+ struct beiscsi_io_task *io_task;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+
+ pwrb_context = &phwi_ctrlr->
+ wrb_context[((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32]
+ & SOL_CID_MASK) >> 6)];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ dw[offsetof(struct amap_sol_cqe, wrb_index) /
+ 32] & SOL_WRB_INDEX_MASK) >> 16)];
+
+ task = pwrb_handle->pio_handle;
+ io_task = task->dd_data;
+ spin_lock_bh(&session->lock);
+ pwrb = pwrb_handle->pwrb;
+ switch ((pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] &
+ WRB_TYPE_MASK) >> 28) {
+ case HWH_TYPE_IO:
+ case HWH_TYPE_IO_RD:
+ if ((task->hdr->opcode & ISCSI_OPCODE_MASK) ==
+ ISCSI_OP_NOOP_OUT) {
+ be_complete_nopin_resp(beiscsi_conn, task, psol);
+ } else
+ be_complete_io(beiscsi_conn, task, psol);
+ break;
+
+ case HWH_TYPE_LOGOUT:
+ be_complete_logout(beiscsi_conn, task, psol);
+ break;
+
+ case HWH_TYPE_LOGIN:
+ SE_DEBUG(DBG_LVL_1,
+ "\t\t No HWH_TYPE_LOGIN Expected in hwi_complete_cmd"
+ "- Solicited path \n");
+ break;
+
+ case HWH_TYPE_TMF:
+ be_complete_tmf(beiscsi_conn, task, psol);
+ break;
+
+ case HWH_TYPE_NOP:
+ be_complete_nopin_resp(beiscsi_conn, task, psol);
+ break;
+
+ default:
+ shost_printk(KERN_WARNING, phba->shost,
+ "wrb_index 0x%x CID 0x%x\n",
+ ((psol->dw[offsetof(struct amap_iscsi_wrb, type) /
+ 32] & SOL_WRB_INDEX_MASK) >> 16),
+ ((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32]
+ & SOL_CID_MASK) >> 6));
+ break;
+ }
+
+ spin_unlock_bh(&session->lock);
+}
+
+static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context
+ *pasync_ctx, unsigned int is_header,
+ unsigned int host_write_ptr)
+{
+ if (is_header)
+ return &pasync_ctx->async_entry[host_write_ptr].
+ header_busy_list;
+ else
+ return &pasync_ctx->async_entry[host_write_ptr].data_busy_list;
+}
+
+static struct async_pdu_handle *
+hwi_get_async_handle(struct beiscsi_hba *phba,
+ struct beiscsi_conn *beiscsi_conn,
+ struct hwi_async_pdu_context *pasync_ctx,
+ struct i_t_dpdu_cqe *pdpdu_cqe, unsigned int *pcq_index)
+{
+ struct be_bus_address phys_addr;
+ struct list_head *pbusy_list;
+ struct async_pdu_handle *pasync_handle = NULL;
+ int buffer_len = 0;
+ unsigned char buffer_index = -1;
+ unsigned char is_header = 0;
+
+ phys_addr.u.a32.address_lo =
+ pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_lo) / 32] -
+ ((pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32]
+ & PDUCQE_DPL_MASK) >> 16);
+ phys_addr.u.a32.address_hi =
+ pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_hi) / 32];
+
+ phys_addr.u.a64.address =
+ *((unsigned long long *)(&phys_addr.u.a64.address));
+
+ switch (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, code) / 32]
+ & PDUCQE_CODE_MASK) {
+ case UNSOL_HDR_NOTIFY:
+ is_header = 1;
+
+ pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1,
+ (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+ index) / 32] & PDUCQE_INDEX_MASK));
+
+ buffer_len = (unsigned int)(phys_addr.u.a64.address -
+ pasync_ctx->async_header.pa_base.u.a64.address);
+
+ buffer_index = buffer_len /
+ pasync_ctx->async_header.buffer_size;
+
+ break;
+ case UNSOL_DATA_NOTIFY:
+ pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe->
+ dw[offsetof(struct amap_i_t_dpdu_cqe,
+ index) / 32] & PDUCQE_INDEX_MASK));
+ buffer_len = (unsigned long)(phys_addr.u.a64.address -
+ pasync_ctx->async_data.pa_base.u.
+ a64.address);
+ buffer_index = buffer_len / pasync_ctx->async_data.buffer_size;
+ break;
+ default:
+ pbusy_list = NULL;
+ shost_printk(KERN_WARNING, phba->shost,
+ "Unexpected code=%d \n",
+ pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+ code) / 32] & PDUCQE_CODE_MASK);
+ return NULL;
+ }
+
+ WARN_ON(!(buffer_index <= pasync_ctx->async_data.num_entries));
+ WARN_ON(list_empty(pbusy_list));
+ list_for_each_entry(pasync_handle, pbusy_list, link) {
+ WARN_ON(pasync_handle->consumed);
+ if (pasync_handle->index == buffer_index)
+ break;
+ }
+
+ WARN_ON(!pasync_handle);
+
+ pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid;
+ pasync_handle->is_header = is_header;
+ pasync_handle->buffer_len = ((pdpdu_cqe->
+ dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32]
+ & PDUCQE_DPL_MASK) >> 16);
+
+ *pcq_index = (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+ index) / 32] & PDUCQE_INDEX_MASK);
+ return pasync_handle;
+}
+
+static unsigned int
+hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx,
+ unsigned int is_header, unsigned int cq_index)
+{
+ struct list_head *pbusy_list;
+ struct async_pdu_handle *pasync_handle;
+ unsigned int num_entries, writables = 0;
+ unsigned int *pep_read_ptr, *pwritables;
+
+
+ if (is_header) {
+ pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr;
+ pwritables = &pasync_ctx->async_header.writables;
+ num_entries = pasync_ctx->async_header.num_entries;
+ } else {
+ pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr;
+ pwritables = &pasync_ctx->async_data.writables;
+ num_entries = pasync_ctx->async_data.num_entries;
+ }
+
+ while ((*pep_read_ptr) != cq_index) {
+ (*pep_read_ptr)++;
+ *pep_read_ptr = (*pep_read_ptr) % num_entries;
+
+ pbusy_list = hwi_get_async_busy_list(pasync_ctx, is_header,
+ *pep_read_ptr);
+ if (writables == 0)
+ WARN_ON(list_empty(pbusy_list));
+
+ if (!list_empty(pbusy_list)) {
+ pasync_handle = list_entry(pbusy_list->next,
+ struct async_pdu_handle,
+ link);
+ WARN_ON(!pasync_handle);
+ pasync_handle->consumed = 1;
+ }
+
+ writables++;
+ }
+
+ if (!writables) {
+ SE_DEBUG(DBG_LVL_1,
+ "Duplicate notification received - index 0x%x!!\n",
+ cq_index);
+ WARN_ON(1);
+ }
+
+ *pwritables = *pwritables + writables;
+ return 0;
+}
+
+static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba,
+ unsigned int cri)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle, *tmp_handle;
+ struct list_head *plist;
+ unsigned int i = 0;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ plist = &pasync_ctx->async_entry[cri].wait_queue.list;
+
+ list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) {
+ list_del(&pasync_handle->link);
+
+ if (i == 0) {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_header.free_list);
+ pasync_ctx->async_header.free_entries++;
+ i++;
+ } else {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_data.free_list);
+ pasync_ctx->async_data.free_entries++;
+ i++;
+ }
+ }
+
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list);
+ pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0;
+ pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
+ return 0;
+}
+
+static struct phys_addr *
+hwi_get_ring_address(struct hwi_async_pdu_context *pasync_ctx,
+ unsigned int is_header, unsigned int host_write_ptr)
+{
+ struct phys_addr *pasync_sge = NULL;
+
+ if (is_header)
+ pasync_sge = pasync_ctx->async_header.ring_base;
+ else
+ pasync_sge = pasync_ctx->async_data.ring_base;
+
+ return pasync_sge + host_write_ptr;
+}
+
+static void hwi_post_async_buffers(struct beiscsi_hba *phba,
+ unsigned int is_header)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle;
+ struct list_head *pfree_link, *pbusy_list;
+ struct phys_addr *pasync_sge;
+ unsigned int ring_id, num_entries;
+ unsigned int host_write_num;
+ unsigned int writables;
+ unsigned int i = 0;
+ u32 doorbell = 0;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ if (is_header) {
+ num_entries = pasync_ctx->async_header.num_entries;
+ writables = min(pasync_ctx->async_header.writables,
+ pasync_ctx->async_header.free_entries);
+ pfree_link = pasync_ctx->async_header.free_list.next;
+ host_write_num = pasync_ctx->async_header.host_write_ptr;
+ ring_id = phwi_ctrlr->default_pdu_hdr.id;
+ } else {
+ num_entries = pasync_ctx->async_data.num_entries;
+ writables = min(pasync_ctx->async_data.writables,
+ pasync_ctx->async_data.free_entries);
+ pfree_link = pasync_ctx->async_data.free_list.next;
+ host_write_num = pasync_ctx->async_data.host_write_ptr;
+ ring_id = phwi_ctrlr->default_pdu_data.id;
+ }
+
+ writables = (writables / 8) * 8;
+ if (writables) {
+ for (i = 0; i < writables; i++) {
+ pbusy_list =
+ hwi_get_async_busy_list(pasync_ctx, is_header,
+ host_write_num);
+ pasync_handle =
+ list_entry(pfree_link, struct async_pdu_handle,
+ link);
+ WARN_ON(!pasync_handle);
+ pasync_handle->consumed = 0;
+
+ pfree_link = pfree_link->next;
+
+ pasync_sge = hwi_get_ring_address(pasync_ctx,
+ is_header, host_write_num);
+
+ pasync_sge->hi = pasync_handle->pa.u.a32.address_lo;
+ pasync_sge->lo = pasync_handle->pa.u.a32.address_hi;
+
+ list_move(&pasync_handle->link, pbusy_list);
+
+ host_write_num++;
+ host_write_num = host_write_num % num_entries;
+ }
+
+ if (is_header) {
+ pasync_ctx->async_header.host_write_ptr =
+ host_write_num;
+ pasync_ctx->async_header.free_entries -= writables;
+ pasync_ctx->async_header.writables -= writables;
+ pasync_ctx->async_header.busy_entries += writables;
+ } else {
+ pasync_ctx->async_data.host_write_ptr = host_write_num;
+ pasync_ctx->async_data.free_entries -= writables;
+ pasync_ctx->async_data.writables -= writables;
+ pasync_ctx->async_data.busy_entries += writables;
+ }
+
+ doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK;
+ doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT;
+ doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT;
+ doorbell |= (writables & DB_DEF_PDU_CQPROC_MASK)
+ << DB_DEF_PDU_CQPROC_SHIFT;
+
+ iowrite32(doorbell, phba->db_va + DB_RXULP0_OFFSET);
+ }
+}
+
+static void hwi_flush_default_pdu_buffer(struct beiscsi_hba *phba,
+ struct beiscsi_conn *beiscsi_conn,
+ struct i_t_dpdu_cqe *pdpdu_cqe)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle = NULL;
+ unsigned int cq_index = -1;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx,
+ pdpdu_cqe, &cq_index);
+ BUG_ON(pasync_handle->is_header != 0);
+ if (pasync_handle->consumed == 0)
+ hwi_update_async_writables(pasync_ctx, pasync_handle->is_header,
+ cq_index);
+
+ hwi_free_async_msg(phba, pasync_handle->cri);
+ hwi_post_async_buffers(phba, pasync_handle->is_header);
+}
+
+static unsigned int
+hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ struct hwi_async_pdu_context *pasync_ctx, unsigned short cri)
+{
+ struct list_head *plist;
+ struct async_pdu_handle *pasync_handle;
+ void *phdr = NULL;
+ unsigned int hdr_len = 0, buf_len = 0;
+ unsigned int status, index = 0, offset = 0;
+ void *pfirst_buffer = NULL;
+ unsigned int num_buf = 0;
+
+ plist = &pasync_ctx->async_entry[cri].wait_queue.list;
+
+ list_for_each_entry(pasync_handle, plist, link) {
+ if (index == 0) {
+ phdr = pasync_handle->pbuffer;
+ hdr_len = pasync_handle->buffer_len;
+ } else {
+ buf_len = pasync_handle->buffer_len;
+ if (!num_buf) {
+ pfirst_buffer = pasync_handle->pbuffer;
+ num_buf++;
+ }
+ memcpy(pfirst_buffer + offset,
+ pasync_handle->pbuffer, buf_len);
+ offset = buf_len;
+ }
+ index++;
+ }
+
+ status = beiscsi_process_async_pdu(beiscsi_conn, phba,
+ beiscsi_conn->beiscsi_conn_cid,
+ phdr, hdr_len, pfirst_buffer,
+ buf_len);
+
+ if (status == 0)
+ hwi_free_async_msg(phba, cri);
+ return 0;
+}
+
+static unsigned int
+hwi_gather_async_pdu(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ struct async_pdu_handle *pasync_handle)
+{
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct hwi_controller *phwi_ctrlr;
+ unsigned int bytes_needed = 0, status = 0;
+ unsigned short cri = pasync_handle->cri;
+ struct pdu_base *ppdu;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ list_del(&pasync_handle->link);
+ if (pasync_handle->is_header) {
+ pasync_ctx->async_header.busy_entries--;
+ if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) {
+ hwi_free_async_msg(phba, cri);
+ BUG();
+ }
+
+ pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
+ pasync_ctx->async_entry[cri].wait_queue.hdr_received = 1;
+ pasync_ctx->async_entry[cri].wait_queue.hdr_len =
+ (unsigned short)pasync_handle->buffer_len;
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_entry[cri].wait_queue.list);
+
+ ppdu = pasync_handle->pbuffer;
+ bytes_needed = ((((ppdu->dw[offsetof(struct amap_pdu_base,
+ data_len_hi) / 32] & PDUBASE_DATALENHI_MASK) << 8) &
+ 0xFFFF0000) | ((be16_to_cpu((ppdu->
+ dw[offsetof(struct amap_pdu_base, data_len_lo) / 32]
+ & PDUBASE_DATALENLO_MASK) >> 16)) & 0x0000FFFF));
+
+ if (status == 0) {
+ pasync_ctx->async_entry[cri].wait_queue.bytes_needed =
+ bytes_needed;
+
+ if (bytes_needed == 0)
+ status = hwi_fwd_async_msg(beiscsi_conn, phba,
+ pasync_ctx, cri);
+ }
+ } else {
+ pasync_ctx->async_data.busy_entries--;
+ if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_entry[cri].wait_queue.
+ list);
+ pasync_ctx->async_entry[cri].wait_queue.
+ bytes_received +=
+ (unsigned short)pasync_handle->buffer_len;
+
+ if (pasync_ctx->async_entry[cri].wait_queue.
+ bytes_received >=
+ pasync_ctx->async_entry[cri].wait_queue.
+ bytes_needed)
+ status = hwi_fwd_async_msg(beiscsi_conn, phba,
+ pasync_ctx, cri);
+ }
+ }
+ return status;
+}
+
+static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ struct i_t_dpdu_cqe *pdpdu_cqe)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle = NULL;
+ unsigned int cq_index = -1;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+ pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx,
+ pdpdu_cqe, &cq_index);
+
+ if (pasync_handle->consumed == 0)
+ hwi_update_async_writables(pasync_ctx, pasync_handle->is_header,
+ cq_index);
+ hwi_gather_async_pdu(beiscsi_conn, phba, pasync_handle);
+ hwi_post_async_buffers(phba, pasync_handle->is_header);
+}
+
+static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_queue_info *cq;
+ struct sol_cqe *sol;
+ struct dmsg_cqe *dmsg;
+ unsigned int num_processed = 0;
+ unsigned int tot_nump = 0;
+ struct beiscsi_conn *beiscsi_conn;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ cq = &phwi_context->be_cq;
+ sol = queue_tail_node(cq);
+
+ while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] &
+ CQE_VALID_MASK) {
+ be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
+
+ beiscsi_conn = phba->conn_table[(u32) (sol->
+ dw[offsetof(struct amap_sol_cqe, cid) / 32] &
+ SOL_CID_MASK) >> 6];
+
+ if (!beiscsi_conn || !beiscsi_conn->ep) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Connection table empty for cid = %d\n",
+ (u32)(sol->dw[offsetof(struct amap_sol_cqe,
+ cid) / 32] & SOL_CID_MASK) >> 6);
+ return 0;
+ }
+
+ if (num_processed >= 32) {
+ hwi_ring_cq_db(phba, phwi_context->be_cq.id,
+ num_processed, 0, 0);
+ tot_nump += num_processed;
+ num_processed = 0;
+ }
+
+ switch ((u32) sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK) {
+ case SOL_CMD_COMPLETE:
+ hwi_complete_cmd(beiscsi_conn, phba, sol);
+ break;
+ case DRIVERMSG_NOTIFY:
+ SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY \n");
+ dmsg = (struct dmsg_cqe *)sol;
+ hwi_complete_drvr_msgs(beiscsi_conn, phba, sol);
+ break;
+ case UNSOL_HDR_NOTIFY:
+ case UNSOL_DATA_NOTIFY:
+ SE_DEBUG(DBG_LVL_8, "Received UNSOL_HDR/DATA_NOTIFY\n");
+ hwi_process_default_pdu_ring(beiscsi_conn, phba,
+ (struct i_t_dpdu_cqe *)sol);
+ break;
+ case CXN_INVALIDATE_INDEX_NOTIFY:
+ case CMD_INVALIDATED_NOTIFY:
+ case CXN_INVALIDATE_NOTIFY:
+ SE_DEBUG(DBG_LVL_1,
+ "Ignoring CQ Error notification for cmd/cxn"
+ "invalidate\n");
+ break;
+ case SOL_CMD_KILLED_DATA_DIGEST_ERR:
+ case CMD_KILLED_INVALID_STATSN_RCVD:
+ case CMD_KILLED_INVALID_R2T_RCVD:
+ case CMD_CXN_KILLED_LUN_INVALID:
+ case CMD_CXN_KILLED_ICD_INVALID:
+ case CMD_CXN_KILLED_ITT_INVALID:
+ case CMD_CXN_KILLED_SEQ_OUTOFORDER:
+ case CMD_CXN_KILLED_INVALID_DATASN_RCVD:
+ SE_DEBUG(DBG_LVL_1,
+ "CQ Error notification for cmd.. "
+ "code %d cid 0x%x\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ (sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & SOL_CID_MASK));
+ break;
+ case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
+ SE_DEBUG(DBG_LVL_1,
+ "Digest error on def pdu ring, dropping..\n");
+ hwi_flush_default_pdu_buffer(phba, beiscsi_conn,
+ (struct i_t_dpdu_cqe *) sol);
+ break;
+ case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL:
+ case CXN_KILLED_BURST_LEN_MISMATCH:
+ case CXN_KILLED_AHS_RCVD:
+ case CXN_KILLED_HDR_DIGEST_ERR:
+ case CXN_KILLED_UNKNOWN_HDR:
+ case CXN_KILLED_STALE_ITT_TTT_RCVD:
+ case CXN_KILLED_INVALID_ITT_TTT_RCVD:
+ case CXN_KILLED_TIMED_OUT:
+ case CXN_KILLED_FIN_RCVD:
+ case CXN_KILLED_BAD_UNSOL_PDU_RCVD:
+ case CXN_KILLED_BAD_WRB_INDEX_ERROR:
+ case CXN_KILLED_OVER_RUN_RESIDUAL:
+ case CXN_KILLED_UNDER_RUN_RESIDUAL:
+ case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN:
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, resetting CID "
+ "0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK);
+ iscsi_conn_failure(beiscsi_conn->conn,
+ ISCSI_ERR_CONN_FAILED);
+ break;
+ case CXN_KILLED_RST_SENT:
+ case CXN_KILLED_RST_RCVD:
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset received/sent "
+ "on CID 0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK);
+ iscsi_conn_failure(beiscsi_conn->conn,
+ ISCSI_ERR_CONN_FAILED);
+ break;
+ default:
+ SE_DEBUG(DBG_LVL_1, "CQ Error Invalid code= %d "
+ "received on CID 0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK);
+ break;
+ }
+
+ AMAP_SET_BITS(struct amap_sol_cqe, valid, sol, 0);
+ queue_tail_inc(cq);
+ sol = queue_tail_node(cq);
+ num_processed++;
+ }
+
+ if (num_processed > 0) {
+ tot_nump += num_processed;
+ hwi_ring_cq_db(phba, phwi_context->be_cq.id, num_processed,
+ 1, 0);
+ }
+ return tot_nump;
+}
+
+static void beiscsi_process_all_cqs(struct work_struct *work)
+{
+ unsigned long flags;
+ struct beiscsi_hba *phba =
+ container_of(work, struct beiscsi_hba, work_cqs);
+
+ if (phba->todo_mcc_cq) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_mcc_cq = 0;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ SE_DEBUG(DBG_LVL_1, "MCC Interrupt Not expected \n");
+ }
+
+ if (phba->todo_cq) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_cq = 0;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ beiscsi_process_cq(phba);
+ }
+}
+
+static int be_iopoll(struct blk_iopoll *iop, int budget)
+{
+ static unsigned int ret;
+ struct beiscsi_hba *phba;
+
+ phba = container_of(iop, struct beiscsi_hba, iopoll);
+
+ ret = beiscsi_process_cq(phba);
+ if (ret < budget) {
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ blk_iopoll_complete(iop);
+ hwi_ring_eq_db(phba, phwi_context->be_eq.q.id, 0,
+ 0, 1, 1);
+ }
+ return ret;
+}
+
+static void
+hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
+ unsigned int num_sg, struct beiscsi_io_task *io_task)
+{
+ struct iscsi_sge *psgl;
+ unsigned short sg_len, index;
+ unsigned int sge_len = 0;
+ unsigned long long addr;
+ struct scatterlist *l_sg;
+ unsigned int offset;
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb,
+ io_task->bhs_pa.u.a32.address_lo);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb,
+ io_task->bhs_pa.u.a32.address_hi);
+
+ l_sg = sg;
+ for (index = 0; (index < num_sg) && (index < 2); index++, sg_next(sg)) {
+ if (index == 0) {
+ sg_len = sg_dma_len(sg);
+ addr = (u64) sg_dma_address(sg);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
+ sg_len);
+ sge_len = sg_len;
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
+ 1);
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
+ 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset,
+ pwrb, sge_len);
+ sg_len = sg_dma_len(sg);
+ addr = (u64) sg_dma_address(sg);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb,
+ sg_len);
+ }
+ }
+ psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag;
+ memset(psgl, 0, sizeof(*psgl) * BE2_SGE);
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len - 2);
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ io_task->bhs_pa.u.a32.address_hi);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ io_task->bhs_pa.u.a32.address_lo);
+
+ if (num_sg == 2)
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 1);
+ sg = l_sg;
+ psgl++;
+ psgl++;
+ offset = 0;
+ for (index = 0; index < num_sg; index++, sg_next(sg), psgl++) {
+ sg_len = sg_dma_len(sg);
+ addr = (u64) sg_dma_address(sg);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, sg_len);
+ AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, offset);
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0);
+ offset += sg_len;
+ }
+ psgl--;
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
+}
+
+static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
+{
+ struct iscsi_sge *psgl;
+ unsigned long long addr;
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct beiscsi_conn *beiscsi_conn = io_task->conn;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+
+ io_task->bhs_len = sizeof(struct be_nonio_bhs) - 2;
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb,
+ io_task->bhs_pa.u.a32.address_lo);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb,
+ io_task->bhs_pa.u.a32.address_hi);
+
+ if (task->data) {
+ if (task->data_count) {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
+ addr = (u64) pci_map_single(phba->pcidev,
+ task->data,
+ task->data_count, 1);
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
+ addr = 0;
+ }
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
+ task->data_count);
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 1);
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
+ addr = 0;
+ }
+
+ psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag;
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len);
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ io_task->bhs_pa.u.a32.address_hi);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ io_task->bhs_pa.u.a32.address_lo);
+ if (task->data) {
+ psgl++;
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, rsvd0, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0);
+
+ psgl++;
+ if (task->data) {
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ (addr >> 32));
+ }
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106);
+ }
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
+}
+
+static void beiscsi_find_mem_req(struct beiscsi_hba *phba)
+{
+ unsigned int num_cq_pages, num_eq_pages, num_async_pdu_buf_pages;
+ unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn;
+ unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages;
+
+ num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \
+ sizeof(struct sol_cqe));
+ num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \
+ sizeof(struct be_eq_entry));
+ num_async_pdu_buf_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ phba->params.defpdu_hdr_sz);
+ num_async_pdu_buf_sgl_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ sizeof(struct phys_addr));
+ num_async_pdu_data_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ phba->params.defpdu_data_sz);
+ num_async_pdu_data_sgl_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ sizeof(struct phys_addr));
+
+ phba->params.hwi_ws_sz = sizeof(struct hwi_controller);
+
+ phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 *
+ BE_ISCSI_PDU_HEADER_SIZE;
+ phba->mem_req[HWI_MEM_ADDN_CONTEXT] =
+ sizeof(struct hwi_context_memory);
+
+ phba->mem_req[HWI_MEM_CQ] = num_cq_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_EQ] = num_eq_pages * PAGE_SIZE;
+
+ phba->mem_req[HWI_MEM_WRB] = sizeof(struct iscsi_wrb)
+ * (phba->params.wrbs_per_cxn)
+ * phba->params.cxns_per_ctrl;
+ wrb_sz_per_cxn = sizeof(struct wrb_handle) *
+ (phba->params.wrbs_per_cxn);
+ phba->mem_req[HWI_MEM_WRBH] = roundup_pow_of_two((wrb_sz_per_cxn) *
+ phba->params.cxns_per_ctrl);
+
+ phba->mem_req[HWI_MEM_SGLH] = sizeof(struct sgl_handle) *
+ phba->params.icds_per_ctrl;
+ phba->mem_req[HWI_MEM_SGE] = sizeof(struct iscsi_sge) *
+ phba->params.num_sge_per_io * phba->params.icds_per_ctrl;
+
+ phba->mem_req[HWI_MEM_ASYNC_HEADER_BUF] =
+ num_async_pdu_buf_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_DATA_BUF] =
+ num_async_pdu_data_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_HEADER_RING] =
+ num_async_pdu_buf_sgl_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_DATA_RING] =
+ num_async_pdu_data_sgl_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_HEADER_HANDLE] =
+ phba->params.asyncpdus_per_ctrl *
+ sizeof(struct async_pdu_handle);
+ phba->mem_req[HWI_MEM_ASYNC_DATA_HANDLE] =
+ phba->params.asyncpdus_per_ctrl *
+ sizeof(struct async_pdu_handle);
+ phba->mem_req[HWI_MEM_ASYNC_PDU_CONTEXT] =
+ sizeof(struct hwi_async_pdu_context) +
+ (phba->params.cxns_per_ctrl * sizeof(struct hwi_async_entry));
+}
+
+static int beiscsi_alloc_mem(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr;
+ dma_addr_t bus_add;
+ struct mem_array *mem_arr, *mem_arr_orig;
+ unsigned int i, j, alloc_size, curr_alloc_size;
+
+ phba->phwi_ctrlr = kmalloc(phba->params.hwi_ws_sz, GFP_KERNEL);
+ if (!phba->phwi_ctrlr)
+ return -ENOMEM;
+
+ phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr),
+ GFP_KERNEL);
+ if (!phba->init_mem) {
+ kfree(phba->phwi_ctrlr);
+ return -ENOMEM;
+ }
+
+ mem_arr_orig = kmalloc(sizeof(*mem_arr_orig) * BEISCSI_MAX_FRAGS_INIT,
+ GFP_KERNEL);
+ if (!mem_arr_orig) {
+ kfree(phba->init_mem);
+ kfree(phba->phwi_ctrlr);
+ return -ENOMEM;
+ }
+
+ mem_descr = phba->init_mem;
+ for (i = 0; i < SE_MEM_MAX; i++) {
+ j = 0;
+ mem_arr = mem_arr_orig;
+ alloc_size = phba->mem_req[i];
+ memset(mem_arr, 0, sizeof(struct mem_array) *
+ BEISCSI_MAX_FRAGS_INIT);
+ curr_alloc_size = min(be_max_phys_size * 1024, alloc_size);
+ do {
+ mem_arr->virtual_address = pci_alloc_consistent(
+ phba->pcidev,
+ curr_alloc_size,
+ &bus_add);
+ if (!mem_arr->virtual_address) {
+ if (curr_alloc_size <= BE_MIN_MEM_SIZE)
+ goto free_mem;
+ if (curr_alloc_size -
+ rounddown_pow_of_two(curr_alloc_size))
+ curr_alloc_size = rounddown_pow_of_two
+ (curr_alloc_size);
+ else
+ curr_alloc_size = curr_alloc_size / 2;
+ } else {
+ mem_arr->bus_address.u.
+ a64.address = (__u64) bus_add;
+ mem_arr->size = curr_alloc_size;
+ alloc_size -= curr_alloc_size;
+ curr_alloc_size = min(be_max_phys_size *
+ 1024, alloc_size);
+ j++;
+ mem_arr++;
+ }
+ } while (alloc_size);
+ mem_descr->num_elements = j;
+ mem_descr->size_in_bytes = phba->mem_req[i];
+ mem_descr->mem_array = kmalloc(sizeof(*mem_arr) * j,
+ GFP_KERNEL);
+ if (!mem_descr->mem_array)
+ goto free_mem;
+
+ memcpy(mem_descr->mem_array, mem_arr_orig,
+ sizeof(struct mem_array) * j);
+ mem_descr++;
+ }
+ kfree(mem_arr_orig);
+ return 0;
+free_mem:
+ mem_descr->num_elements = j;
+ while ((i) || (j)) {
+ for (j = mem_descr->num_elements; j > 0; j--) {
+ pci_free_consistent(phba->pcidev,
+ mem_descr->mem_array[j - 1].size,
+ mem_descr->mem_array[j - 1].
+ virtual_address,
+ mem_descr->mem_array[j - 1].
+ bus_address.u.a64.address);
+ }
+ if (i) {
+ i--;
+ kfree(mem_descr->mem_array);
+ mem_descr--;
+ }
+ }
+ kfree(mem_arr_orig);
+ kfree(phba->init_mem);
+ kfree(phba->phwi_ctrlr);
+ return -ENOMEM;
+}
+
+static int beiscsi_get_memory(struct beiscsi_hba *phba)
+{
+ beiscsi_find_mem_req(phba);
+ return beiscsi_alloc_mem(phba);
+}
+
+static void iscsi_init_global_templates(struct beiscsi_hba *phba)
+{
+ struct pdu_data_out *pdata_out;
+ struct pdu_nop_out *pnop_out;
+ struct be_mem_descriptor *mem_descr;
+
+ mem_descr = phba->init_mem;
+ mem_descr += ISCSI_MEM_GLOBAL_HEADER;
+ pdata_out =
+ (struct pdu_data_out *)mem_descr->mem_array[0].virtual_address;
+ memset(pdata_out, 0, BE_ISCSI_PDU_HEADER_SIZE);
+
+ AMAP_SET_BITS(struct amap_pdu_data_out, opcode, pdata_out,
+ IIOC_SCSI_DATA);
+
+ pnop_out =
+ (struct pdu_nop_out *)((unsigned char *)mem_descr->mem_array[0].
+ virtual_address + BE_ISCSI_PDU_HEADER_SIZE);
+
+ memset(pnop_out, 0, BE_ISCSI_PDU_HEADER_SIZE);
+ AMAP_SET_BITS(struct amap_pdu_nop_out, ttt, pnop_out, 0xFFFFFFFF);
+ AMAP_SET_BITS(struct amap_pdu_nop_out, f_bit, pnop_out, 1);
+ AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0);
+}
+
+static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb;
+ struct wrb_handle *pwrb_handle;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_wrb_context *pwrb_context;
+ struct iscsi_wrb *pwrb;
+ unsigned int num_cxn_wrbh;
+ unsigned int num_cxn_wrb, j, idx, index;
+
+ mem_descr_wrbh = phba->init_mem;
+ mem_descr_wrbh += HWI_MEM_WRBH;
+
+ mem_descr_wrb = phba->init_mem;
+ mem_descr_wrb += HWI_MEM_WRB;
+
+ idx = 0;
+ pwrb_handle = mem_descr_wrbh->mem_array[idx].virtual_address;
+ num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) /
+ ((sizeof(struct wrb_handle)) *
+ phba->params.wrbs_per_cxn));
+ phwi_ctrlr = phba->phwi_ctrlr;
+
+ for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
+ pwrb_context = &phwi_ctrlr->wrb_context[index];
+ SE_DEBUG(DBG_LVL_8, "cid=%d pwrb_context=%p \n", index,
+ pwrb_context);
+ pwrb_context->pwrb_handle_base =
+ kzalloc(sizeof(struct wrb_handle *) *
+ phba->params.wrbs_per_cxn, GFP_KERNEL);
+ pwrb_context->pwrb_handle_basestd =
+ kzalloc(sizeof(struct wrb_handle *) *
+ phba->params.wrbs_per_cxn, GFP_KERNEL);
+ if (num_cxn_wrbh) {
+ pwrb_context->alloc_index = 0;
+ pwrb_context->wrb_handles_available = 0;
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_context->pwrb_handle_base[j] = pwrb_handle;
+ pwrb_context->pwrb_handle_basestd[j] =
+ pwrb_handle;
+ pwrb_context->wrb_handles_available++;
+ pwrb_handle++;
+ }
+ pwrb_context->free_index = 0;
+ num_cxn_wrbh--;
+ } else {
+ idx++;
+ pwrb_handle =
+ mem_descr_wrbh->mem_array[idx].virtual_address;
+ num_cxn_wrbh =
+ ((mem_descr_wrbh->mem_array[idx].size) /
+ ((sizeof(struct wrb_handle)) *
+ phba->params.wrbs_per_cxn));
+ pwrb_context->alloc_index = 0;
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_context->pwrb_handle_base[j] = pwrb_handle;
+ pwrb_context->pwrb_handle_basestd[j] =
+ pwrb_handle;
+ pwrb_context->wrb_handles_available++;
+ pwrb_handle++;
+ }
+ pwrb_context->free_index = 0;
+ num_cxn_wrbh--;
+ }
+ }
+ idx = 0;
+ pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
+ num_cxn_wrb =
+ ((mem_descr_wrb->mem_array[idx].size) / (sizeof(struct iscsi_wrb)) *
+ phba->params.wrbs_per_cxn);
+
+ for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) {
+ pwrb_context = &phwi_ctrlr->wrb_context[index];
+ if (num_cxn_wrb) {
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_handle = pwrb_context->pwrb_handle_base[j];
+ pwrb_handle->pwrb = pwrb;
+ pwrb++;
+ }
+ num_cxn_wrb--;
+ } else {
+ idx++;
+ pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
+ num_cxn_wrb = ((mem_descr_wrb->mem_array[idx].size) /
+ (sizeof(struct iscsi_wrb)) *
+ phba->params.wrbs_per_cxn);
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_handle = pwrb_context->pwrb_handle_base[j];
+ pwrb_handle->pwrb = pwrb;
+ pwrb++;
+ }
+ num_cxn_wrb--;
+ }
+ }
+}
+
+static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hba_parameters *p = &phba->params;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_header_h, *pasync_data_h;
+ unsigned int index;
+ struct be_mem_descriptor *mem_descr;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_PDU_CONTEXT;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_ctrlr->phwi_ctxt->pasync_ctx = (struct hwi_async_pdu_context *)
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx;
+ memset(pasync_ctx, 0, sizeof(*pasync_ctx));
+
+ pasync_ctx->async_header.num_entries = p->asyncpdus_per_ctrl;
+ pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz;
+ pasync_ctx->async_data.buffer_size = p->defpdu_data_sz;
+ pasync_ctx->async_data.num_entries = p->asyncpdus_per_ctrl;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_BUF;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_BUF"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_header.va_base =
+ mem_descr->mem_array[0].virtual_address;
+
+ pasync_ctx->async_header.pa_base.u.a64.address =
+ mem_descr->mem_array[0].bus_address.u.a64.address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_RING;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_RING"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+ pasync_ctx->async_header.ring_base =
+ mem_descr->mem_array[0].virtual_address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_HANDLE;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_HANDLE"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_header.handle_base =
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx->async_header.writables = 0;
+ INIT_LIST_HEAD(&pasync_ctx->async_header.free_list);
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_BUF;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+ pasync_ctx->async_data.va_base =
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx->async_data.pa_base.u.a64.address =
+ mem_descr->mem_array[0].bus_address.u.a64.address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_RING;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_RING"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_data.ring_base =
+ mem_descr->mem_array[0].virtual_address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_HANDLE;
+ if (!mem_descr->mem_array[0].virtual_address)
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_data.handle_base =
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx->async_data.writables = 0;
+ INIT_LIST_HEAD(&pasync_ctx->async_data.free_list);
+
+ pasync_header_h =
+ (struct async_pdu_handle *)pasync_ctx->async_header.handle_base;
+ pasync_data_h =
+ (struct async_pdu_handle *)pasync_ctx->async_data.handle_base;
+
+ for (index = 0; index < p->asyncpdus_per_ctrl; index++) {
+ pasync_header_h->cri = -1;
+ pasync_header_h->index = (char)index;
+ INIT_LIST_HEAD(&pasync_header_h->link);
+ pasync_header_h->pbuffer =
+ (void *)((unsigned long)
+ (pasync_ctx->async_header.va_base) +
+ (p->defpdu_hdr_sz * index));
+
+ pasync_header_h->pa.u.a64.address =
+ pasync_ctx->async_header.pa_base.u.a64.address +
+ (p->defpdu_hdr_sz * index);
+
+ list_add_tail(&pasync_header_h->link,
+ &pasync_ctx->async_header.free_list);
+ pasync_header_h++;
+ pasync_ctx->async_header.free_entries++;
+ pasync_ctx->async_header.writables++;
+
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[index].wait_queue.list);
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[index].
+ header_busy_list);
+ pasync_data_h->cri = -1;
+ pasync_data_h->index = (char)index;
+ INIT_LIST_HEAD(&pasync_data_h->link);
+ pasync_data_h->pbuffer =
+ (void *)((unsigned long)
+ (pasync_ctx->async_data.va_base) +
+ (p->defpdu_data_sz * index));
+
+ pasync_data_h->pa.u.a64.address =
+ pasync_ctx->async_data.pa_base.u.a64.address +
+ (p->defpdu_data_sz * index);
+
+ list_add_tail(&pasync_data_h->link,
+ &pasync_ctx->async_data.free_list);
+ pasync_data_h++;
+ pasync_ctx->async_data.free_entries++;
+ pasync_ctx->async_data.writables++;
+
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[index].data_busy_list);
+ }
+
+ pasync_ctx->async_header.host_write_ptr = 0;
+ pasync_ctx->async_header.ep_read_ptr = -1;
+ pasync_ctx->async_data.host_write_ptr = 0;
+ pasync_ctx->async_data.ep_read_ptr = -1;
+}
+
+static int
+be_sgl_create_contiguous(void *virtual_address,
+ u64 physical_address, u32 length,
+ struct be_dma_mem *sgl)
+{
+ WARN_ON(!virtual_address);
+ WARN_ON(!physical_address);
+ WARN_ON(!length > 0);
+ WARN_ON(!sgl);
+
+ sgl->va = virtual_address;
+ sgl->dma = physical_address;
+ sgl->size = length;
+
+ return 0;
+}
+
+static void be_sgl_destroy_contiguous(struct be_dma_mem *sgl)
+{
+ memset(sgl, 0, sizeof(*sgl));
+}
+
+static void
+hwi_build_be_sgl_arr(struct beiscsi_hba *phba,
+ struct mem_array *pmem, struct be_dma_mem *sgl)
+{
+ if (sgl->va)
+ be_sgl_destroy_contiguous(sgl);
+
+ be_sgl_create_contiguous(pmem->virtual_address,
+ pmem->bus_address.u.a64.address,
+ pmem->size, sgl);
+}
+
+static void
+hwi_build_be_sgl_by_offset(struct beiscsi_hba *phba,
+ struct mem_array *pmem, struct be_dma_mem *sgl)
+{
+ if (sgl->va)
+ be_sgl_destroy_contiguous(sgl);
+
+ be_sgl_create_contiguous((unsigned char *)pmem->virtual_address,
+ pmem->bus_address.u.a64.address,
+ pmem->size, sgl);
+}
+
+static int be_fill_queue(struct be_queue_info *q,
+ u16 len, u16 entry_size, void *vaddress)
+{
+ struct be_dma_mem *mem = &q->dma_mem;
+
+ memset(q, 0, sizeof(*q));
+ q->len = len;
+ q->entry_size = entry_size;
+ mem->size = len * entry_size;
+ mem->va = vaddress;
+ if (!mem->va)
+ return -ENOMEM;
+ memset(mem->va, 0, mem->size);
+ return 0;
+}
+
+static int beiscsi_create_eq(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *eq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *eq_vaddress;
+
+ idx = 0;
+ eq = &phwi_context->be_eq.q;
+ mem = &eq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_EQ;
+ eq_vaddress = mem_descr->mem_array[idx].virtual_address;
+
+ ret = be_fill_queue(eq, phba->params.num_eq_entries,
+ sizeof(struct be_eq_entry), eq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for EQ \n");
+ return ret;
+ }
+
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+
+ ret = beiscsi_cmd_eq_create(&phba->ctrl, eq,
+ phwi_context->be_eq.cur_eqd);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_cmd_eq_create"
+ "Failedfor EQ \n");
+ return ret;
+ }
+ SE_DEBUG(DBG_LVL_8, "eq id is %d\n", phwi_context->be_eq.q.id);
+ return 0;
+}
+
+static int beiscsi_create_cq(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *cq, *eq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *cq_vaddress;
+
+ idx = 0;
+ cq = &phwi_context->be_cq;
+ eq = &phwi_context->be_eq.q;
+ mem = &cq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_CQ;
+ cq_vaddress = mem_descr->mem_array[idx].virtual_address;
+ ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2,
+ sizeof(struct sol_cqe), cq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for ISCSI CQ \n");
+ return ret;
+ }
+
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false, false, 0);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_cmd_eq_create Failed for ISCSI CQ \n");
+ return ret;
+ }
+ SE_DEBUG(DBG_LVL_8, "iscsi cq id is %d\n", phwi_context->be_cq.id);
+ SE_DEBUG(DBG_LVL_8, "ISCSI CQ CREATED\n");
+ return 0;
+}
+
+static int
+beiscsi_create_def_hdr(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context,
+ struct hwi_controller *phwi_ctrlr,
+ unsigned int def_pdu_ring_sz)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *dq, *cq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *dq_vaddress;
+
+ idx = 0;
+ dq = &phwi_context->be_def_hdrq;
+ cq = &phwi_context->be_cq;
+ mem = &dq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_RING;
+ dq_vaddress = mem_descr->mem_array[idx].virtual_address;
+ ret = be_fill_queue(dq, mem_descr->mem_array[0].size /
+ sizeof(struct phys_addr),
+ sizeof(struct phys_addr), dq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for DEF PDU HDR\n");
+ return ret;
+ }
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq,
+ def_pdu_ring_sz,
+ phba->params.defpdu_hdr_sz);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_cmd_create_default_pdu_queue Failed DEFHDR\n");
+ return ret;
+ }
+ phwi_ctrlr->default_pdu_hdr.id = phwi_context->be_def_hdrq.id;
+ SE_DEBUG(DBG_LVL_8, "iscsi def pdu id is %d\n",
+ phwi_context->be_def_hdrq.id);
+ hwi_post_async_buffers(phba, 1);
+ return 0;
+}
+
+static int
+beiscsi_create_def_data(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context,
+ struct hwi_controller *phwi_ctrlr,
+ unsigned int def_pdu_ring_sz)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *dataq, *cq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *dq_vaddress;
+
+ idx = 0;
+ dataq = &phwi_context->be_def_dataq;
+ cq = &phwi_context->be_cq;
+ mem = &dataq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_RING;
+ dq_vaddress = mem_descr->mem_array[idx].virtual_address;
+ ret = be_fill_queue(dataq, mem_descr->mem_array[0].size /
+ sizeof(struct phys_addr),
+ sizeof(struct phys_addr), dq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for DEF PDU DATA\n");
+ return ret;
+ }
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq,
+ def_pdu_ring_sz,
+ phba->params.defpdu_data_sz);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_cmd_create_default_pdu_queue Failed"
+ " for DEF PDU DATA\n");
+ return ret;
+ }
+ phwi_ctrlr->default_pdu_data.id = phwi_context->be_def_dataq.id;
+ SE_DEBUG(DBG_LVL_8, "iscsi def data id is %d\n",
+ phwi_context->be_def_dataq.id);
+ hwi_post_async_buffers(phba, 0);
+ SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED \n");
+ return 0;
+}
+
+static int
+beiscsi_post_pages(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr;
+ struct mem_array *pm_arr;
+ unsigned int page_offset, i;
+ struct be_dma_mem sgl;
+ int status;
+
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_SGE;
+ pm_arr = mem_descr->mem_array;
+
+ page_offset = (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io *
+ phba->fw_config.iscsi_icd_start) / PAGE_SIZE;
+ for (i = 0; i < mem_descr->num_elements; i++) {
+ hwi_build_be_sgl_arr(phba, pm_arr, &sgl);
+ status = be_cmd_iscsi_post_sgl_pages(&phba->ctrl, &sgl,
+ page_offset,
+ (pm_arr->size / PAGE_SIZE));
+ page_offset += pm_arr->size / PAGE_SIZE;
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "post sgl failed.\n");
+ return status;
+ }
+ pm_arr++;
+ }
+ SE_DEBUG(DBG_LVL_8, "POSTED PAGES \n");
+ return 0;
+}
+
+static int
+beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context,
+ struct hwi_controller *phwi_ctrlr)
+{
+ unsigned int wrb_mem_index, offset, size, num_wrb_rings;
+ u64 pa_addr_lo;
+ unsigned int idx, num, i;
+ struct mem_array *pwrb_arr;
+ void *wrb_vaddr;
+ struct be_dma_mem sgl;
+ struct be_mem_descriptor *mem_descr;
+ int status;
+
+ idx = 0;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_WRB;
+ pwrb_arr = kmalloc(sizeof(*pwrb_arr) * phba->params.cxns_per_ctrl,
+ GFP_KERNEL);
+ if (!pwrb_arr) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Memory alloc failed in create wrb ring.\n");
+ return -ENOMEM;
+ }
+ wrb_vaddr = mem_descr->mem_array[idx].virtual_address;
+ pa_addr_lo = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ num_wrb_rings = mem_descr->mem_array[idx].size /
+ (phba->params.wrbs_per_cxn * sizeof(struct iscsi_wrb));
+
+ for (num = 0; num < phba->params.cxns_per_ctrl; num++) {
+ if (num_wrb_rings) {
+ pwrb_arr[num].virtual_address = wrb_vaddr;
+ pwrb_arr[num].bus_address.u.a64.address = pa_addr_lo;
+ pwrb_arr[num].size = phba->params.wrbs_per_cxn *
+ sizeof(struct iscsi_wrb);
+ wrb_vaddr += pwrb_arr[num].size;
+ pa_addr_lo += pwrb_arr[num].size;
+ num_wrb_rings--;
+ } else {
+ idx++;
+ wrb_vaddr = mem_descr->mem_array[idx].virtual_address;
+ pa_addr_lo = mem_descr->mem_array[idx].\
+ bus_address.u.a64.address;
+ num_wrb_rings = mem_descr->mem_array[idx].size /
+ (phba->params.wrbs_per_cxn *
+ sizeof(struct iscsi_wrb));
+ pwrb_arr[num].virtual_address = wrb_vaddr;
+ pwrb_arr[num].bus_address.u.a64.address\
+ = pa_addr_lo;
+ pwrb_arr[num].size = phba->params.wrbs_per_cxn *
+ sizeof(struct iscsi_wrb);
+ wrb_vaddr += pwrb_arr[num].size;
+ pa_addr_lo += pwrb_arr[num].size;
+ num_wrb_rings--;
+ }
+ }
+ for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+ wrb_mem_index = 0;
+ offset = 0;
+ size = 0;
+
+ hwi_build_be_sgl_by_offset(phba, &pwrb_arr[i], &sgl);
+ status = be_cmd_wrbq_create(&phba->ctrl, &sgl,
+ &phwi_context->be_wrbq[i]);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "wrbq create failed.");
+ return status;
+ }
+ phwi_ctrlr->wrb_context[i].cid = phwi_context->be_wrbq[i].id;
+ }
+ kfree(pwrb_arr);
+ return 0;
+}
+
+static void free_wrb_handles(struct beiscsi_hba *phba)
+{
+ unsigned int index;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_wrb_context *pwrb_context;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
+ pwrb_context = &phwi_ctrlr->wrb_context[index];
+ kfree(pwrb_context->pwrb_handle_base);
+ kfree(pwrb_context->pwrb_handle_basestd);
+ }
+}
+
+static void hwi_cleanup(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *q;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ int i;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+ q = &phwi_context->be_wrbq[i];
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ);
+ }
+
+ free_wrb_handles(phba);
+
+ q = &phwi_context->be_def_hdrq;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+ q = &phwi_context->be_def_dataq;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+ beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
+
+ q = &phwi_context->be_cq;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+
+ q = &phwi_context->be_eq.q;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
+}
+
+static int hwi_init_port(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ unsigned int def_pdu_ring_sz;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ int status;
+
+ def_pdu_ring_sz =
+ phba->params.asyncpdus_per_ctrl * sizeof(struct phys_addr);
+ phwi_ctrlr = phba->phwi_ctrlr;
+
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ phwi_context->be_eq.max_eqd = 0;
+ phwi_context->be_eq.min_eqd = 0;
+ phwi_context->be_eq.cur_eqd = 64;
+ phwi_context->be_eq.enable_aic = false;
+ be_cmd_fw_initialize(&phba->ctrl);
+ status = beiscsi_create_eq(phba, phwi_context);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost, "EQ not created \n");
+ goto error;
+ }
+
+ status = mgmt_check_supported_fw(ctrl);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Unsupported fw version \n");
+ goto error;
+ }
+
+ status = mgmt_get_fw_config(ctrl, phba);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Error getting fw config\n");
+ goto error;
+ }
+
+ status = beiscsi_create_cq(phba, phwi_context);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost, "CQ not created\n");
+ goto error;
+ }
+
+ status = beiscsi_create_def_hdr(phba, phwi_context, phwi_ctrlr,
+ def_pdu_ring_sz);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Default Header not created\n");
+ goto error;
+ }
+
+ status = beiscsi_create_def_data(phba, phwi_context,
+ phwi_ctrlr, def_pdu_ring_sz);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Default Data not created\n");
+ goto error;
+ }
+
+ status = beiscsi_post_pages(phba);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost, "Post SGL Pages Failed\n");
+ goto error;
+ }
+
+ status = beiscsi_create_wrb_rings(phba, phwi_context, phwi_ctrlr);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "WRB Rings not created\n");
+ goto error;
+ }
+
+ SE_DEBUG(DBG_LVL_8, "hwi_init_port success\n");
+ return 0;
+
+error:
+ shost_printk(KERN_ERR, phba->shost, "hwi_init_port failed");
+ hwi_cleanup(phba);
+ return -ENOMEM;
+}
+
+
+static int hwi_init_controller(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) {
+ phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba->
+ init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address;
+ SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p \n",
+ phwi_ctrlr->phwi_ctxt);
+ } else {
+ shost_printk(KERN_ERR, phba->shost,
+ "HWI_MEM_ADDN_CONTEXT is more than one element."
+ "Failing to load\n");
+ return -ENOMEM;
+ }
+
+ iscsi_init_global_templates(phba);
+ beiscsi_init_wrb_handle(phba);
+ hwi_init_async_pdu_ctx(phba);
+ if (hwi_init_port(phba) != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "hwi_init_controller failed\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void beiscsi_free_mem(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr;
+ int i, j;
+
+ mem_descr = phba->init_mem;
+ i = 0;
+ j = 0;
+ for (i = 0; i < SE_MEM_MAX; i++) {
+ for (j = mem_descr->num_elements; j > 0; j--) {
+ pci_free_consistent(phba->pcidev,
+ mem_descr->mem_array[j - 1].size,
+ mem_descr->mem_array[j - 1].virtual_address,
+ mem_descr->mem_array[j - 1].bus_address.
+ u.a64.address);
+ }
+ kfree(mem_descr->mem_array);
+ mem_descr++;
+ }
+ kfree(phba->init_mem);
+ kfree(phba->phwi_ctrlr);
+}
+
+static int beiscsi_init_controller(struct beiscsi_hba *phba)
+{
+ int ret = -ENOMEM;
+
+ ret = beiscsi_get_memory(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe -"
+ "Failed in beiscsi_alloc_memory \n");
+ return ret;
+ }
+
+ ret = hwi_init_controller(phba);
+ if (ret)
+ goto free_init;
+ SE_DEBUG(DBG_LVL_8, "Return success from beiscsi_init_controller");
+ return 0;
+
+free_init:
+ beiscsi_free_mem(phba);
+ return -ENOMEM;
+}
+
+static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg;
+ struct sgl_handle *psgl_handle;
+ struct iscsi_sge *pfrag;
+ unsigned int arr_index, i, idx;
+
+ phba->io_sgl_hndl_avbl = 0;
+ phba->eh_sgl_hndl_avbl = 0;
+ mem_descr_sglh = phba->init_mem;
+ mem_descr_sglh += HWI_MEM_SGLH;
+ if (1 == mem_descr_sglh->num_elements) {
+ phba->io_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) *
+ phba->params.ios_per_ctrl,
+ GFP_KERNEL);
+ if (!phba->io_sgl_hndl_base) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ return -ENOMEM;
+ }
+ phba->eh_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) *
+ (phba->params.icds_per_ctrl -
+ phba->params.ios_per_ctrl),
+ GFP_KERNEL);
+ if (!phba->eh_sgl_hndl_base) {
+ kfree(phba->io_sgl_hndl_base);
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ return -ENOMEM;
+ }
+ } else {
+ shost_printk(KERN_ERR, phba->shost,
+ "HWI_MEM_SGLH is more than one element."
+ "Failing to load\n");
+ return -ENOMEM;
+ }
+
+ arr_index = 0;
+ idx = 0;
+ while (idx < mem_descr_sglh->num_elements) {
+ psgl_handle = mem_descr_sglh->mem_array[idx].virtual_address;
+
+ for (i = 0; i < (mem_descr_sglh->mem_array[idx].size /
+ sizeof(struct sgl_handle)); i++) {
+ if (arr_index < phba->params.ios_per_ctrl) {
+ phba->io_sgl_hndl_base[arr_index] = psgl_handle;
+ phba->io_sgl_hndl_avbl++;
+ arr_index++;
+ } else {
+ phba->eh_sgl_hndl_base[arr_index -
+ phba->params.ios_per_ctrl] =
+ psgl_handle;
+ arr_index++;
+ phba->eh_sgl_hndl_avbl++;
+ }
+ psgl_handle++;
+ }
+ idx++;
+ }
+ SE_DEBUG(DBG_LVL_8,
+ "phba->io_sgl_hndl_avbl=%d"
+ "phba->eh_sgl_hndl_avbl=%d \n",
+ phba->io_sgl_hndl_avbl,
+ phba->eh_sgl_hndl_avbl);
+ mem_descr_sg = phba->init_mem;
+ mem_descr_sg += HWI_MEM_SGE;
+ SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d \n",
+ mem_descr_sg->num_elements);
+ arr_index = 0;
+ idx = 0;
+ while (idx < mem_descr_sg->num_elements) {
+ pfrag = mem_descr_sg->mem_array[idx].virtual_address;
+
+ for (i = 0;
+ i < (mem_descr_sg->mem_array[idx].size) /
+ (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io);
+ i++) {
+ if (arr_index < phba->params.ios_per_ctrl)
+ psgl_handle = phba->io_sgl_hndl_base[arr_index];
+ else
+ psgl_handle = phba->eh_sgl_hndl_base[arr_index -
+ phba->params.ios_per_ctrl];
+ psgl_handle->pfrag = pfrag;
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, pfrag, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0);
+ pfrag += phba->params.num_sge_per_io;
+ psgl_handle->sgl_index =
+ phba->fw_config.iscsi_cid_start + arr_index++;
+ }
+ idx++;
+ }
+ phba->io_sgl_free_index = 0;
+ phba->io_sgl_alloc_index = 0;
+ phba->eh_sgl_free_index = 0;
+ phba->eh_sgl_alloc_index = 0;
+ return 0;
+}
+
+static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
+{
+ int i, new_cid;
+
+ phba->cid_array = kmalloc(sizeof(void *) * phba->params.cxns_per_ctrl,
+ GFP_KERNEL);
+ if (!phba->cid_array) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Failed to allocate memory in "
+ "hba_setup_cid_tbls\n");
+ return -ENOMEM;
+ }
+ phba->ep_array = kmalloc(sizeof(struct iscsi_endpoint *) *
+ phba->params.cxns_per_ctrl * 2, GFP_KERNEL);
+ if (!phba->ep_array) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Failed to allocate memory in "
+ "hba_setup_cid_tbls \n");
+ kfree(phba->cid_array);
+ return -ENOMEM;
+ }
+ new_cid = phba->fw_config.iscsi_icd_start;
+ for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+ phba->cid_array[i] = new_cid;
+ new_cid += 2;
+ }
+ phba->avlbl_cids = phba->params.cxns_per_ctrl;
+ return 0;
+}
+
+static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_queue_info *eq;
+ u8 __iomem *addr;
+ u32 reg;
+ u32 enabled;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+
+ eq = &phwi_context->be_eq.q;
+ addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg +
+ PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
+ reg = ioread32(addr);
+ SE_DEBUG(DBG_LVL_8, "reg =x%08x \n", reg);
+
+ enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ if (!enabled) {
+ reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr);
+ iowrite32(reg, addr);
+ SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+
+ hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "In hwi_enable_intr, Not Enabled \n");
+ return true;
+}
+
+static void hwi_disable_intr(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
+ u32 reg = ioread32(addr);
+
+ u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ if (enabled) {
+ reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ iowrite32(reg, addr);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "In hwi_disable_intr, Already Disabled \n");
+}
+
+static int beiscsi_init_port(struct beiscsi_hba *phba)
+{
+ int ret;
+
+ ret = beiscsi_init_controller(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_dev_probe - Failed in"
+ "beiscsi_init_controller \n");
+ return ret;
+ }
+ ret = beiscsi_init_sgl_handle(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_dev_probe - Failed in"
+ "beiscsi_init_sgl_handle \n");
+ goto do_cleanup_ctrlr;
+ }
+
+ if (hba_setup_cid_tbls(phba)) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Failed in hba_setup_cid_tbls\n");
+ kfree(phba->io_sgl_hndl_base);
+ kfree(phba->eh_sgl_hndl_base);
+ goto do_cleanup_ctrlr;
+ }
+
+ return ret;
+
+do_cleanup_ctrlr:
+ hwi_cleanup(phba);
+ return ret;
+}
+
+static void hwi_purge_eq(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_queue_info *eq;
+ struct be_eq_entry *eqe = NULL;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ eq = &phwi_context->be_eq.q;
+ eqe = queue_tail_node(eq);
+
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ }
+}
+
+static void beiscsi_clean_port(struct beiscsi_hba *phba)
+{
+ unsigned char mgmt_status;
+
+ mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0);
+ if (mgmt_status)
+ shost_printk(KERN_WARNING, phba->shost,
+ "mgmt_epfw_cleanup FAILED \n");
+ hwi_cleanup(phba);
+ hwi_purge_eq(phba);
+ kfree(phba->io_sgl_hndl_base);
+ kfree(phba->eh_sgl_hndl_base);
+ kfree(phba->cid_array);
+ kfree(phba->ep_array);
+}
+
+void
+beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_offload_params *params)
+{
+ struct wrb_handle *pwrb_handle;
+ struct iscsi_target_context_update_wrb *pwrb = NULL;
+ struct be_mem_descriptor *mem_descr;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ u32 doorbell = 0;
+
+ /*
+ * We can always use 0 here because it is reserved by libiscsi for
+ * login/startup related tasks.
+ */
+ pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 0);
+ pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb;
+ memset(pwrb, 0, sizeof(*pwrb));
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ max_burst_length, pwrb, params->dw[offsetof
+ (struct amap_beiscsi_offload_params,
+ max_burst_length) / 32]);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ max_send_data_segment_length, pwrb,
+ params->dw[offsetof(struct amap_beiscsi_offload_params,
+ max_send_data_segment_length) / 32]);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ first_burst_length,
+ pwrb,
+ params->dw[offsetof(struct amap_beiscsi_offload_params,
+ first_burst_length) / 32]);
+
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ erl) / 32] & OFFLD_PARAMS_ERL));
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ dde) / 32] & OFFLD_PARAMS_DDE) >> 2);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ hde) / 32] & OFFLD_PARAMS_HDE) >> 3);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ imd) / 32] & OFFLD_PARAMS_IMD) >> 5);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn,
+ pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ exp_statsn) / 32] + 1));
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb,
+ 0x7);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx,
+ pwrb, pwrb_handle->wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb,
+ pwrb, pwrb_handle->nxt_wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ session_state, pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack,
+ pwrb, 1);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq,
+ pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb,
+ 0);
+
+ mem_descr = phba->init_mem;
+ mem_descr += ISCSI_MEM_GLOBAL_HEADER;
+
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ pad_buffer_addr_hi, pwrb,
+ mem_descr->mem_array[0].bus_address.u.a32.address_hi);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ pad_buffer_addr_lo, pwrb,
+ mem_descr->mem_array[0].bus_address.u.a32.address_lo);
+
+ be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb));
+
+ doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
+ doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) <<
+ DB_DEF_PDU_WRB_INDEX_SHIFT;
+ doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
+
+ iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
+}
+
+static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt,
+ int *index, int *age)
+{
+ *index = be32_to_cpu(itt) >> 16;
+ if (age)
+ *age = conn->session->age;
+}
+
+/**
+ * beiscsi_alloc_pdu - allocates pdu and related resources
+ * @task: libiscsi task
+ * @opcode: opcode of pdu for task
+ *
+ * This is called with the session lock held. It will allocate
+ * the wrb and sgl if needed for the command. And it will prep
+ * the pdu's itt. beiscsi_parse_pdu will later translate
+ * the pdu itt to the libiscsi task itt.
+ */
+static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+ itt_t itt;
+ struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
+ dma_addr_t paddr;
+
+ io_task->cmd_bhs = pci_pool_alloc(beiscsi_sess->bhs_pool,
+ GFP_KERNEL, &paddr);
+
+ if (!io_task->cmd_bhs)
+ return -ENOMEM;
+
+ io_task->bhs_pa.u.a64.address = paddr;
+ io_task->pwrb_handle = alloc_wrb_handle(phba,
+ beiscsi_conn->beiscsi_conn_cid,
+ task->itt);
+ io_task->pwrb_handle->pio_handle = task;
+ io_task->conn = beiscsi_conn;
+
+ task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
+ task->hdr_max = sizeof(struct be_cmd_bhs);
+
+ if (task->sc) {
+ spin_lock(&phba->io_sgl_lock);
+ io_task->psgl_handle = alloc_io_sgl_handle(phba);
+ spin_unlock(&phba->io_sgl_lock);
+ if (!io_task->psgl_handle)
+ goto free_hndls;
+
+ } else {
+ io_task->scsi_cmnd = NULL;
+ if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
+ if (!beiscsi_conn->login_in_progress) {
+ spin_lock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = (struct sgl_handle *)
+ alloc_mgmt_sgl_handle(phba);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ if (!io_task->psgl_handle)
+ goto free_hndls;
+
+ beiscsi_conn->login_in_progress = 1;
+ beiscsi_conn->plogin_sgl_handle =
+ io_task->psgl_handle;
+ } else {
+ io_task->psgl_handle =
+ beiscsi_conn->plogin_sgl_handle;
+ }
+ } else {
+ spin_lock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = alloc_mgmt_sgl_handle(phba);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ if (!io_task->psgl_handle)
+ goto free_hndls;
+ }
+ }
+ itt = (itt_t) cpu_to_be32(((unsigned int)task->itt << 16) |
+ (unsigned int)(io_task->psgl_handle->sgl_index));
+ io_task->cmd_bhs->iscsi_hdr.itt = itt;
+ return 0;
+
+free_hndls:
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid];
+ free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
+ io_task->bhs_pa.u.a64.address);
+ SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed \n");
+ return -ENOMEM;
+}
+
+static void beiscsi_cleanup_task(struct iscsi_task *task)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid];
+ if (io_task->pwrb_handle) {
+ free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ }
+
+ if (io_task->cmd_bhs) {
+ pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
+ io_task->bhs_pa.u.a64.address);
+ }
+
+ if (task->sc) {
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->io_sgl_lock);
+ free_io_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->io_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ } else {
+ if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN)
+ return;
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->mgmt_sgl_lock);
+ free_mgmt_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ }
+}
+
+static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
+ unsigned int num_sg, unsigned int xferlen,
+ unsigned int writedir)
+{
+
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_wrb *pwrb = NULL;
+ unsigned int doorbell = 0;
+
+ pwrb = io_task->pwrb_handle->pwrb;
+ io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0;
+ io_task->bhs_len = sizeof(struct be_cmd_bhs);
+
+ if (writedir) {
+ SE_DEBUG(DBG_LVL_4, " WRITE Command \t");
+ memset(&io_task->cmd_bhs->iscsi_data_pdu, 0, 48);
+ AMAP_SET_BITS(struct amap_pdu_data_out, itt,
+ &io_task->cmd_bhs->iscsi_data_pdu,
+ (unsigned int)io_task->cmd_bhs->iscsi_hdr.itt);
+ AMAP_SET_BITS(struct amap_pdu_data_out, opcode,
+ &io_task->cmd_bhs->iscsi_data_pdu,
+ ISCSI_OPCODE_SCSI_DATA_OUT);
+ AMAP_SET_BITS(struct amap_pdu_data_out, final_bit,
+ &io_task->cmd_bhs->iscsi_data_pdu, 1);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
+ } else {
+ SE_DEBUG(DBG_LVL_4, "READ Command \t");
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
+ }
+ memcpy(&io_task->cmd_bhs->iscsi_data_pdu.
+ dw[offsetof(struct amap_pdu_data_out, lun) / 32],
+ io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun));
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb,
+ cpu_to_be16((unsigned short)io_task->cmd_bhs->iscsi_hdr.
+ lun[0]));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
+ io_task->pwrb_handle->wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
+ be32_to_cpu(task->cmdsn));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
+ io_task->psgl_handle->sgl_index);
+
+ hwi_write_sgl(pwrb, sg, num_sg, io_task);
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
+ io_task->pwrb_handle->nxt_wrb_index);
+ be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
+
+ doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
+ doorbell |= (io_task->pwrb_handle->wrb_index &
+ DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
+ doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
+
+ iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
+ return 0;
+}
+
+static int beiscsi_mtask(struct iscsi_task *task)
+{
+ struct beiscsi_io_task *aborted_io_task, *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_wrb *pwrb = NULL;
+ unsigned int doorbell = 0;
+ struct iscsi_task *aborted_task;
+
+ pwrb = io_task->pwrb_handle->pwrb;
+ AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
+ be32_to_cpu(task->cmdsn));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
+ io_task->pwrb_handle->wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
+ io_task->psgl_handle->sgl_index);
+
+ switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
+ case ISCSI_OP_LOGIN:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, TGT_DM_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_NOOP_OUT:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_TEXT:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_SCSI_TMFUNC:
+ aborted_task = iscsi_itt_to_task(conn,
+ ((struct iscsi_tm *)task->hdr)->rtt);
+ if (!aborted_task)
+ return 0;
+ aborted_io_task = aborted_task->dd_data;
+ if (!aborted_io_task->scsi_cmnd)
+ return 0;
+
+ mgmt_invalidate_icds(phba,
+ aborted_io_task->psgl_handle->sgl_index,
+ beiscsi_conn->beiscsi_conn_cid);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_TMF_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_LOGOUT:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ HWH_TYPE_LOGOUT);
+ hwi_write_buffer(pwrb, task);
+ break;
+
+ default:
+ SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported \n",
+ task->hdr->opcode & ISCSI_OPCODE_MASK);
+ return -EINVAL;
+ }
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb,
+ be32_to_cpu(task->data_count));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
+ io_task->pwrb_handle->nxt_wrb_index);
+ be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
+
+ doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
+ doorbell |= (io_task->pwrb_handle->wrb_index &
+ DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
+ doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
+ iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
+ return 0;
+}
+
+static int beiscsi_task_xmit(struct iscsi_task *task)
+{
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct scsi_cmnd *sc = task->sc;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct scatterlist *sg;
+ int num_sg;
+ unsigned int writedir = 0, xferlen = 0;
+
+ SE_DEBUG(DBG_LVL_4, "\n cid=%d In beiscsi_task_xmit task=%p conn=%p \t"
+ "beiscsi_conn=%p \n", beiscsi_conn->beiscsi_conn_cid,
+ task, conn, beiscsi_conn);
+ if (!sc)
+ return beiscsi_mtask(task);
+
+ io_task->scsi_cmnd = sc;
+ num_sg = scsi_dma_map(sc);
+ if (num_sg < 0) {
+ SE_DEBUG(DBG_LVL_1, " scsi_dma_map Failed\n")
+ return num_sg;
+ }
+ SE_DEBUG(DBG_LVL_4, "xferlen=0x%08x scmd=%p num_sg=%d sernum=%lu\n",
+ (scsi_bufflen(sc)), sc, num_sg, sc->serial_number);
+ xferlen = scsi_bufflen(sc);
+ sg = scsi_sglist(sc);
+ if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ writedir = 1;
+ SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x \n",
+ task->imm_count);
+ } else
+ writedir = 0;
+ return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
+}
+
+static void beiscsi_remove(struct pci_dev *pcidev)
+{
+ struct beiscsi_hba *phba = NULL;
+
+ phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev);
+ if (!phba) {
+ dev_err(&pcidev->dev, "beiscsi_remove called with no phba \n");
+ return;
+ }
+
+ hwi_disable_intr(phba);
+ if (phba->pcidev->irq)
+ free_irq(phba->pcidev->irq, phba);
+ destroy_workqueue(phba->wq);
+ if (blk_iopoll_enabled)
+ blk_iopoll_disable(&phba->iopoll);
+
+ beiscsi_clean_port(phba);
+ beiscsi_free_mem(phba);
+ beiscsi_unmap_pci_function(phba);
+ pci_free_consistent(phba->pcidev,
+ phba->ctrl.mbox_mem_alloced.size,
+ phba->ctrl.mbox_mem_alloced.va,
+ phba->ctrl.mbox_mem_alloced.dma);
+ iscsi_host_remove(phba->shost);
+ pci_dev_put(phba->pcidev);
+ iscsi_host_free(phba->shost);
+}
+
+static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
+ const struct pci_device_id *id)
+{
+ struct beiscsi_hba *phba = NULL;
+ int ret;
+
+ ret = beiscsi_enable_pci(pcidev);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to enable pci device \n");
+ return ret;
+ }
+
+ phba = beiscsi_hba_alloc(pcidev);
+ if (!phba) {
+ dev_err(&pcidev->dev, "beiscsi_dev_probe-"
+ " Failed in beiscsi_hba_alloc \n");
+ goto disable_pci;
+ }
+
+ pci_set_drvdata(pcidev, phba);
+ ret = be_ctrl_init(phba, pcidev);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed in be_ctrl_init\n");
+ goto hba_free;
+ }
+
+ spin_lock_init(&phba->io_sgl_lock);
+ spin_lock_init(&phba->mgmt_sgl_lock);
+ spin_lock_init(&phba->isr_lock);
+ beiscsi_get_params(phba);
+ ret = beiscsi_init_port(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed in beiscsi_init_port\n");
+ goto free_port;
+ }
+
+ snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u",
+ phba->shost->host_no);
+ phba->wq = create_singlethread_workqueue(phba->wq_name);
+ if (!phba->wq) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to allocate work queue\n");
+ goto free_twq;
+ }
+
+ INIT_WORK(&phba->work_cqs, beiscsi_process_all_cqs);
+
+ if (blk_iopoll_enabled) {
+ blk_iopoll_init(&phba->iopoll, be_iopoll_budget, be_iopoll);
+ blk_iopoll_enable(&phba->iopoll);
+ }
+
+ ret = beiscsi_init_irqs(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to beiscsi_init_irqs\n");
+ goto free_blkenbld;
+ }
+ ret = hwi_enable_intr(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to hwi_enable_intr\n");
+ goto free_ctrlr;
+ }
+
+ SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED \n\n\n");
+ return 0;
+
+free_ctrlr:
+ if (phba->pcidev->irq)
+ free_irq(phba->pcidev->irq, phba);
+free_blkenbld:
+ destroy_workqueue(phba->wq);
+ if (blk_iopoll_enabled)
+ blk_iopoll_disable(&phba->iopoll);
+free_twq:
+ beiscsi_clean_port(phba);
+ beiscsi_free_mem(phba);
+free_port:
+ pci_free_consistent(phba->pcidev,
+ phba->ctrl.mbox_mem_alloced.size,
+ phba->ctrl.mbox_mem_alloced.va,
+ phba->ctrl.mbox_mem_alloced.dma);
+ beiscsi_unmap_pci_function(phba);
+hba_free:
+ iscsi_host_remove(phba->shost);
+ pci_dev_put(phba->pcidev);
+ iscsi_host_free(phba->shost);
+disable_pci:
+ pci_disable_device(pcidev);
+ return ret;
+}
+
+struct iscsi_transport beiscsi_iscsi_transport = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .caps = CAP_RECOVERY_L0 | CAP_HDRDGST |
+ CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD,
+ .param_mask = ISCSI_MAX_RECV_DLENGTH |
+ ISCSI_MAX_XMIT_DLENGTH |
+ ISCSI_HDRDGST_EN |
+ ISCSI_DATADGST_EN |
+ ISCSI_INITIAL_R2T_EN |
+ ISCSI_MAX_R2T |
+ ISCSI_IMM_DATA_EN |
+ ISCSI_FIRST_BURST |
+ ISCSI_MAX_BURST |
+ ISCSI_PDU_INORDER_EN |
+ ISCSI_DATASEQ_INORDER_EN |
+ ISCSI_ERL |
+ ISCSI_CONN_PORT |
+ ISCSI_CONN_ADDRESS |
+ ISCSI_EXP_STATSN |
+ ISCSI_PERSISTENT_PORT |
+ ISCSI_PERSISTENT_ADDRESS |
+ ISCSI_TARGET_NAME | ISCSI_TPGT |
+ ISCSI_USERNAME | ISCSI_PASSWORD |
+ ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+ ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+ ISCSI_LU_RESET_TMO |
+ ISCSI_PING_TMO | ISCSI_RECV_TMO |
+ ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
+ .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
+ ISCSI_HOST_INITIATOR_NAME,
+ .create_session = beiscsi_session_create,
+ .destroy_session = beiscsi_session_destroy,
+ .create_conn = beiscsi_conn_create,
+ .bind_conn = beiscsi_conn_bind,
+ .destroy_conn = iscsi_conn_teardown,
+ .set_param = beiscsi_set_param,
+ .get_conn_param = beiscsi_conn_get_param,
+ .get_session_param = iscsi_session_get_param,
+ .get_host_param = beiscsi_get_host_param,
+ .start_conn = beiscsi_conn_start,
+ .stop_conn = beiscsi_conn_stop,
+ .send_pdu = iscsi_conn_send_pdu,
+ .xmit_task = beiscsi_task_xmit,
+ .cleanup_task = beiscsi_cleanup_task,
+ .alloc_pdu = beiscsi_alloc_pdu,
+ .parse_pdu_itt = beiscsi_parse_pdu,
+ .get_stats = beiscsi_conn_get_stats,
+ .ep_connect = beiscsi_ep_connect,
+ .ep_poll = beiscsi_ep_poll,
+ .ep_disconnect = beiscsi_ep_disconnect,
+ .session_recovery_timedout = iscsi_session_recovery_timedout,
+};
+
+static struct pci_driver beiscsi_pci_driver = {
+ .name = DRV_NAME,
+ .probe = beiscsi_dev_probe,
+ .remove = beiscsi_remove,
+ .id_table = beiscsi_pci_id_table
+};
+
+static int __init beiscsi_module_init(void)
+{
+ int ret;
+
+ beiscsi_scsi_transport =
+ iscsi_register_transport(&beiscsi_iscsi_transport);
+ if (!beiscsi_scsi_transport) {
+ SE_DEBUG(DBG_LVL_1,
+ "beiscsi_module_init - Unable to register beiscsi"
+ "transport.\n");
+ ret = -ENOMEM;
+ }
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n",
+ &beiscsi_iscsi_transport);
+
+ ret = pci_register_driver(&beiscsi_pci_driver);
+ if (ret) {
+ SE_DEBUG(DBG_LVL_1,
+ "beiscsi_module_init - Unable to register"
+ "beiscsi pci driver.\n");
+ goto unregister_iscsi_transport;
+ }
+ return 0;
+
+unregister_iscsi_transport:
+ iscsi_unregister_transport(&beiscsi_iscsi_transport);
+ return ret;
+}
+
+static void __exit beiscsi_module_exit(void)
+{
+ pci_unregister_driver(&beiscsi_pci_driver);
+ iscsi_unregister_transport(&beiscsi_iscsi_transport);
+}
+
+module_init(beiscsi_module_init);
+module_exit(beiscsi_module_exit);
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
new file mode 100644
index 000000000000..53c9b70ac7ac
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -0,0 +1,837 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#ifndef _BEISCSI_MAIN_
+#define _BEISCSI_MAIN_
+
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/in.h>
+#include <linux/blk-iopoll.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include "be.h"
+
+
+
+#define DRV_NAME "be2iscsi"
+#define BUILD_STR "2.0.527.0"
+
+#define BE_NAME "ServerEngines BladeEngine2" \
+ "Linux iSCSI Driver version" BUILD_STR
+#define DRV_DESC BE_NAME " " "Driver"
+
+#define BE_VENDOR_ID 0x19A2
+#define BE_DEVICE_ID1 0x212
+#define OC_DEVICE_ID1 0x702
+#define OC_DEVICE_ID2 0x703
+
+#define BE2_MAX_SESSIONS 64
+#define BE2_CMDS_PER_CXN 128
+#define BE2_LOGOUTS BE2_MAX_SESSIONS
+#define BE2_TMFS 16
+#define BE2_NOPOUT_REQ 16
+#define BE2_ASYNCPDUS BE2_MAX_SESSIONS
+#define BE2_MAX_ICDS 2048
+#define BE2_SGE 32
+#define BE2_DEFPDU_HDR_SZ 64
+#define BE2_DEFPDU_DATA_SZ 8192
+#define BE2_IO_DEPTH \
+ (BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ))
+
+#define BEISCSI_SGLIST_ELEMENTS BE2_SGE
+
+#define BEISCSI_MAX_CMNDS 1024 /* Max IO's per Ctrlr sht->can_queue */
+#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */
+#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */
+
+#define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */
+#define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */
+#define BEISCSI_NUM_DEVICES_SUPPORTED 0x01
+#define BEISCSI_MAX_FRAGS_INIT 192
+#define BE_NUM_MSIX_ENTRIES 1
+#define MPU_EP_SEMAPHORE 0xac
+
+#define BE_SENSE_INFO_SIZE 258
+#define BE_ISCSI_PDU_HEADER_SIZE 64
+#define BE_MIN_MEM_SIZE 16384
+
+#define IIOC_SCSI_DATA 0x05 /* Write Operation */
+
+#define DBG_LVL 0x00000001
+#define DBG_LVL_1 0x00000001
+#define DBG_LVL_2 0x00000002
+#define DBG_LVL_3 0x00000004
+#define DBG_LVL_4 0x00000008
+#define DBG_LVL_5 0x00000010
+#define DBG_LVL_6 0x00000020
+#define DBG_LVL_7 0x00000040
+#define DBG_LVL_8 0x00000080
+
+#define SE_DEBUG(debug_mask, fmt, args...) \
+do { \
+ if (debug_mask & DBG_LVL) { \
+ printk(KERN_ERR "(%s():%d):", __func__, __LINE__);\
+ printk(fmt, ##args); \
+ } \
+} while (0);
+
+/**
+ * hardware needs the async PDU buffers to be posted in multiples of 8
+ * So have atleast 8 of them by default
+ */
+
+#define HWI_GET_ASYNC_PDU_CTX(phwi) (phwi->phwi_ctxt->pasync_ctx)
+
+/********* Memory BAR register ************/
+#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
+/**
+ * Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
+ * Disable" may still globally block interrupts in addition to individual
+ * interrupt masks; a mechanism for the device driver to block all interrupts
+ * atomically without having to arbitrate for the PCI Interrupt Disable bit
+ * with the OS.
+ */
+#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
+
+/********* ISR0 Register offset **********/
+#define CEV_ISR0_OFFSET 0xC18
+#define CEV_ISR_SIZE 4
+
+/**
+ * Macros for reading/writing a protection domain or CSR registers
+ * in BladeEngine.
+ */
+
+#define DB_TXULP0_OFFSET 0x40
+#define DB_RXULP0_OFFSET 0xA0
+/********* Event Q door bell *************/
+#define DB_EQ_OFFSET DB_CQ_OFFSET
+#define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */
+/* Clear the interrupt for this eq */
+#define DB_EQ_CLR_SHIFT (9) /* bit 9 */
+/* Must be 1 */
+#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */
+/* Number of event entries processed */
+#define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
+/* Rearm bit */
+#define DB_EQ_REARM_SHIFT (29) /* bit 29 */
+
+/********* Compl Q door bell *************/
+#define DB_CQ_OFFSET 0x120
+#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+/* Number of event entries processed */
+#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
+/* Rearm bit */
+#define DB_CQ_REARM_SHIFT (29) /* bit 29 */
+
+#define GET_HWI_CONTROLLER_WS(pc) (pc->phwi_ctrlr)
+#define HWI_GET_DEF_BUFQ_ID(pc) (((struct hwi_controller *)\
+ (GET_HWI_CONTROLLER_WS(pc)))->default_pdu_data.id)
+#define HWI_GET_DEF_HDRQ_ID(pc) (((struct hwi_controller *)\
+ (GET_HWI_CONTROLLER_WS(pc)))->default_pdu_hdr.id)
+
+#define PAGES_REQUIRED(x) \
+ ((x < PAGE_SIZE) ? 1 : ((x + PAGE_SIZE - 1) / PAGE_SIZE))
+
+enum be_mem_enum {
+ HWI_MEM_ADDN_CONTEXT,
+ HWI_MEM_CQ,
+ HWI_MEM_EQ,
+ HWI_MEM_WRB,
+ HWI_MEM_WRBH,
+ HWI_MEM_SGLH, /* 5 */
+ HWI_MEM_SGE,
+ HWI_MEM_ASYNC_HEADER_BUF,
+ HWI_MEM_ASYNC_DATA_BUF,
+ HWI_MEM_ASYNC_HEADER_RING,
+ HWI_MEM_ASYNC_DATA_RING, /* 10 */
+ HWI_MEM_ASYNC_HEADER_HANDLE,
+ HWI_MEM_ASYNC_DATA_HANDLE,
+ HWI_MEM_ASYNC_PDU_CONTEXT,
+ ISCSI_MEM_GLOBAL_HEADER,
+ SE_MEM_MAX /* 15 */
+};
+
+struct be_bus_address32 {
+ unsigned int address_lo;
+ unsigned int address_hi;
+};
+
+struct be_bus_address64 {
+ unsigned long long address;
+};
+
+struct be_bus_address {
+ union {
+ struct be_bus_address32 a32;
+ struct be_bus_address64 a64;
+ } u;
+};
+
+struct mem_array {
+ struct be_bus_address bus_address; /* Bus address of location */
+ void *virtual_address; /* virtual address to the location */
+ unsigned int size; /* Size required by memory block */
+};
+
+struct be_mem_descriptor {
+ unsigned int index; /* Index of this memory parameter */
+ unsigned int category; /* type indicates cached/non-cached */
+ unsigned int num_elements; /* number of elements in this
+ * descriptor
+ */
+ unsigned int alignment_mask; /* Alignment mask for this block */
+ unsigned int size_in_bytes; /* Size required by memory block */
+ struct mem_array *mem_array;
+};
+
+struct sgl_handle {
+ unsigned int sgl_index;
+ struct iscsi_sge *pfrag;
+};
+
+struct hba_parameters {
+ unsigned int ios_per_ctrl;
+ unsigned int cxns_per_ctrl;
+ unsigned int asyncpdus_per_ctrl;
+ unsigned int icds_per_ctrl;
+ unsigned int num_sge_per_io;
+ unsigned int defpdu_hdr_sz;
+ unsigned int defpdu_data_sz;
+ unsigned int num_cq_entries;
+ unsigned int num_eq_entries;
+ unsigned int wrbs_per_cxn;
+ unsigned int crashmode;
+ unsigned int hba_num;
+
+ unsigned int mgmt_ws_sz;
+ unsigned int hwi_ws_sz;
+
+ unsigned int eto;
+ unsigned int ldto;
+
+ unsigned int dbg_flags;
+ unsigned int num_cxn;
+
+ unsigned int eq_timer;
+ /**
+ * These are calculated from other params. They're here
+ * for debug purposes
+ */
+ unsigned int num_mcc_pages;
+ unsigned int num_mcc_cq_pages;
+ unsigned int num_cq_pages;
+ unsigned int num_eq_pages;
+
+ unsigned int num_async_pdu_buf_pages;
+ unsigned int num_async_pdu_buf_sgl_pages;
+ unsigned int num_async_pdu_buf_cq_pages;
+
+ unsigned int num_async_pdu_hdr_pages;
+ unsigned int num_async_pdu_hdr_sgl_pages;
+ unsigned int num_async_pdu_hdr_cq_pages;
+
+ unsigned int num_sge;
+};
+
+struct beiscsi_hba {
+ struct hba_parameters params;
+ struct hwi_controller *phwi_ctrlr;
+ unsigned int mem_req[SE_MEM_MAX];
+ /* PCI BAR mapped addresses */
+ u8 __iomem *csr_va; /* CSR */
+ u8 __iomem *db_va; /* Door Bell */
+ u8 __iomem *pci_va; /* PCI Config */
+ struct be_bus_address csr_pa; /* CSR */
+ struct be_bus_address db_pa; /* CSR */
+ struct be_bus_address pci_pa; /* CSR */
+ /* PCI representation of our HBA */
+ struct pci_dev *pcidev;
+ unsigned int state;
+ unsigned short asic_revision;
+ struct blk_iopoll iopoll;
+ struct be_mem_descriptor *init_mem;
+
+ unsigned short io_sgl_alloc_index;
+ unsigned short io_sgl_free_index;
+ unsigned short io_sgl_hndl_avbl;
+ struct sgl_handle **io_sgl_hndl_base;
+
+ unsigned short eh_sgl_alloc_index;
+ unsigned short eh_sgl_free_index;
+ unsigned short eh_sgl_hndl_avbl;
+ struct sgl_handle **eh_sgl_hndl_base;
+ spinlock_t io_sgl_lock;
+ spinlock_t mgmt_sgl_lock;
+ spinlock_t isr_lock;
+ unsigned int age;
+ unsigned short avlbl_cids;
+ unsigned short cid_alloc;
+ unsigned short cid_free;
+ struct beiscsi_conn *conn_table[BE2_MAX_SESSIONS * 2];
+ struct list_head hba_queue;
+ unsigned short *cid_array;
+ struct iscsi_endpoint **ep_array;
+ struct Scsi_Host *shost;
+ struct {
+ /**
+ * group together since they are used most frequently
+ * for cid to cri conversion
+ */
+ unsigned int iscsi_cid_start;
+ unsigned int phys_port;
+
+ unsigned int isr_offset;
+ unsigned int iscsi_icd_start;
+ unsigned int iscsi_cid_count;
+ unsigned int iscsi_icd_count;
+ unsigned int pci_function;
+
+ unsigned short cid_alloc;
+ unsigned short cid_free;
+ unsigned short avlbl_cids;
+ spinlock_t cid_lock;
+ } fw_config;
+
+ u8 mac_address[ETH_ALEN];
+ unsigned short todo_cq;
+ unsigned short todo_mcc_cq;
+ char wq_name[20];
+ struct workqueue_struct *wq; /* The actuak work queue */
+ struct work_struct work_cqs; /* The work being queued */
+ struct be_ctrl_info ctrl;
+};
+
+struct beiscsi_session {
+ struct pci_pool *bhs_pool;
+};
+
+/**
+ * struct beiscsi_conn - iscsi connection structure
+ */
+struct beiscsi_conn {
+ struct iscsi_conn *conn;
+ struct beiscsi_hba *phba;
+ u32 exp_statsn;
+ u32 beiscsi_conn_cid;
+ struct beiscsi_endpoint *ep;
+ unsigned short login_in_progress;
+ struct sgl_handle *plogin_sgl_handle;
+ struct beiscsi_session *beiscsi_sess;
+};
+
+/* This structure is used by the chip */
+struct pdu_data_out {
+ u32 dw[12];
+};
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_pdu_data_out {
+ u8 opcode[6]; /* opcode */
+ u8 rsvd0[2]; /* should be 0 */
+ u8 rsvd1[7];
+ u8 final_bit; /* F bit */
+ u8 rsvd2[16];
+ u8 ahs_length[8]; /* no AHS */
+ u8 data_len_hi[8];
+ u8 data_len_lo[16]; /* DataSegmentLength */
+ u8 lun[64];
+ u8 itt[32]; /* ITT; initiator task tag */
+ u8 ttt[32]; /* TTT; valid for R2T or 0xffffffff */
+ u8 rsvd3[32];
+ u8 exp_stat_sn[32];
+ u8 rsvd4[32];
+ u8 data_sn[32];
+ u8 buffer_offset[32];
+ u8 rsvd5[32];
+};
+
+struct be_cmd_bhs {
+ struct iscsi_cmd iscsi_hdr;
+ unsigned char pad1[16];
+ struct pdu_data_out iscsi_data_pdu;
+ unsigned char pad2[BE_SENSE_INFO_SIZE -
+ sizeof(struct pdu_data_out)];
+};
+
+struct beiscsi_io_task {
+ struct wrb_handle *pwrb_handle;
+ struct sgl_handle *psgl_handle;
+ struct beiscsi_conn *conn;
+ struct scsi_cmnd *scsi_cmnd;
+ unsigned int cmd_sn;
+ unsigned int flags;
+ unsigned short cid;
+ unsigned short header_len;
+
+ struct be_cmd_bhs *cmd_bhs;
+ struct be_bus_address bhs_pa;
+ unsigned short bhs_len;
+};
+
+struct be_nonio_bhs {
+ struct iscsi_hdr iscsi_hdr;
+ unsigned char pad1[16];
+ struct pdu_data_out iscsi_data_pdu;
+ unsigned char pad2[BE_SENSE_INFO_SIZE -
+ sizeof(struct pdu_data_out)];
+};
+
+struct be_status_bhs {
+ struct iscsi_cmd iscsi_hdr;
+ unsigned char pad1[16];
+ /**
+ * The plus 2 below is to hold the sense info length that gets
+ * DMA'ed by RxULP
+ */
+ unsigned char sense_info[BE_SENSE_INFO_SIZE];
+};
+
+struct iscsi_sge {
+ u32 dw[4];
+};
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_iscsi_sge {
+ u8 addr_hi[32];
+ u8 addr_lo[32];
+ u8 sge_offset[22]; /* DWORD 2 */
+ u8 rsvd0[9]; /* DWORD 2 */
+ u8 last_sge; /* DWORD 2 */
+ u8 len[17]; /* DWORD 3 */
+ u8 rsvd1[15]; /* DWORD 3 */
+};
+
+struct beiscsi_offload_params {
+ u32 dw[5];
+};
+
+#define OFFLD_PARAMS_ERL 0x00000003
+#define OFFLD_PARAMS_DDE 0x00000004
+#define OFFLD_PARAMS_HDE 0x00000008
+#define OFFLD_PARAMS_IR2T 0x00000010
+#define OFFLD_PARAMS_IMD 0x00000020
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_beiscsi_offload_params {
+ u8 max_burst_length[32];
+ u8 max_send_data_segment_length[32];
+ u8 first_burst_length[32];
+ u8 erl[2];
+ u8 dde[1];
+ u8 hde[1];
+ u8 ir2t[1];
+ u8 imd[1];
+ u8 pad[26];
+ u8 exp_statsn[32];
+};
+
+/* void hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba, struct sol_cqe *psol);*/
+
+struct async_pdu_handle {
+ struct list_head link;
+ struct be_bus_address pa;
+ void *pbuffer;
+ unsigned int consumed;
+ unsigned char index;
+ unsigned char is_header;
+ unsigned short cri;
+ unsigned long buffer_len;
+};
+
+struct hwi_async_entry {
+ struct {
+ unsigned char hdr_received;
+ unsigned char hdr_len;
+ unsigned short bytes_received;
+ unsigned int bytes_needed;
+ struct list_head list;
+ } wait_queue;
+
+ struct list_head header_busy_list;
+ struct list_head data_busy_list;
+};
+
+#define BE_MIN_ASYNC_ENTRIES 128
+
+struct hwi_async_pdu_context {
+ struct {
+ struct be_bus_address pa_base;
+ void *va_base;
+ void *ring_base;
+ struct async_pdu_handle *handle_base;
+
+ unsigned int host_write_ptr;
+ unsigned int ep_read_ptr;
+ unsigned int writables;
+
+ unsigned int free_entries;
+ unsigned int busy_entries;
+ unsigned int buffer_size;
+ unsigned int num_entries;
+
+ struct list_head free_list;
+ } async_header;
+
+ struct {
+ struct be_bus_address pa_base;
+ void *va_base;
+ void *ring_base;
+ struct async_pdu_handle *handle_base;
+
+ unsigned int host_write_ptr;
+ unsigned int ep_read_ptr;
+ unsigned int writables;
+
+ unsigned int free_entries;
+ unsigned int busy_entries;
+ unsigned int buffer_size;
+ struct list_head free_list;
+ unsigned int num_entries;
+ } async_data;
+
+ /**
+ * This is a varying size list! Do not add anything
+ * after this entry!!
+ */
+ struct hwi_async_entry async_entry[BE_MIN_ASYNC_ENTRIES];
+};
+
+#define PDUCQE_CODE_MASK 0x0000003F
+#define PDUCQE_DPL_MASK 0xFFFF0000
+#define PDUCQE_INDEX_MASK 0x0000FFFF
+
+struct i_t_dpdu_cqe {
+ u32 dw[4];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_i_t_dpdu_cqe {
+ u8 db_addr_hi[32];
+ u8 db_addr_lo[32];
+ u8 code[6];
+ u8 cid[10];
+ u8 dpl[16];
+ u8 index[16];
+ u8 num_cons[10];
+ u8 rsvd0[4];
+ u8 final;
+ u8 valid;
+} __packed;
+
+#define CQE_VALID_MASK 0x80000000
+#define CQE_CODE_MASK 0x0000003F
+#define CQE_CID_MASK 0x0000FFC0
+
+#define EQE_VALID_MASK 0x00000001
+#define EQE_MAJORCODE_MASK 0x0000000E
+#define EQE_RESID_MASK 0xFFFF0000
+
+struct be_eq_entry {
+ u32 dw[1];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_eq_entry {
+ u8 valid; /* DWORD 0 */
+ u8 major_code[3]; /* DWORD 0 */
+ u8 minor_code[12]; /* DWORD 0 */
+ u8 resource_id[16]; /* DWORD 0 */
+
+} __packed;
+
+struct cq_db {
+ u32 dw[1];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_cq_db {
+ u8 qid[10];
+ u8 event[1];
+ u8 rsvd0[5];
+ u8 num_popped[13];
+ u8 rearm[1];
+ u8 rsvd1[2];
+} __packed;
+
+void beiscsi_process_eq(struct beiscsi_hba *phba);
+
+
+struct iscsi_wrb {
+ u32 dw[16];
+} __packed;
+
+#define WRB_TYPE_MASK 0xF0000000
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_iscsi_wrb {
+ u8 lun[14]; /* DWORD 0 */
+ u8 lt; /* DWORD 0 */
+ u8 invld; /* DWORD 0 */
+ u8 wrb_idx[8]; /* DWORD 0 */
+ u8 dsp; /* DWORD 0 */
+ u8 dmsg; /* DWORD 0 */
+ u8 undr_run; /* DWORD 0 */
+ u8 over_run; /* DWORD 0 */
+ u8 type[4]; /* DWORD 0 */
+ u8 ptr2nextwrb[8]; /* DWORD 1 */
+ u8 r2t_exp_dtl[24]; /* DWORD 1 */
+ u8 sgl_icd_idx[12]; /* DWORD 2 */
+ u8 rsvd0[20]; /* DWORD 2 */
+ u8 exp_data_sn[32]; /* DWORD 3 */
+ u8 iscsi_bhs_addr_hi[32]; /* DWORD 4 */
+ u8 iscsi_bhs_addr_lo[32]; /* DWORD 5 */
+ u8 cmdsn_itt[32]; /* DWORD 6 */
+ u8 dif_ref_tag[32]; /* DWORD 7 */
+ u8 sge0_addr_hi[32]; /* DWORD 8 */
+ u8 sge0_addr_lo[32]; /* DWORD 9 */
+ u8 sge0_offset[22]; /* DWORD 10 */
+ u8 pbs; /* DWORD 10 */
+ u8 dif_mode[2]; /* DWORD 10 */
+ u8 rsvd1[6]; /* DWORD 10 */
+ u8 sge0_last; /* DWORD 10 */
+ u8 sge0_len[17]; /* DWORD 11 */
+ u8 dif_meta_tag[14]; /* DWORD 11 */
+ u8 sge0_in_ddr; /* DWORD 11 */
+ u8 sge1_addr_hi[32]; /* DWORD 12 */
+ u8 sge1_addr_lo[32]; /* DWORD 13 */
+ u8 sge1_r2t_offset[22]; /* DWORD 14 */
+ u8 rsvd2[9]; /* DWORD 14 */
+ u8 sge1_last; /* DWORD 14 */
+ u8 sge1_len[17]; /* DWORD 15 */
+ u8 ref_sgl_icd_idx[12]; /* DWORD 15 */
+ u8 rsvd3[2]; /* DWORD 15 */
+ u8 sge1_in_ddr; /* DWORD 15 */
+
+} __packed;
+
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ int index);
+void
+free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
+
+struct pdu_nop_out {
+ u32 dw[12];
+};
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_pdu_nop_out {
+ u8 opcode[6]; /* opcode 0x00 */
+ u8 i_bit; /* I Bit */
+ u8 x_bit; /* reserved; should be 0 */
+ u8 fp_bit_filler1[7];
+ u8 f_bit; /* always 1 */
+ u8 reserved1[16];
+ u8 ahs_length[8]; /* no AHS */
+ u8 data_len_hi[8];
+ u8 data_len_lo[16]; /* DataSegmentLength */
+ u8 lun[64];
+ u8 itt[32]; /* initiator id for ping or 0xffffffff */
+ u8 ttt[32]; /* target id for ping or 0xffffffff */
+ u8 cmd_sn[32];
+ u8 exp_stat_sn[32];
+ u8 reserved5[128];
+};
+
+#define PDUBASE_OPCODE_MASK 0x0000003F
+#define PDUBASE_DATALENHI_MASK 0x0000FF00
+#define PDUBASE_DATALENLO_MASK 0xFFFF0000
+
+struct pdu_base {
+ u32 dw[16];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_pdu_base {
+ u8 opcode[6];
+ u8 i_bit; /* immediate bit */
+ u8 x_bit; /* reserved, always 0 */
+ u8 reserved1[24]; /* opcode-specific fields */
+ u8 ahs_length[8]; /* length units is 4 byte words */
+ u8 data_len_hi[8];
+ u8 data_len_lo[16]; /* DatasegmentLength */
+ u8 lun[64]; /* lun or opcode-specific fields */
+ u8 itt[32]; /* initiator task tag */
+ u8 reserved4[224];
+};
+
+struct iscsi_target_context_update_wrb {
+ u32 dw[16];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_iscsi_target_context_update_wrb {
+ u8 lun[14]; /* DWORD 0 */
+ u8 lt; /* DWORD 0 */
+ u8 invld; /* DWORD 0 */
+ u8 wrb_idx[8]; /* DWORD 0 */
+ u8 dsp; /* DWORD 0 */
+ u8 dmsg; /* DWORD 0 */
+ u8 undr_run; /* DWORD 0 */
+ u8 over_run; /* DWORD 0 */
+ u8 type[4]; /* DWORD 0 */
+ u8 ptr2nextwrb[8]; /* DWORD 1 */
+ u8 max_burst_length[19]; /* DWORD 1 */
+ u8 rsvd0[5]; /* DWORD 1 */
+ u8 rsvd1[15]; /* DWORD 2 */
+ u8 max_send_data_segment_length[17]; /* DWORD 2 */
+ u8 first_burst_length[14]; /* DWORD 3 */
+ u8 rsvd2[2]; /* DWORD 3 */
+ u8 tx_wrbindex_drv_msg[8]; /* DWORD 3 */
+ u8 rsvd3[5]; /* DWORD 3 */
+ u8 session_state[3]; /* DWORD 3 */
+ u8 rsvd4[16]; /* DWORD 4 */
+ u8 tx_jumbo; /* DWORD 4 */
+ u8 hde; /* DWORD 4 */
+ u8 dde; /* DWORD 4 */
+ u8 erl[2]; /* DWORD 4 */
+ u8 domain_id[5]; /* DWORD 4 */
+ u8 mode; /* DWORD 4 */
+ u8 imd; /* DWORD 4 */
+ u8 ir2t; /* DWORD 4 */
+ u8 notpredblq[2]; /* DWORD 4 */
+ u8 compltonack; /* DWORD 4 */
+ u8 stat_sn[32]; /* DWORD 5 */
+ u8 pad_buffer_addr_hi[32]; /* DWORD 6 */
+ u8 pad_buffer_addr_lo[32]; /* DWORD 7 */
+ u8 pad_addr_hi[32]; /* DWORD 8 */
+ u8 pad_addr_lo[32]; /* DWORD 9 */
+ u8 rsvd5[32]; /* DWORD 10 */
+ u8 rsvd6[32]; /* DWORD 11 */
+ u8 rsvd7[32]; /* DWORD 12 */
+ u8 rsvd8[32]; /* DWORD 13 */
+ u8 rsvd9[32]; /* DWORD 14 */
+ u8 rsvd10[32]; /* DWORD 15 */
+
+} __packed;
+
+struct be_ring {
+ u32 pages; /* queue size in pages */
+ u32 id; /* queue id assigned by beklib */
+ u32 num; /* number of elements in queue */
+ u32 cidx; /* consumer index */
+ u32 pidx; /* producer index -- not used by most rings */
+ u32 item_size; /* size in bytes of one object */
+
+ void *va; /* The virtual address of the ring. This
+ * should be last to allow 32 & 64 bit debugger
+ * extensions to work.
+ */
+};
+
+struct hwi_wrb_context {
+ struct list_head wrb_handle_list;
+ struct list_head wrb_handle_drvr_list;
+ struct wrb_handle **pwrb_handle_base;
+ struct wrb_handle **pwrb_handle_basestd;
+ struct iscsi_wrb *plast_wrb;
+ unsigned short alloc_index;
+ unsigned short free_index;
+ unsigned short wrb_handles_available;
+ unsigned short cid;
+};
+
+struct hwi_controller {
+ struct list_head io_sgl_list;
+ struct list_head eh_sgl_list;
+ struct sgl_handle *psgl_handle_base;
+ unsigned int wrb_mem_index;
+
+ struct hwi_wrb_context wrb_context[BE2_MAX_SESSIONS * 2];
+ struct mcc_wrb *pmcc_wrb_base;
+ struct be_ring default_pdu_hdr;
+ struct be_ring default_pdu_data;
+ struct hwi_context_memory *phwi_ctxt;
+ unsigned short cq_errors[CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN];
+};
+
+enum hwh_type_enum {
+ HWH_TYPE_IO = 1,
+ HWH_TYPE_LOGOUT = 2,
+ HWH_TYPE_TMF = 3,
+ HWH_TYPE_NOP = 4,
+ HWH_TYPE_IO_RD = 5,
+ HWH_TYPE_LOGIN = 11,
+ HWH_TYPE_INVALID = 0xFFFFFFFF
+};
+
+struct wrb_handle {
+ enum hwh_type_enum type;
+ unsigned short wrb_index;
+ unsigned short nxt_wrb_index;
+
+ struct iscsi_task *pio_handle;
+ struct iscsi_wrb *pwrb;
+};
+
+struct hwi_context_memory {
+ struct be_eq_obj be_eq;
+ struct be_queue_info be_cq;
+ struct be_queue_info be_mcc_cq;
+ struct be_queue_info be_mcc;
+
+ struct be_queue_info be_def_hdrq;
+ struct be_queue_info be_def_dataq;
+
+ struct be_queue_info be_wrbq[BE2_MAX_SESSIONS];
+ struct be_mcc_wrb_context *pbe_mcc_context;
+
+ struct hwi_async_pdu_context *pasync_ctx;
+};
+
+#endif
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
new file mode 100644
index 000000000000..12e644fc746e
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -0,0 +1,321 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#include "be_mgmt.h"
+#include "be_iscsi.h"
+
+unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_fw_cfg *req = embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req));
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_fw_cfg *pfw_cfg;
+ pfw_cfg = req;
+ phba->fw_config.phys_port = pfw_cfg->phys_port;
+ phba->fw_config.iscsi_icd_start =
+ pfw_cfg->ulp[0].icd_base;
+ phba->fw_config.iscsi_icd_count =
+ pfw_cfg->ulp[0].icd_count;
+ phba->fw_config.iscsi_cid_start =
+ pfw_cfg->ulp[0].sq_base;
+ phba->fw_config.iscsi_cid_count =
+ pfw_cfg->ulp[0].sq_count;
+ } else {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed in mgmt_get_fw_config \n");
+ }
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl)
+{
+ struct be_dma_mem nonemb_cmd;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mgmt_controller_attributes *req;
+ struct be_sge *sge = nonembedded_sgl(wrb);
+ int status = 0;
+
+ nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
+ sizeof(struct be_mgmt_controller_attributes),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1,
+ "Failed to allocate memory for mgmt_check_supported_fw"
+ "\n");
+ return -1;
+ }
+ nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
+ req = nonemb_cmd.va;
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req));
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd.size);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va;
+ SE_DEBUG(DBG_LVL_8, "Firmware version of CMD: %s\n",
+ resp->params.hba_attribs.flashrom_version_string);
+ SE_DEBUG(DBG_LVL_8, "Firmware version is : %s\n",
+ resp->params.hba_attribs.firmware_version_string);
+ SE_DEBUG(DBG_LVL_8,
+ "Developer Build, not performing version check...\n");
+
+ } else
+ SE_DEBUG(DBG_LVL_1, " Failed in mgmt_check_supported_fw\n");
+ if (nonemb_cmd.va)
+ pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct iscsi_cleanup_req *req = embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
+
+ req->chute = chute;
+ req->hdr_ring_id = 0;
+ req->data_ring_id = 0;
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ shost_printk(KERN_WARNING, phba->shost,
+ " mgmt_epfw_cleanup , FAILED\n");
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+ unsigned int icd, unsigned int cid)
+{
+ struct be_dma_mem nonemb_cmd;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_sge *sge = nonembedded_sgl(wrb);
+ struct invalidate_commands_params_in *req;
+ int status = 0;
+
+ nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
+ sizeof(struct invalidate_commands_params_in),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1,
+ "Failed to allocate memory for"
+ "mgmt_invalidate_icds \n");
+ return -1;
+ }
+ nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
+ req = nonemb_cmd.va;
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS,
+ sizeof(*req));
+ req->ref_handle = 0;
+ req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE;
+ req->icd_count = 0;
+ req->table[req->icd_count].icd = icd;
+ req->table[req->icd_count].cid = cid;
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd.size);
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n");
+ spin_unlock(&ctrl->mbox_lock);
+ if (nonemb_cmd.va)
+ pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ return status;
+}
+
+unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+ struct beiscsi_endpoint *beiscsi_ep,
+ unsigned short cid,
+ unsigned short issue_reset,
+ unsigned short savecfg_flag)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct iscsi_invalidate_connection_params_in *req =
+ embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION,
+ sizeof(*req));
+ req->session_handle = beiscsi_ep->fw_handle;
+ req->cid = cid;
+ if (issue_reset)
+ req->cleanup_type = CMD_ISCSI_CONNECTION_ISSUE_TCP_RST;
+ else
+ req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE;
+ req->save_cfg = savecfg_flag;
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n");
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+ unsigned short cid, unsigned int upload_flag)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct tcp_upload_params_in *req = embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD,
+ OPCODE_COMMON_TCP_UPLOAD, sizeof(*req));
+ req->id = (unsigned short)cid;
+ req->upload_type = (unsigned char)upload_flag;
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n");
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int mgmt_open_connection(struct beiscsi_hba *phba,
+ struct sockaddr *dst_addr,
+ struct beiscsi_endpoint *beiscsi_ep)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr;
+ struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct tcp_connect_and_offload_in *req = embedded_payload(wrb);
+ unsigned short def_hdr_id;
+ unsigned short def_data_id;
+ struct phys_addr template_address = { 0, 0 };
+ struct phys_addr *ptemplate_address;
+ int status = 0;
+ unsigned short cid = beiscsi_ep->ep_cid;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba);
+ def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba);
+
+ ptemplate_address = &template_address;
+ ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address);
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD,
+ sizeof(*req));
+ if (dst_addr->sa_family == PF_INET) {
+ __be32 s_addr = daddr_in->sin_addr.s_addr;
+ req->ip_address.ip_type = BE2_IPV4;
+ req->ip_address.ip_address[0] = s_addr & 0x000000ff;
+ req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8;
+ req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16;
+ req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24;
+ req->tcp_port = ntohs(daddr_in->sin_port);
+ beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr;
+ beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port);
+ beiscsi_ep->ip_type = BE2_IPV4;
+ } else if (dst_addr->sa_family == PF_INET6) {
+ req->ip_address.ip_type = BE2_IPV6;
+ memcpy(&req->ip_address.ip_address,
+ &daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
+ req->tcp_port = ntohs(daddr_in6->sin6_port);
+ beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port);
+ memcpy(&beiscsi_ep->dst6_addr,
+ &daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
+ beiscsi_ep->ip_type = BE2_IPV6;
+ } else{
+ shost_printk(KERN_ERR, phba->shost, "unknown addr family %d\n",
+ dst_addr->sa_family);
+ spin_unlock(&ctrl->mbox_lock);
+ return -EINVAL;
+
+ }
+ req->cid = cid;
+ req->cq_id = phwi_context->be_cq.id;
+ req->defq_id = def_hdr_id;
+ req->hdr_ring_id = def_hdr_id;
+ req->data_ring_id = def_data_id;
+ req->do_offload = 1;
+ req->dataout_template_pa.lo = ptemplate_address->lo;
+ req->dataout_template_pa.hi = ptemplate_address->hi;
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct iscsi_endpoint *ep;
+ struct tcp_connect_and_offload_out *ptcpcnct_out =
+ embedded_payload(wrb);
+
+ ep = phba->ep_array[ptcpcnct_out->cid];
+ beiscsi_ep = ep->dd_data;
+ beiscsi_ep->fw_handle = 0;
+ beiscsi_ep->cid_vld = 1;
+ SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
+ } else
+ SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed\n");
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
new file mode 100644
index 000000000000..00e816ee8070
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -0,0 +1,249 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#ifndef _BEISCSI_MGMT_
+#define _BEISCSI_MGMT_
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include "be_iscsi.h"
+#include "be_main.h"
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_sge {
+ u8 pa_lo[32]; /* dword 0 */
+ u8 pa_hi[32]; /* dword 1 */
+ u8 length[32]; /* DWORD 2 */
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_wrb_payload {
+ union {
+ struct amap_mcc_sge sgl[19];
+ u8 embedded[59 * 32]; /* DWORDS 57 to 115 */
+ } u;
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_wrb {
+ u8 embedded; /* DWORD 0 */
+ u8 rsvd0[2]; /* DWORD 0 */
+ u8 sge_count[5]; /* DWORD 0 */
+ u8 rsvd1[16]; /* DWORD 0 */
+ u8 special[8]; /* DWORD 0 */
+ u8 payload_length[32];
+ u8 tag[64]; /* DWORD 2 */
+ u8 rsvd2[32]; /* DWORD 4 */
+ struct amap_mcc_wrb_payload payload;
+};
+
+struct mcc_sge {
+ u32 pa_lo; /* dword 0 */
+ u32 pa_hi; /* dword 1 */
+ u32 length; /* DWORD 2 */
+} __packed;
+
+struct mcc_wrb_payload {
+ union {
+ struct mcc_sge sgl[19];
+ u32 embedded[59]; /* DWORDS 57 to 115 */
+ } u;
+} __packed;
+
+#define MCC_WRB_EMBEDDED_MASK 0x00000001
+
+struct mcc_wrb {
+ u32 dw[0]; /* DWORD 0 */
+ u32 payload_length;
+ u32 tag[2]; /* DWORD 2 */
+ u32 rsvd2[1]; /* DWORD 4 */
+ struct mcc_wrb_payload payload;
+};
+
+unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
+int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr,
+ struct beiscsi_endpoint *beiscsi_ep);
+
+unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+ unsigned short cid,
+ unsigned int upload_flag);
+unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+ unsigned int icd, unsigned int cid);
+
+struct iscsi_invalidate_connection_params_in {
+ struct be_cmd_req_hdr hdr;
+ unsigned int session_handle;
+ unsigned short cid;
+ unsigned short unused;
+ unsigned short cleanup_type;
+ unsigned short save_cfg;
+} __packed;
+
+struct iscsi_invalidate_connection_params_out {
+ unsigned int session_handle;
+ unsigned short cid;
+ unsigned short unused;
+} __packed;
+
+union iscsi_invalidate_connection_params {
+ struct iscsi_invalidate_connection_params_in request;
+ struct iscsi_invalidate_connection_params_out response;
+} __packed;
+
+struct invalidate_command_table {
+ unsigned short icd;
+ unsigned short cid;
+} __packed;
+
+struct invalidate_commands_params_in {
+ struct be_cmd_req_hdr hdr;
+ unsigned int ref_handle;
+ unsigned int icd_count;
+ struct invalidate_command_table table[128];
+ unsigned short cleanup_type;
+ unsigned short unused;
+} __packed;
+
+struct invalidate_commands_params_out {
+ unsigned int ref_handle;
+ unsigned int icd_count;
+ unsigned int icd_status[128];
+} __packed;
+
+union invalidate_commands_params {
+ struct invalidate_commands_params_in request;
+ struct invalidate_commands_params_out response;
+} __packed;
+
+struct mgmt_hba_attributes {
+ u8 flashrom_version_string[32];
+ u8 manufacturer_name[32];
+ u32 supported_modes;
+ u8 seeprom_version_lo;
+ u8 seeprom_version_hi;
+ u8 rsvd0[2];
+ u32 fw_cmd_data_struct_version;
+ u32 ep_fw_data_struct_version;
+ u32 future_reserved[12];
+ u32 default_extended_timeout;
+ u8 controller_model_number[32];
+ u8 controller_description[64];
+ u8 controller_serial_number[32];
+ u8 ip_version_string[32];
+ u8 firmware_version_string[32];
+ u8 bios_version_string[32];
+ u8 redboot_version_string[32];
+ u8 driver_version_string[32];
+ u8 fw_on_flash_version_string[32];
+ u32 functionalities_supported;
+ u16 max_cdblength;
+ u8 asic_revision;
+ u8 generational_guid[16];
+ u8 hba_port_count;
+ u16 default_link_down_timeout;
+ u8 iscsi_ver_min_max;
+ u8 multifunction_device;
+ u8 cache_valid;
+ u8 hba_status;
+ u8 max_domains_supported;
+ u8 phy_port;
+ u32 firmware_post_status;
+ u32 hba_mtu[8];
+ u32 future_u32[4];
+} __packed;
+
+struct mgmt_controller_attributes {
+ struct mgmt_hba_attributes hba_attribs;
+ u16 pci_vendor_id;
+ u16 pci_device_id;
+ u16 pci_sub_vendor_id;
+ u16 pci_sub_system_id;
+ u8 pci_bus_number;
+ u8 pci_device_number;
+ u8 pci_function_number;
+ u8 interface_type;
+ u64 unique_identifier;
+ u8 netfilters;
+ u8 rsvd0[3];
+ u8 future_u32[4];
+} __packed;
+
+struct be_mgmt_controller_attributes {
+ struct be_cmd_req_hdr hdr;
+ struct mgmt_controller_attributes params;
+} __packed;
+
+struct be_mgmt_controller_attributes_resp {
+ struct be_cmd_resp_hdr hdr;
+ struct mgmt_controller_attributes params;
+} __packed;
+
+/* configuration management */
+
+#define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws)
+
+/* MGMT CMD flags */
+
+#define MGMT_CMDH_FREE (1<<0)
+
+/* --- MGMT_ERROR_CODES --- */
+/* Error Codes returned in the status field of the CMD response header */
+#define MGMT_STATUS_SUCCESS 0 /* The CMD completed without errors */
+#define MGMT_STATUS_FAILED 1 /* Error status in the Status field of */
+ /* the CMD_RESPONSE_HEADER */
+
+#define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\
+ pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ bus_address.u.a32.address_lo; \
+ pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ bus_address.u.a32.address_hi; \
+}
+
+struct beiscsi_endpoint {
+ struct beiscsi_hba *phba;
+ struct beiscsi_sess *sess;
+ struct beiscsi_conn *conn;
+ unsigned short ip_type;
+ char dst6_addr[ISCSI_ADDRESS_BUF_LEN];
+ unsigned long dst_addr;
+ unsigned short ep_cid;
+ unsigned int fw_handle;
+ u16 dst_tcpport;
+ u16 cid_vld;
+};
+
+unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba);
+
+unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+ struct beiscsi_endpoint *beiscsi_ep,
+ unsigned short cid,
+ unsigned short issue_reset,
+ unsigned short savecfg_flag);
+#endif
diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile
new file mode 100644
index 000000000000..1d6009490d1c
--- /dev/null
+++ b/drivers/scsi/bfa/Makefile
@@ -0,0 +1,15 @@
+obj-$(CONFIG_SCSI_BFA_FC) := bfa.o
+
+bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o
+
+bfa-y += bfa_core.o bfa_ioc.o bfa_iocfc.o bfa_fcxp.o bfa_lps.o
+bfa-y += bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o
+bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o
+bfa-y += bfa_itnim.o bfa_fcpim.o bfa_tskim.o bfa_log.o bfa_log_module.o
+bfa-y += bfa_csdebug.o bfa_sm.o plog.o
+
+bfa-y += fcbuild.o fabric.o fcpim.o vfapi.o fcptm.o bfa_fcs.o bfa_fcs_port.o
+bfa-y += bfa_fcs_uf.o bfa_fcs_lport.o fab.o fdmi.o ms.o ns.o scn.o loop.o
+bfa-y += lport_api.o n2n.o rport.o rport_api.o rport_ftrs.o vport.o
+
+ccflags-y := -I$(obj) -I$(obj)/include -I$(obj)/include/cna
diff --git a/drivers/scsi/bfa/bfa_callback_priv.h b/drivers/scsi/bfa/bfa_callback_priv.h
new file mode 100644
index 000000000000..1e3265c9f7d4
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_callback_priv.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_CALLBACK_PRIV_H__
+#define __BFA_CALLBACK_PRIV_H__
+
+#include <cs/bfa_q.h>
+
+typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete);
+
+/**
+ * Generic BFA callback element.
+ */
+struct bfa_cb_qe_s {
+ struct list_head qe;
+ bfa_cb_cbfn_t cbfn;
+ bfa_boolean_t once;
+ u32 rsvd;
+ void *cbarg;
+};
+
+#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
+ (__hcb_qe)->cbfn = (__cbfn); \
+ (__hcb_qe)->cbarg = (__cbarg); \
+ list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \
+} while (0)
+
+#define bfa_cb_dequeue(__hcb_qe) list_del(&(__hcb_qe)->qe)
+
+#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
+ (__hcb_qe)->cbfn = (__cbfn); \
+ (__hcb_qe)->cbarg = (__cbarg); \
+ if (!(__hcb_qe)->once) { \
+ list_add_tail((__hcb_qe), &(__bfa)->comp_q); \
+ (__hcb_qe)->once = BFA_TRUE; \
+ } \
+} while (0)
+
+#define bfa_cb_queue_done(__hcb_qe) do { \
+ (__hcb_qe)->once = BFA_FALSE; \
+} while (0)
+
+#endif /* __BFA_CALLBACK_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
new file mode 100644
index 000000000000..0050c838c358
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_cb_ioim_macros.h BFA IOIM driver interface macros.
+ */
+
+#ifndef __BFA_HCB_IOIM_MACROS_H__
+#define __BFA_HCB_IOIM_MACROS_H__
+
+#include <bfa_os_inc.h>
+/*
+ * #include <linux/dma-mapping.h>
+ *
+ * #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include
+ * <scsi/scsi_device.h> #include <scsi/scsi_host.h>
+ */
+#include "bfad_im_compat.h"
+
+/*
+ * task attribute values in FCP-2 FCP_CMND IU
+ */
+#define SIMPLE_Q 0
+#define HEAD_OF_Q 1
+#define ORDERED_Q 2
+#define ACA_Q 4
+#define UNTAGGED 5
+
+static inline lun_t
+bfad_int_to_lun(u32 luno)
+{
+ union {
+ u16 scsi_lun[4];
+ lun_t bfa_lun;
+ } lun;
+
+ lun.bfa_lun = 0;
+ lun.scsi_lun[0] = bfa_os_htons(luno);
+
+ return (lun.bfa_lun);
+}
+
+/**
+ * Get LUN for the I/O request
+ */
+#define bfa_cb_ioim_get_lun(__dio) \
+ bfad_int_to_lun(((struct scsi_cmnd *)__dio)->device->lun)
+
+/**
+ * Get CDB for the I/O request
+ */
+static inline u8 *
+bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+
+ return ((u8 *) cmnd->cmnd);
+}
+
+/**
+ * Get I/O direction (read/write) for the I/O request
+ */
+static inline enum fcp_iodir
+bfa_cb_ioim_get_iodir(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ enum dma_data_direction dmadir;
+
+ dmadir = cmnd->sc_data_direction;
+ if (dmadir == DMA_TO_DEVICE)
+ return FCP_IODIR_WRITE;
+ else if (dmadir == DMA_FROM_DEVICE)
+ return FCP_IODIR_READ;
+ else
+ return FCP_IODIR_NONE;
+}
+
+/**
+ * Get IO size in bytes for the I/O request
+ */
+static inline u32
+bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+
+ return (scsi_bufflen(cmnd));
+}
+
+/**
+ * Get timeout for the I/O request
+ */
+static inline u8
+bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ /*
+ * TBD: need a timeout for scsi passthru
+ */
+ if (cmnd->device->host == NULL)
+ return 4;
+
+ return 0;
+}
+
+/**
+ * Get SG element for the I/O request given the SG element index
+ */
+static inline union bfi_addr_u
+bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct scatterlist *sge;
+ u64 addr;
+
+ sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
+ addr = (u64) sg_dma_address(sge);
+
+ return (*(union bfi_addr_u *) &addr);
+}
+
+static inline u32
+bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct scatterlist *sge;
+ u32 len;
+
+ sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
+ len = sg_dma_len(sge);
+
+ return len;
+}
+
+/**
+ * Get Command Reference Number for the I/O request. 0 if none.
+ */
+static inline u8
+bfa_cb_ioim_get_crn(struct bfad_ioim_s *dio)
+{
+ return 0;
+}
+
+/**
+ * Get SAM-3 priority for the I/O request. 0 is default.
+ */
+static inline u8
+bfa_cb_ioim_get_priority(struct bfad_ioim_s *dio)
+{
+ return 0;
+}
+
+/**
+ * Get task attributes for the I/O request. Default is FCP_TASK_ATTR_SIMPLE(0).
+ */
+static inline u8
+bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ u8 task_attr = UNTAGGED;
+
+ if (cmnd->device->tagged_supported) {
+ switch (cmnd->tag) {
+ case HEAD_OF_QUEUE_TAG:
+ task_attr = HEAD_OF_Q;
+ break;
+ case ORDERED_QUEUE_TAG:
+ task_attr = ORDERED_Q;
+ break;
+ default:
+ task_attr = SIMPLE_Q;
+ break;
+ }
+ }
+
+ return task_attr;
+}
+
+/**
+ * Get CDB length in bytes for the I/O request. Default is FCP_CMND_CDB_LEN(16).
+ */
+static inline u8
+bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+
+ return (cmnd->cmd_len);
+}
+
+
+
+#endif /* __BFA_HCB_IOIM_MACROS_H__ */
diff --git a/drivers/scsi/bfa/bfa_cee.c b/drivers/scsi/bfa/bfa_cee.c
new file mode 100644
index 000000000000..7a959c34e789
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_cee.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2005-2009 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 <defs/bfa_defs_cee.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+#include <cs/bfa_debug.h>
+#include <cee/bfa_cee.h>
+#include <bfi/bfi_cee.h>
+#include <bfi/bfi.h>
+#include <bfa_ioc.h>
+#include <cna/bfa_cna_trcmod.h>
+
+BFA_TRC_FILE(CNA, CEE);
+
+#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
+
+static void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg);
+static void bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s
+ *dcbcx_stats);
+static void bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s
+ *lldp_stats);
+static void bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats);
+static void bfa_cee_format_cee_cfg(void *buffer);
+static void bfa_cee_format_cee_stats(void *buffer);
+
+static void
+bfa_cee_format_cee_stats(void *buffer)
+{
+ struct bfa_cee_stats_s *cee_stats = buffer;
+ bfa_cee_format_dcbcx_stats(&cee_stats->dcbx_stats);
+ bfa_cee_format_lldp_stats(&cee_stats->lldp_stats);
+ bfa_cee_format_cfg_stats(&cee_stats->cfg_stats);
+}
+
+static void
+bfa_cee_format_cee_cfg(void *buffer)
+{
+ struct bfa_cee_attr_s *cee_cfg = buffer;
+ bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote);
+}
+
+static void
+bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s *dcbcx_stats)
+{
+ dcbcx_stats->subtlvs_unrecognized =
+ bfa_os_ntohl(dcbcx_stats->subtlvs_unrecognized);
+ dcbcx_stats->negotiation_failed =
+ bfa_os_ntohl(dcbcx_stats->negotiation_failed);
+ dcbcx_stats->remote_cfg_changed =
+ bfa_os_ntohl(dcbcx_stats->remote_cfg_changed);
+ dcbcx_stats->tlvs_received = bfa_os_ntohl(dcbcx_stats->tlvs_received);
+ dcbcx_stats->tlvs_invalid = bfa_os_ntohl(dcbcx_stats->tlvs_invalid);
+ dcbcx_stats->seqno = bfa_os_ntohl(dcbcx_stats->seqno);
+ dcbcx_stats->ackno = bfa_os_ntohl(dcbcx_stats->ackno);
+ dcbcx_stats->recvd_seqno = bfa_os_ntohl(dcbcx_stats->recvd_seqno);
+ dcbcx_stats->recvd_ackno = bfa_os_ntohl(dcbcx_stats->recvd_ackno);
+}
+
+static void
+bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s *lldp_stats)
+{
+ lldp_stats->frames_transmitted =
+ bfa_os_ntohl(lldp_stats->frames_transmitted);
+ lldp_stats->frames_aged_out = bfa_os_ntohl(lldp_stats->frames_aged_out);
+ lldp_stats->frames_discarded =
+ bfa_os_ntohl(lldp_stats->frames_discarded);
+ lldp_stats->frames_in_error = bfa_os_ntohl(lldp_stats->frames_in_error);
+ lldp_stats->frames_rcvd = bfa_os_ntohl(lldp_stats->frames_rcvd);
+ lldp_stats->tlvs_discarded = bfa_os_ntohl(lldp_stats->tlvs_discarded);
+ lldp_stats->tlvs_unrecognized =
+ bfa_os_ntohl(lldp_stats->tlvs_unrecognized);
+}
+
+static void
+bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats)
+{
+ cfg_stats->cee_status_down = bfa_os_ntohl(cfg_stats->cee_status_down);
+ cfg_stats->cee_status_up = bfa_os_ntohl(cfg_stats->cee_status_up);
+ cfg_stats->cee_hw_cfg_changed =
+ bfa_os_ntohl(cfg_stats->cee_hw_cfg_changed);
+ cfg_stats->recvd_invalid_cfg =
+ bfa_os_ntohl(cfg_stats->recvd_invalid_cfg);
+}
+
+static void
+bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg)
+{
+ lldp_cfg->time_to_interval = bfa_os_ntohs(lldp_cfg->time_to_interval);
+ lldp_cfg->enabled_system_cap =
+ bfa_os_ntohs(lldp_cfg->enabled_system_cap);
+}
+
+/**
+ * bfa_cee_attr_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_attr_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_cee_stats_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_stats_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status)
+{
+ cee->get_attr_status = status;
+ bfa_trc(cee, 0);
+ if (status == BFA_STATUS_OK) {
+ bfa_trc(cee, 0);
+ /*
+ * The requested data has been copied to the DMA area, *process
+ * it.
+ */
+ memcpy(cee->attr, cee->attr_dma.kva,
+ sizeof(struct bfa_cee_attr_s));
+ bfa_cee_format_cee_cfg(cee->attr);
+ }
+ cee->get_attr_pending = BFA_FALSE;
+ if (cee->cbfn.get_attr_cbfn) {
+ bfa_trc(cee, 0);
+ cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status);
+ }
+ bfa_trc(cee, 0);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
+{
+ cee->get_stats_status = status;
+ bfa_trc(cee, 0);
+ if (status == BFA_STATUS_OK) {
+ bfa_trc(cee, 0);
+ /*
+ * The requested data has been copied to the DMA area, process
+ * it.
+ */
+ memcpy(cee->stats, cee->stats_dma.kva,
+ sizeof(struct bfa_cee_stats_s));
+ bfa_cee_format_cee_stats(cee->stats);
+ }
+ cee->get_stats_pending = BFA_FALSE;
+ bfa_trc(cee, 0);
+ if (cee->cbfn.get_stats_cbfn) {
+ bfa_trc(cee, 0);
+ cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status);
+ }
+ bfa_trc(cee, 0);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
+{
+ cee->reset_stats_status = status;
+ cee->reset_stats_pending = BFA_FALSE;
+ if (cee->cbfn.reset_stats_cbfn)
+ cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status);
+}
+
+/**
+ * bfa_cee_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+u32
+bfa_cee_meminfo(void)
+{
+ return (bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo());
+}
+
+/**
+ * bfa_cee_mem_claim()
+ *
+ *
+ * @param[in] cee CEE module pointer
+ * dma_kva Kernel Virtual Address of CEE DMA Memory
+ * dma_pa Physical Address of CEE DMA Memory
+ *
+ * @return void
+ */
+void
+bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa)
+{
+ cee->attr_dma.kva = dma_kva;
+ cee->attr_dma.pa = dma_pa;
+ cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo();
+ cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo();
+ cee->attr = (struct bfa_cee_attr_s *)dma_kva;
+ cee->stats =
+ (struct bfa_cee_stats_s *)(dma_kva + bfa_cee_attr_meminfo());
+}
+
+/**
+ * bfa_cee_get_attr()
+ *
+ * Send the request to the f/w to fetch CEE attributes.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr,
+ bfa_cee_get_attr_cbfn_t cbfn, void *cbarg)
+{
+ struct bfi_cee_get_req_s *cmd;
+
+ bfa_assert((cee != NULL) && (cee->ioc != NULL));
+ bfa_trc(cee, 0);
+ if (!bfa_ioc_is_operational(cee->ioc)) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+ if (cee->get_attr_pending == BFA_TRUE) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_DEVBUSY;
+ }
+ cee->get_attr_pending = BFA_TRUE;
+ cmd = (struct bfi_cee_get_req_s *)cee->get_cfg_mb.msg;
+ cee->attr = attr;
+ cee->cbfn.get_attr_cbfn = cbfn;
+ cee->cbfn.get_attr_cbarg = cbarg;
+ bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ,
+ bfa_ioc_portid(cee->ioc));
+ bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa);
+ bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb);
+ bfa_trc(cee, 0);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_get_stats()
+ *
+ * Send the request to the f/w to fetch CEE statistics.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats,
+ bfa_cee_get_stats_cbfn_t cbfn, void *cbarg)
+{
+ struct bfi_cee_get_req_s *cmd;
+
+ bfa_assert((cee != NULL) && (cee->ioc != NULL));
+
+ if (!bfa_ioc_is_operational(cee->ioc)) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+ if (cee->get_stats_pending == BFA_TRUE) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_DEVBUSY;
+ }
+ cee->get_stats_pending = BFA_TRUE;
+ cmd = (struct bfi_cee_get_req_s *)cee->get_stats_mb.msg;
+ cee->stats = stats;
+ cee->cbfn.get_stats_cbfn = cbfn;
+ cee->cbfn.get_stats_cbarg = cbarg;
+ bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ,
+ bfa_ioc_portid(cee->ioc));
+ bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa);
+ bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb);
+ bfa_trc(cee, 0);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_reset_stats()
+ *
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+bfa_cee_reset_stats(struct bfa_cee_s *cee, bfa_cee_reset_stats_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_cee_reset_stats_s *cmd;
+
+ bfa_assert((cee != NULL) && (cee->ioc != NULL));
+ if (!bfa_ioc_is_operational(cee->ioc)) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+ if (cee->reset_stats_pending == BFA_TRUE) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_DEVBUSY;
+ }
+ cee->reset_stats_pending = BFA_TRUE;
+ cmd = (struct bfi_cee_reset_stats_s *)cee->reset_stats_mb.msg;
+ cee->cbfn.reset_stats_cbfn = cbfn;
+ cee->cbfn.reset_stats_cbarg = cbarg;
+ bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS,
+ bfa_ioc_portid(cee->ioc));
+ bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb);
+ bfa_trc(cee, 0);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_isrs()
+ *
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+void
+bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m)
+{
+ union bfi_cee_i2h_msg_u *msg;
+ struct bfi_cee_get_rsp_s *get_rsp;
+ struct bfa_cee_s *cee = (struct bfa_cee_s *)cbarg;
+ msg = (union bfi_cee_i2h_msg_u *)m;
+ get_rsp = (struct bfi_cee_get_rsp_s *)m;
+ bfa_trc(cee, msg->mh.msg_id);
+ switch (msg->mh.msg_id) {
+ case BFI_CEE_I2H_GET_CFG_RSP:
+ bfa_trc(cee, get_rsp->cmd_status);
+ bfa_cee_get_attr_isr(cee, get_rsp->cmd_status);
+ break;
+ case BFI_CEE_I2H_GET_STATS_RSP:
+ bfa_cee_get_stats_isr(cee, get_rsp->cmd_status);
+ break;
+ case BFI_CEE_I2H_RESET_STATS_RSP:
+ bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status);
+ break;
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * bfa_cee_hbfail()
+ *
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+void
+bfa_cee_hbfail(void *arg)
+{
+ struct bfa_cee_s *cee;
+ cee = (struct bfa_cee_s *)arg;
+
+ if (cee->get_attr_pending == BFA_TRUE) {
+ cee->get_attr_status = BFA_STATUS_FAILED;
+ cee->get_attr_pending = BFA_FALSE;
+ if (cee->cbfn.get_attr_cbfn) {
+ cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+ if (cee->get_stats_pending == BFA_TRUE) {
+ cee->get_stats_status = BFA_STATUS_FAILED;
+ cee->get_stats_pending = BFA_FALSE;
+ if (cee->cbfn.get_stats_cbfn) {
+ cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+ if (cee->reset_stats_pending == BFA_TRUE) {
+ cee->reset_stats_status = BFA_STATUS_FAILED;
+ cee->reset_stats_pending = BFA_FALSE;
+ if (cee->cbfn.reset_stats_cbfn) {
+ cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+}
+
+/**
+ * bfa_cee_attach()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ * ioc - Pointer to the ioc module data structure
+ * dev - Pointer to the device driver module data structure
+ * The device driver specific mbox ISR functions have
+ * this pointer as one of the parameters.
+ * trcmod -
+ * logmod -
+ *
+ * @return void
+ */
+void
+bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev,
+ struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod)
+{
+ bfa_assert(cee != NULL);
+ cee->dev = dev;
+ cee->trcmod = trcmod;
+ cee->logmod = logmod;
+ cee->ioc = ioc;
+
+ bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
+ bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee);
+ bfa_ioc_hbfail_register(cee->ioc, &cee->hbfail);
+ bfa_trc(cee, 0);
+}
+
+/**
+ * bfa_cee_detach()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ *
+ * @return void
+ */
+void
+bfa_cee_detach(struct bfa_cee_s *cee)
+{
+ /*
+ * For now, just check if there is some ioctl pending and mark that as
+ * failed?
+ */
+ /* bfa_cee_hbfail(cee); */
+}
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
new file mode 100644
index 000000000000..44e2d1155c51
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <defs/bfa_defs_pci.h>
+#include <cs/bfa_debug.h>
+#include <bfa_iocfc.h>
+
+#define DEF_CFG_NUM_FABRICS 1
+#define DEF_CFG_NUM_LPORTS 256
+#define DEF_CFG_NUM_CQS 4
+#define DEF_CFG_NUM_IOIM_REQS (BFA_IOIM_MAX)
+#define DEF_CFG_NUM_TSKIM_REQS 128
+#define DEF_CFG_NUM_FCXP_REQS 64
+#define DEF_CFG_NUM_UF_BUFS 64
+#define DEF_CFG_NUM_RPORTS 1024
+#define DEF_CFG_NUM_ITNIMS (DEF_CFG_NUM_RPORTS)
+#define DEF_CFG_NUM_TINS 256
+
+#define DEF_CFG_NUM_SGPGS 2048
+#define DEF_CFG_NUM_REQQ_ELEMS 256
+#define DEF_CFG_NUM_RSPQ_ELEMS 64
+#define DEF_CFG_NUM_SBOOT_TGTS 16
+#define DEF_CFG_NUM_SBOOT_LUNS 16
+
+/**
+ * Use this function query the memory requirement of the BFA library.
+ * This function needs to be called before bfa_attach() to get the
+ * memory required of the BFA layer for a given driver configuration.
+ *
+ * This call will fail, if the cap is out of range compared to pre-defined
+ * values within the BFA library
+ *
+ * @param[in] cfg - pointer to bfa_ioc_cfg_t. Driver layer should indicate
+ * its configuration in this structure.
+ * The default values for struct bfa_iocfc_cfg_s can be
+ * fetched using bfa_cfg_get_default() API.
+ *
+ * If cap's boundary check fails, the library will use
+ * the default bfa_cap_t values (and log a warning msg).
+ *
+ * @param[out] meminfo - pointer to bfa_meminfo_t. This content
+ * indicates the memory type (see bfa_mem_type_t) and
+ * amount of memory required.
+ *
+ * Driver should allocate the memory, populate the
+ * starting address for each block and provide the same
+ * structure as input parameter to bfa_attach() call.
+ *
+ * @return void
+ *
+ * Special Considerations: @note
+ */
+void
+bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
+{
+ int i;
+ u32 km_len = 0, dm_len = 0;
+
+ bfa_assert((cfg != NULL) && (meminfo != NULL));
+
+ bfa_os_memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
+ meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type =
+ BFA_MEM_TYPE_KVA;
+ meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type =
+ BFA_MEM_TYPE_DMA;
+
+ bfa_iocfc_meminfo(cfg, &km_len, &dm_len);
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->meminfo(cfg, &km_len, &dm_len);
+
+
+ meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len;
+ meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len;
+}
+
+/**
+ * Use this function to do attach the driver instance with the BFA
+ * library. This function will not trigger any HW initialization
+ * process (which will be done in bfa_init() call)
+ *
+ * This call will fail, if the cap is out of range compared to
+ * pre-defined values within the BFA library
+ *
+ * @param[out] bfa Pointer to bfa_t.
+ * @param[in] bfad Opaque handle back to the driver's IOC structure
+ * @param[in] cfg Pointer to bfa_ioc_cfg_t. Should be same structure
+ * that was used in bfa_cfg_get_meminfo().
+ * @param[in] meminfo Pointer to bfa_meminfo_t. The driver should
+ * use the bfa_cfg_get_meminfo() call to
+ * find the memory blocks required, allocate the
+ * required memory and provide the starting addresses.
+ * @param[in] pcidev pointer to struct bfa_pcidev_s
+ *
+ * @return
+ * void
+ *
+ * Special Considerations:
+ *
+ * @note
+ *
+ */
+void
+bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ int i;
+ struct bfa_mem_elem_s *melem;
+
+ bfa->fcs = BFA_FALSE;
+
+ bfa_assert((cfg != NULL) && (meminfo != NULL));
+
+ /**
+ * initialize all memory pointers for iterative allocation
+ */
+ for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
+ melem = meminfo->meminfo + i;
+ melem->kva_curp = melem->kva;
+ melem->dma_curp = melem->dma;
+ }
+
+ bfa_iocfc_attach(bfa, bfad, cfg, meminfo, pcidev);
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev);
+
+}
+
+/**
+ * Use this function to delete a BFA IOC. IOC should be stopped (by
+ * calling bfa_stop()) before this function call.
+ *
+ * @param[in] bfa - pointer to bfa_t.
+ *
+ * @return
+ * void
+ *
+ * Special Considerations:
+ *
+ * @note
+ */
+void
+bfa_detach(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->detach(bfa);
+
+ bfa_iocfc_detach(bfa);
+}
+
+
+void
+bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod)
+{
+ bfa->trcmod = trcmod;
+}
+
+
+void
+bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod)
+{
+ bfa->logm = logmod;
+}
+
+
+void
+bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen)
+{
+ bfa->aen = aen;
+}
+
+void
+bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog)
+{
+ bfa->plog = plog;
+}
+
+/**
+ * Initialize IOC.
+ *
+ * This function will return immediately, when the IOC initialization is
+ * completed, the bfa_cb_init() will be called.
+ *
+ * @param[in] bfa instance
+ *
+ * @return void
+ *
+ * Special Considerations:
+ *
+ * @note
+ * When this function returns, the driver should register the interrupt service
+ * routine(s) and enable the device interrupts. If this is not done,
+ * bfa_cb_init() will never get called
+ */
+void
+bfa_init(struct bfa_s *bfa)
+{
+ bfa_iocfc_init(bfa);
+}
+
+/**
+ * Use this function initiate the IOC configuration setup. This function
+ * will return immediately.
+ *
+ * @param[in] bfa instance
+ *
+ * @return None
+ */
+void
+bfa_start(struct bfa_s *bfa)
+{
+ bfa_iocfc_start(bfa);
+}
+
+/**
+ * Use this function quiese the IOC. This function will return immediately,
+ * when the IOC is actually stopped, the bfa_cb_stop() will be called.
+ *
+ * @param[in] bfa - pointer to bfa_t.
+ *
+ * @return None
+ *
+ * Special Considerations:
+ * bfa_cb_stop() could be called before or after bfa_stop() returns.
+ *
+ * @note
+ * In case of any failure, we could handle it automatically by doing a
+ * reset and then succeed the bfa_stop() call.
+ */
+void
+bfa_stop(struct bfa_s *bfa)
+{
+ bfa_iocfc_stop(bfa);
+}
+
+void
+bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q)
+{
+ INIT_LIST_HEAD(comp_q);
+ list_splice_tail_init(&bfa->comp_q, comp_q);
+}
+
+void
+bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q)
+{
+ struct list_head *qe;
+ struct list_head *qen;
+ struct bfa_cb_qe_s *hcb_qe;
+
+ list_for_each_safe(qe, qen, comp_q) {
+ hcb_qe = (struct bfa_cb_qe_s *) qe;
+ hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
+ }
+}
+
+void
+bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
+{
+ struct list_head *qe;
+ struct bfa_cb_qe_s *hcb_qe;
+
+ while (!list_empty(comp_q)) {
+ bfa_q_deq(comp_q, &qe);
+ hcb_qe = (struct bfa_cb_qe_s *) qe;
+ hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE);
+ }
+}
+
+void
+bfa_attach_fcs(struct bfa_s *bfa)
+{
+ bfa->fcs = BFA_TRUE;
+}
+
+/**
+ * Periodic timer heart beat from driver
+ */
+void
+bfa_timer_tick(struct bfa_s *bfa)
+{
+ bfa_timer_beat(&bfa->timer_mod);
+}
+
+#ifndef BFA_BIOS_BUILD
+/**
+ * Return the list of PCI vendor/device id lists supported by this
+ * BFA instance.
+ */
+void
+bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids)
+{
+ static struct bfa_pciid_s __pciids[] = {
+ {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P},
+ {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P},
+ {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT},
+ };
+
+ *npciids = sizeof(__pciids) / sizeof(__pciids[0]);
+ *pciids = __pciids;
+}
+
+/**
+ * Use this function query the default struct bfa_iocfc_cfg_s value (compiled
+ * into BFA layer). The OS driver can then turn back and overwrite entries that
+ * have been configured by the user.
+ *
+ * @param[in] cfg - pointer to bfa_ioc_cfg_t
+ *
+ * @return
+ * void
+ *
+ * Special Considerations:
+ * note
+ */
+void
+bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg)
+{
+ cfg->fwcfg.num_fabrics = DEF_CFG_NUM_FABRICS;
+ cfg->fwcfg.num_lports = DEF_CFG_NUM_LPORTS;
+ cfg->fwcfg.num_rports = DEF_CFG_NUM_RPORTS;
+ cfg->fwcfg.num_ioim_reqs = DEF_CFG_NUM_IOIM_REQS;
+ cfg->fwcfg.num_tskim_reqs = DEF_CFG_NUM_TSKIM_REQS;
+ cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS;
+ cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS;
+ cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS;
+
+ cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS;
+ cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS;
+ cfg->drvcfg.num_sgpgs = DEF_CFG_NUM_SGPGS;
+ cfg->drvcfg.num_sboot_tgts = DEF_CFG_NUM_SBOOT_TGTS;
+ cfg->drvcfg.num_sboot_luns = DEF_CFG_NUM_SBOOT_LUNS;
+ cfg->drvcfg.path_tov = BFA_FCPIM_PATHTOV_DEF;
+ cfg->drvcfg.ioc_recover = BFA_FALSE;
+ cfg->drvcfg.delay_comp = BFA_FALSE;
+
+}
+
+void
+bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg)
+{
+ bfa_cfg_get_default(cfg);
+ cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN;
+ cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN;
+ cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN;
+ cfg->fwcfg.num_uf_bufs = BFA_UF_MIN;
+ cfg->fwcfg.num_rports = BFA_RPORT_MIN;
+
+ cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
+ cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN;
+ cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN;
+ cfg->drvcfg.min_cfg = BFA_TRUE;
+}
+
+void
+bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr)
+{
+ bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
+}
+
+/**
+ * Retrieve firmware trace information on IOC failure.
+ */
+bfa_status_t
+bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
+{
+ return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen);
+}
+
+/**
+ * Fetch firmware trace data.
+ *
+ * @param[in] bfa BFA instance
+ * @param[out] trcdata Firmware trace buffer
+ * @param[in,out] trclen Firmware trace buffer len
+ *
+ * @retval BFA_STATUS_OK Firmware trace is fetched.
+ * @retval BFA_STATUS_INPROGRESS Firmware trace fetch is in progress.
+ */
+bfa_status_t
+bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
+{
+ return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
+}
+#endif
diff --git a/drivers/scsi/bfa/bfa_csdebug.c b/drivers/scsi/bfa/bfa_csdebug.c
new file mode 100644
index 000000000000..1b71d349451a
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_csdebug.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2005-2009 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 <cs/bfa_debug.h>
+#include <bfa_os_inc.h>
+#include <cs/bfa_q.h>
+#include <log/bfa_log_hal.h>
+
+/**
+ * cs_debug_api
+ */
+
+
+void
+bfa_panic(int line, char *file, char *panicstr)
+{
+ bfa_log(NULL, BFA_LOG_HAL_ASSERT, file, line, panicstr);
+ bfa_os_panic();
+}
+
+void
+bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event)
+{
+ bfa_log(logm, BFA_LOG_HAL_SM_ASSERT, file, line, event);
+ bfa_os_panic();
+}
+
+int
+bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
+{
+ struct list_head *tqe;
+
+ tqe = bfa_q_next(q);
+ while (tqe != q) {
+ if (tqe == qe)
+ return (1);
+ tqe = bfa_q_next(tqe);
+ if (tqe == NULL)
+ break;
+ }
+ return (0);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
new file mode 100644
index 000000000000..401babe3494e
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <log/bfa_log_hal.h>
+
+BFA_TRC_FILE(HAL, FCPIM);
+BFA_MODULE(fcpim);
+
+/**
+ * hal_fcpim_mod BFA FCP Initiator Mode module
+ */
+
+/**
+ * Compute and return memory needed by FCP(im) module.
+ */
+static void
+bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ bfa_itnim_meminfo(cfg, km_len, dm_len);
+
+ /**
+ * IO memory
+ */
+ if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN)
+ cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN;
+ else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX)
+ cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX;
+
+ *km_len += cfg->fwcfg.num_ioim_reqs *
+ (sizeof(struct bfa_ioim_s) + sizeof(struct bfa_ioim_sp_s));
+
+ *dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN;
+
+ /**
+ * task management command memory
+ */
+ if (cfg->fwcfg.num_tskim_reqs < BFA_TSKIM_MIN)
+ cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN;
+ *km_len += cfg->fwcfg.num_tskim_reqs * sizeof(struct bfa_tskim_s);
+}
+
+
+static void
+bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ bfa_trc(bfa, cfg->drvcfg.path_tov);
+ bfa_trc(bfa, cfg->fwcfg.num_rports);
+ bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs);
+ bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs);
+
+ fcpim->bfa = bfa;
+ fcpim->num_itnims = cfg->fwcfg.num_rports;
+ fcpim->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs;
+ fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs;
+ fcpim->path_tov = cfg->drvcfg.path_tov;
+ fcpim->delay_comp = cfg->drvcfg.delay_comp;
+
+ bfa_itnim_attach(fcpim, meminfo);
+ bfa_tskim_attach(fcpim, meminfo);
+ bfa_ioim_attach(fcpim, meminfo);
+}
+
+static void
+bfa_fcpim_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcpim_detach(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ bfa_ioim_detach(fcpim);
+ bfa_tskim_detach(fcpim);
+}
+
+static void
+bfa_fcpim_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcpim_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcpim_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_itnim_s *itnim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+ itnim = (struct bfa_itnim_s *) qe;
+ bfa_itnim_iocdisable(itnim);
+ }
+}
+
+void
+bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ fcpim->path_tov = path_tov * 1000;
+ if (fcpim->path_tov > BFA_FCPIM_PATHTOV_MAX)
+ fcpim->path_tov = BFA_FCPIM_PATHTOV_MAX;
+}
+
+u16
+bfa_fcpim_path_tov_get(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ return (fcpim->path_tov / 1000);
+}
+
+bfa_status_t
+bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_fcpim_stats_s *modstats)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ *modstats = fcpim->stats;
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcpim_clr_modstats(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ memset(&fcpim->stats, 0, sizeof(struct bfa_fcpim_stats_s));
+
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ bfa_assert(q_depth <= BFA_IOCFC_QDEPTH_MAX);
+
+ fcpim->q_depth = q_depth;
+}
+
+u16
+bfa_fcpim_qdepth_get(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ return (fcpim->q_depth);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h
new file mode 100644
index 000000000000..153206cfb37a
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcpim_priv.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCPIM_PRIV_H__
+#define __BFA_FCPIM_PRIV_H__
+
+#include <bfa_fcpim.h>
+#include <defs/bfa_defs_fcpim.h>
+#include <cs/bfa_wc.h>
+#include "bfa_sgpg_priv.h"
+
+#define BFA_ITNIM_MIN 32
+#define BFA_ITNIM_MAX 1024
+
+#define BFA_IOIM_MIN 8
+#define BFA_IOIM_MAX 2000
+
+#define BFA_TSKIM_MIN 4
+#define BFA_TSKIM_MAX 512
+#define BFA_FCPIM_PATHTOV_DEF (30 * 1000) /* in millisecs */
+#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */
+
+#define bfa_fcpim_stats(__fcpim, __stats) \
+ (__fcpim)->stats.__stats ++
+
+struct bfa_fcpim_mod_s {
+ struct bfa_s *bfa;
+ struct bfa_itnim_s *itnim_arr;
+ struct bfa_ioim_s *ioim_arr;
+ struct bfa_ioim_sp_s *ioim_sp_arr;
+ struct bfa_tskim_s *tskim_arr;
+ struct bfa_dma_s snsbase;
+ int num_itnims;
+ int num_ioim_reqs;
+ int num_tskim_reqs;
+ u32 path_tov;
+ u16 q_depth;
+ u16 rsvd;
+ struct list_head itnim_q; /* queue of active itnim */
+ struct list_head ioim_free_q; /* free IO resources */
+ struct list_head ioim_resfree_q; /* IOs waiting for f/w */
+ struct list_head ioim_comp_q; /* IO global comp Q */
+ struct list_head tskim_free_q;
+ u32 ios_active; /* current active IOs */
+ u32 delay_comp;
+ struct bfa_fcpim_stats_s stats;
+};
+
+struct bfa_ioim_s;
+struct bfa_tskim_s;
+
+/**
+ * BFA IO (initiator mode)
+ */
+struct bfa_ioim_s {
+ struct list_head qe; /* queue elememt */
+ bfa_sm_t sm; /* BFA ioim state machine */
+ struct bfa_s *bfa; /* BFA module */
+ struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
+ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
+ struct bfad_ioim_s *dio; /* driver IO handle */
+ u16 iotag; /* FWI IO tag */
+ u16 abort_tag; /* unqiue abort request tag */
+ u16 nsges; /* number of SG elements */
+ u16 nsgpgs; /* number of SG pages */
+ struct bfa_sgpg_s *sgpg; /* first SG page */
+ struct list_head sgpg_q; /* allocated SG pages */
+ struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
+ bfa_cb_cbfn_t io_cbfn; /* IO completion handler */
+ struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
+};
+
+struct bfa_ioim_sp_s {
+ struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */
+ u8 *snsinfo; /* sense info for this IO */
+ struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ bfa_boolean_t abort_explicit; /* aborted by OS */
+ struct bfa_tskim_s *tskim; /* Relevant TM cmd */
+};
+
+/**
+ * BFA Task management command (initiator mode)
+ */
+struct bfa_tskim_s {
+ struct list_head qe;
+ bfa_sm_t sm;
+ struct bfa_s *bfa; /* BFA module */
+ struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
+ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
+ struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */
+ bfa_boolean_t notify; /* notify itnim on TM comp */
+ lun_t lun; /* lun if applicable */
+ enum fcp_tm_cmnd tm_cmnd; /* task management command */
+ u16 tsk_tag; /* FWI IO tag */
+ u8 tsecs; /* timeout in seconds */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct list_head io_q; /* queue of affected IOs */
+ struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
+ enum bfi_tskim_status tsk_status; /* TM status */
+};
+
+/**
+ * BFA i-t-n (initiator mode)
+ */
+struct bfa_itnim_s {
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* i-t-n im BFA state machine */
+ struct bfa_s *bfa; /* bfa instance */
+ struct bfa_rport_s *rport; /* bfa rport */
+ void *ditn; /* driver i-t-n structure */
+ struct bfi_mhdr_s mhdr; /* pre-built mhdr */
+ u8 msg_no; /* itnim/rport firmware handle */
+ u8 reqq; /* CQ for requests */
+ struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
+ struct list_head pending_q; /* queue of pending IO requests*/
+ struct list_head io_q; /* queue of active IO requests */
+ struct list_head io_cleanup_q; /* IO being cleaned up */
+ struct list_head tsk_q; /* queue of active TM commands */
+ struct list_head delay_comp_q;/* queue of failed inflight cmds */
+ bfa_boolean_t seq_rec; /* SQER supported */
+ bfa_boolean_t is_online; /* itnim is ONLINE for IO */
+ bfa_boolean_t iotov_active; /* IO TOV timer is active */
+ struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_timer_s timer; /* pending IO TOV */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct bfa_fcpim_mod_s *fcpim; /* fcpim module */
+ struct bfa_itnim_hal_stats_s stats;
+};
+
+#define bfa_itnim_is_online(_itnim) (_itnim)->is_online
+#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod)
+#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \
+ (&fcpim->ioim_arr[_iotag])
+#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \
+ (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)])
+
+/*
+ * function prototypes
+ */
+void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim,
+ struct bfa_meminfo_s *minfo);
+void bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim);
+void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_ioim_good_comp_isr(struct bfa_s *bfa,
+ struct bfi_msg_s *msg);
+void bfa_ioim_cleanup(struct bfa_ioim_s *ioim);
+void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim,
+ struct bfa_tskim_s *tskim);
+void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim);
+void bfa_ioim_tov(struct bfa_ioim_s *ioim);
+
+void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim,
+ struct bfa_meminfo_s *minfo);
+void bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim);
+void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_tskim_iodone(struct bfa_tskim_s *tskim);
+void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim);
+void bfa_tskim_cleanup(struct bfa_tskim_s *tskim);
+
+void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len);
+void bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim,
+ struct bfa_meminfo_s *minfo);
+void bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim);
+void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim);
+void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_itnim_iodone(struct bfa_itnim_s *itnim);
+void bfa_itnim_tskdone(struct bfa_itnim_s *itnim);
+bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim);
+
+#endif /* __BFA_FCPIM_PRIV_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c
new file mode 100644
index 000000000000..992435987deb
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcport.c
@@ -0,0 +1,1671 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_pport.h>
+#include <cs/bfa_debug.h>
+#include <aen/bfa_aen.h>
+#include <cs/bfa_plog.h>
+#include <aen/bfa_aen_port.h>
+
+BFA_TRC_FILE(HAL, PPORT);
+BFA_MODULE(pport);
+
+#define bfa_pport_callback(__pport, __event) do { \
+ if ((__pport)->bfa->fcs) { \
+ (__pport)->event_cbfn((__pport)->event_cbarg, (__event)); \
+ } else { \
+ (__pport)->hcb_event = (__event); \
+ bfa_cb_queue((__pport)->bfa, &(__pport)->hcb_qe, \
+ __bfa_cb_port_event, (__pport)); \
+ } \
+} while (0)
+
+/*
+ * The port is considered disabled if corresponding physical port or IOC are
+ * disabled explicitly
+ */
+#define BFA_PORT_IS_DISABLED(bfa) \
+ ((bfa_pport_is_disabled(bfa) == BFA_TRUE) || \
+ (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))
+
+/*
+ * forward declarations
+ */
+static bfa_boolean_t bfa_pport_send_enable(struct bfa_pport_s *port);
+static bfa_boolean_t bfa_pport_send_disable(struct bfa_pport_s *port);
+static void bfa_pport_update_linkinfo(struct bfa_pport_s *pport);
+static void bfa_pport_reset_linkinfo(struct bfa_pport_s *pport);
+static void bfa_pport_set_wwns(struct bfa_pport_s *port);
+static void __bfa_cb_port_event(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete);
+static void bfa_port_stats_timeout(void *cbarg);
+static void bfa_port_stats_clr_timeout(void *cbarg);
+
+/**
+ * bfa_pport_private
+ */
+
+/**
+ * BFA port state machine events
+ */
+enum bfa_pport_sm_event {
+ BFA_PPORT_SM_START = 1, /* start port state machine */
+ BFA_PPORT_SM_STOP = 2, /* stop port state machine */
+ BFA_PPORT_SM_ENABLE = 3, /* enable port */
+ BFA_PPORT_SM_DISABLE = 4, /* disable port state machine */
+ BFA_PPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */
+ BFA_PPORT_SM_LINKUP = 6, /* firmware linkup event */
+ BFA_PPORT_SM_LINKDOWN = 7, /* firmware linkup down */
+ BFA_PPORT_SM_QRESUME = 8, /* CQ space available */
+ BFA_PPORT_SM_HWFAIL = 9, /* IOC h/w failure */
+};
+
+static void bfa_pport_sm_uninit(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_enabling(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_linkdown(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_linkup(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_disabling(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_disabled(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_stopped(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_iocdown(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_iocfail(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+
+static struct bfa_sm_table_s hal_pport_sm_table[] = {
+ {BFA_SM(bfa_pport_sm_uninit), BFA_PPORT_ST_UNINIT},
+ {BFA_SM(bfa_pport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT},
+ {BFA_SM(bfa_pport_sm_enabling), BFA_PPORT_ST_ENABLING},
+ {BFA_SM(bfa_pport_sm_linkdown), BFA_PPORT_ST_LINKDOWN},
+ {BFA_SM(bfa_pport_sm_linkup), BFA_PPORT_ST_LINKUP},
+ {BFA_SM(bfa_pport_sm_disabling_qwait),
+ BFA_PPORT_ST_DISABLING_QWAIT},
+ {BFA_SM(bfa_pport_sm_disabling), BFA_PPORT_ST_DISABLING},
+ {BFA_SM(bfa_pport_sm_disabled), BFA_PPORT_ST_DISABLED},
+ {BFA_SM(bfa_pport_sm_stopped), BFA_PPORT_ST_STOPPED},
+ {BFA_SM(bfa_pport_sm_iocdown), BFA_PPORT_ST_IOCDOWN},
+ {BFA_SM(bfa_pport_sm_iocfail), BFA_PPORT_ST_IOCDOWN},
+};
+
+static void
+bfa_pport_aen_post(struct bfa_pport_s *pport, enum bfa_port_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = pport->bfa->logm;
+ wwn_t pwwn = pport->pwwn;
+ char pwwn_ptr[BFA_STRING_32];
+ struct bfa_ioc_attr_s ioc_attr;
+
+ wwn2str(pwwn_ptr, pwwn);
+ switch (event) {
+ case BFA_PORT_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_PORT_ONLINE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_PORT_OFFLINE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_ENABLE:
+ bfa_log(logmod, BFA_AEN_PORT_ENABLE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_DISABLE:
+ bfa_log(logmod, BFA_AEN_PORT_DISABLE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_PORT_DISCONNECT, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_QOS_NEG:
+ bfa_log(logmod, BFA_AEN_PORT_QOS_NEG, pwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ bfa_ioc_get_attr(&pport->bfa->ioc, &ioc_attr);
+ aen_data.port.ioc_type = ioc_attr.ioc_type;
+ aen_data.port.pwwn = pwwn;
+}
+
+static void
+bfa_pport_sm_uninit(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ /**
+ * Start event after IOC is configured and BFA is started.
+ */
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Port is persistently configured to be in enabled state. Do
+ * not change state. Port enabling is done when START event is
+ * received.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * If a port is persistently configured to be disabled, the
+ * first event will a port disable request.
+ */
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_QRESUME:
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ bfa_pport_send_enable(pport);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already enable is in progress.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Just send disable request to firmware when room becomes
+ * available in request queue.
+ */
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link events when doing back-to-back
+ * enable/disables.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_enabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_FWRSP:
+ case BFA_PPORT_SM_LINKDOWN:
+ bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ bfa_pport_update_linkinfo(pport);
+ bfa_sm_set_state(pport, bfa_pport_sm_linkup);
+
+ bfa_assert(pport->event_cbfn);
+ bfa_pport_callback(pport, BFA_PPORT_LINKUP);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already being enabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ if (bfa_pport_send_disable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_linkdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_LINKUP:
+ bfa_pport_update_linkinfo(pport);
+ bfa_sm_set_state(pport, bfa_pport_sm_linkup);
+ bfa_assert(pport->event_cbfn);
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup");
+ bfa_pport_callback(pport, BFA_PPORT_LINKUP);
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_ONLINE);
+ /**
+ * If QoS is enabled and it is not online,
+ * Send a separate event.
+ */
+ if ((pport->cfg.qos_enabled)
+ && (bfa_os_ntohl(pport->qos_attr.state) != BFA_QOS_ONLINE))
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_QOS_NEG);
+
+ break;
+
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link down event.
+ */
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already enabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ if (bfa_pport_send_disable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_linkup(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already enabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ if (bfa_pport_send_disable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+
+ bfa_pport_reset_linkinfo(pport);
+ bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_LINKDOWN:
+ bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
+ bfa_pport_reset_linkinfo(pport);
+ bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
+ if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ } else {
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
+ }
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ bfa_pport_reset_linkinfo(pport);
+ if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ } else {
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
+ }
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ bfa_pport_reset_linkinfo(pport);
+ bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
+ if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ } else {
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
+ }
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_QRESUME:
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ bfa_pport_send_disable(pport);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Already being disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link events when doing back-to-back
+ * enable/disables.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_disabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_FWRSP:
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Already being disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link events when doing back-to-back
+ * enable/disables.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_disabled(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ /**
+ * Ignore start event for a port that is disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Already disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_stopped(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+ break;
+
+ default:
+ /**
+ * Ignore all other events.
+ */
+ ;
+ }
+}
+
+/**
+ * Port is enabled. IOC is down/failed.
+ */
+static void
+bfa_pport_sm_iocdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+ break;
+
+ default:
+ /**
+ * Ignore all events.
+ */
+ ;
+ }
+}
+
+/**
+ * Port is disabled. IOC is down/failed.
+ */
+static void
+bfa_pport_sm_iocfail(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ /**
+ * Ignore all events.
+ */
+ ;
+ }
+}
+
+
+
+/**
+ * bfa_pport_private
+ */
+
+static void
+__bfa_cb_port_event(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_pport_s *pport = cbarg;
+
+ if (complete)
+ pport->event_cbfn(pport->event_cbarg, pport->hcb_event);
+}
+
+#define PPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), \
+ BFA_CACHELINE_SZ))
+
+static void
+bfa_pport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
+ u32 *dm_len)
+{
+ *dm_len += PPORT_STATS_DMA_SZ;
+}
+
+static void
+bfa_pport_qresume(void *cbarg)
+{
+ struct bfa_pport_s *port = cbarg;
+
+ bfa_sm_send_event(port, BFA_PPORT_SM_QRESUME);
+}
+
+static void
+bfa_pport_mem_claim(struct bfa_pport_s *pport, struct bfa_meminfo_s *meminfo)
+{
+ u8 *dm_kva;
+ u64 dm_pa;
+
+ dm_kva = bfa_meminfo_dma_virt(meminfo);
+ dm_pa = bfa_meminfo_dma_phys(meminfo);
+
+ pport->stats_kva = dm_kva;
+ pport->stats_pa = dm_pa;
+ pport->stats = (union bfa_pport_stats_u *)dm_kva;
+
+ dm_kva += PPORT_STATS_DMA_SZ;
+ dm_pa += PPORT_STATS_DMA_SZ;
+
+ bfa_meminfo_dma_virt(meminfo) = dm_kva;
+ bfa_meminfo_dma_phys(meminfo) = dm_pa;
+}
+
+/**
+ * Memory initialization.
+ */
+static void
+bfa_pport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ struct bfa_pport_cfg_s *port_cfg = &pport->cfg;
+
+ bfa_os_memset(pport, 0, sizeof(struct bfa_pport_s));
+ pport->bfa = bfa;
+
+ bfa_pport_mem_claim(pport, meminfo);
+
+ bfa_sm_set_state(pport, bfa_pport_sm_uninit);
+
+ /**
+ * initialize and set default configuration
+ */
+ port_cfg->topology = BFA_PPORT_TOPOLOGY_P2P;
+ port_cfg->speed = BFA_PPORT_SPEED_AUTO;
+ port_cfg->trunked = BFA_FALSE;
+ port_cfg->maxfrsize = 0;
+
+ port_cfg->trl_def_speed = BFA_PPORT_SPEED_1GBPS;
+
+ bfa_reqq_winit(&pport->reqq_wait, bfa_pport_qresume, pport);
+}
+
+static void
+bfa_pport_initdone(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ /**
+ * Initialize port attributes from IOC hardware data.
+ */
+ bfa_pport_set_wwns(pport);
+ if (pport->cfg.maxfrsize == 0)
+ pport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
+ pport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
+ pport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
+
+ bfa_assert(pport->cfg.maxfrsize);
+ bfa_assert(pport->cfg.rx_bbcredit);
+ bfa_assert(pport->speed_sup);
+}
+
+static void
+bfa_pport_detach(struct bfa_s *bfa)
+{
+}
+
+/**
+ * Called when IOC is ready.
+ */
+static void
+bfa_pport_start(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_START);
+}
+
+/**
+ * Called before IOC is stopped.
+ */
+static void
+bfa_pport_stop(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_STOP);
+}
+
+/**
+ * Called when IOC failure is detected.
+ */
+static void
+bfa_pport_iocdisable(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_HWFAIL);
+}
+
+static void
+bfa_pport_update_linkinfo(struct bfa_pport_s *pport)
+{
+ struct bfi_pport_event_s *pevent = pport->event_arg.i2hmsg.event;
+
+ pport->speed = pevent->link_state.speed;
+ pport->topology = pevent->link_state.topology;
+
+ if (pport->topology == BFA_PPORT_TOPOLOGY_LOOP)
+ pport->myalpa = pevent->link_state.tl.loop_info.myalpa;
+
+ /*
+ * QoS Details
+ */
+ bfa_os_assign(pport->qos_attr, pevent->link_state.qos_attr);
+ bfa_os_assign(pport->qos_vc_attr, pevent->link_state.qos_vc_attr);
+
+ bfa_trc(pport->bfa, pport->speed);
+ bfa_trc(pport->bfa, pport->topology);
+}
+
+static void
+bfa_pport_reset_linkinfo(struct bfa_pport_s *pport)
+{
+ pport->speed = BFA_PPORT_SPEED_UNKNOWN;
+ pport->topology = BFA_PPORT_TOPOLOGY_NONE;
+}
+
+/**
+ * Send port enable message to firmware.
+ */
+static bfa_boolean_t
+bfa_pport_send_enable(struct bfa_pport_s *port)
+{
+ struct bfi_pport_enable_req_s *m;
+
+ /**
+ * Increment message tag before queue check, so that responses to old
+ * requests are discarded.
+ */
+ port->msgtag++;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+ if (!m) {
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_ENABLE_REQ,
+ bfa_lpuid(port->bfa));
+ m->nwwn = port->nwwn;
+ m->pwwn = port->pwwn;
+ m->port_cfg = port->cfg;
+ m->msgtag = port->msgtag;
+ m->port_cfg.maxfrsize = bfa_os_htons(port->cfg.maxfrsize);
+ bfa_dma_be_addr_set(m->stats_dma_addr, port->stats_pa);
+ bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_lo);
+ bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_hi);
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+ return BFA_TRUE;
+}
+
+/**
+ * Send port disable message to firmware.
+ */
+static bfa_boolean_t
+bfa_pport_send_disable(struct bfa_pport_s *port)
+{
+ bfi_pport_disable_req_t *m;
+
+ /**
+ * Increment message tag before queue check, so that responses to old
+ * requests are discarded.
+ */
+ port->msgtag++;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+ if (!m) {
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_DISABLE_REQ,
+ bfa_lpuid(port->bfa));
+ m->msgtag = port->msgtag;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+
+ return BFA_TRUE;
+}
+
+static void
+bfa_pport_set_wwns(struct bfa_pport_s *port)
+{
+ port->pwwn = bfa_ioc_get_pwwn(&port->bfa->ioc);
+ port->nwwn = bfa_ioc_get_nwwn(&port->bfa->ioc);
+
+ bfa_trc(port->bfa, port->pwwn);
+ bfa_trc(port->bfa, port->nwwn);
+}
+
+static void
+bfa_port_send_txcredit(void *port_cbarg)
+{
+
+ struct bfa_pport_s *port = port_cbarg;
+ struct bfi_pport_set_svc_params_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+ if (!m) {
+ bfa_trc(port->bfa, port->cfg.tx_bbcredit);
+ return;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_SET_SVC_PARAMS_REQ,
+ bfa_lpuid(port->bfa));
+ m->tx_bbcredit = bfa_os_htons((u16) port->cfg.tx_bbcredit);
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+}
+
+
+
+/**
+ * bfa_pport_public
+ */
+
+/**
+ * Firmware message handler.
+ */
+void
+bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ union bfi_pport_i2h_msg_u i2hmsg;
+
+ i2hmsg.msg = msg;
+ pport->event_arg.i2hmsg = i2hmsg;
+
+ switch (msg->mhdr.msg_id) {
+ case BFI_PPORT_I2H_ENABLE_RSP:
+ if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
+ bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
+ break;
+
+ case BFI_PPORT_I2H_DISABLE_RSP:
+ if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
+ bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
+ break;
+
+ case BFI_PPORT_I2H_EVENT:
+ switch (i2hmsg.event->link_state.linkstate) {
+ case BFA_PPORT_LINKUP:
+ bfa_sm_send_event(pport, BFA_PPORT_SM_LINKUP);
+ break;
+ case BFA_PPORT_LINKDOWN:
+ bfa_sm_send_event(pport, BFA_PPORT_SM_LINKDOWN);
+ break;
+ case BFA_PPORT_TRUNK_LINKDOWN:
+ /** todo: event notification */
+ break;
+ }
+ break;
+
+ case BFI_PPORT_I2H_GET_STATS_RSP:
+ case BFI_PPORT_I2H_GET_QOS_STATS_RSP:
+ /*
+ * check for timer pop before processing the rsp
+ */
+ if (pport->stats_busy == BFA_FALSE
+ || pport->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&pport->timer);
+ pport->stats_status = i2hmsg.getstats_rsp->status;
+ bfa_cb_queue(pport->bfa, &pport->hcb_qe, __bfa_cb_port_stats,
+ pport);
+ break;
+ case BFI_PPORT_I2H_CLEAR_STATS_RSP:
+ case BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP:
+ /*
+ * check for timer pop before processing the rsp
+ */
+ if (pport->stats_busy == BFA_FALSE
+ || pport->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&pport->timer);
+ pport->stats_status = BFA_STATUS_OK;
+ bfa_cb_queue(pport->bfa, &pport->hcb_qe,
+ __bfa_cb_port_stats_clr, pport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_pport_api
+ */
+
+/**
+ * Registered callback for port events.
+ */
+void
+bfa_pport_event_register(struct bfa_s *bfa,
+ void (*cbfn) (void *cbarg, bfa_pport_event_t event),
+ void *cbarg)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ pport->event_cbfn = cbfn;
+ pport->event_cbarg = cbarg;
+}
+
+bfa_status_t
+bfa_pport_enable(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ if (pport->diag_busy)
+ return (BFA_STATUS_DIAG_BUSY);
+ else if (bfa_sm_cmp_state
+ (BFA_PORT_MOD(bfa), bfa_pport_sm_disabling_qwait))
+ return (BFA_STATUS_DEVBUSY);
+
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_ENABLE);
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_pport_disable(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_DISABLE);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Configure port speed.
+ */
+bfa_status_t
+bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, speed);
+
+ if ((speed != BFA_PPORT_SPEED_AUTO) && (speed > pport->speed_sup)) {
+ bfa_trc(bfa, pport->speed_sup);
+ return BFA_STATUS_UNSUPP_SPEED;
+ }
+
+ pport->cfg.speed = speed;
+
+ return (BFA_STATUS_OK);
+}
+
+/**
+ * Get current speed.
+ */
+enum bfa_pport_speed
+bfa_pport_get_speed(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->speed;
+}
+
+/**
+ * Configure port topology.
+ */
+bfa_status_t
+bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, topology);
+ bfa_trc(bfa, pport->cfg.topology);
+
+ switch (topology) {
+ case BFA_PPORT_TOPOLOGY_P2P:
+ case BFA_PPORT_TOPOLOGY_LOOP:
+ case BFA_PPORT_TOPOLOGY_AUTO:
+ break;
+
+ default:
+ return BFA_STATUS_EINVAL;
+ }
+
+ pport->cfg.topology = topology;
+ return (BFA_STATUS_OK);
+}
+
+/**
+ * Get current topology.
+ */
+enum bfa_pport_topology
+bfa_pport_get_topology(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->topology;
+}
+
+bfa_status_t
+bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, alpa);
+ bfa_trc(bfa, pport->cfg.cfg_hardalpa);
+ bfa_trc(bfa, pport->cfg.hardalpa);
+
+ pport->cfg.cfg_hardalpa = BFA_TRUE;
+ pport->cfg.hardalpa = alpa;
+
+ return (BFA_STATUS_OK);
+}
+
+bfa_status_t
+bfa_pport_clr_hardalpa(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, pport->cfg.cfg_hardalpa);
+ bfa_trc(bfa, pport->cfg.hardalpa);
+
+ pport->cfg.cfg_hardalpa = BFA_FALSE;
+ return (BFA_STATUS_OK);
+}
+
+bfa_boolean_t
+bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ *alpa = port->cfg.hardalpa;
+ return port->cfg.cfg_hardalpa;
+}
+
+u8
+bfa_pport_get_myalpa(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->myalpa;
+}
+
+bfa_status_t
+bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, maxfrsize);
+ bfa_trc(bfa, pport->cfg.maxfrsize);
+
+ /*
+ * with in range
+ */
+ if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ))
+ return (BFA_STATUS_INVLD_DFSZ);
+
+ /*
+ * power of 2, if not the max frame size of 2112
+ */
+ if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1)))
+ return (BFA_STATUS_INVLD_DFSZ);
+
+ pport->cfg.maxfrsize = maxfrsize;
+ return (BFA_STATUS_OK);
+}
+
+u16
+bfa_pport_get_maxfrsize(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->cfg.maxfrsize;
+}
+
+u32
+bfa_pport_mypid(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->mypid;
+}
+
+u8
+bfa_pport_get_rx_bbcredit(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->cfg.rx_bbcredit;
+}
+
+void
+bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ port->cfg.tx_bbcredit = (u8) tx_bbcredit;
+ bfa_port_send_txcredit(port);
+}
+
+/**
+ * Get port attributes.
+ */
+
+wwn_t
+bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ if (node)
+ return pport->nwwn;
+ else
+ return pport->pwwn;
+}
+
+void
+bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s));
+
+ attr->nwwn = pport->nwwn;
+ attr->pwwn = pport->pwwn;
+
+ bfa_os_memcpy(&attr->pport_cfg, &pport->cfg,
+ sizeof(struct bfa_pport_cfg_s));
+ /*
+ * speed attributes
+ */
+ attr->pport_cfg.speed = pport->cfg.speed;
+ attr->speed_supported = pport->speed_sup;
+ attr->speed = pport->speed;
+ attr->cos_supported = FC_CLASS_3;
+
+ /*
+ * topology attributes
+ */
+ attr->pport_cfg.topology = pport->cfg.topology;
+ attr->topology = pport->topology;
+
+ /*
+ * beacon attributes
+ */
+ attr->beacon = pport->beacon;
+ attr->link_e2e_beacon = pport->link_e2e_beacon;
+ attr->plog_enabled = bfa_plog_get_setting(pport->bfa->plog);
+
+ attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
+ attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa);
+ attr->port_state = bfa_sm_to_state(hal_pport_sm_table, pport->sm);
+ if (bfa_ioc_is_disabled(&pport->bfa->ioc))
+ attr->port_state = BFA_PPORT_ST_IOCDIS;
+ else if (bfa_ioc_fw_mismatch(&pport->bfa->ioc))
+ attr->port_state = BFA_PPORT_ST_FWMISMATCH;
+}
+
+static void
+bfa_port_stats_query(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+ bfi_pport_get_stats_req_t *msg;
+
+ msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+
+ if (!msg) {
+ port->stats_qfull = BFA_TRUE;
+ bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_query,
+ port);
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
+ return;
+ }
+ port->stats_qfull = BFA_FALSE;
+
+ bfa_os_memset(msg, 0, sizeof(bfi_pport_get_stats_req_t));
+ bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_GET_STATS_REQ,
+ bfa_lpuid(port->bfa));
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+
+ return;
+}
+
+static void
+bfa_port_stats_clear(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+ bfi_pport_clear_stats_req_t *msg;
+
+ msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+
+ if (!msg) {
+ port->stats_qfull = BFA_TRUE;
+ bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_clear,
+ port);
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
+ return;
+ }
+ port->stats_qfull = BFA_FALSE;
+
+ bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_stats_req_t));
+ bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_STATS_REQ,
+ bfa_lpuid(port->bfa));
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+ return;
+}
+
+static void
+bfa_port_qos_stats_clear(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+ bfi_pport_clear_qos_stats_req_t *msg;
+
+ msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+
+ if (!msg) {
+ port->stats_qfull = BFA_TRUE;
+ bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_qos_stats_clear,
+ port);
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
+ return;
+ }
+ port->stats_qfull = BFA_FALSE;
+
+ bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_qos_stats_req_t));
+ bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ,
+ bfa_lpuid(port->bfa));
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+ return;
+}
+
+static void
+bfa_pport_stats_swap(union bfa_pport_stats_u *d, union bfa_pport_stats_u *s)
+{
+ u32 *dip = (u32 *) d;
+ u32 *sip = (u32 *) s;
+ int i;
+
+ /*
+ * Do 64 bit fields swap first
+ */
+ for (i = 0;
+ i <
+ ((sizeof(union bfa_pport_stats_u) -
+ sizeof(struct bfa_qos_stats_s)) / sizeof(u32)); i = i + 2) {
+#ifdef __BIGENDIAN
+ dip[i] = bfa_os_ntohl(sip[i]);
+ dip[i + 1] = bfa_os_ntohl(sip[i + 1]);
+#else
+ dip[i] = bfa_os_ntohl(sip[i + 1]);
+ dip[i + 1] = bfa_os_ntohl(sip[i]);
+#endif
+ }
+
+ /*
+ * Now swap the 32 bit fields
+ */
+ for (; i < (sizeof(union bfa_pport_stats_u) / sizeof(u32)); ++i)
+ dip[i] = bfa_os_ntohl(sip[i]);
+}
+
+static void
+__bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_pport_s *port = cbarg;
+
+ if (complete) {
+ port->stats_cbfn(port->stats_cbarg, port->stats_status);
+ } else {
+ port->stats_busy = BFA_FALSE;
+ port->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_port_stats_clr_timeout(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+
+ bfa_trc(port->bfa, port->stats_qfull);
+
+ if (port->stats_qfull) {
+ bfa_reqq_wcancel(&port->stats_reqq_wait);
+ port->stats_qfull = BFA_FALSE;
+ }
+
+ port->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats_clr, port);
+}
+
+static void
+__bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_pport_s *port = cbarg;
+
+ if (complete) {
+ if (port->stats_status == BFA_STATUS_OK)
+ bfa_pport_stats_swap(port->stats_ret, port->stats);
+ port->stats_cbfn(port->stats_cbarg, port->stats_status);
+ } else {
+ port->stats_busy = BFA_FALSE;
+ port->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_port_stats_timeout(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+
+ bfa_trc(port->bfa, port->stats_qfull);
+
+ if (port->stats_qfull) {
+ bfa_reqq_wcancel(&port->stats_reqq_wait);
+ port->stats_qfull = BFA_FALSE;
+ }
+
+ port->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats, port);
+}
+
+#define BFA_PORT_STATS_TOV 1000
+
+/**
+ * Fetch port attributes.
+ */
+bfa_status_t
+bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ if (port->stats_busy) {
+ bfa_trc(bfa, port->stats_busy);
+ return (BFA_STATUS_DEVBUSY);
+ }
+
+ port->stats_busy = BFA_TRUE;
+ port->stats_ret = stats;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+
+ bfa_port_stats_query(port);
+
+ bfa_timer_start(bfa, &port->timer, bfa_port_stats_timeout, port,
+ BFA_PORT_STATS_TOV);
+ return (BFA_STATUS_OK);
+}
+
+bfa_status_t
+bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ if (port->stats_busy) {
+ bfa_trc(bfa, port->stats_busy);
+ return (BFA_STATUS_DEVBUSY);
+ }
+
+ port->stats_busy = BFA_TRUE;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+
+ bfa_port_stats_clear(port);
+
+ bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
+ BFA_PORT_STATS_TOV);
+ return (BFA_STATUS_OK);
+}
+
+bfa_status_t
+bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, bitmap);
+ bfa_trc(bfa, pport->cfg.trunked);
+ bfa_trc(bfa, pport->cfg.trunk_ports);
+
+ if (!bitmap || (bitmap & (bitmap - 1)))
+ return BFA_STATUS_EINVAL;
+
+ pport->cfg.trunked = BFA_TRUE;
+ pport->cfg.trunk_ports = bitmap;
+
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ qos_attr->state = bfa_os_ntohl(pport->qos_attr.state);
+ qos_attr->total_bb_cr = bfa_os_ntohl(pport->qos_attr.total_bb_cr);
+}
+
+void
+bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
+ struct bfa_qos_vc_attr_s *qos_vc_attr)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ struct bfa_qos_vc_attr_s *bfa_vc_attr = &pport->qos_vc_attr;
+ u32 i = 0;
+
+ qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count);
+ qos_vc_attr->shared_credit = bfa_os_ntohs(bfa_vc_attr->shared_credit);
+ qos_vc_attr->elp_opmode_flags =
+ bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags);
+
+ /*
+ * Individual VC info
+ */
+ while (i < qos_vc_attr->total_vc_count) {
+ qos_vc_attr->vc_info[i].vc_credit =
+ bfa_vc_attr->vc_info[i].vc_credit;
+ qos_vc_attr->vc_info[i].borrow_credit =
+ bfa_vc_attr->vc_info[i].borrow_credit;
+ qos_vc_attr->vc_info[i].priority =
+ bfa_vc_attr->vc_info[i].priority;
+ ++i;
+ }
+}
+
+/**
+ * Fetch QoS Stats.
+ */
+bfa_status_t
+bfa_pport_get_qos_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg)
+{
+ /*
+ * QoS stats is embedded in port stats
+ */
+ return (bfa_pport_get_stats(bfa, stats, cbfn, cbarg));
+}
+
+bfa_status_t
+bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ if (port->stats_busy) {
+ bfa_trc(bfa, port->stats_busy);
+ return (BFA_STATUS_DEVBUSY);
+ }
+
+ port->stats_busy = BFA_TRUE;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+
+ bfa_port_qos_stats_clear(port);
+
+ bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
+ BFA_PORT_STATS_TOV);
+ return (BFA_STATUS_OK);
+}
+
+/**
+ * Fetch port attributes.
+ */
+bfa_status_t
+bfa_pport_trunk_disable(struct bfa_s *bfa)
+{
+ return (BFA_STATUS_OK);
+}
+
+bfa_boolean_t
+bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ *bitmap = port->cfg.trunk_ports;
+ return port->cfg.trunked;
+}
+
+bfa_boolean_t
+bfa_pport_is_disabled(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return (bfa_sm_to_state(hal_pport_sm_table, port->sm) ==
+ BFA_PPORT_ST_DISABLED);
+
+}
+
+bfa_boolean_t
+bfa_pport_is_ratelim(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+return (pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE);
+
+}
+
+void
+bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, on_off);
+ bfa_trc(bfa, pport->cfg.qos_enabled);
+
+ pport->cfg.qos_enabled = on_off;
+}
+
+void
+bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, on_off);
+ bfa_trc(bfa, pport->cfg.ratelimit);
+
+ pport->cfg.ratelimit = on_off;
+ if (pport->cfg.trl_def_speed == BFA_PPORT_SPEED_UNKNOWN)
+ pport->cfg.trl_def_speed = BFA_PPORT_SPEED_1GBPS;
+}
+
+/**
+ * Configure default minimum ratelim speed
+ */
+bfa_status_t
+bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, speed);
+
+ /*
+ * Auto and speeds greater than the supported speed, are invalid
+ */
+ if ((speed == BFA_PPORT_SPEED_AUTO) || (speed > pport->speed_sup)) {
+ bfa_trc(bfa, pport->speed_sup);
+ return BFA_STATUS_UNSUPP_SPEED;
+ }
+
+ pport->cfg.trl_def_speed = speed;
+
+ return (BFA_STATUS_OK);
+}
+
+/**
+ * Get default minimum ratelim speed
+ */
+enum bfa_pport_speed
+bfa_pport_get_ratelim_speed(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, pport->cfg.trl_def_speed);
+ return (pport->cfg.trl_def_speed);
+
+}
+
+void
+bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, status);
+ bfa_trc(bfa, pport->diag_busy);
+
+ pport->diag_busy = status;
+}
+
+void
+bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
+ bfa_boolean_t link_e2e_beacon)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, beacon);
+ bfa_trc(bfa, link_e2e_beacon);
+ bfa_trc(bfa, pport->beacon);
+ bfa_trc(bfa, pport->link_e2e_beacon);
+
+ pport->beacon = beacon;
+ pport->link_e2e_beacon = link_e2e_beacon;
+}
+
+bfa_boolean_t
+bfa_pport_is_linkup(struct bfa_s *bfa)
+{
+ return bfa_sm_cmp_state(BFA_PORT_MOD(bfa), bfa_pport_sm_linkup);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
new file mode 100644
index 000000000000..7cb39a306ea9
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs.c BFA FCS main
+ */
+
+#include <fcs/bfa_fcs.h>
+#include "fcs_port.h"
+#include "fcs_uf.h"
+#include "fcs_vport.h"
+#include "fcs_rport.h"
+#include "fcs_fabric.h"
+#include "fcs_fcpim.h"
+#include "fcs_fcptm.h"
+#include "fcbuild.h"
+#include "fcs.h"
+#include "bfad_drv.h"
+#include <fcb/bfa_fcb.h>
+
+/**
+ * FCS sub-modules
+ */
+struct bfa_fcs_mod_s {
+ void (*modinit) (struct bfa_fcs_s *fcs);
+ void (*modexit) (struct bfa_fcs_s *fcs);
+};
+
+#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit }
+
+static struct bfa_fcs_mod_s fcs_modules[] = {
+ BFA_FCS_MODULE(bfa_fcs_pport),
+ BFA_FCS_MODULE(bfa_fcs_uf),
+ BFA_FCS_MODULE(bfa_fcs_fabric),
+ BFA_FCS_MODULE(bfa_fcs_vport),
+ BFA_FCS_MODULE(bfa_fcs_rport),
+ BFA_FCS_MODULE(bfa_fcs_fcpim),
+};
+
+/**
+ * fcs_api BFA FCS API
+ */
+
+static void
+bfa_fcs_exit_comp(void *fcs_cbarg)
+{
+ struct bfa_fcs_s *fcs = fcs_cbarg;
+ struct bfad_s *bfad = fcs->bfad;
+
+ complete(&bfad->comp);
+}
+
+
+
+/**
+ * fcs_api BFA FCS API
+ */
+
+/**
+ * FCS instance initialization.
+ *
+ * param[in] fcs FCS instance
+ * param[in] bfa BFA instance
+ * param[in] bfad BFA driver instance
+ *
+ * return None
+ */
+void
+bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
+ bfa_boolean_t min_cfg)
+{
+ int i;
+ struct bfa_fcs_mod_s *mod;
+
+ fcs->bfa = bfa;
+ fcs->bfad = bfad;
+ fcs->min_cfg = min_cfg;
+
+ bfa_attach_fcs(bfa);
+ fcbuild_init();
+
+ for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
+ mod = &fcs_modules[i];
+ mod->modinit(fcs);
+ }
+}
+
+/**
+ * Start FCS operations.
+ */
+void
+bfa_fcs_start(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_fabric_modstart(fcs);
+}
+
+/**
+ * FCS driver details initialization.
+ *
+ * param[in] fcs FCS instance
+ * param[in] driver_info Driver Details
+ *
+ * return None
+ */
+void
+bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
+ struct bfa_fcs_driver_info_s *driver_info)
+{
+
+ fcs->driver_info = *driver_info;
+
+ bfa_fcs_fabric_psymb_init(&fcs->fabric);
+}
+
+/**
+ * FCS instance cleanup and exit.
+ *
+ * param[in] fcs FCS instance
+ * return None
+ */
+void
+bfa_fcs_exit(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_mod_s *mod;
+ int nmods, i;
+
+ bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs);
+
+ nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]);
+
+ for (i = 0; i < nmods; i++) {
+ bfa_wc_up(&fcs->wc);
+
+ mod = &fcs_modules[i];
+ mod->modexit(fcs);
+ }
+
+ bfa_wc_wait(&fcs->wc);
+}
+
+
+void
+bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod)
+{
+ fcs->trcmod = trcmod;
+}
+
+
+void
+bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod)
+{
+ fcs->logm = logmod;
+}
+
+
+void
+bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen)
+{
+ fcs->aen = aen;
+}
+
+void
+bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs)
+{
+ bfa_wc_down(&fcs->wc);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
new file mode 100644
index 000000000000..8975ed041dc0
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -0,0 +1,940 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_port.c BFA FCS port
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <fcb/bfa_fcb_port.h>
+#include <bfa_svc.h>
+#include <log/bfa_log_fcs.h>
+#include "fcs.h"
+#include "fcs_lport.h"
+#include "fcs_vport.h"
+#include "fcs_rport.h"
+#include "fcs_fcxp.h"
+#include "fcs_trcmod.h"
+#include "lport_priv.h"
+#include <aen/bfa_aen_lport.h>
+
+BFA_TRC_FILE(FCS, PORT);
+
+/**
+ * Forward declarations
+ */
+
+static void bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
+ enum bfa_lport_aen_event event);
+static void bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs, u8 reason_code,
+ u8 reason_code_expl);
+static void bfa_fcs_port_plogi(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi);
+static void bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_deleted(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_echo(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs,
+ struct fc_echo_s *echo, u16 len);
+static void bfa_fcs_port_rnid(struct bfa_fcs_port_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_port_s *port,
+ struct fc_rnid_general_topology_data_s *gen_topo_data);
+
+static struct {
+ void (*init) (struct bfa_fcs_port_s *port);
+ void (*online) (struct bfa_fcs_port_s *port);
+ void (*offline) (struct bfa_fcs_port_s *port);
+} __port_action[] = {
+ {
+ bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online,
+ bfa_fcs_port_unknown_offline}, {
+ bfa_fcs_port_fab_init, bfa_fcs_port_fab_online,
+ bfa_fcs_port_fab_offline}, {
+ bfa_fcs_port_loop_init, bfa_fcs_port_loop_online,
+ bfa_fcs_port_loop_offline}, {
+bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online,
+ bfa_fcs_port_n2n_offline},};
+
+/**
+ * fcs_port_sm FCS logical port state machine
+ */
+
+enum bfa_fcs_port_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,
+};
+
+static void bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+
+static void
+bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_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_port_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_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_port_sm_online);
+ bfa_fcs_port_online_actions(port);
+ break;
+
+ case BFA_FCS_PORT_SM_DELETE:
+ bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_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_port_sm_offline);
+ bfa_fcs_port_offline_actions(port);
+ 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_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ } else {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
+ list_for_each_safe(qe, qen, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ bfa_fcs_rport_delete(rport);
+ }
+ }
+ break;
+
+ case BFA_FCS_PORT_SM_DELRPORT:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_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_port_sm_online);
+ bfa_fcs_port_online_actions(port);
+ break;
+
+ case BFA_FCS_PORT_SM_DELETE:
+ if (port->num_rports == 0) {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ } else {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
+ list_for_each_safe(qe, qen, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ bfa_fcs_rport_delete(rport);
+ }
+ }
+ break;
+
+ case BFA_FCS_PORT_SM_DELRPORT:
+ case BFA_FCS_PORT_SM_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_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_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ }
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_port_pvt
+ */
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
+ enum bfa_lport_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = port->fcs->logm;
+ enum bfa_port_role role = port->port_cfg.roles;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(port);
+ char lpwwn_ptr[BFA_STRING_32];
+ char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] =
+ { "Initiator", "Target", "IPFC" };
+
+ wwn2str(lpwwn_ptr, lpwwn);
+
+ bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
+
+ switch (event) {
+ case BFA_LPORT_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_NEW:
+ bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_DELETE:
+ bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.lport.vf_id = port->fabric->vf_id;
+ aen_data.lport.roles = role;
+ aen_data.lport.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
+ aen_data.lport.lpwwn = lpwwn;
+}
+
+/*
+ * Send a LS reject
+ */
+static void
+bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_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->s_id);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_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_port_plogi(struct bfa_fcs_port_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_port_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_port_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_port_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;
+ }
+
+ /**
+ * First, check if we know the device by pwwn.
+ */
+ rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name);
+ if (rport) {
+ /**
+ * Direct Attach P2P mode: handle address assigned by the rport.
+ */
+ if ((!bfa_fcs_fabric_is_switched(port->fabric))
+ &&
+ (memcmp
+ ((void *)&bfa_fcs_port_get_pwwn(port),
+ (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
+ port->pid = 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_port_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.
+ */
+ bfa_assert(rport->pwwn != plogi->port_name);
+ bfa_fcs_rport_logo_imp(rport);
+
+ /**
+ * Inbound PLOGI from a new device (with old PID).
+ */
+ bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
+ return;
+ }
+
+ /**
+ * PLOGI crossing each other.
+ */
+ bfa_assert(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_port_echo(struct bfa_fcs_port_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);
+ bfa_trc(port->fcs, rx_len);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_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, 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_port_rnid(struct bfa_fcs_port_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);
+ 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_port_get_pwwn(port);
+ common_id_data.node_name = bfa_fcs_port_get_nwwn(port);
+
+ len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_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);
+
+ return;
+}
+
+/*
+ * Fill out General Topolpgy Discovery Data for RNID ELS.
+ */
+static void
+bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
+ struct fc_rnid_general_topology_data_s *gen_topo_data)
+{
+
+ bfa_os_memset(gen_topo_data, 0,
+ sizeof(struct fc_rnid_general_topology_data_s));
+
+ gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST);
+ gen_topo_data->phy_port_num = 0; /* @todo */
+ gen_topo_data->num_attached_nodes = bfa_os_htonl(1);
+}
+
+static void
+bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port)
+{
+ bfa_trc(port->fcs, port->fabric->oper_type);
+
+ __port_action[port->fabric->fab_type].init(port);
+ __port_action[port->fabric->fab_type].online(port);
+
+ bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE);
+ bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles,
+ port->fabric->vf_drv, (port->vport == NULL) ?
+ NULL : port->vport->vport_drv);
+}
+
+static void
+bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port)
+{
+ struct list_head *qe, *qen;
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, port->fabric->oper_type);
+
+ __port_action[port->fabric->fab_type].offline(port);
+
+ if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) {
+ bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
+ } else {
+ bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE);
+ }
+ bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles,
+ port->fabric->vf_drv,
+ (port->vport == NULL) ? NULL : port->vport->vport_drv);
+
+ list_for_each_safe(qe, qen, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ bfa_fcs_rport_offline(rport);
+ }
+}
+
+static void
+bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port)
+{
+ bfa_assert(0);
+}
+
+static void
+bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port)
+{
+ bfa_assert(0);
+}
+
+static void
+bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port)
+{
+ bfa_assert(0);
+}
+
+static void
+bfa_fcs_port_deleted(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE);
+
+ /*
+ * Base port will be deleted by the OS driver
+ */
+ if (port->vport) {
+ bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles,
+ port->fabric->vf_drv,
+ port->vport ? port->vport->vport_drv : NULL);
+ bfa_fcs_vport_delete_comp(port->vport);
+ } else {
+ bfa_fcs_fabric_port_delete_comp(port->fabric);
+ }
+}
+
+
+
+/**
+ * fcs_lport_api BFA FCS port API
+ */
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_port_modinit(struct bfa_fcs_s *fcs)
+{
+
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_port_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+/**
+ * Unsolicited frame receive handling.
+ */
+void
+bfa_fcs_port_uf_recv(struct bfa_fcs_port_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);
+
+ if (!bfa_fcs_port_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_port_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_port_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_port_rnid(lport, fchs,
+ (struct fc_rnid_cmd_s *) els_cmd, len);
+ return;
+ }
+
+ /**
+ * look for a matching remote port ID
+ */
+ rport = bfa_fcs_port_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->type);
+ bfa_assert(0);
+ return;
+ }
+
+ bfa_trc(lport->fcs, els_cmd->els_code);
+ if (els_cmd->els_code == FC_ELS_RSCN) {
+ bfa_fcs_port_scn_process_rscn(lport, fchs, len);
+ return;
+ }
+
+ if (els_cmd->els_code == FC_ELS_LOGO) {
+ /**
+ * @todo Handle LOGO frames received.
+ */
+ bfa_trc(lport->fcs, els_cmd->els_code);
+ return;
+ }
+
+ if (els_cmd->els_code == FC_ELS_PRLI) {
+ /**
+ * @todo Handle PRLI frames received.
+ */
+ bfa_trc(lport->fcs, els_cmd->els_code);
+ return;
+ }
+
+ /**
+ * Unhandled ELS frames. Send a LS_RJT.
+ */
+ bfa_fcs_port_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_port_get_rport_by_pid(struct bfa_fcs_port_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;
+}
+
+/**
+ * PWWN based Lookup for a R-Port in the Port R-Port Queue
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_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_port_get_rport_by_nwwn(struct bfa_fcs_port_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);
+}
+
+/**
+ * Called by rport module when new rports are discovered.
+ */
+void
+bfa_fcs_port_add_rport(struct bfa_fcs_port_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_port_del_rport(struct bfa_fcs_port_s *port,
+ struct bfa_fcs_rport_s *rport)
+{
+ bfa_assert(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_port_online(struct bfa_fcs_port_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_port_offline(struct bfa_fcs_port_s *port)
+{
+ bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
+}
+
+/**
+ * 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_port_delete(struct bfa_fcs_port_s *port)
+{
+ bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
+}
+
+/**
+ * Called by fabric in private loop topology to process LIP event.
+ */
+void
+bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Return TRUE if port is online, else return FALSE
+ */
+bfa_boolean_t
+bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
+{
+ return (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online));
+}
+
+/**
+ * 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_port_s *lport, struct bfa_fcs_s *fcs,
+ u16 vf_id, struct bfa_port_cfg_s *port_cfg,
+ struct bfa_fcs_vport_s *vport)
+{
+ lport->fcs = fcs;
+ lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
+ bfa_os_assign(lport->port_cfg, *port_cfg);
+ lport->vport = vport;
+ lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
+ bfa_lps_get_tag(lport->fabric->lps);
+
+ INIT_LIST_HEAD(&lport->rport_q);
+ lport->num_rports = 0;
+
+ lport->bfad_port =
+ bfa_fcb_port_new(fcs->bfad, lport, lport->port_cfg.roles,
+ lport->fabric->vf_drv,
+ vport ? vport->vport_drv : NULL);
+ bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW);
+
+ bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit);
+ bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
+}
+
+
+
+/**
+ * fcs_lport_api
+ */
+
+void
+bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
+ struct bfa_port_attr_s *port_attr)
+{
+ if (bfa_sm_cmp_state(port, bfa_fcs_port_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 = bfa_fcs_fabric_port_type(port->fabric);
+ port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
+ port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port);
+ memcpy(port_attr->fabric_ip_addr,
+ bfa_fcs_port_get_fabric_ipaddr(port),
+ BFA_FCS_FABRIC_IPADDR_SZ);
+
+ if (port->vport != NULL)
+ port_attr->port_type = BFA_PPORT_TYPE_VPORT;
+
+ } else {
+ port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
+ port_attr->state = BFA_PORT_UNINIT;
+ }
+
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcs_port.c b/drivers/scsi/bfa/bfa_fcs_port.c
new file mode 100644
index 000000000000..9c4b24e62de1
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs_port.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_pport.c BFA FCS PPORT ( physical port)
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs_fabric.h>
+#include "fcs_trcmod.h"
+#include "fcs.h"
+#include "fcs_fabric.h"
+#include "fcs_port.h"
+
+BFA_TRC_FILE(FCS, PPORT);
+
+static void
+bfa_fcs_pport_event_handler(void *cbarg, bfa_pport_event_t event)
+{
+ struct bfa_fcs_s *fcs = cbarg;
+
+ bfa_trc(fcs, event);
+
+ switch (event) {
+ case BFA_PPORT_LINKUP:
+ bfa_fcs_fabric_link_up(&fcs->fabric);
+ break;
+
+ case BFA_PPORT_LINKDOWN:
+ bfa_fcs_fabric_link_down(&fcs->fabric);
+ break;
+
+ case BFA_PPORT_TRUNK_LINKDOWN:
+ bfa_assert(0);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+void
+bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs)
+{
+ bfa_pport_event_register(fcs->bfa, bfa_fcs_pport_event_handler,
+ fcs);
+}
+
+void
+bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
diff --git a/drivers/scsi/bfa/bfa_fcs_uf.c b/drivers/scsi/bfa/bfa_fcs_uf.c
new file mode 100644
index 000000000000..ad01db6444b2
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs_uf.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_uf.c BFA FCS UF ( Unsolicited Frames)
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs_fabric.h>
+#include "fcs.h"
+#include "fcs_trcmod.h"
+#include "fcs_fabric.h"
+#include "fcs_uf.h"
+
+BFA_TRC_FILE(FCS, UF);
+
+/**
+ * BFA callback for unsolicited frame receive handler.
+ *
+ * @param[in] cbarg callback arg for receive handler
+ * @param[in] uf unsolicited frame descriptor
+ *
+ * @return None
+ */
+static void
+bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
+{
+ struct bfa_fcs_s *fcs = (struct bfa_fcs_s *) cbarg;
+ struct fchs_s *fchs = bfa_uf_get_frmbuf(uf);
+ u16 len = bfa_uf_get_frmlen(uf);
+ struct fc_vft_s *vft;
+ struct bfa_fcs_fabric_s *fabric;
+
+ /**
+ * check for VFT header
+ */
+ if (fchs->routing == FC_RTG_EXT_HDR &&
+ fchs->cat_info == FC_CAT_VFT_HDR) {
+ bfa_stats(fcs, uf.tagged);
+ vft = bfa_uf_get_frmbuf(uf);
+ if (fcs->port_vfid == vft->vf_id)
+ fabric = &fcs->fabric;
+ else
+ fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id);
+
+ /**
+ * drop frame if vfid is unknown
+ */
+ if (!fabric) {
+ bfa_assert(0);
+ bfa_stats(fcs, uf.vfid_unknown);
+ bfa_uf_free(uf);
+ return;
+ }
+
+ /**
+ * skip vft header
+ */
+ fchs = (struct fchs_s *) (vft + 1);
+ len -= sizeof(struct fc_vft_s);
+
+ bfa_trc(fcs, vft->vf_id);
+ } else {
+ bfa_stats(fcs, uf.untagged);
+ fabric = &fcs->fabric;
+ }
+
+ bfa_trc(fcs, ((u32 *) fchs)[0]);
+ bfa_trc(fcs, ((u32 *) fchs)[1]);
+ bfa_trc(fcs, ((u32 *) fchs)[2]);
+ bfa_trc(fcs, ((u32 *) fchs)[3]);
+ bfa_trc(fcs, ((u32 *) fchs)[4]);
+ bfa_trc(fcs, ((u32 *) fchs)[5]);
+ bfa_trc(fcs, len);
+
+ bfa_fcs_fabric_uf_recv(fabric, fchs, len);
+ bfa_uf_free(uf);
+}
+
+void
+bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs)
+{
+ bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs);
+}
+
+void
+bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c
new file mode 100644
index 000000000000..4754a0e9006a
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcxp.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfi/bfi_uf.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, FCXP);
+BFA_MODULE(fcxp);
+
+/**
+ * forward declarations
+ */
+static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete);
+static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
+ struct bfi_fcxp_send_rsp_s *fcxp_rsp);
+static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen,
+ struct bfa_fcxp_s *fcxp, struct fchs_s *fchs);
+static void bfa_fcxp_qresume(void *cbarg);
+static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp,
+ struct bfi_fcxp_send_req_s *send_req);
+
+/**
+ * fcxp_pvt BFA FCXP private functions
+ */
+
+static void
+claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
+{
+ u8 *dm_kva = NULL;
+ u64 dm_pa;
+ u32 buf_pool_sz;
+
+ dm_kva = bfa_meminfo_dma_virt(mi);
+ dm_pa = bfa_meminfo_dma_phys(mi);
+
+ buf_pool_sz = mod->req_pld_sz * mod->num_fcxps;
+
+ /*
+ * Initialize the fcxp req payload list
+ */
+ mod->req_pld_list_kva = dm_kva;
+ mod->req_pld_list_pa = dm_pa;
+ dm_kva += buf_pool_sz;
+ dm_pa += buf_pool_sz;
+ bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz);
+
+ /*
+ * Initialize the fcxp rsp payload list
+ */
+ buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps;
+ mod->rsp_pld_list_kva = dm_kva;
+ mod->rsp_pld_list_pa = dm_pa;
+ dm_kva += buf_pool_sz;
+ dm_pa += buf_pool_sz;
+ bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz);
+
+ bfa_meminfo_dma_virt(mi) = dm_kva;
+ bfa_meminfo_dma_phys(mi) = dm_pa;
+}
+
+static void
+claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
+{
+ u16 i;
+ struct bfa_fcxp_s *fcxp;
+
+ fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi);
+ bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);
+
+ INIT_LIST_HEAD(&mod->fcxp_free_q);
+ INIT_LIST_HEAD(&mod->fcxp_active_q);
+
+ mod->fcxp_list = fcxp;
+
+ for (i = 0; i < mod->num_fcxps; i++) {
+ fcxp->fcxp_mod = mod;
+ fcxp->fcxp_tag = i;
+
+ list_add_tail(&fcxp->qe, &mod->fcxp_free_q);
+ bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp);
+ fcxp->reqq_waiting = BFA_FALSE;
+
+ fcxp = fcxp + 1;
+ }
+
+ bfa_meminfo_kva(mi) = (void *)fcxp;
+}
+
+static void
+bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
+ u32 *dm_len)
+{
+ u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs;
+
+ if (num_fcxp_reqs == 0)
+ return;
+
+ /*
+ * Account for req/rsp payload
+ */
+ *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs;
+ if (cfg->drvcfg.min_cfg)
+ *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs;
+ else
+ *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs;
+
+ /*
+ * Account for fcxp structs
+ */
+ *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs;
+}
+
+static void
+bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s));
+ mod->bfa = bfa;
+ mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs;
+
+ /**
+ * Initialize FCXP request and response payload sizes.
+ */
+ mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ;
+ if (!cfg->drvcfg.min_cfg)
+ mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ;
+
+ INIT_LIST_HEAD(&mod->wait_q);
+
+ claim_fcxp_req_rsp_mem(mod, meminfo);
+ claim_fcxps_mem(mod, meminfo);
+}
+
+static void
+bfa_fcxp_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+ struct bfa_fcxp_s *fcxp;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &mod->fcxp_active_q) {
+ fcxp = (struct bfa_fcxp_s *) qe;
+ if (fcxp->caller == NULL) {
+ fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
+ BFA_STATUS_IOC_FAILURE, 0, 0, NULL);
+ bfa_fcxp_free(fcxp);
+ } else {
+ fcxp->rsp_status = BFA_STATUS_IOC_FAILURE;
+ bfa_cb_queue(bfa, &fcxp->hcb_qe,
+ __bfa_fcxp_send_cbfn, fcxp);
+ }
+ }
+}
+
+static struct bfa_fcxp_s *
+bfa_fcxp_get(struct bfa_fcxp_mod_s *fm)
+{
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_q_deq(&fm->fcxp_free_q, &fcxp);
+
+ if (fcxp)
+ list_add_tail(&fcxp->qe, &fm->fcxp_active_q);
+
+ return (fcxp);
+}
+
+static void
+bfa_fcxp_put(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+ struct bfa_fcxp_wqe_s *wqe;
+
+ bfa_q_deq(&mod->wait_q, &wqe);
+ if (wqe) {
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+ wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp);
+ return;
+ }
+
+ bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp));
+ list_del(&fcxp->qe);
+ list_add_tail(&fcxp->qe, &mod->fcxp_free_q);
+}
+
+static void
+bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg,
+ bfa_status_t req_status, u32 rsp_len,
+ u32 resid_len, struct fchs_s *rsp_fchs)
+{
+ /**discarded fcxp completion */
+}
+
+static void
+__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_fcxp_s *fcxp = cbarg;
+
+ if (complete) {
+ fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
+ fcxp->rsp_status, fcxp->rsp_len,
+ fcxp->residue_len, &fcxp->rsp_fchs);
+ } else {
+ bfa_fcxp_free(fcxp);
+ }
+}
+
+static void
+hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+ struct bfa_fcxp_s *fcxp;
+ u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag);
+
+ bfa_trc(bfa, fcxp_tag);
+
+ fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len);
+
+ /**
+ * @todo f/w should not set residue to non-0 when everything
+ * is received.
+ */
+ if (fcxp_rsp->req_status == BFA_STATUS_OK)
+ fcxp_rsp->residue_len = 0;
+ else
+ fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len);
+
+ fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag);
+
+ bfa_assert(fcxp->send_cbfn != NULL);
+
+ hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp);
+
+ if (fcxp->send_cbfn != NULL) {
+ if (fcxp->caller == NULL) {
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+
+ fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
+ fcxp_rsp->req_status, fcxp_rsp->rsp_len,
+ fcxp_rsp->residue_len, &fcxp_rsp->fchs);
+ /*
+ * fcxp automatically freed on return from the callback
+ */
+ bfa_fcxp_free(fcxp);
+ } else {
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+ fcxp->rsp_status = fcxp_rsp->req_status;
+ fcxp->rsp_len = fcxp_rsp->rsp_len;
+ fcxp->residue_len = fcxp_rsp->residue_len;
+ fcxp->rsp_fchs = fcxp_rsp->fchs;
+
+ bfa_cb_queue(bfa, &fcxp->hcb_qe,
+ __bfa_fcxp_send_cbfn, fcxp);
+ }
+ } else {
+ bfa_trc(bfa, fcxp_tag);
+ }
+}
+
+static void
+hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa)
+{
+ union bfi_addr_u sga_zero = { {0} };
+
+ sge->sg_len = reqlen;
+ sge->flags = BFI_SGE_DATA_LAST;
+ bfa_dma_addr_set(sge[0].sga, req_pa);
+ bfa_sge_to_be(sge);
+ sge++;
+
+ sge->sga = sga_zero;
+ sge->sg_len = reqlen;
+ sge->flags = BFI_SGE_PGDLEN;
+ bfa_sge_to_be(sge);
+}
+
+static void
+hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp,
+ struct fchs_s *fchs)
+{
+ /*
+ * TODO: TX ox_id
+ */
+ if (reqlen > 0) {
+ if (fcxp->use_ireqbuf) {
+ u32 pld_w0 =
+ *((u32 *) BFA_FCXP_REQ_PLD(fcxp));
+
+ bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_TX,
+ reqlen + sizeof(struct fchs_s), fchs, pld_w0);
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_TX, reqlen + sizeof(struct fchs_s),
+ fchs);
+ }
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX,
+ reqlen + sizeof(struct fchs_s), fchs);
+ }
+}
+
+static void
+hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
+ struct bfi_fcxp_send_rsp_s *fcxp_rsp)
+{
+ if (fcxp_rsp->rsp_len > 0) {
+ if (fcxp->use_irspbuf) {
+ u32 pld_w0 =
+ *((u32 *) BFA_FCXP_RSP_PLD(fcxp));
+
+ bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_RX,
+ (u16) fcxp_rsp->rsp_len,
+ &fcxp_rsp->fchs, pld_w0);
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_RX,
+ (u16) fcxp_rsp->rsp_len,
+ &fcxp_rsp->fchs);
+ }
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX,
+ (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs);
+ }
+}
+
+/**
+ * Handler to resume sending fcxp when space in available in cpe queue.
+ */
+static void
+bfa_fcxp_qresume(void *cbarg)
+{
+ struct bfa_fcxp_s *fcxp = cbarg;
+ struct bfa_s *bfa = fcxp->fcxp_mod->bfa;
+ struct bfi_fcxp_send_req_s *send_req;
+
+ fcxp->reqq_waiting = BFA_FALSE;
+ send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
+ bfa_fcxp_queue(fcxp, send_req);
+}
+
+/**
+ * Queue fcxp send request to foimrware.
+ */
+static void
+bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
+{
+ struct bfa_s *bfa = fcxp->fcxp_mod->bfa;
+ struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info;
+ struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info;
+ struct bfa_rport_s *rport = reqi->bfa_rport;
+
+ bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ,
+ bfa_lpuid(bfa));
+
+ send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag);
+ if (rport) {
+ send_req->rport_fw_hndl = rport->fw_handle;
+ send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz);
+ if (send_req->max_frmsz == 0)
+ send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+ } else {
+ send_req->rport_fw_hndl = 0;
+ send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+ }
+
+ send_req->vf_id = bfa_os_htons(reqi->vf_id);
+ send_req->lp_tag = reqi->lp_tag;
+ send_req->class = reqi->class;
+ send_req->rsp_timeout = rspi->rsp_timeout;
+ send_req->cts = reqi->cts;
+ send_req->fchs = reqi->fchs;
+
+ send_req->req_len = bfa_os_htonl(reqi->req_tot_len);
+ send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen);
+
+ /*
+ * setup req sgles
+ */
+ if (fcxp->use_ireqbuf == 1) {
+ hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len,
+ BFA_FCXP_REQ_PLD_PA(fcxp));
+ } else {
+ if (fcxp->nreq_sgles > 0) {
+ bfa_assert(fcxp->nreq_sgles == 1);
+ hal_fcxp_set_local_sges(send_req->req_sge,
+ reqi->req_tot_len,
+ fcxp->req_sga_cbfn(fcxp->caller,
+ 0));
+ } else {
+ bfa_assert(reqi->req_tot_len == 0);
+ hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
+ }
+ }
+
+ /*
+ * setup rsp sgles
+ */
+ if (fcxp->use_irspbuf == 1) {
+ bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ);
+
+ hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen,
+ BFA_FCXP_RSP_PLD_PA(fcxp));
+
+ } else {
+ if (fcxp->nrsp_sgles > 0) {
+ bfa_assert(fcxp->nrsp_sgles == 1);
+ hal_fcxp_set_local_sges(send_req->rsp_sge,
+ rspi->rsp_maxlen,
+ fcxp->rsp_sga_cbfn(fcxp->caller,
+ 0));
+ } else {
+ bfa_assert(rspi->rsp_maxlen == 0);
+ hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
+ }
+ }
+
+ hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs);
+
+ bfa_reqq_produce(bfa, BFA_REQQ_FCXP);
+
+ bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP));
+ bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP));
+}
+
+
+/**
+ * hal_fcxp_api BFA FCXP API
+ */
+
+/**
+ * Allocate an FCXP instance to send a response or to send a request
+ * that has a response. Request/response buffers are allocated by caller.
+ *
+ * @param[in] bfa BFA bfa instance
+ * @param[in] nreq_sgles Number of SG elements required for request
+ * buffer. 0, if fcxp internal buffers are used.
+ * Use bfa_fcxp_get_reqbuf() to get the
+ * internal req buffer.
+ * @param[in] req_sgles SG elements describing request buffer. Will be
+ * copied in by BFA and hence can be freed on
+ * return from this function.
+ * @param[in] get_req_sga function ptr to be called to get a request SG
+ * Address (given the sge index).
+ * @param[in] get_req_sglen function ptr to be called to get a request SG
+ * len (given the sge index).
+ * @param[in] get_rsp_sga function ptr to be called to get a response SG
+ * Address (given the sge index).
+ * @param[in] get_rsp_sglen function ptr to be called to get a response SG
+ * len (given the sge index).
+ *
+ * @return FCXP instance. NULL on failure.
+ */
+struct bfa_fcxp_s *
+bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
+ int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn,
+ bfa_fcxp_get_sglen_t req_sglen_cbfn,
+ bfa_fcxp_get_sgaddr_t rsp_sga_cbfn,
+ bfa_fcxp_get_sglen_t rsp_sglen_cbfn)
+{
+ struct bfa_fcxp_s *fcxp = NULL;
+ u32 nreq_sgpg, nrsp_sgpg;
+
+ bfa_assert(bfa != NULL);
+
+ fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa));
+ if (fcxp == NULL)
+ return (NULL);
+
+ bfa_trc(bfa, fcxp->fcxp_tag);
+
+ fcxp->caller = caller;
+
+ if (nreq_sgles == 0) {
+ fcxp->use_ireqbuf = 1;
+ } else {
+ bfa_assert(req_sga_cbfn != NULL);
+ bfa_assert(req_sglen_cbfn != NULL);
+
+ fcxp->use_ireqbuf = 0;
+ fcxp->req_sga_cbfn = req_sga_cbfn;
+ fcxp->req_sglen_cbfn = req_sglen_cbfn;
+
+ fcxp->nreq_sgles = nreq_sgles;
+
+ /*
+ * alloc required sgpgs
+ */
+ if (nreq_sgles > BFI_SGE_INLINE) {
+ nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
+
+ if (bfa_sgpg_malloc
+ (bfa, &fcxp->req_sgpg_q, nreq_sgpg)
+ != BFA_STATUS_OK) {
+ /* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe,
+ nreq_sgpg); */
+ /*
+ * TODO
+ */
+ }
+ }
+ }
+
+ if (nrsp_sgles == 0) {
+ fcxp->use_irspbuf = 1;
+ } else {
+ bfa_assert(rsp_sga_cbfn != NULL);
+ bfa_assert(rsp_sglen_cbfn != NULL);
+
+ fcxp->use_irspbuf = 0;
+ fcxp->rsp_sga_cbfn = rsp_sga_cbfn;
+ fcxp->rsp_sglen_cbfn = rsp_sglen_cbfn;
+
+ fcxp->nrsp_sgles = nrsp_sgles;
+ /*
+ * alloc required sgpgs
+ */
+ if (nrsp_sgles > BFI_SGE_INLINE) {
+ nrsp_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
+
+ if (bfa_sgpg_malloc
+ (bfa, &fcxp->rsp_sgpg_q, nrsp_sgpg)
+ != BFA_STATUS_OK) {
+ /* bfa_sgpg_wait(bfa, &fcxp->rsp_sgpg_wqe,
+ nrsp_sgpg); */
+ /*
+ * TODO
+ */
+ }
+ }
+ }
+
+ return (fcxp);
+}
+
+/**
+ * Get the internal request buffer pointer
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return pointer to the internal request buffer
+ */
+void *
+bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+ void *reqbuf;
+
+ bfa_assert(fcxp->use_ireqbuf == 1);
+ reqbuf = ((u8 *)mod->req_pld_list_kva) +
+ fcxp->fcxp_tag * mod->req_pld_sz;
+ return reqbuf;
+}
+
+u32
+bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+
+ return mod->req_pld_sz;
+}
+
+/**
+ * Get the internal response buffer pointer
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return pointer to the internal request buffer
+ */
+void *
+bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+ void *rspbuf;
+
+ bfa_assert(fcxp->use_irspbuf == 1);
+
+ rspbuf = ((u8 *)mod->rsp_pld_list_kva) +
+ fcxp->fcxp_tag * mod->rsp_pld_sz;
+ return rspbuf;
+}
+
+/**
+ * Free the BFA FCXP
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return void
+ */
+void
+bfa_fcxp_free(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+
+ bfa_assert(fcxp != NULL);
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+ bfa_fcxp_put(fcxp);
+}
+
+/**
+ * Send a FCXP request
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports
+ * @param[in] vf_id virtual Fabric ID
+ * @param[in] lp_tag lport tag
+ * @param[in] cts use Continous sequence
+ * @param[in] cos fc Class of Service
+ * @param[in] reqlen request length, does not include FCHS length
+ * @param[in] fchs fc Header Pointer. The header content will be copied
+ * in by BFA.
+ *
+ * @param[in] cbfn call back function to be called on receiving
+ * the response
+ * @param[in] cbarg arg for cbfn
+ * @param[in] rsp_timeout
+ * response timeout
+ *
+ * @return bfa_status_t
+ */
+void
+bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
+ u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos,
+ u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn,
+ void *cbarg, u32 rsp_maxlen, u8 rsp_timeout)
+{
+ struct bfa_s *bfa = fcxp->fcxp_mod->bfa;
+ struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info;
+ struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info;
+ struct bfi_fcxp_send_req_s *send_req;
+
+ bfa_trc(bfa, fcxp->fcxp_tag);
+
+ /**
+ * setup request/response info
+ */
+ reqi->bfa_rport = rport;
+ reqi->vf_id = vf_id;
+ reqi->lp_tag = lp_tag;
+ reqi->class = cos;
+ rspi->rsp_timeout = rsp_timeout;
+ reqi->cts = cts;
+ reqi->fchs = *fchs;
+ reqi->req_tot_len = reqlen;
+ rspi->rsp_maxlen = rsp_maxlen;
+ fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp;
+ fcxp->send_cbarg = cbarg;
+
+ /**
+ * If no room in CPE queue, wait for
+ */
+ send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
+ if (!send_req) {
+ bfa_trc(bfa, fcxp->fcxp_tag);
+ fcxp->reqq_waiting = BFA_TRUE;
+ bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe);
+ return;
+ }
+
+ bfa_fcxp_queue(fcxp, send_req);
+}
+
+/**
+ * Abort a BFA FCXP
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return void
+ */
+bfa_status_t
+bfa_fcxp_abort(struct bfa_fcxp_s *fcxp)
+{
+ bfa_assert(0);
+ return (BFA_STATUS_OK);
+}
+
+void
+bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe,
+ bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ bfa_assert(list_empty(&mod->fcxp_free_q));
+
+ wqe->alloc_cbfn = alloc_cbfn;
+ wqe->alloc_cbarg = alloc_cbarg;
+ list_add_tail(&wqe->qe, &mod->wait_q);
+}
+
+void
+bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe));
+ list_del(&wqe->qe);
+}
+
+void
+bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
+{
+ /**
+ * If waiting for room in request queue, cancel reqq wait
+ * and free fcxp.
+ */
+ if (fcxp->reqq_waiting) {
+ fcxp->reqq_waiting = BFA_FALSE;
+ bfa_reqq_wcancel(&fcxp->reqq_wqe);
+ bfa_fcxp_free(fcxp);
+ return;
+ }
+
+ fcxp->send_cbfn = bfa_fcxp_null_comp;
+}
+
+
+
+/**
+ * hal_fcxp_public BFA FCXP public functions
+ */
+
+void
+bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
+{
+ switch (msg->mhdr.msg_id) {
+ case BFI_FCXP_I2H_SEND_RSP:
+ hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg);
+ break;
+
+ default:
+ bfa_trc(bfa, msg->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+u32
+bfa_fcxp_get_maxrsp(struct bfa_s *bfa)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ return mod->rsp_pld_sz;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcxp_priv.h b/drivers/scsi/bfa/bfa_fcxp_priv.h
new file mode 100644
index 000000000000..4cda49397da0
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcxp_priv.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCXP_PRIV_H__
+#define __BFA_FCXP_PRIV_H__
+
+#include <cs/bfa_sm.h>
+#include <protocol/fc.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_fcxp.h>
+
+#define BFA_FCXP_MIN (1)
+#define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256)
+#define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256)
+
+struct bfa_fcxp_mod_s {
+ struct bfa_s *bfa; /* backpointer to BFA */
+ struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */
+ u16 num_fcxps; /* max num FCXP requests */
+ struct list_head fcxp_free_q; /* free FCXPs */
+ struct list_head fcxp_active_q; /* active FCXPs */
+ void *req_pld_list_kva; /* list of FCXP req pld */
+ u64 req_pld_list_pa; /* list of FCXP req pld */
+ void *rsp_pld_list_kva; /* list of FCXP resp pld */
+ u64 rsp_pld_list_pa; /* list of FCXP resp pld */
+ struct list_head wait_q; /* wait queue for free fcxp */
+ u32 req_pld_sz;
+ u32 rsp_pld_sz;
+};
+
+#define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod)
+#define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag])
+
+typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp,
+ void *cb_arg, bfa_status_t req_status,
+ u32 rsp_len, u32 resid_len,
+ struct fchs_s *rsp_fchs);
+
+/**
+ * Information needed for a FCXP request
+ */
+struct bfa_fcxp_req_info_s {
+ struct bfa_rport_s *bfa_rport; /* Pointer to the bfa rport that was
+ *returned from bfa_rport_create().
+ *This could be left NULL for WKA or for
+ *FCXP interactions before the rport
+ *nexus is established
+ */
+ struct fchs_s fchs; /* request FC header structure */
+ u8 cts; /* continous sequence */
+ u8 class; /* FC class for the request/response */
+ u16 max_frmsz; /* max send frame size */
+ u16 vf_id; /* vsan tag if applicable */
+ u8 lp_tag; /* lport tag */
+ u32 req_tot_len; /* request payload total length */
+};
+
+struct bfa_fcxp_rsp_info_s {
+ struct fchs_s rsp_fchs; /* Response frame's FC header will
+ * be *sent back in this field */
+ u8 rsp_timeout; /* timeout in seconds, 0-no response
+ */
+ u8 rsvd2[3];
+ u32 rsp_maxlen; /* max response length expected */
+};
+
+struct bfa_fcxp_s {
+ struct list_head qe; /* fcxp queue element */
+ bfa_sm_t sm; /* state machine */
+ void *caller; /* driver or fcs */
+ struct bfa_fcxp_mod_s *fcxp_mod;
+ /* back pointer to fcxp mod */
+ u16 fcxp_tag; /* internal tag */
+ struct bfa_fcxp_req_info_s req_info;
+ /* request info */
+ struct bfa_fcxp_rsp_info_s rsp_info;
+ /* response info */
+ u8 use_ireqbuf; /* use internal req buf */
+ u8 use_irspbuf; /* use internal rsp buf */
+ u32 nreq_sgles; /* num request SGLEs */
+ u32 nrsp_sgles; /* num response SGLEs */
+ struct list_head req_sgpg_q; /* SG pages for request buf */
+ struct list_head req_sgpg_wqe; /* wait queue for req SG page */
+ struct list_head rsp_sgpg_q; /* SG pages for response buf */
+ struct list_head rsp_sgpg_wqe; /* wait queue for rsp SG page */
+
+ bfa_fcxp_get_sgaddr_t req_sga_cbfn;
+ /* SG elem addr user function */
+ bfa_fcxp_get_sglen_t req_sglen_cbfn;
+ /* SG elem len user function */
+ bfa_fcxp_get_sgaddr_t rsp_sga_cbfn;
+ /* SG elem addr user function */
+ bfa_fcxp_get_sglen_t rsp_sglen_cbfn;
+ /* SG elem len user function */
+ bfa_cb_fcxp_send_t send_cbfn; /* send completion callback */
+ void *send_cbarg; /* callback arg */
+ struct bfa_sge_s req_sge[BFA_FCXP_MAX_SGES];
+ /* req SG elems */
+ struct bfa_sge_s rsp_sge[BFA_FCXP_MAX_SGES];
+ /* rsp SG elems */
+ u8 rsp_status; /* comp: rsp status */
+ u32 rsp_len; /* comp: actual response len */
+ u32 residue_len; /* comp: residual rsp length */
+ struct fchs_s rsp_fchs; /* comp: response fchs */
+ struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */
+ struct bfa_reqq_wait_s reqq_wqe;
+ bfa_boolean_t reqq_waiting;
+};
+
+#define BFA_FCXP_REQ_PLD(_fcxp) (bfa_fcxp_get_reqbuf(_fcxp))
+
+#define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs))
+#define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp))
+
+#define BFA_FCXP_REQ_PLD_PA(_fcxp) \
+ ((_fcxp)->fcxp_mod->req_pld_list_pa + \
+ ((_fcxp)->fcxp_mod->req_pld_sz * (_fcxp)->fcxp_tag))
+
+#define BFA_FCXP_RSP_PLD_PA(_fcxp) \
+ ((_fcxp)->fcxp_mod->rsp_pld_list_pa + \
+ ((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag))
+
+void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+#endif /* __BFA_FCXP_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_fwimg_priv.h b/drivers/scsi/bfa/bfa_fwimg_priv.h
new file mode 100644
index 000000000000..1ec1355924d9
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fwimg_priv.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FWIMG_PRIV_H__
+#define __BFA_FWIMG_PRIV_H__
+
+#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */
+#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32))
+
+extern u32 *bfi_image_ct_get_chunk(u32 off);
+extern u32 bfi_image_ct_size;
+extern u32 *bfi_image_cb_get_chunk(u32 off);
+extern u32 bfi_image_cb_size;
+extern u32 *bfi_image_cb;
+extern u32 *bfi_image_ct;
+
+#endif /* __BFA_FWIMG_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
new file mode 100644
index 000000000000..ede1438619e2
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa_priv.h>
+#include <bfi/bfi_cbreg.h>
+
+void
+bfa_hwcb_reginit(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
+ bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+ int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
+
+ if (fn == 0) {
+ bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK);
+ } else {
+ bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK);
+ }
+
+ for (i = 0; i < BFI_IOC_MAX_CQS; i++) {
+ /*
+ * CPE registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->cpe_q_pi[i] = (kva + CPE_Q_PI(q));
+ bfa_regs->cpe_q_ci[i] = (kva + CPE_Q_CI(q));
+ bfa_regs->cpe_q_depth[i] = (kva + CPE_Q_DEPTH(q));
+
+ /*
+ * RME registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->rme_q_pi[i] = (kva + RME_Q_PI(q));
+ bfa_regs->rme_q_ci[i] = (kva + RME_Q_CI(q));
+ bfa_regs->rme_q_depth[i] = (kva + RME_Q_DEPTH(q));
+ }
+}
+
+void
+bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq)
+{
+}
+
+static void
+bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq)
+{
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
+ __HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq));
+}
+
+void
+bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
+ u32 *num_vecs, u32 *max_vec_bit)
+{
+#define __HFN_NUMINTS 13
+ if (bfa_ioc_pcifn(&bfa->ioc) == 0) {
+ *msix_vecs_bmap = (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
+ __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
+ __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
+ __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
+ __HFN_INT_MBOX_LPU0);
+ *max_vec_bit = __HFN_INT_MBOX_LPU0;
+ } else {
+ *msix_vecs_bmap = (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
+ __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
+ __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
+ __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
+ __HFN_INT_MBOX_LPU1);
+ *max_vec_bit = __HFN_INT_MBOX_LPU1;
+ }
+
+ *msix_vecs_bmap |= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
+ __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
+ *num_vecs = __HFN_NUMINTS;
+}
+
+/**
+ * No special setup required for crossbow -- vector assignments are implicit.
+ */
+void
+bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs)
+{
+ int i;
+
+ bfa_assert((nvecs == 1) || (nvecs == __HFN_NUMINTS));
+
+ bfa->msix.nvecs = nvecs;
+ if (nvecs == 1) {
+ for (i = 0; i < BFA_MSIX_CB_MAX; i++)
+ bfa->msix.handler[i] = bfa_msix_all;
+ return;
+ }
+
+ for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q7; i++)
+ bfa->msix.handler[i] = bfa_msix_reqq;
+
+ for (i = BFA_MSIX_RME_Q0; i <= BFA_MSIX_RME_Q7; i++)
+ bfa->msix.handler[i] = bfa_msix_rspq;
+
+ for (; i < BFA_MSIX_CB_MAX; i++)
+ bfa->msix.handler[i] = bfa_msix_lpu_err;
+}
+
+/**
+ * Crossbow -- dummy, interrupts are masked
+ */
+void
+bfa_hwcb_msix_install(struct bfa_s *bfa)
+{
+}
+
+void
+bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
+{
+}
+
+/**
+ * No special enable/disable -- vector assignments are implicit.
+ */
+void
+bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
+{
+ bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
new file mode 100644
index 000000000000..51ae5740e6e9
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa_priv.h>
+#include <bfi/bfi_ctreg.h>
+#include <bfa_ioc.h>
+
+BFA_TRC_FILE(HAL, IOCFC_CT);
+
+static u32 __ct_msix_err_vec_reg[] = {
+ HOST_MSIX_ERR_INDEX_FN0,
+ HOST_MSIX_ERR_INDEX_FN1,
+ HOST_MSIX_ERR_INDEX_FN2,
+ HOST_MSIX_ERR_INDEX_FN3,
+};
+
+static void
+bfa_hwct_msix_lpu_err_set(struct bfa_s *bfa, bfa_boolean_t msix, int vec)
+{
+ int fn = bfa_ioc_pcifn(&bfa->ioc);
+ bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+
+ if (msix)
+ bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], vec);
+ else
+ bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], 0);
+}
+
+/**
+ * Dummy interrupt handler for handling spurious interrupt during chip-reinit.
+ */
+static void
+bfa_hwct_msix_dummy(struct bfa_s *bfa, int vec)
+{
+}
+
+void
+bfa_hwct_reginit(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
+ bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+ int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
+
+ if (fn == 0) {
+ bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK);
+ } else {
+ bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK);
+ }
+
+ for (i = 0; i < BFI_IOC_MAX_CQS; i++) {
+ /*
+ * CPE registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->cpe_q_pi[i] = (kva + CPE_PI_PTR_Q(q << 5));
+ bfa_regs->cpe_q_ci[i] = (kva + CPE_CI_PTR_Q(q << 5));
+ bfa_regs->cpe_q_depth[i] = (kva + CPE_DEPTH_Q(q << 5));
+ bfa_regs->cpe_q_ctrl[i] = (kva + CPE_QCTRL_Q(q << 5));
+
+ /*
+ * RME registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->rme_q_pi[i] = (kva + RME_PI_PTR_Q(q << 5));
+ bfa_regs->rme_q_ci[i] = (kva + RME_CI_PTR_Q(q << 5));
+ bfa_regs->rme_q_depth[i] = (kva + RME_DEPTH_Q(q << 5));
+ bfa_regs->rme_q_ctrl[i] = (kva + RME_QCTRL_Q(q << 5));
+ }
+}
+
+void
+bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
+{
+ u32 r32;
+
+ r32 = bfa_reg_read(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
+ bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq], r32);
+}
+
+void
+bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
+ u32 *num_vecs, u32 *max_vec_bit)
+{
+ *msix_vecs_bmap = (1 << BFA_MSIX_CT_MAX) - 1;
+ *max_vec_bit = (1 << (BFA_MSIX_CT_MAX - 1));
+ *num_vecs = BFA_MSIX_CT_MAX;
+}
+
+/**
+ * Setup MSI-X vector for catapult
+ */
+void
+bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs)
+{
+ bfa_assert((nvecs == 1) || (nvecs == BFA_MSIX_CT_MAX));
+ bfa_trc(bfa, nvecs);
+
+ bfa->msix.nvecs = nvecs;
+ bfa_hwct_msix_uninstall(bfa);
+}
+
+void
+bfa_hwct_msix_install(struct bfa_s *bfa)
+{
+ int i;
+
+ if (bfa->msix.nvecs == 0)
+ return;
+
+ if (bfa->msix.nvecs == 1) {
+ for (i = 0; i < BFA_MSIX_CT_MAX; i++)
+ bfa->msix.handler[i] = bfa_msix_all;
+ return;
+ }
+
+ for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q3; i++)
+ bfa->msix.handler[i] = bfa_msix_reqq;
+
+ for (; i <= BFA_MSIX_RME_Q3; i++)
+ bfa->msix.handler[i] = bfa_msix_rspq;
+
+ bfa_assert(i == BFA_MSIX_LPU_ERR);
+ bfa->msix.handler[BFA_MSIX_LPU_ERR] = bfa_msix_lpu_err;
+}
+
+void
+bfa_hwct_msix_uninstall(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; i < BFA_MSIX_CT_MAX; i++)
+ bfa->msix.handler[i] = bfa_hwct_msix_dummy;
+}
+
+/**
+ * Enable MSI-X vectors
+ */
+void
+bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
+{
+ bfa_trc(bfa, 0);
+ bfa_hwct_msix_lpu_err_set(bfa, msix, BFA_MSIX_LPU_ERR);
+ bfa_ioc_isr_mode_set(&bfa->ioc, msix);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c
new file mode 100644
index 000000000000..0ca125712a04
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_intr.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfi/bfi_cbreg.h>
+#include <bfa_port_priv.h>
+#include <bfa_intr_priv.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, INTR);
+
+static void
+bfa_msix_errint(struct bfa_s *bfa, u32 intr)
+{
+ bfa_ioc_error_isr(&bfa->ioc);
+}
+
+static void
+bfa_msix_lpu(struct bfa_s *bfa)
+{
+ bfa_ioc_mbox_isr(&bfa->ioc);
+}
+
+void
+bfa_msix_all(struct bfa_s *bfa, int vec)
+{
+ bfa_intx(bfa);
+}
+
+/**
+ * hal_intr_api
+ */
+bfa_boolean_t
+bfa_intx(struct bfa_s *bfa)
+{
+ u32 intr, qintr;
+ int queue;
+
+ intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+ if (!intr)
+ return BFA_FALSE;
+
+ /**
+ * RME completion queue interrupt
+ */
+ qintr = intr & __HFN_INT_RME_MASK;
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
+
+ for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue ++) {
+ if (intr & (__HFN_INT_RME_Q0 << queue))
+ bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
+ }
+ intr &= ~qintr;
+ if (!intr)
+ return BFA_TRUE;
+
+ /**
+ * CPE completion queue interrupt
+ */
+ qintr = intr & __HFN_INT_CPE_MASK;
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
+
+ for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
+ if (intr & (__HFN_INT_CPE_Q0 << queue))
+ bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
+ }
+ intr &= ~qintr;
+ if (!intr)
+ return BFA_TRUE;
+
+ bfa_msix_lpu_err(bfa, intr);
+
+ return BFA_TRUE;
+}
+
+void
+bfa_isr_enable(struct bfa_s *bfa)
+{
+ u32 intr_unmask;
+ int pci_func = bfa_ioc_pcifn(&bfa->ioc);
+
+ bfa_trc(bfa, pci_func);
+
+ bfa_msix_install(bfa);
+ intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
+ __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
+
+ if (pci_func == 0)
+ intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
+ __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
+ __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
+ __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
+ __HFN_INT_MBOX_LPU0);
+ else
+ intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
+ __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
+ __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
+ __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
+ __HFN_INT_MBOX_LPU1);
+
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask);
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
+ bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0);
+}
+
+void
+bfa_isr_disable(struct bfa_s *bfa)
+{
+ bfa_isr_mode_set(bfa, BFA_FALSE);
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
+ bfa_msix_uninstall(bfa);
+}
+
+void
+bfa_msix_reqq(struct bfa_s *bfa, int qid)
+{
+ struct list_head *waitq, *qe, *qen;
+ struct bfa_reqq_wait_s *wqe;
+
+ qid &= (BFI_IOC_MAX_CQS - 1);
+
+ waitq = bfa_reqq(bfa, qid);
+ list_for_each_safe(qe, qen, waitq) {
+ /**
+ * Callback only as long as there is room in request queue
+ */
+ if (bfa_reqq_full(bfa, qid))
+ break;
+
+ list_del(qe);
+ wqe = (struct bfa_reqq_wait_s *) qe;
+ wqe->qresume(wqe->cbarg);
+ }
+}
+
+void
+bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ bfa_trc(bfa, m->mhdr.msg_class);
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_trc(bfa, m->mhdr.mtag.i2htok);
+ bfa_assert(0);
+ bfa_trc_stop(bfa->trcmod);
+}
+
+void
+bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid)
+{
+ struct bfi_msg_s *m;
+ u32 pi, ci;
+
+ bfa_trc_fp(bfa, rsp_qid);
+
+ rsp_qid &= (BFI_IOC_MAX_CQS - 1);
+
+ bfa->iocfc.hwif.hw_rspq_ack(bfa, rsp_qid);
+
+ ci = bfa_rspq_ci(bfa, rsp_qid);
+ pi = bfa_rspq_pi(bfa, rsp_qid);
+
+ bfa_trc_fp(bfa, ci);
+ bfa_trc_fp(bfa, pi);
+
+ if (bfa->rme_process) {
+ while (ci != pi) {
+ m = bfa_rspq_elem(bfa, rsp_qid, ci);
+ bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX);
+
+ bfa_isrs[m->mhdr.msg_class] (bfa, m);
+
+ CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems);
+ }
+ }
+
+ /**
+ * update CI
+ */
+ bfa_rspq_ci(bfa, rsp_qid) = pi;
+ bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[rsp_qid], pi);
+ bfa_os_mmiowb();
+}
+
+void
+bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
+{
+ u32 intr;
+
+ intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+
+ if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1))
+ bfa_msix_lpu(bfa);
+
+ if (intr & (__HFN_INT_ERR_EMC |
+ __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 |
+ __HFN_INT_ERR_PSS))
+ bfa_msix_errint(bfa, intr);
+}
+
+void
+bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
+{
+ bfa_isrs[mc] = isr_func;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_intr_priv.h b/drivers/scsi/bfa/bfa_intr_priv.h
new file mode 100644
index 000000000000..8ce6e6b105c8
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_intr_priv.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_INTR_PRIV_H__
+#define __BFA_INTR_PRIV_H__
+
+/**
+ * Message handler
+ */
+typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
+void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
+void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
+
+
+#define bfa_reqq_pi(__bfa, __reqq) (__bfa)->iocfc.req_cq_pi[__reqq]
+#define bfa_reqq_ci(__bfa, __reqq) \
+ *(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva)
+
+#define bfa_reqq_full(__bfa, __reqq) \
+ (((bfa_reqq_pi(__bfa, __reqq) + 1) & \
+ ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1)) == \
+ bfa_reqq_ci(__bfa, __reqq))
+
+#define bfa_reqq_next(__bfa, __reqq) \
+ (bfa_reqq_full(__bfa, __reqq) ? NULL : \
+ ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \
+ + bfa_reqq_pi((__bfa), (__reqq)))))
+
+#define bfa_reqq_produce(__bfa, __reqq) do { \
+ (__bfa)->iocfc.req_cq_pi[__reqq]++; \
+ (__bfa)->iocfc.req_cq_pi[__reqq] &= \
+ ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \
+ bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq], \
+ (__bfa)->iocfc.req_cq_pi[__reqq]); \
+ bfa_os_mmiowb(); \
+} while (0)
+
+#define bfa_rspq_pi(__bfa, __rspq) \
+ *(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)
+
+#define bfa_rspq_ci(__bfa, __rspq) (__bfa)->iocfc.rsp_cq_ci[__rspq]
+#define bfa_rspq_elem(__bfa, __rspq, __ci) \
+ &((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci]
+
+#define CQ_INCR(__index, __size) \
+ (__index)++; (__index) &= ((__size) - 1)
+
+/**
+ * Queue element to wait for room in request queue. FIFO order is
+ * maintained when fullfilling requests.
+ */
+struct bfa_reqq_wait_s {
+ struct list_head qe;
+ void (*qresume) (void *cbarg);
+ void *cbarg;
+};
+
+/**
+ * Circular queue usage assignments
+ */
+enum {
+ BFA_REQQ_IOC = 0, /* all low-priority IOC msgs */
+ BFA_REQQ_FCXP = 0, /* all FCXP messages */
+ BFA_REQQ_LPS = 0, /* all lport service msgs */
+ BFA_REQQ_PORT = 0, /* all port messages */
+ BFA_REQQ_FLASH = 0, /* for flash module */
+ BFA_REQQ_DIAG = 0, /* for diag module */
+ BFA_REQQ_RPORT = 0, /* all port messages */
+ BFA_REQQ_SBOOT = 0, /* all san boot messages */
+ BFA_REQQ_QOS_LO = 1, /* all low priority IO */
+ BFA_REQQ_QOS_MD = 2, /* all medium priority IO */
+ BFA_REQQ_QOS_HI = 3, /* all high priority IO */
+};
+
+static inline void
+bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
+ void *cbarg)
+{
+ wqe->qresume = qresume;
+ wqe->cbarg = cbarg;
+}
+
+#define bfa_reqq(__bfa, __reqq) &(__bfa)->reqq_waitq[__reqq]
+
+/**
+ * static inline void
+ * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe)
+ */
+#define bfa_reqq_wait(__bfa, __reqq, __wqe) do { \
+ \
+ struct list_head *waitq = bfa_reqq(__bfa, __reqq); \
+ \
+ bfa_assert(((__reqq) < BFI_IOC_MAX_CQS)); \
+ bfa_assert((__wqe)->qresume && (__wqe)->cbarg); \
+ \
+ list_add_tail(&(__wqe)->qe, waitq); \
+} while (0)
+
+#define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe)
+
+#endif /* __BFA_INTR_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
new file mode 100644
index 000000000000..149348934ce3
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -0,0 +1,2382 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_ioc.h>
+#include <bfa_fwimg_priv.h>
+#include <bfa_trcmod_priv.h>
+#include <cs/bfa_debug.h>
+#include <bfi/bfi_ioc.h>
+#include <bfi/bfi_ctreg.h>
+#include <aen/bfa_aen_ioc.h>
+#include <aen/bfa_aen.h>
+#include <log/bfa_log_hal.h>
+#include <defs/bfa_defs_pci.h>
+
+BFA_TRC_FILE(HAL, IOC);
+
+/**
+ * IOC local definitions
+ */
+#define BFA_IOC_TOV 2000 /* msecs */
+#define BFA_IOC_HB_TOV 1000 /* msecs */
+#define BFA_IOC_HB_FAIL_MAX 4
+#define BFA_IOC_HWINIT_MAX 2
+#define BFA_IOC_FWIMG_MINSZ (16 * 1024)
+#define BFA_IOC_TOV_RECOVER (BFA_IOC_HB_FAIL_MAX * BFA_IOC_HB_TOV \
+ + BFA_IOC_TOV)
+
+#define bfa_ioc_timer_start(__ioc) \
+ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \
+ bfa_ioc_timeout, (__ioc), BFA_IOC_TOV)
+#define bfa_ioc_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer)
+
+#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS)
+#define BFA_DBG_FWTRC_LEN \
+ (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \
+ (sizeof(struct bfa_trc_mod_s) - \
+ BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
+#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
+#define bfa_ioc_stats(_ioc, _stats) (_ioc)->stats._stats ++
+
+#define BFA_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
+bfa_boolean_t bfa_auto_recover = BFA_FALSE;
+
+/*
+ * forward declarations
+ */
+static void bfa_ioc_aen_post(struct bfa_ioc_s *bfa,
+ enum bfa_ioc_aen_event event);
+static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
+static void bfa_ioc_timeout(void *ioc);
+static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc);
+static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc);
+static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc);
+static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force);
+static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
+static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_recover(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc);
+static void bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc);
+static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
+static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
+
+/**
+ * bfa_ioc_sm
+ */
+
+/**
+ * IOC state machine events
+ */
+enum ioc_event {
+ IOC_E_ENABLE = 1, /* IOC enable request */
+ IOC_E_DISABLE = 2, /* IOC disable request */
+ IOC_E_TIMEOUT = 3, /* f/w response timeout */
+ IOC_E_FWREADY = 4, /* f/w initialization done */
+ IOC_E_FWRSP_GETATTR = 5, /* IOC get attribute response */
+ IOC_E_FWRSP_ENABLE = 6, /* enable f/w response */
+ IOC_E_FWRSP_DISABLE = 7, /* disable f/w response */
+ IOC_E_HBFAIL = 8, /* heartbeat failure */
+ IOC_E_HWERROR = 9, /* hardware error interrupt */
+ IOC_E_SEMLOCKED = 10, /* h/w semaphore is locked */
+ IOC_E_DETACH = 11, /* driver detach cleanup */
+};
+
+bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event);
+
+static struct bfa_sm_table_s ioc_sm_table[] = {
+ {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
+ {BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH},
+ {BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH},
+ {BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT},
+ {BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT},
+ {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT},
+ {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
+ {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
+ {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
+ {BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL},
+ {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
+ {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
+};
+
+/**
+ * Reset entry actions -- initialize state machine
+ */
+static void
+bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc)
+{
+ ioc->retry_count = 0;
+ ioc->auto_recover = bfa_auto_recover;
+}
+
+/**
+ * Beginning state. IOC is in reset state.
+ */
+static void
+bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_ENABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ break;
+
+ case IOC_E_DETACH:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Semaphore should be acquired for version check.
+ */
+static void
+bfa_ioc_sm_fwcheck_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting h/w semaphore to continue with version check.
+ */
+static void
+bfa_ioc_sm_fwcheck(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_SEMLOCKED:
+ if (bfa_ioc_firmware_lock(ioc)) {
+ ioc->retry_count = 0;
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ } else {
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch);
+ }
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_DETACH:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Notify enable completion callback and generate mismatch AEN.
+ */
+static void
+bfa_ioc_sm_mismatch_entry(struct bfa_ioc_s *ioc)
+{
+ /**
+ * Provide enable completion callback and AEN notification only once.
+ */
+ if (ioc->retry_count == 0) {
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH);
+ }
+ ioc->retry_count++;
+ bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * Awaiting firmware version match.
+ */
+static void
+bfa_ioc_sm_mismatch(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_DETACH:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Request for semaphore.
+ */
+static void
+bfa_ioc_sm_semwait_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting semaphore for h/w initialzation.
+ */
+static void
+bfa_ioc_sm_semwait(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_SEMLOCKED:
+ ioc->retry_count = 0;
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_hwinit_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_reset(ioc, BFA_FALSE);
+}
+
+/**
+ * Hardware is being initialized. Interrupts are enabled.
+ * Holding hardware semaphore lock.
+ */
+static void
+bfa_ioc_sm_hwinit(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_FWREADY:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_TIMEOUT:
+ ioc->retry_count++;
+ if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_reset(ioc, BFA_TRUE);
+ break;
+ }
+
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_enable(ioc);
+}
+
+/**
+ * Host IOC function is being enabled, awaiting response from firmware.
+ * Semaphore is acquired.
+ */
+static void
+bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_FWRSP_ENABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_TIMEOUT:
+ ioc->retry_count++;
+ if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+ bfa_reg_write(ioc->ioc_regs.ioc_fwstate,
+ BFI_IOC_UNINIT);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ break;
+ }
+
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_FWREADY:
+ bfa_ioc_send_enable(ioc);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_getattr(ioc);
+}
+
+/**
+ * IOC configuration in progress. Timer is active.
+ */
+static void
+bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_FWRSP_GETATTR:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)
+{
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
+ bfa_ioc_hb_monitor(ioc);
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE);
+}
+
+static void
+bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_ENABLE:
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hb_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ break;
+
+ case IOC_E_HWERROR:
+ case IOC_E_FWREADY:
+ /**
+ * Hard error or IOC recovery by other function.
+ * Treat it same as heartbeat failure.
+ */
+ bfa_ioc_hb_stop(ioc);
+ /*
+ * !!! fall through !!!
+ */
+
+ case IOC_E_HBFAIL:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE);
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_disable(ioc);
+}
+
+/**
+ * IOC is being disabled
+ */
+static void
+bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_HWERROR:
+ case IOC_E_FWRSP_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * !!! fall through !!!
+ */
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * IOC disable completion entry.
+ */
+static void
+bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_disable_comp(ioc);
+}
+
+static void
+bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_ENABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ case IOC_E_DISABLE:
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ case IOC_E_DETACH:
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc)
+{
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * Hardware initialization failed.
+ */
+static void
+bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_DETACH:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_hbfail_entry(struct bfa_ioc_s *ioc)
+{
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify_s *notify;
+
+ /**
+ * Mark IOC as failed in hardware and stop firmware.
+ */
+ bfa_ioc_lpu_stop(ioc);
+ bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_HBFAIL);
+
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
+ bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P);
+ /*
+ * Wait for halt to take effect
+ */
+ bfa_reg_read(ioc->ioc_regs.ll_halt);
+ }
+
+ /**
+ * Notify driver and common modules registered for notification.
+ */
+ ioc->cbfn->hbfail_cbfn(ioc->bfa);
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify_s *)qe;
+ notify->cbfn(notify->cbarg);
+ }
+
+ /**
+ * Flush any queued up mailbox requests.
+ */
+ bfa_ioc_mbox_hbfail(ioc);
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL);
+
+ /**
+ * Trigger auto-recovery after a delay.
+ */
+ if (ioc->auto_recover) {
+ bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer,
+ bfa_ioc_timeout, ioc, BFA_IOC_TOV_RECOVER);
+ }
+}
+
+/**
+ * IOC heartbeat failure.
+ */
+static void
+bfa_ioc_sm_hbfail(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+
+ case IOC_E_ENABLE:
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ break;
+
+ case IOC_E_DISABLE:
+ if (ioc->auto_recover)
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ case IOC_E_FWREADY:
+ /**
+ * Recovery is already initiated by other function.
+ */
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+
+/**
+ * bfa_ioc_pvt BFA IOC private functions
+ */
+
+static void
+bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)
+{
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify_s *notify;
+
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+
+ /**
+ * Notify common modules registered for notification.
+ */
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify_s *)qe;
+ notify->cbfn(notify->cbarg);
+ }
+}
+
+static void
+bfa_ioc_sem_timeout(void *ioc_arg)
+{
+ struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg;
+
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+static void
+bfa_ioc_usage_sem_get(struct bfa_ioc_s *ioc)
+{
+ u32 r32;
+ int cnt = 0;
+#define BFA_SEM_SPINCNT 1000
+
+ do {
+ r32 = bfa_reg_read(ioc->ioc_regs.ioc_usage_sem_reg);
+ cnt++;
+ if (cnt > BFA_SEM_SPINCNT)
+ break;
+ } while (r32 != 0);
+ bfa_assert(cnt < BFA_SEM_SPINCNT);
+}
+
+static void
+bfa_ioc_usage_sem_release(struct bfa_ioc_s *ioc)
+{
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_sem_reg, 1);
+}
+
+static void
+bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
+{
+ u32 r32;
+
+ /**
+ * First read to the semaphore register will return 0, subsequent reads
+ * will return 1. Semaphore is released by writing 0 to the register
+ */
+ r32 = bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+ if (r32 == 0) {
+ bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED);
+ return;
+ }
+
+ bfa_timer_begin(ioc->timer_mod, &ioc->sem_timer, bfa_ioc_sem_timeout,
+ ioc, BFA_IOC_TOV);
+}
+
+static void
+bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc)
+{
+ bfa_reg_write(ioc->ioc_regs.ioc_sem_reg, 1);
+}
+
+static void
+bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc)
+{
+ bfa_timer_stop(&ioc->sem_timer);
+}
+
+/**
+ * Initialize LPU local memory (aka secondary memory / SRAM)
+ */
+static void
+bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
+{
+ u32 pss_ctl;
+ int i;
+#define PSS_LMEM_INIT_TIME 10000
+
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl &= ~__PSS_LMEM_RESET;
+ pss_ctl |= __PSS_LMEM_INIT_EN;
+ pss_ctl |= __PSS_I2C_CLK_DIV(3UL); /* i2c workaround 12.5khz clock */
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+
+ /**
+ * wait for memory initialization to be complete
+ */
+ i = 0;
+ do {
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ i++;
+ } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
+
+ /**
+ * If memory initialization is not successful, IOC timeout will catch
+ * such failures.
+ */
+ bfa_assert(pss_ctl & __PSS_LMEM_INIT_DONE);
+ bfa_trc(ioc, pss_ctl);
+
+ pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+}
+
+static void
+bfa_ioc_lpu_start(struct bfa_ioc_s *ioc)
+{
+ u32 pss_ctl;
+
+ /**
+ * Take processor out of reset.
+ */
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl &= ~__PSS_LPU0_RESET;
+
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+}
+
+static void
+bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc)
+{
+ u32 pss_ctl;
+
+ /**
+ * Put processors in reset.
+ */
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
+
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+}
+
+/**
+ * Get driver and firmware versions.
+ */
+static void
+bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
+{
+ u32 pgnum, pgoff;
+ u32 loff = 0;
+ int i;
+ u32 *fwsig = (u32 *) fwhdr;
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+
+ for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32));
+ i++) {
+ fwsig[i] = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
+ loff += sizeof(u32);
+ }
+}
+
+static u32 *
+bfa_ioc_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
+{
+ if (ioc->ctdev)
+ return bfi_image_ct_get_chunk(off);
+ return bfi_image_cb_get_chunk(off);
+}
+
+static u32
+bfa_ioc_fwimg_get_size(struct bfa_ioc_s *ioc)
+{
+return (ioc->ctdev) ? bfi_image_ct_size : bfi_image_cb_size;
+}
+
+/**
+ * Returns TRUE if same.
+ */
+static bfa_boolean_t
+bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
+{
+ struct bfi_ioc_image_hdr_s *drv_fwhdr;
+ int i;
+
+ drv_fwhdr =
+ (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+
+ for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
+ if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) {
+ bfa_trc(ioc, i);
+ bfa_trc(ioc, fwhdr->md5sum[i]);
+ bfa_trc(ioc, drv_fwhdr->md5sum[i]);
+ return BFA_FALSE;
+ }
+ }
+
+ bfa_trc(ioc, fwhdr->md5sum[0]);
+ return BFA_TRUE;
+}
+
+/**
+ * Return true if current running version is valid. Firmware signature and
+ * execution context (driver/bios) must match.
+ */
+static bfa_boolean_t
+bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr;
+
+ /**
+ * If bios/efi boot (flash based) -- return true
+ */
+ if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ return BFA_TRUE;
+
+ bfa_ioc_fwver_get(ioc, &fwhdr);
+ drv_fwhdr =
+ (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+
+ if (fwhdr.signature != drv_fwhdr->signature) {
+ bfa_trc(ioc, fwhdr.signature);
+ bfa_trc(ioc, drv_fwhdr->signature);
+ return BFA_FALSE;
+ }
+
+ if (fwhdr.exec != drv_fwhdr->exec) {
+ bfa_trc(ioc, fwhdr.exec);
+ bfa_trc(ioc, drv_fwhdr->exec);
+ return BFA_FALSE;
+ }
+
+ return bfa_ioc_fwver_cmp(ioc, &fwhdr);
+}
+
+/**
+ * Return true if firmware of current driver matches the running firmware.
+ */
+static bfa_boolean_t
+bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc)
+{
+ enum bfi_ioc_state ioc_fwstate;
+ u32 usecnt;
+ struct bfi_ioc_image_hdr_s fwhdr;
+
+ /**
+ * Firmware match check is relevant only for CNA.
+ */
+ if (!ioc->cna)
+ return BFA_TRUE;
+
+ /**
+ * If bios boot (flash based) -- do not increment usage count
+ */
+ if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ return BFA_TRUE;
+
+ bfa_ioc_usage_sem_get(ioc);
+ usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+
+ /**
+ * If usage count is 0, always return TRUE.
+ */
+ if (usecnt == 0) {
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1);
+ bfa_ioc_usage_sem_release(ioc);
+ bfa_trc(ioc, usecnt);
+ return BFA_TRUE;
+ }
+
+ ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+ bfa_trc(ioc, ioc_fwstate);
+
+ /**
+ * Use count cannot be non-zero and chip in uninitialized state.
+ */
+ bfa_assert(ioc_fwstate != BFI_IOC_UNINIT);
+
+ /**
+ * Check if another driver with a different firmware is active
+ */
+ bfa_ioc_fwver_get(ioc, &fwhdr);
+ if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
+ bfa_ioc_usage_sem_release(ioc);
+ bfa_trc(ioc, usecnt);
+ return BFA_FALSE;
+ }
+
+ /**
+ * Same firmware version. Increment the reference count.
+ */
+ usecnt++;
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+ bfa_ioc_usage_sem_release(ioc);
+ bfa_trc(ioc, usecnt);
+ return BFA_TRUE;
+}
+
+static void
+bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc)
+{
+ u32 usecnt;
+
+ /**
+ * Firmware lock is relevant only for CNA.
+ * If bios boot (flash based) -- do not decrement usage count
+ */
+ if (!ioc->cna || (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ))
+ return;
+
+ /**
+ * decrement usage count
+ */
+ bfa_ioc_usage_sem_get(ioc);
+ usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+ bfa_assert(usecnt > 0);
+
+ usecnt--;
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+ bfa_trc(ioc, usecnt);
+
+ bfa_ioc_usage_sem_release(ioc);
+}
+
+/**
+ * Conditionally flush any pending message from firmware at start.
+ */
+static void
+bfa_ioc_msgflush(struct bfa_ioc_s *ioc)
+{
+ u32 r32;
+
+ r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+ if (r32)
+ bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
+}
+
+
+static void
+bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
+{
+ enum bfi_ioc_state ioc_fwstate;
+ bfa_boolean_t fwvalid;
+
+ ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+
+ if (force)
+ ioc_fwstate = BFI_IOC_UNINIT;
+
+ bfa_trc(ioc, ioc_fwstate);
+
+ /**
+ * check if firmware is valid
+ */
+ fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
+ BFA_FALSE : bfa_ioc_fwver_valid(ioc);
+
+ if (!fwvalid) {
+ bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+ return;
+ }
+
+ /**
+ * If hardware initialization is in progress (initialized by other IOC),
+ * just wait for an initialization completion interrupt.
+ */
+ if (ioc_fwstate == BFI_IOC_INITING) {
+ bfa_trc(ioc, ioc_fwstate);
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ return;
+ }
+
+ /**
+ * If IOC function is disabled and firmware version is same,
+ * just re-enable IOC.
+ */
+ if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
+ bfa_trc(ioc, ioc_fwstate);
+
+ /**
+ * When using MSI-X any pending firmware ready event should
+ * be flushed. Otherwise MSI-X interrupts are not delivered.
+ */
+ bfa_ioc_msgflush(ioc);
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ return;
+ }
+
+ /**
+ * Initialize the h/w for any other states.
+ */
+ bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+}
+
+static void
+bfa_ioc_timeout(void *ioc_arg)
+{
+ struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg;
+
+ bfa_trc(ioc, 0);
+ bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
+}
+
+void
+bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len)
+{
+ u32 *msgp = (u32 *) ioc_msg;
+ u32 i;
+
+ bfa_trc(ioc, msgp[0]);
+ bfa_trc(ioc, len);
+
+ bfa_assert(len <= BFI_IOC_MSGLEN_MAX);
+
+ /*
+ * first write msg to mailbox registers
+ */
+ for (i = 0; i < len / sizeof(u32); i++)
+ bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32),
+ bfa_os_wtole(msgp[i]));
+
+ for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
+ bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32), 0);
+
+ /*
+ * write 1 to mailbox CMD to trigger LPU event
+ */
+ bfa_reg_write(ioc->ioc_regs.hfn_mbox_cmd, 1);
+ (void)bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+}
+
+static void
+bfa_ioc_send_enable(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_ctrl_req_s enable_req;
+
+ bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
+ bfa_ioc_portid(ioc));
+ enable_req.ioc_class = ioc->ioc_mc;
+ bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s));
+}
+
+static void
+bfa_ioc_send_disable(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_ctrl_req_s disable_req;
+
+ bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
+ bfa_ioc_portid(ioc));
+ bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req_s));
+}
+
+static void
+bfa_ioc_send_getattr(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_getattr_req_s attr_req;
+
+ bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
+ bfa_ioc_portid(ioc));
+ bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
+ bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
+}
+
+static void
+bfa_ioc_hb_check(void *cbarg)
+{
+ struct bfa_ioc_s *ioc = cbarg;
+ u32 hb_count;
+
+ hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+ if (ioc->hb_count == hb_count) {
+ ioc->hb_fail++;
+ } else {
+ ioc->hb_count = hb_count;
+ ioc->hb_fail = 0;
+ }
+
+ if (ioc->hb_fail >= BFA_IOC_HB_FAIL_MAX) {
+ bfa_log(ioc->logm, BFA_LOG_HAL_HEARTBEAT_FAILURE, hb_count);
+ ioc->hb_fail = 0;
+ bfa_ioc_recover(ioc);
+ return;
+ }
+
+ bfa_ioc_mbox_poll(ioc);
+ bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc,
+ BFA_IOC_HB_TOV);
+}
+
+static void
+bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc)
+{
+ ioc->hb_fail = 0;
+ ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+ bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc,
+ BFA_IOC_HB_TOV);
+}
+
+static void
+bfa_ioc_hb_stop(struct bfa_ioc_s *ioc)
+{
+ bfa_timer_stop(&ioc->ioc_timer);
+}
+
+/**
+ * Host to LPU mailbox message addresses
+ */
+static struct {
+ u32 hfn_mbox, lpu_mbox, hfn_pgn;
+} iocreg_fnreg[] = {
+ {
+ HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0}, {
+ HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1}, {
+ HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2}, {
+ HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3}
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 0
+ */
+static struct {
+ u32 hfn, lpu;
+} iocreg_mbcmd_p0[] = {
+ {
+ HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT}, {
+ HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT}, {
+ HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT}, {
+ HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT}
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 1
+ */
+static struct {
+ u32 hfn, lpu;
+} iocreg_mbcmd_p1[] = {
+ {
+ HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT}, {
+ HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT}, {
+ HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT}, {
+ HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT}
+};
+
+/**
+ * Shared IRQ handling in INTX mode
+ */
+static struct {
+ u32 isr, msk;
+} iocreg_shirq_next[] = {
+ {
+ HOSTFN1_INT_STATUS, HOSTFN1_INT_MSK}, {
+ HOSTFN2_INT_STATUS, HOSTFN2_INT_MSK}, {
+ HOSTFN3_INT_STATUS, HOSTFN3_INT_MSK}, {
+HOSTFN0_INT_STATUS, HOSTFN0_INT_MSK},};
+
+static void
+bfa_ioc_reg_init(struct bfa_ioc_s *ioc)
+{
+ bfa_os_addr_t rb;
+ int pcifn = bfa_ioc_pcifn(ioc);
+
+ rb = bfa_ioc_bar0(ioc);
+
+ ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
+ ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
+ ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
+
+ if (ioc->port_id == 0) {
+ ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
+ ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
+ ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+ } else {
+ ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
+ ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+ ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
+ ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+ }
+
+ /**
+ * Shared IRQ handling in INTX mode
+ */
+ ioc->ioc_regs.shirq_isr_next = rb + iocreg_shirq_next[pcifn].isr;
+ ioc->ioc_regs.shirq_msk_next = rb + iocreg_shirq_next[pcifn].msk;
+
+ /*
+ * PSS control registers
+ */
+ ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
+ ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
+ ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
+
+ /*
+ * IOC semaphore registers and serialization
+ */
+ ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
+ ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
+ ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+
+ /**
+ * sram memory access
+ */
+ ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
+ ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB;
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT)
+ ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
+}
+
+/**
+ * Initiate a full firmware download.
+ */
+static void
+bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
+ u32 boot_param)
+{
+ u32 *fwimg;
+ u32 pgnum, pgoff;
+ u32 loff = 0;
+ u32 chunkno = 0;
+ u32 i;
+
+ /**
+ * Initialize LMEM first before code download
+ */
+ bfa_ioc_lmem_init(ioc);
+
+ /**
+ * Flash based firmware boot
+ */
+ bfa_trc(ioc, bfa_ioc_fwimg_get_size(ioc));
+ if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ boot_type = BFI_BOOT_TYPE_FLASH;
+ fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno);
+ fwimg[BFI_BOOT_TYPE_OFF / sizeof(u32)] = bfa_os_swap32(boot_type);
+ fwimg[BFI_BOOT_PARAM_OFF / sizeof(u32)] =
+ bfa_os_swap32(boot_param);
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+
+ for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) {
+
+ if (BFA_FLASH_CHUNK_NO(i) != chunkno) {
+ chunkno = BFA_FLASH_CHUNK_NO(i);
+ fwimg = bfa_ioc_fwimg_get_chunk(ioc,
+ BFA_FLASH_CHUNK_ADDR(chunkno));
+ }
+
+ /**
+ * write smem
+ */
+ bfa_mem_write(ioc->ioc_regs.smem_page_start, loff,
+ fwimg[BFA_FLASH_OFFSET_IN_CHUNK(i)]);
+
+ loff += sizeof(u32);
+
+ /**
+ * handle page offset wrap around
+ */
+ loff = PSS_SMEM_PGOFF(loff);
+ if (loff == 0) {
+ pgnum++;
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ }
+ }
+
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
+ bfa_ioc_smem_pgnum(ioc, 0));
+}
+
+static void
+bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force)
+{
+ bfa_ioc_hwinit(ioc, force);
+}
+
+/**
+ * Update BFA configuration from firmware configuration.
+ */
+static void
+bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_attr_s *attr = ioc->attr;
+
+ attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop);
+ attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize);
+
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
+}
+
+/**
+ * Attach time initialization of mbox logic.
+ */
+static void
+bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ int mc;
+
+ INIT_LIST_HEAD(&mod->cmd_q);
+ for (mc = 0; mc < BFI_MC_MAX; mc++) {
+ mod->mbhdlr[mc].cbfn = NULL;
+ mod->mbhdlr[mc].cbarg = ioc->bfa;
+ }
+}
+
+/**
+ * Mbox poll timer -- restarts any pending mailbox requests.
+ */
+static void
+bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ struct bfa_mbox_cmd_s *cmd;
+ u32 stat;
+
+ /**
+ * If no command pending, do nothing
+ */
+ if (list_empty(&mod->cmd_q))
+ return;
+
+ /**
+ * If previous command is not yet fetched by firmware, do nothing
+ */
+ stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+ if (stat)
+ return;
+
+ /**
+ * Enqueue command to firmware.
+ */
+ bfa_q_deq(&mod->cmd_q, &cmd);
+ bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Cleanup any pending requests.
+ */
+static void
+bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ struct bfa_mbox_cmd_s *cmd;
+
+ while (!list_empty(&mod->cmd_q))
+ bfa_q_deq(&mod->cmd_q, &cmd);
+}
+
+/**
+ * Initialize IOC to port mapping.
+ */
+
+#define FNC_PERS_FN_SHIFT(__fn) ((__fn) * 8)
+static void
+bfa_ioc_map_port(struct bfa_ioc_s *ioc)
+{
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ u32 r32;
+
+ /**
+ * For crossbow, port id is same as pci function.
+ */
+ if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT) {
+ ioc->port_id = bfa_ioc_pcifn(ioc);
+ return;
+ }
+
+ /**
+ * For catapult, base port id on personality register and IOC type
+ */
+ r32 = bfa_reg_read(rb + FNC_PERS_REG);
+ r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
+ ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
+
+ bfa_trc(ioc, bfa_ioc_pcifn(ioc));
+ bfa_trc(ioc, ioc->port_id);
+}
+
+
+
+/**
+ * bfa_ioc_public
+ */
+
+/**
+* Set interrupt mode for a function: INTX or MSIX
+ */
+void
+bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
+{
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ u32 r32, mode;
+
+ r32 = bfa_reg_read(rb + FNC_PERS_REG);
+ bfa_trc(ioc, r32);
+
+ mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
+ __F0_INTX_STATUS;
+
+ /**
+ * If already in desired mode, do not change anything
+ */
+ if (!msix && mode)
+ return;
+
+ if (msix)
+ mode = __F0_INTX_STATUS_MSIX;
+ else
+ mode = __F0_INTX_STATUS_INTA;
+
+ r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+ r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+ bfa_trc(ioc, r32);
+
+ bfa_reg_write(rb + FNC_PERS_REG, r32);
+}
+
+bfa_status_t
+bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
+{
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ u32 pll_sclk, pll_fclk, r32;
+
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
+ pll_sclk =
+ __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
+ __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(0U) |
+ __APP_PLL_312_JITLMT0_1(3U) |
+ __APP_PLL_312_CNTLMT0_1(1U);
+ pll_fclk =
+ __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
+ __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(0U) |
+ __APP_PLL_425_JITLMT0_1(3U) |
+ __APP_PLL_425_CNTLMT0_1(1U);
+
+ /**
+ * For catapult, choose operational mode FC/FCoE
+ */
+ if (ioc->fcmode) {
+ bfa_reg_write((rb + OP_MODE), 0);
+ bfa_reg_write((rb + ETH_MAC_SER_REG),
+ __APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2
+ | __APP_EMS_CHANNEL_SEL);
+ } else {
+ ioc->pllinit = BFA_TRUE;
+ bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE);
+ bfa_reg_write((rb + ETH_MAC_SER_REG),
+ __APP_EMS_REFCKBUFEN1);
+ }
+ } else {
+ pll_sclk =
+ __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
+ __APP_PLL_312_P0_1(3U) | __APP_PLL_312_JITLMT0_1(3U) |
+ __APP_PLL_312_CNTLMT0_1(3U);
+ pll_fclk =
+ __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
+ __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
+ __APP_PLL_425_JITLMT0_1(3U) |
+ __APP_PLL_425_CNTLMT0_1(3U);
+ }
+
+ bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
+ bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
+
+ bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ __APP_PLL_312_BYPASS | __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ __APP_PLL_425_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ __APP_PLL_425_BYPASS | __APP_PLL_425_LOGIC_SOFT_RESET);
+ bfa_os_udelay(2);
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ __APP_PLL_425_LOGIC_SOFT_RESET);
+
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET);
+
+ /**
+ * Wait for PLLs to lock.
+ */
+ bfa_os_udelay(2000);
+ bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk);
+
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
+ bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
+ bfa_os_udelay(1000);
+ r32 = bfa_reg_read((rb + MBIST_STAT_REG));
+ bfa_trc(ioc, r32);
+ }
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Interface used by diag module to do firmware boot with memory test
+ * as the entry vector.
+ */
+void
+bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param)
+{
+ bfa_os_addr_t rb;
+
+ bfa_ioc_stats(ioc, ioc_boots);
+
+ if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
+ return;
+
+ /**
+ * Initialize IOC state of all functions on a chip reset.
+ */
+ rb = ioc->pcidev.pci_bar_kva;
+ if (boot_param == BFI_BOOT_TYPE_MEMTEST) {
+ bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_MEMTEST);
+ bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_MEMTEST);
+ } else {
+ bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_INITING);
+ bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING);
+ }
+
+ bfa_ioc_download_fw(ioc, boot_type, boot_param);
+
+ /**
+ * Enable interrupts just before starting LPU
+ */
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ bfa_ioc_lpu_start(ioc);
+}
+
+/**
+ * Enable/disable IOC failure auto recovery.
+ */
+void
+bfa_ioc_auto_recover(bfa_boolean_t auto_recover)
+{
+ bfa_auto_recover = BFA_FALSE;
+}
+
+
+bfa_boolean_t
+bfa_ioc_is_operational(struct bfa_ioc_s *ioc)
+{
+ return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
+}
+
+void
+bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg)
+{
+ u32 *msgp = mbmsg;
+ u32 r32;
+ int i;
+
+ /**
+ * read the MBOX msg
+ */
+ for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
+ i++) {
+ r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox +
+ i * sizeof(u32));
+ msgp[i] = bfa_os_htonl(r32);
+ }
+
+ /**
+ * turn off mailbox interrupt by clearing mailbox status
+ */
+ bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
+ bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+void
+bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m)
+{
+ union bfi_ioc_i2h_msg_u *msg;
+
+ msg = (union bfi_ioc_i2h_msg_u *)m;
+
+ bfa_ioc_stats(ioc, ioc_isrs);
+
+ switch (msg->mh.msg_id) {
+ case BFI_IOC_I2H_HBEAT:
+ break;
+
+ case BFI_IOC_I2H_READY_EVENT:
+ bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ break;
+
+ case BFI_IOC_I2H_ENABLE_REPLY:
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE);
+ break;
+
+ case BFI_IOC_I2H_DISABLE_REPLY:
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE);
+ break;
+
+ case BFI_IOC_I2H_GETATTR_REPLY:
+ bfa_ioc_getattr_reply(ioc);
+ break;
+
+ default:
+ bfa_trc(ioc, msg->mh.msg_id);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IOC attach time initialization and setup.
+ *
+ * @param[in] ioc memory for IOC
+ * @param[in] bfa driver instance structure
+ * @param[in] trcmod kernel trace module
+ * @param[in] aen kernel aen event module
+ * @param[in] logm kernel logging module
+ */
+void
+bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn,
+ struct bfa_timer_mod_s *timer_mod, struct bfa_trc_mod_s *trcmod,
+ struct bfa_aen_s *aen, struct bfa_log_mod_s *logm)
+{
+ ioc->bfa = bfa;
+ ioc->cbfn = cbfn;
+ ioc->timer_mod = timer_mod;
+ ioc->trcmod = trcmod;
+ ioc->aen = aen;
+ ioc->logm = logm;
+ ioc->fcmode = BFA_FALSE;
+ ioc->pllinit = BFA_FALSE;
+ ioc->dbg_fwsave_once = BFA_TRUE;
+
+ bfa_ioc_mbox_attach(ioc);
+ INIT_LIST_HEAD(&ioc->hb_notify_q);
+
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+}
+
+/**
+ * Driver detach time IOC cleanup.
+ */
+void
+bfa_ioc_detach(struct bfa_ioc_s *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_DETACH);
+}
+
+/**
+ * Setup IOC PCI properties.
+ *
+ * @param[in] pcidev PCI device information for this IOC
+ */
+void
+bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
+ enum bfi_mclass mc)
+{
+ ioc->ioc_mc = mc;
+ ioc->pcidev = *pcidev;
+ ioc->ctdev = (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT);
+ ioc->cna = ioc->ctdev && !ioc->fcmode;
+
+ bfa_ioc_map_port(ioc);
+ bfa_ioc_reg_init(ioc);
+}
+
+/**
+ * Initialize IOC dma memory
+ *
+ * @param[in] dm_kva kernel virtual address of IOC dma memory
+ * @param[in] dm_pa physical address of IOC dma memory
+ */
+void
+bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa)
+{
+ /**
+ * dma memory for firmware attribute
+ */
+ ioc->attr_dma.kva = dm_kva;
+ ioc->attr_dma.pa = dm_pa;
+ ioc->attr = (struct bfi_ioc_attr_s *)dm_kva;
+}
+
+/**
+ * Return size of dma memory required.
+ */
+u32
+bfa_ioc_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_ioc_enable(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_stats(ioc, ioc_enables);
+ ioc->dbg_fwsave_once = BFA_TRUE;
+
+ bfa_fsm_send_event(ioc, IOC_E_ENABLE);
+}
+
+void
+bfa_ioc_disable(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_stats(ioc, ioc_disables);
+ bfa_fsm_send_event(ioc, IOC_E_DISABLE);
+}
+
+/**
+ * Returns memory required for saving firmware trace in case of crash.
+ * Driver must call this interface to allocate memory required for
+ * automatic saving of firmware trace. Driver should call
+ * bfa_ioc_debug_memclaim() right after bfa_ioc_attach() to setup this
+ * trace memory.
+ */
+int
+bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover)
+{
+return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
+}
+
+/**
+ * Initialize memory for saving firmware trace. Driver must initialize
+ * trace memory before call bfa_ioc_enable().
+ */
+void
+bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave)
+{
+ bfa_assert(ioc->auto_recover);
+ ioc->dbg_fwsave = dbg_fwsave;
+ ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->auto_recover);
+}
+
+u32
+bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr)
+{
+ return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
+}
+
+u32
+bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr)
+{
+ return PSS_SMEM_PGOFF(fmaddr);
+}
+
+/**
+ * Register mailbox message handler functions
+ *
+ * @param[in] ioc IOC instance
+ * @param[in] mcfuncs message class handler functions
+ */
+void
+bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ int mc;
+
+ for (mc = 0; mc < BFI_MC_MAX; mc++)
+ mod->mbhdlr[mc].cbfn = mcfuncs[mc];
+}
+
+/**
+ * Register mailbox message handler function, to be called by common modules
+ */
+void
+bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
+ bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+
+ mod->mbhdlr[mc].cbfn = cbfn;
+ mod->mbhdlr[mc].cbarg = cbarg;
+}
+
+/**
+ * Queue a mailbox command request to firmware. Waits if mailbox is busy.
+ * Responsibility of caller to serialize
+ *
+ * @param[in] ioc IOC instance
+ * @param[i] cmd Mailbox command
+ */
+void
+bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ u32 stat;
+
+ /**
+ * If a previous command is pending, queue new command
+ */
+ if (!list_empty(&mod->cmd_q)) {
+ list_add_tail(&cmd->qe, &mod->cmd_q);
+ return;
+ }
+
+ /**
+ * If mailbox is busy, queue command for poll timer
+ */
+ stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+ if (stat) {
+ list_add_tail(&cmd->qe, &mod->cmd_q);
+ return;
+ }
+
+ /**
+ * mailbox is free -- queue command to firmware
+ */
+ bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Handle mailbox interrupts
+ */
+void
+bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ struct bfi_mbmsg_s m;
+ int mc;
+
+ bfa_ioc_msgget(ioc, &m);
+
+ /**
+ * Treat IOC message class as special.
+ */
+ mc = m.mh.msg_class;
+ if (mc == BFI_MC_IOC) {
+ bfa_ioc_isr(ioc, &m);
+ return;
+ }
+
+ if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
+ return;
+
+ mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
+}
+
+void
+bfa_ioc_error_isr(struct bfa_ioc_s *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_HWERROR);
+}
+
+#ifndef BFA_BIOS_BUILD
+
+/**
+ * return true if IOC is disabled
+ */
+bfa_boolean_t
+bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
+{
+ return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling)
+ || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled));
+}
+
+/**
+ * return true if IOC firmware is different.
+ */
+bfa_boolean_t
+bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)
+{
+ return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset)
+ || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_fwcheck)
+ || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch));
+}
+
+#define bfa_ioc_state_disabled(__sm) \
+ (((__sm) == BFI_IOC_UNINIT) || \
+ ((__sm) == BFI_IOC_INITING) || \
+ ((__sm) == BFI_IOC_HWINIT) || \
+ ((__sm) == BFI_IOC_DISABLED) || \
+ ((__sm) == BFI_IOC_HBFAIL) || \
+ ((__sm) == BFI_IOC_CFG_DISABLED))
+
+/**
+ * Check if adapter is disabled -- both IOCs should be in a disabled
+ * state.
+ */
+bfa_boolean_t
+bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)
+{
+ u32 ioc_state;
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+
+ if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))
+ return BFA_FALSE;
+
+ ioc_state = bfa_reg_read(rb + BFA_IOC0_STATE_REG);
+ if (!bfa_ioc_state_disabled(ioc_state))
+ return BFA_FALSE;
+
+ ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG);
+ if (!bfa_ioc_state_disabled(ioc_state))
+ return BFA_FALSE;
+
+ return BFA_TRUE;
+}
+
+/**
+ * Add to IOC heartbeat failure notification queue. To be used by common
+ * modules such as
+ */
+void
+bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
+ struct bfa_ioc_hbfail_notify_s *notify)
+{
+ list_add_tail(&notify->qe, &ioc->hb_notify_q);
+}
+
+#define BFA_MFG_NAME "Brocade"
+void
+bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
+ struct bfa_adapter_attr_s *ad_attr)
+{
+ struct bfi_ioc_attr_s *ioc_attr;
+ char model[BFA_ADAPTER_MODEL_NAME_LEN];
+
+ ioc_attr = ioc->attr;
+ bfa_os_memcpy((void *)&ad_attr->serial_num,
+ (void *)ioc_attr->brcd_serialnum,
+ BFA_ADAPTER_SERIAL_NUM_LEN);
+
+ bfa_os_memcpy(&ad_attr->fw_ver, ioc_attr->fw_version, BFA_VERSION_LEN);
+ bfa_os_memcpy(&ad_attr->optrom_ver, ioc_attr->optrom_version,
+ BFA_VERSION_LEN);
+ bfa_os_memcpy(&ad_attr->manufacturer, BFA_MFG_NAME,
+ BFA_ADAPTER_MFG_NAME_LEN);
+ bfa_os_memcpy(&ad_attr->vpd, &ioc_attr->vpd,
+ sizeof(struct bfa_mfg_vpd_s));
+
+ ad_attr->nports = BFI_ADAPTER_GETP(NPORTS, ioc_attr->adapter_prop);
+ ad_attr->max_speed = BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop);
+
+ /**
+ * model name
+ */
+ if (BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop) == 10) {
+ strcpy(model, "BR-10?0");
+ model[5] = '0' + ad_attr->nports;
+ } else {
+ strcpy(model, "Brocade-??5");
+ model[8] =
+ '0' + BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop);
+ model[9] = '0' + ad_attr->nports;
+ }
+
+ if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
+ ad_attr->prototype = 1;
+ else
+ ad_attr->prototype = 0;
+
+ bfa_os_memcpy(&ad_attr->model, model, BFA_ADAPTER_MODEL_NAME_LEN);
+ bfa_os_memcpy(&ad_attr->model_descr, &ad_attr->model,
+ BFA_ADAPTER_MODEL_NAME_LEN);
+
+ ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
+ ad_attr->mac = bfa_ioc_get_mac(ioc);
+
+ ad_attr->pcie_gen = ioc_attr->pcie_gen;
+ ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
+ ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
+ ad_attr->asic_rev = ioc_attr->asic_rev;
+ ad_attr->hw_ver[0] = 'R';
+ ad_attr->hw_ver[1] = 'e';
+ ad_attr->hw_ver[2] = 'v';
+ ad_attr->hw_ver[3] = '-';
+ ad_attr->hw_ver[4] = ioc_attr->asic_rev;
+ ad_attr->hw_ver[5] = '\0';
+
+ ad_attr->cna_capable = ioc->cna;
+}
+
+void
+bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
+{
+ bfa_os_memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
+
+ ioc_attr->state = bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+ ioc_attr->port_id = ioc->port_id;
+
+ if (!ioc->ctdev)
+ ioc_attr->ioc_type = BFA_IOC_TYPE_FC;
+ else if (ioc->ioc_mc == BFI_MC_IOCFC)
+ ioc_attr->ioc_type = BFA_IOC_TYPE_FCoE;
+ else if (ioc->ioc_mc == BFI_MC_LL)
+ ioc_attr->ioc_type = BFA_IOC_TYPE_LL;
+
+ bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
+
+ ioc_attr->pci_attr.device_id = ioc->pcidev.device_id;
+ ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func;
+ ioc_attr->pci_attr.chip_rev[0] = 'R';
+ ioc_attr->pci_attr.chip_rev[1] = 'e';
+ ioc_attr->pci_attr.chip_rev[2] = 'v';
+ ioc_attr->pci_attr.chip_rev[3] = '-';
+ ioc_attr->pci_attr.chip_rev[4] = ioc_attr->adapter_attr.asic_rev;
+ ioc_attr->pci_attr.chip_rev[5] = '\0';
+}
+
+/**
+ * hal_wwn_public
+ */
+wwn_t
+bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc)
+{
+ union {
+ wwn_t wwn;
+ u8 byte[sizeof(wwn_t)];
+ }
+ w;
+
+ w.wwn = ioc->attr->mfg_wwn;
+
+ if (bfa_ioc_portid(ioc) == 1)
+ w.byte[7]++;
+
+ return w.wwn;
+}
+
+wwn_t
+bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc)
+{
+ union {
+ wwn_t wwn;
+ u8 byte[sizeof(wwn_t)];
+ }
+ w;
+
+ w.wwn = ioc->attr->mfg_wwn;
+
+ if (bfa_ioc_portid(ioc) == 1)
+ w.byte[7]++;
+
+ w.byte[0] = 0x20;
+
+ return w.wwn;
+}
+
+wwn_t
+bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst)
+{
+ union {
+ wwn_t wwn;
+ u8 byte[sizeof(wwn_t)];
+ }
+ w , w5;
+
+ bfa_trc(ioc, inst);
+
+ w.wwn = ioc->attr->mfg_wwn;
+ w5.byte[0] = 0x50 | w.byte[2] >> 4;
+ w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4;
+ w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4;
+ w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4;
+ w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4;
+ w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4;
+ w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8;
+ w5.byte[7] = (inst & 0xff);
+
+ return w5.wwn;
+}
+
+u64
+bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
+{
+ return ioc->attr->mfg_wwn;
+}
+
+mac_t
+bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
+{
+ mac_t mac;
+
+ mac = ioc->attr->mfg_mac;
+ mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
+
+ return mac;
+}
+
+void
+bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
+{
+ ioc->fcmode = BFA_TRUE;
+ ioc->port_id = bfa_ioc_pcifn(ioc);
+}
+
+bfa_boolean_t
+bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
+{
+ return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT);
+}
+
+/**
+ * Return true if interrupt should be claimed.
+ */
+bfa_boolean_t
+bfa_ioc_intx_claim(struct bfa_ioc_s *ioc)
+{
+ u32 isr, msk;
+
+ /**
+ * Always claim if not catapult.
+ */
+ if (!ioc->ctdev)
+ return BFA_TRUE;
+
+ /**
+ * FALSE if next device is claiming interrupt.
+ * TRUE if next device is not interrupting or not present.
+ */
+ msk = bfa_reg_read(ioc->ioc_regs.shirq_msk_next);
+ isr = bfa_reg_read(ioc->ioc_regs.shirq_isr_next);
+ return !(isr & ~msk);
+}
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = ioc->logm;
+ s32 inst_num = 0;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ switch (event) {
+ case BFA_IOC_AEN_HBGOOD:
+ bfa_log(logmod, BFA_AEN_IOC_HBGOOD, inst_num);
+ break;
+ case BFA_IOC_AEN_HBFAIL:
+ bfa_log(logmod, BFA_AEN_IOC_HBFAIL, inst_num);
+ break;
+ case BFA_IOC_AEN_ENABLE:
+ bfa_log(logmod, BFA_AEN_IOC_ENABLE, inst_num);
+ break;
+ case BFA_IOC_AEN_DISABLE:
+ bfa_log(logmod, BFA_AEN_IOC_DISABLE, inst_num);
+ break;
+ case BFA_IOC_AEN_FWMISMATCH:
+ bfa_log(logmod, BFA_AEN_IOC_FWMISMATCH, inst_num);
+ break;
+ default:
+ break;
+ }
+
+ memset(&aen_data.ioc.pwwn, 0, sizeof(aen_data.ioc.pwwn));
+ memset(&aen_data.ioc.mac, 0, sizeof(aen_data.ioc.mac));
+ bfa_ioc_get_attr(ioc, &ioc_attr);
+ switch (ioc_attr.ioc_type) {
+ case BFA_IOC_TYPE_FC:
+ aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc);
+ break;
+ case BFA_IOC_TYPE_FCoE:
+ aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc);
+ aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+ break;
+ case BFA_IOC_TYPE_LL:
+ aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+ break;
+ default:
+ bfa_assert(ioc_attr.ioc_type == BFA_IOC_TYPE_FC);
+ break;
+ }
+ aen_data.ioc.ioc_type = ioc_attr.ioc_type;
+}
+
+/**
+ * Retrieve saved firmware trace from a prior IOC failure.
+ */
+bfa_status_t
+bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
+{
+ int tlen;
+
+ if (ioc->dbg_fwsave_len == 0)
+ return BFA_STATUS_ENOFSAVE;
+
+ tlen = *trclen;
+ if (tlen > ioc->dbg_fwsave_len)
+ tlen = ioc->dbg_fwsave_len;
+
+ bfa_os_memcpy(trcdata, ioc->dbg_fwsave, tlen);
+ *trclen = tlen;
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Retrieve saved firmware trace from a prior IOC failure.
+ */
+bfa_status_t
+bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
+{
+ u32 pgnum;
+ u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc));
+ int i, tlen;
+ u32 *tbuf = trcdata, r32;
+
+ bfa_trc(ioc, *trclen);
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ loff = bfa_ioc_smem_pgoff(ioc, loff);
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+
+ tlen = *trclen;
+ if (tlen > BFA_DBG_FWTRC_LEN)
+ tlen = BFA_DBG_FWTRC_LEN;
+ tlen /= sizeof(u32);
+
+ bfa_trc(ioc, tlen);
+
+ for (i = 0; i < tlen; i++) {
+ r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
+ tbuf[i] = bfa_os_ntohl(r32);
+ loff += sizeof(u32);
+
+ /**
+ * handle page offset wrap around
+ */
+ loff = PSS_SMEM_PGOFF(loff);
+ if (loff == 0) {
+ pgnum++;
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ }
+ }
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
+ bfa_ioc_smem_pgnum(ioc, 0));
+ bfa_trc(ioc, pgnum);
+
+ *trclen = tlen * sizeof(u32);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Save firmware trace if configured.
+ */
+static void
+bfa_ioc_debug_save(struct bfa_ioc_s *ioc)
+{
+ int tlen;
+
+ if (ioc->dbg_fwsave_len) {
+ tlen = ioc->dbg_fwsave_len;
+ bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
+ }
+}
+
+/**
+ * Firmware failure detected. Start recovery actions.
+ */
+static void
+bfa_ioc_recover(struct bfa_ioc_s *ioc)
+{
+ if (ioc->dbg_fwsave_once) {
+ ioc->dbg_fwsave_once = BFA_FALSE;
+ bfa_ioc_debug_save(ioc);
+ }
+
+ bfa_ioc_stats(ioc, ioc_hbfails);
+ bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
+}
+
+#else
+
+static void
+bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+{
+}
+
+static void
+bfa_ioc_recover(struct bfa_ioc_s *ioc)
+{
+ bfa_assert(0);
+}
+
+#endif
+
+
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
new file mode 100644
index 000000000000..58efd4b13143
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_IOC_H__
+#define __BFA_IOC_H__
+
+#include <cs/bfa_sm.h>
+#include <bfi/bfi.h>
+#include <bfi/bfi_ioc.h>
+#include <bfi/bfi_boot.h>
+#include <bfa_timer.h>
+
+/**
+ * PCI device information required by IOC
+ */
+struct bfa_pcidev_s {
+ int pci_slot;
+ u8 pci_func;
+ u16 device_id;
+ bfa_os_addr_t pci_bar_kva;
+};
+
+/**
+ * Structure used to remember the DMA-able memory block's KVA and Physical
+ * Address
+ */
+struct bfa_dma_s {
+ void *kva; /*! Kernel virtual address */
+ u64 pa; /*! Physical address */
+};
+
+#define BFA_DMA_ALIGN_SZ 256
+#define BFA_ROUNDUP(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1))
+
+
+
+#define bfa_dma_addr_set(dma_addr, pa) \
+ __bfa_dma_addr_set(&dma_addr, (u64)pa)
+
+static inline void
+__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+ dma_addr->a32.addr_lo = (u32) pa;
+ dma_addr->a32.addr_hi = (u32) (bfa_os_u32(pa));
+}
+
+
+#define bfa_dma_be_addr_set(dma_addr, pa) \
+ __bfa_dma_be_addr_set(&dma_addr, (u64)pa)
+static inline void
+__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+ dma_addr->a32.addr_lo = (u32) bfa_os_htonl(pa);
+ dma_addr->a32.addr_hi = (u32) bfa_os_htonl(bfa_os_u32(pa));
+}
+
+struct bfa_ioc_regs_s {
+ bfa_os_addr_t hfn_mbox_cmd;
+ bfa_os_addr_t hfn_mbox;
+ bfa_os_addr_t lpu_mbox_cmd;
+ bfa_os_addr_t lpu_mbox;
+ bfa_os_addr_t pss_ctl_reg;
+ bfa_os_addr_t app_pll_fast_ctl_reg;
+ bfa_os_addr_t app_pll_slow_ctl_reg;
+ bfa_os_addr_t ioc_sem_reg;
+ bfa_os_addr_t ioc_usage_sem_reg;
+ bfa_os_addr_t ioc_usage_reg;
+ bfa_os_addr_t host_page_num_fn;
+ bfa_os_addr_t heartbeat;
+ bfa_os_addr_t ioc_fwstate;
+ bfa_os_addr_t ll_halt;
+ bfa_os_addr_t shirq_isr_next;
+ bfa_os_addr_t shirq_msk_next;
+ bfa_os_addr_t smem_page_start;
+ u32 smem_pg0;
+};
+
+#define bfa_reg_read(_raddr) bfa_os_reg_read(_raddr)
+#define bfa_reg_write(_raddr, _val) bfa_os_reg_write(_raddr, _val)
+#define bfa_mem_read(_raddr, _off) bfa_os_mem_read(_raddr, _off)
+#define bfa_mem_write(_raddr, _off, _val) \
+ bfa_os_mem_write(_raddr, _off, _val)
+/**
+ * IOC Mailbox structures
+ */
+struct bfa_mbox_cmd_s {
+ struct list_head qe;
+ u32 msg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * IOC mailbox module
+ */
+typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m);
+struct bfa_ioc_mbox_mod_s {
+ struct list_head cmd_q; /* pending mbox queue */
+ int nmclass; /* number of handlers */
+ struct {
+ bfa_ioc_mbox_mcfunc_t cbfn; /* message handlers */
+ void *cbarg;
+ } mbhdlr[BFI_MC_MAX];
+};
+
+/**
+ * IOC callback function interfaces
+ */
+typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status);
+typedef void (*bfa_ioc_disable_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_hbfail_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_reset_cbfn_t)(void *bfa);
+struct bfa_ioc_cbfn_s {
+ bfa_ioc_enable_cbfn_t enable_cbfn;
+ bfa_ioc_disable_cbfn_t disable_cbfn;
+ bfa_ioc_hbfail_cbfn_t hbfail_cbfn;
+ bfa_ioc_reset_cbfn_t reset_cbfn;
+};
+
+/**
+ * Heartbeat failure notification queue element.
+ */
+struct bfa_ioc_hbfail_notify_s {
+ struct list_head qe;
+ bfa_ioc_hbfail_cbfn_t cbfn;
+ void *cbarg;
+};
+
+/**
+ * Initialize a heartbeat failure notification structure
+ */
+#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do { \
+ (__notify)->cbfn = (__cbfn); \
+ (__notify)->cbarg = (__cbarg); \
+} while (0)
+
+struct bfa_ioc_s {
+ bfa_fsm_t fsm;
+ struct bfa_s *bfa;
+ struct bfa_pcidev_s pcidev;
+ struct bfa_timer_mod_s *timer_mod;
+ struct bfa_timer_s ioc_timer;
+ struct bfa_timer_s sem_timer;
+ u32 hb_count;
+ u32 hb_fail;
+ u32 retry_count;
+ struct list_head hb_notify_q;
+ void *dbg_fwsave;
+ int dbg_fwsave_len;
+ bfa_boolean_t dbg_fwsave_once;
+ enum bfi_mclass ioc_mc;
+ struct bfa_ioc_regs_s ioc_regs;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_aen_s *aen;
+ struct bfa_log_mod_s *logm;
+ struct bfa_ioc_drv_stats_s stats;
+ bfa_boolean_t auto_recover;
+ bfa_boolean_t fcmode;
+ bfa_boolean_t ctdev;
+ bfa_boolean_t cna;
+ bfa_boolean_t pllinit;
+ u8 port_id;
+
+ struct bfa_dma_s attr_dma;
+ struct bfi_ioc_attr_s *attr;
+ struct bfa_ioc_cbfn_s *cbfn;
+ struct bfa_ioc_mbox_mod_s mbox_mod;
+};
+
+#define bfa_ioc_pcifn(__ioc) (__ioc)->pcidev.pci_func
+#define bfa_ioc_devid(__ioc) (__ioc)->pcidev.device_id
+#define bfa_ioc_bar0(__ioc) (__ioc)->pcidev.pci_bar_kva
+#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_ioc_fetch_stats(__ioc, __stats) \
+ ((__stats)->drv_stats) = (__ioc)->stats
+#define bfa_ioc_clr_stats(__ioc) \
+ bfa_os_memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
+#define bfa_ioc_maxfrsize(__ioc) (__ioc)->attr->maxfrsize
+#define bfa_ioc_rx_bbcredit(__ioc) (__ioc)->attr->rx_bbcredit
+#define bfa_ioc_speed_sup(__ioc) \
+ BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
+
+/**
+ * IOC mailbox interface
+ */
+void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd);
+void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc,
+ bfa_ioc_mbox_mcfunc_t *mcfuncs);
+void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc);
+void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len);
+void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg);
+void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
+ bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
+
+/**
+ * IOC interfaces
+ */
+void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa,
+ struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod,
+ struct bfa_trc_mod_s *trcmod,
+ struct bfa_aen_s *aen, struct bfa_log_mod_s *logm);
+void bfa_ioc_detach(struct bfa_ioc_s *ioc);
+void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
+ enum bfi_mclass mc);
+u32 bfa_ioc_meminfo(void);
+void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa);
+void bfa_ioc_enable(struct bfa_ioc_s *ioc);
+void bfa_ioc_disable(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc);
+
+void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param);
+void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg);
+void bfa_ioc_error_isr(struct bfa_ioc_s *ioc);
+void bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t intx);
+bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc);
+void bfa_ioc_cfg_complete(struct bfa_ioc_s *ioc);
+void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr);
+void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
+ struct bfa_adapter_attr_s *ad_attr);
+int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover);
+void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave);
+bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata,
+ int *trclen);
+bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata,
+ int *trclen);
+u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr);
+u32 bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr);
+void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc);
+void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
+ struct bfa_ioc_hbfail_notify_s *notify);
+
+/*
+ * bfa mfg wwn API functions
+ */
+wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst);
+mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc);
+u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc);
+
+#endif /* __BFA_IOC_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c
new file mode 100644
index 000000000000..12350b022d63
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_iocfc.c
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 2005-2009 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 <cs/bfa_debug.h>
+#include <bfa_priv.h>
+#include <log/bfa_log_hal.h>
+#include <bfi/bfi_boot.h>
+#include <bfi/bfi_cbreg.h>
+#include <aen/bfa_aen_ioc.h>
+#include <defs/bfa_defs_iocfc.h>
+#include <defs/bfa_defs_pci.h>
+#include "bfa_callback_priv.h"
+#include "bfad_drv.h"
+
+BFA_TRC_FILE(HAL, IOCFC);
+
+/**
+ * IOC local definitions
+ */
+#define BFA_IOCFC_TOV 5000 /* msecs */
+
+enum {
+ BFA_IOCFC_ACT_NONE = 0,
+ BFA_IOCFC_ACT_INIT = 1,
+ BFA_IOCFC_ACT_STOP = 2,
+ BFA_IOCFC_ACT_DISABLE = 3,
+};
+
+/*
+ * forward declarations
+ */
+static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status);
+static void bfa_iocfc_disable_cbfn(void *bfa_arg);
+static void bfa_iocfc_hbfail_cbfn(void *bfa_arg);
+static void bfa_iocfc_reset_cbfn(void *bfa_arg);
+static void bfa_iocfc_stats_clear(void *bfa_arg);
+static void bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d,
+ struct bfa_fw_stats_s *s);
+static void bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete);
+static void bfa_iocfc_stats_clr_timeout(void *bfa_arg);
+static void bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete);
+static void bfa_iocfc_stats_timeout(void *bfa_arg);
+
+static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn;
+
+/**
+ * bfa_ioc_pvt BFA IOC private functions
+ */
+
+static void
+bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
+{
+ int i, per_reqq_sz, per_rspq_sz;
+
+ per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+ per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+
+ /*
+ * Calculate CQ size
+ */
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ *dm_len = *dm_len + per_reqq_sz;
+ *dm_len = *dm_len + per_rspq_sz;
+ }
+
+ /*
+ * Calculate Shadow CI/PI size
+ */
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++)
+ *dm_len += (2 * BFA_CACHELINE_SZ);
+}
+
+static void
+bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
+{
+ *dm_len +=
+ BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
+ *dm_len +=
+ BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
+ BFA_CACHELINE_SZ);
+ *dm_len += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
+}
+
+/**
+ * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ
+ */
+static void
+bfa_iocfc_send_cfg(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfg_req_s cfg_req;
+ struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo;
+ struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg;
+ int i;
+
+ bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS);
+ bfa_trc(bfa, cfg->fwcfg.num_cqs);
+
+ iocfc->cfgdone = BFA_FALSE;
+ bfa_iocfc_reset_queues(bfa);
+
+ /**
+ * initialize IOC configuration info
+ */
+ cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG;
+ cfg_info->num_cqs = cfg->fwcfg.num_cqs;
+
+ bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa);
+ bfa_dma_be_addr_set(cfg_info->stats_addr, iocfc->stats_pa);
+
+ /**
+ * dma map REQ and RSP circular queues and shadow pointers
+ */
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ bfa_dma_be_addr_set(cfg_info->req_cq_ba[i],
+ iocfc->req_cq_ba[i].pa);
+ bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i],
+ iocfc->req_cq_shadow_ci[i].pa);
+ cfg_info->req_cq_elems[i] =
+ bfa_os_htons(cfg->drvcfg.num_reqq_elems);
+
+ bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i],
+ iocfc->rsp_cq_ba[i].pa);
+ bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i],
+ iocfc->rsp_cq_shadow_pi[i].pa);
+ cfg_info->rsp_cq_elems[i] =
+ bfa_os_htons(cfg->drvcfg.num_rspq_elems);
+ }
+
+ /**
+ * dma map IOC configuration itself
+ */
+ bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
+ bfa_lpuid(bfa));
+ bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa);
+
+ bfa_ioc_mbox_send(&bfa->ioc, &cfg_req,
+ sizeof(struct bfi_iocfc_cfg_req_s));
+}
+
+static void
+bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ bfa->bfad = bfad;
+ iocfc->bfa = bfa;
+ iocfc->action = BFA_IOCFC_ACT_NONE;
+
+ bfa_os_assign(iocfc->cfg, *cfg);
+
+ /**
+ * Initialize chip specific handlers.
+ */
+ if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) {
+ iocfc->hwif.hw_reginit = bfa_hwct_reginit;
+ iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack;
+ iocfc->hwif.hw_msix_init = bfa_hwct_msix_init;
+ iocfc->hwif.hw_msix_install = bfa_hwct_msix_install;
+ iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall;
+ iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set;
+ iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs;
+ } else {
+ iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
+ iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
+ iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init;
+ iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install;
+ iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall;
+ iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set;
+ iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs;
+ }
+
+ iocfc->hwif.hw_reginit(bfa);
+ bfa->msix.nvecs = 0;
+}
+
+static void
+bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo)
+{
+ u8 *dm_kva;
+ u64 dm_pa;
+ int i, per_reqq_sz, per_rspq_sz;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ int dbgsz;
+
+ dm_kva = bfa_meminfo_dma_virt(meminfo);
+ dm_pa = bfa_meminfo_dma_phys(meminfo);
+
+ /*
+ * First allocate dma memory for IOC.
+ */
+ bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa);
+ dm_kva += bfa_ioc_meminfo();
+ dm_pa += bfa_ioc_meminfo();
+
+ /*
+ * Claim DMA-able memory for the request/response queues and for shadow
+ * ci/pi registers
+ */
+ per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+ per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ iocfc->req_cq_ba[i].kva = dm_kva;
+ iocfc->req_cq_ba[i].pa = dm_pa;
+ bfa_os_memset(dm_kva, 0, per_reqq_sz);
+ dm_kva += per_reqq_sz;
+ dm_pa += per_reqq_sz;
+
+ iocfc->rsp_cq_ba[i].kva = dm_kva;
+ iocfc->rsp_cq_ba[i].pa = dm_pa;
+ bfa_os_memset(dm_kva, 0, per_rspq_sz);
+ dm_kva += per_rspq_sz;
+ dm_pa += per_rspq_sz;
+ }
+
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ iocfc->req_cq_shadow_ci[i].kva = dm_kva;
+ iocfc->req_cq_shadow_ci[i].pa = dm_pa;
+ dm_kva += BFA_CACHELINE_SZ;
+ dm_pa += BFA_CACHELINE_SZ;
+
+ iocfc->rsp_cq_shadow_pi[i].kva = dm_kva;
+ iocfc->rsp_cq_shadow_pi[i].pa = dm_pa;
+ dm_kva += BFA_CACHELINE_SZ;
+ dm_pa += BFA_CACHELINE_SZ;
+ }
+
+ /*
+ * Claim DMA-able memory for the config info page
+ */
+ bfa->iocfc.cfg_info.kva = dm_kva;
+ bfa->iocfc.cfg_info.pa = dm_pa;
+ bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva;
+ dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
+
+ /*
+ * Claim DMA-able memory for the config response
+ */
+ bfa->iocfc.cfgrsp_dma.kva = dm_kva;
+ bfa->iocfc.cfgrsp_dma.pa = dm_pa;
+ bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva;
+
+ dm_kva +=
+ BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
+ BFA_CACHELINE_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
+ BFA_CACHELINE_SZ);
+
+ /*
+ * Claim DMA-able memory for iocfc stats
+ */
+ bfa->iocfc.stats_kva = dm_kva;
+ bfa->iocfc.stats_pa = dm_pa;
+ bfa->iocfc.fw_stats = (struct bfa_fw_stats_s *) dm_kva;
+ dm_kva += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
+
+ bfa_meminfo_dma_virt(meminfo) = dm_kva;
+ bfa_meminfo_dma_phys(meminfo) = dm_pa;
+
+ dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover);
+ if (dbgsz > 0) {
+ bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo));
+ bfa_meminfo_kva(meminfo) += dbgsz;
+ }
+}
+
+/**
+ * BFA submodules initialization completion notification.
+ */
+static void
+bfa_iocfc_initdone_submod(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->initdone(bfa);
+}
+
+/**
+ * Start BFA submodules.
+ */
+static void
+bfa_iocfc_start_submod(struct bfa_s *bfa)
+{
+ int i;
+
+ bfa->rme_process = BFA_TRUE;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->start(bfa);
+}
+
+/**
+ * Disable BFA submodules.
+ */
+static void
+bfa_iocfc_disable_submod(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->iocdisable(bfa);
+}
+
+static void
+bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ if (complete) {
+ if (bfa->iocfc.cfgdone)
+ bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
+ else
+ bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
+ } else
+ bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
+}
+
+static void
+bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfad_s *bfad = bfa->bfad;
+
+ if (compl)
+ complete(&bfad->comp);
+
+ else
+ bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
+}
+
+static void
+bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfad_s *bfad = bfa->bfad;
+
+ if (compl)
+ complete(&bfad->disable_comp);
+}
+
+/**
+ * Update BFA configuration from firmware configuration.
+ */
+static void
+bfa_iocfc_cfgrsp(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+ struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg;
+ struct bfi_iocfc_cfg_s *cfginfo = iocfc->cfginfo;
+
+ fwcfg->num_cqs = fwcfg->num_cqs;
+ fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs);
+ fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs);
+ fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs);
+ fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs);
+ fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports);
+
+ cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce;
+ cfginfo->intr_attr.delay = bfa_os_ntohs(cfgrsp->intr_attr.delay);
+ cfginfo->intr_attr.latency = bfa_os_ntohs(cfgrsp->intr_attr.latency);
+
+ iocfc->cfgdone = BFA_TRUE;
+
+ /**
+ * Configuration is complete - initialize/start submodules
+ */
+ if (iocfc->action == BFA_IOCFC_ACT_INIT)
+ bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
+ else
+ bfa_iocfc_start_submod(bfa);
+}
+
+static void
+bfa_iocfc_stats_clear(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_stats_req_s stats_req;
+
+ bfa_timer_start(bfa, &iocfc->stats_timer,
+ bfa_iocfc_stats_clr_timeout, bfa,
+ BFA_IOCFC_TOV);
+
+ bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CLEAR_STATS_REQ,
+ bfa_lpuid(bfa));
+ bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
+ sizeof(struct bfi_iocfc_stats_req_s));
+}
+
+static void
+bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, struct bfa_fw_stats_s *s)
+{
+ u32 *dip = (u32 *) d;
+ u32 *sip = (u32 *) s;
+ int i;
+
+ for (i = 0; i < (sizeof(struct bfa_fw_stats_s) / sizeof(u32)); i++)
+ dip[i] = bfa_os_ntohl(sip[i]);
+}
+
+static void
+bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (complete) {
+ bfa_ioc_clr_stats(&bfa->ioc);
+ iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
+ } else {
+ iocfc->stats_busy = BFA_FALSE;
+ iocfc->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_iocfc_stats_clr_timeout(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ bfa_trc(bfa, 0);
+
+ iocfc->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_clr_cb, bfa);
+}
+
+static void
+bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (complete) {
+ if (iocfc->stats_status == BFA_STATUS_OK) {
+ bfa_os_memset(iocfc->stats_ret, 0,
+ sizeof(*iocfc->stats_ret));
+ bfa_iocfc_stats_swap(&iocfc->stats_ret->fw_stats,
+ iocfc->fw_stats);
+ }
+ iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
+ } else {
+ iocfc->stats_busy = BFA_FALSE;
+ iocfc->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_iocfc_stats_timeout(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ bfa_trc(bfa, 0);
+
+ iocfc->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, bfa);
+}
+
+static void
+bfa_iocfc_stats_query(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_stats_req_s stats_req;
+
+ bfa_timer_start(bfa, &iocfc->stats_timer,
+ bfa_iocfc_stats_timeout, bfa, BFA_IOCFC_TOV);
+
+ bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_GET_STATS_REQ,
+ bfa_lpuid(bfa));
+ bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
+ sizeof(struct bfi_iocfc_stats_req_s));
+}
+
+void
+bfa_iocfc_reset_queues(struct bfa_s *bfa)
+{
+ int q;
+
+ for (q = 0; q < BFI_IOC_MAX_CQS; q++) {
+ bfa_reqq_ci(bfa, q) = 0;
+ bfa_reqq_pi(bfa, q) = 0;
+ bfa_rspq_ci(bfa, q) = 0;
+ bfa_rspq_pi(bfa, q) = 0;
+ }
+}
+
+/**
+ * IOC enable request is complete
+ */
+static void
+bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ if (status != BFA_STATUS_OK) {
+ bfa_isr_disable(bfa);
+ if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
+ bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
+ bfa_iocfc_init_cb, bfa);
+ return;
+ }
+
+ bfa_iocfc_initdone_submod(bfa);
+ bfa_iocfc_send_cfg(bfa);
+}
+
+/**
+ * IOC disable request is complete
+ */
+static void
+bfa_iocfc_disable_cbfn(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ bfa_isr_disable(bfa);
+ bfa_iocfc_disable_submod(bfa);
+
+ if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP)
+ bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb,
+ bfa);
+ else {
+ bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE);
+ bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb,
+ bfa);
+ }
+}
+
+/**
+ * Notify sub-modules of hardware failure.
+ */
+static void
+bfa_iocfc_hbfail_cbfn(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ bfa->rme_process = BFA_FALSE;
+
+ bfa_isr_disable(bfa);
+ bfa_iocfc_disable_submod(bfa);
+
+ if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
+ bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb,
+ bfa);
+}
+
+/**
+ * Actions on chip-reset completion.
+ */
+static void
+bfa_iocfc_reset_cbfn(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ bfa_iocfc_reset_queues(bfa);
+ bfa_isr_enable(bfa);
+}
+
+
+
+/**
+ * bfa_ioc_public
+ */
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ /* dma memory for IOC */
+ *dm_len += bfa_ioc_meminfo();
+
+ bfa_iocfc_fw_cfg_sz(cfg, dm_len);
+ bfa_iocfc_cqs_sz(cfg, dm_len);
+ *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover);
+}
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ int i;
+
+ bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn;
+ bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn;
+ bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn;
+ bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn;
+
+ bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod,
+ bfa->trcmod, bfa->aen, bfa->logm);
+ bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
+ bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs);
+
+ /**
+ * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode.
+ */
+ if (0)
+ bfa_ioc_set_fcmode(&bfa->ioc);
+
+ bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev);
+ bfa_iocfc_mem_claim(bfa, cfg, meminfo);
+ bfa_timer_init(&bfa->timer_mod);
+
+ INIT_LIST_HEAD(&bfa->comp_q);
+ for (i = 0; i < BFI_IOC_MAX_CQS; i++)
+ INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
+}
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_detach(struct bfa_s *bfa)
+{
+ bfa_ioc_detach(&bfa->ioc);
+}
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_init(struct bfa_s *bfa)
+{
+ bfa->iocfc.action = BFA_IOCFC_ACT_INIT;
+ bfa_ioc_enable(&bfa->ioc);
+ bfa_msix_install(bfa);
+}
+
+/**
+ * IOC start called from bfa_start(). Called to start IOC operations
+ * at driver instantiation for this instance.
+ */
+void
+bfa_iocfc_start(struct bfa_s *bfa)
+{
+ if (bfa->iocfc.cfgdone)
+ bfa_iocfc_start_submod(bfa);
+}
+
+/**
+ * IOC stop called from bfa_stop(). Called only when driver is unloaded
+ * for this instance.
+ */
+void
+bfa_iocfc_stop(struct bfa_s *bfa)
+{
+ bfa->iocfc.action = BFA_IOCFC_ACT_STOP;
+
+ bfa->rme_process = BFA_FALSE;
+ bfa_ioc_disable(&bfa->ioc);
+}
+
+void
+bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m)
+{
+ struct bfa_s *bfa = bfaarg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ union bfi_iocfc_i2h_msg_u *msg;
+
+ msg = (union bfi_iocfc_i2h_msg_u *) m;
+ bfa_trc(bfa, msg->mh.msg_id);
+
+ switch (msg->mh.msg_id) {
+ case BFI_IOCFC_I2H_CFG_REPLY:
+ iocfc->cfg_reply = &msg->cfg_reply;
+ bfa_iocfc_cfgrsp(bfa);
+ break;
+
+ case BFI_IOCFC_I2H_GET_STATS_RSP:
+ if (iocfc->stats_busy == BFA_FALSE
+ || iocfc->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&iocfc->stats_timer);
+ iocfc->stats_status = BFA_STATUS_OK;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb,
+ bfa);
+ break;
+ case BFI_IOCFC_I2H_CLEAR_STATS_RSP:
+ /*
+ * check for timer pop before processing the rsp
+ */
+ if (iocfc->stats_busy == BFA_FALSE
+ || iocfc->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&iocfc->stats_timer);
+ iocfc->stats_status = BFA_STATUS_OK;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe,
+ bfa_iocfc_stats_clr_cb, bfa);
+ break;
+ case BFI_IOCFC_I2H_UPDATEQ_RSP:
+ iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK);
+ break;
+ default:
+ bfa_assert(0);
+ }
+}
+
+#ifndef BFA_BIOS_BUILD
+void
+bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr)
+{
+ bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr);
+}
+
+u64
+bfa_adapter_get_id(struct bfa_s *bfa)
+{
+ return bfa_ioc_get_adid(&bfa->ioc);
+}
+
+void
+bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ attr->intr_attr = iocfc->cfginfo->intr_attr;
+ attr->config = iocfc->cfg;
+}
+
+bfa_status_t
+bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_set_intr_req_s *m;
+
+ iocfc->cfginfo->intr_attr = *attr;
+ if (!bfa_iocfc_is_operational(bfa))
+ return BFA_STATUS_OK;
+
+ m = bfa_reqq_next(bfa, BFA_REQQ_IOC);
+ if (!m)
+ return BFA_STATUS_DEVBUSY;
+
+ bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ,
+ bfa_lpuid(bfa));
+ m->coalesce = attr->coalesce;
+ m->delay = bfa_os_htons(attr->delay);
+ m->latency = bfa_os_htons(attr->latency);
+
+ bfa_trc(bfa, attr->delay);
+ bfa_trc(bfa, attr->latency);
+
+ bfa_reqq_produce(bfa, BFA_REQQ_IOC);
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1);
+ bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa);
+}
+
+bfa_status_t
+bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
+ bfa_cb_ioc_t cbfn, void *cbarg)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (iocfc->stats_busy) {
+ bfa_trc(bfa, iocfc->stats_busy);
+ return (BFA_STATUS_DEVBUSY);
+ }
+
+ iocfc->stats_busy = BFA_TRUE;
+ iocfc->stats_ret = stats;
+ iocfc->stats_cbfn = cbfn;
+ iocfc->stats_cbarg = cbarg;
+
+ bfa_iocfc_stats_query(bfa);
+
+ return (BFA_STATUS_OK);
+}
+
+bfa_status_t
+bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (iocfc->stats_busy) {
+ bfa_trc(bfa, iocfc->stats_busy);
+ return (BFA_STATUS_DEVBUSY);
+ }
+
+ iocfc->stats_busy = BFA_TRUE;
+ iocfc->stats_cbfn = cbfn;
+ iocfc->stats_cbarg = cbarg;
+
+ bfa_iocfc_stats_clear(bfa);
+ return (BFA_STATUS_OK);
+}
+
+/**
+ * Enable IOC after it is disabled.
+ */
+void
+bfa_iocfc_enable(struct bfa_s *bfa)
+{
+ bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
+ "IOC Enable");
+ bfa_ioc_enable(&bfa->ioc);
+}
+
+void
+bfa_iocfc_disable(struct bfa_s *bfa)
+{
+ bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
+ "IOC Disable");
+ bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE;
+
+ bfa->rme_process = BFA_FALSE;
+ bfa_ioc_disable(&bfa->ioc);
+}
+
+
+bfa_boolean_t
+bfa_iocfc_is_operational(struct bfa_s *bfa)
+{
+ return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone;
+}
+
+/**
+ * Return boot target port wwns -- read from boot information in flash.
+ */
+void
+bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+ *nwwns = cfgrsp->bootwwns.nwwns;
+ *wwns = cfgrsp->bootwwns.wwn;
+}
+
+#endif
+
+
diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h
new file mode 100644
index 000000000000..7ad177ed4cfc
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_iocfc.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_IOCFC_H__
+#define __BFA_IOCFC_H__
+
+#include <bfa_ioc.h>
+#include <bfa.h>
+#include <bfi/bfi_iocfc.h>
+#include <bfa_callback_priv.h>
+
+#define BFA_REQQ_NELEMS_MIN (4)
+#define BFA_RSPQ_NELEMS_MIN (4)
+
+struct bfa_iocfc_regs_s {
+ bfa_os_addr_t intr_status;
+ bfa_os_addr_t intr_mask;
+ bfa_os_addr_t cpe_q_pi[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t cpe_q_ci[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t cpe_q_depth[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t cpe_q_ctrl[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_ci[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_pi[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_depth[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_ctrl[BFI_IOC_MAX_CQS];
+};
+
+/**
+ * MSIX vector handlers
+ */
+#define BFA_MSIX_MAX_VECTORS 22
+typedef void (*bfa_msix_handler_t)(struct bfa_s *bfa, int vec);
+struct bfa_msix_s {
+ int nvecs;
+ bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS];
+};
+
+/**
+ * Chip specific interfaces
+ */
+struct bfa_hwif_s {
+ void (*hw_reginit)(struct bfa_s *bfa);
+ void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq);
+ void (*hw_msix_init)(struct bfa_s *bfa, int nvecs);
+ void (*hw_msix_install)(struct bfa_s *bfa);
+ void (*hw_msix_uninstall)(struct bfa_s *bfa);
+ void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix);
+ void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap,
+ u32 *nvecs, u32 *maxvec);
+};
+typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status);
+
+struct bfa_iocfc_s {
+ struct bfa_s *bfa;
+ struct bfa_iocfc_cfg_s cfg;
+ int action;
+
+ u32 req_cq_pi[BFI_IOC_MAX_CQS];
+ u32 rsp_cq_ci[BFI_IOC_MAX_CQS];
+
+ struct bfa_cb_qe_s init_hcb_qe;
+ struct bfa_cb_qe_s stop_hcb_qe;
+ struct bfa_cb_qe_s dis_hcb_qe;
+ struct bfa_cb_qe_s stats_hcb_qe;
+ bfa_boolean_t cfgdone;
+
+ struct bfa_dma_s cfg_info;
+ struct bfi_iocfc_cfg_s *cfginfo;
+ struct bfa_dma_s cfgrsp_dma;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp;
+ struct bfi_iocfc_cfg_reply_s *cfg_reply;
+
+ u8 *stats_kva;
+ u64 stats_pa;
+ struct bfa_fw_stats_s *fw_stats;
+ struct bfa_timer_s stats_timer; /* timer */
+ struct bfa_iocfc_stats_s *stats_ret; /* driver stats location */
+ bfa_status_t stats_status; /* stats/statsclr status */
+ bfa_boolean_t stats_busy; /* outstanding stats */
+ bfa_cb_ioc_t stats_cbfn; /* driver callback function */
+ void *stats_cbarg; /* user callback arg */
+
+ struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS];
+ struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS];
+ struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS];
+ struct bfa_dma_s rsp_cq_shadow_pi[BFI_IOC_MAX_CQS];
+ struct bfa_iocfc_regs_s bfa_regs; /* BFA device registers */
+ struct bfa_hwif_s hwif;
+
+ bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */
+ void *updateq_cbarg; /* bios callback arg */
+};
+
+#define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc)
+#define bfa_msix_init(__bfa, __nvecs) \
+ (__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)
+#define bfa_msix_install(__bfa) \
+ (__bfa)->iocfc.hwif.hw_msix_install(__bfa)
+#define bfa_msix_uninstall(__bfa) \
+ (__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)
+#define bfa_isr_mode_set(__bfa, __msix) \
+ (__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)
+#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \
+ (__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)
+
+/*
+ * FC specific IOC functions.
+ */
+void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len);
+void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad,
+ struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+void bfa_iocfc_detach(struct bfa_s *bfa);
+void bfa_iocfc_init(struct bfa_s *bfa);
+void bfa_iocfc_start(struct bfa_s *bfa);
+void bfa_iocfc_stop(struct bfa_s *bfa);
+void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg);
+void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa);
+bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa);
+void bfa_iocfc_reset_queues(struct bfa_s *bfa);
+void bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba,
+ u32 reqq_sci, u32 rspq_spi,
+ bfa_cb_iocfc_t cbfn, void *cbarg);
+
+void bfa_msix_all(struct bfa_s *bfa, int vec);
+void bfa_msix_reqq(struct bfa_s *bfa, int vec);
+void bfa_msix_rspq(struct bfa_s *bfa, int vec);
+void bfa_msix_lpu_err(struct bfa_s *bfa, int vec);
+
+void bfa_hwcb_reginit(struct bfa_s *bfa);
+void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs);
+void bfa_hwcb_msix_install(struct bfa_s *bfa);
+void bfa_hwcb_msix_uninstall(struct bfa_s *bfa);
+void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
+void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
+ u32 *nvecs, u32 *maxvec);
+void bfa_hwct_reginit(struct bfa_s *bfa);
+void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs);
+void bfa_hwct_msix_install(struct bfa_s *bfa);
+void bfa_hwct_msix_uninstall(struct bfa_s *bfa);
+void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
+void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
+ u32 *nvecs, u32 *maxvec);
+
+void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len);
+void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi,
+ bfa_boolean_t mincfg);
+void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns);
+
+#endif /* __BFA_IOCFC_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_iocfc_q.c b/drivers/scsi/bfa/bfa_iocfc_q.c
new file mode 100644
index 000000000000..500a17df40b2
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_iocfc_q.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include "bfa_intr_priv.h"
+
+BFA_TRC_FILE(HAL, IOCFC_Q);
+
+void
+bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba,
+ u32 reqq_sci, u32 rspq_spi, bfa_cb_iocfc_t cbfn,
+ void *cbarg)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_updateq_req_s updateq_req;
+
+ iocfc->updateq_cbfn = cbfn;
+ iocfc->updateq_cbarg = cbarg;
+
+ bfi_h2i_set(updateq_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_UPDATEQ_REQ,
+ bfa_lpuid(bfa));
+
+ updateq_req.reqq_ba = bfa_os_htonl(reqq_ba);
+ updateq_req.rspq_ba = bfa_os_htonl(rspq_ba);
+ updateq_req.reqq_sci = bfa_os_htonl(reqq_sci);
+ updateq_req.rspq_spi = bfa_os_htonl(rspq_spi);
+
+ bfa_ioc_mbox_send(&bfa->ioc, &updateq_req,
+ sizeof(struct bfi_iocfc_updateq_req_s));
+}
diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c
new file mode 100644
index 000000000000..7ae2552e1e14
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_ioim.c
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <cs/bfa_debug.h>
+#include <bfa_cb_ioim_macros.h>
+
+BFA_TRC_FILE(HAL, IOIM);
+
+/*
+ * forward declarations.
+ */
+static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_sge_setup(struct bfa_ioim_s *ioim);
+static void bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim);
+static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim);
+static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
+
+/**
+ * bfa_ioim_sm
+ */
+
+/**
+ * IO state machine events
+ */
+enum bfa_ioim_event {
+ BFA_IOIM_SM_START = 1, /* io start request from host */
+ BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */
+ BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */
+ BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */
+ BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */
+ BFA_IOIM_SM_FREE = 6, /* io resource is freed */
+ BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */
+ BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */
+ BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */
+ BFA_IOIM_SM_QRESUME = 10, /* CQ space available to queue IO */
+ BFA_IOIM_SM_SGALLOCED = 11, /* SG page allocation successful */
+ BFA_IOIM_SM_SQRETRY = 12, /* sequence recovery retry */
+ BFA_IOIM_SM_HCB = 13, /* bfa callback complete */
+ BFA_IOIM_SM_CLEANUP = 14, /* IO cleanup from itnim */
+ BFA_IOIM_SM_TMSTART = 15, /* IO cleanup from tskim */
+ BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */
+ BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */
+ BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */
+};
+
+/*
+ * forward declaration of IO state machine
+ */
+static void bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_active(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_abort(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+
+/**
+ * IO is not started (unallocated).
+ */
+static void
+bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_trc_fp(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_START:
+ if (!bfa_itnim_is_online(ioim->itnim)) {
+ if (!bfa_itnim_hold_io(ioim->itnim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe,
+ &ioim->fcpim->ioim_comp_q);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+ __bfa_cb_ioim_pathtov, ioim);
+ } else {
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe,
+ &ioim->itnim->pending_q);
+ }
+ break;
+ }
+
+ if (ioim->nsges > BFI_SGE_INLINE) {
+ if (!bfa_ioim_sge_setup(ioim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc);
+ return;
+ }
+ }
+
+ if (!bfa_ioim_send_ioreq(ioim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
+ break;
+ }
+
+ bfa_sm_set_state(ioim, bfa_ioim_sm_active);
+ break;
+
+ case BFA_IOIM_SM_IOTOV:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+ __bfa_cb_ioim_pathtov, ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ /**
+ * IO in pending queue can get abort requests. Complete abort
+ * requests immediately.
+ */
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_assert(bfa_q_is_on_q(&ioim->itnim->pending_q, ioim));
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is waiting for SG pages.
+ */
+static void
+bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_SGALLOCED:
+ if (!bfa_ioim_send_ioreq(ioim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
+ break;
+ }
+ bfa_sm_set_state(ioim, bfa_ioim_sm_active);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is active.
+ */
+static void
+bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_trc_fp(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_COMP_GOOD:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+ __bfa_cb_ioim_good_comp, ioim);
+ break;
+
+ case BFA_IOIM_SM_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ ioim->iosp->abort_explicit = BFA_TRUE;
+ ioim->io_cbfn = __bfa_cb_ioim_abort;
+
+ if (bfa_ioim_send_abort(ioim))
+ bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
+ else {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull);
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ }
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ ioim->iosp->abort_explicit = BFA_FALSE;
+ ioim->io_cbfn = __bfa_cb_ioim_failed;
+
+ if (bfa_ioim_send_abort(ioim))
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
+ else {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ }
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is being aborted, waiting for completion from firmware.
+ */
+static void
+bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ case BFA_IOIM_SM_DONE:
+ case BFA_IOIM_SM_FREE:
+ break;
+
+ case BFA_IOIM_SM_ABORT_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_COMP_UTAG:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
+ ioim->iosp->abort_explicit = BFA_FALSE;
+
+ if (bfa_ioim_send_abort(ioim))
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
+ else {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ }
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is being cleaned up (implicit abort), waiting for completion from
+ * firmware.
+ */
+static void
+bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ case BFA_IOIM_SM_DONE:
+ case BFA_IOIM_SM_FREE:
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ /**
+ * IO is already being aborted implicitly
+ */
+ ioim->io_cbfn = __bfa_cb_ioim_abort;
+ break;
+
+ case BFA_IOIM_SM_ABORT_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_COMP_UTAG:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ /**
+ * IO can be in cleanup state already due to TM command. 2nd cleanup
+ * request comes from ITN offline event.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is waiting for room in request CQ
+ */
+static void
+bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_QRESUME:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_active);
+ bfa_ioim_send_ioreq(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Active IO is being aborted, waiting for room in request CQ.
+ */
+static void
+bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_QRESUME:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
+ bfa_ioim_send_abort(ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
+ ioim->iosp->abort_explicit = BFA_FALSE;
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
+ break;
+
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Active IO is being cleaned up, waiting for room in request CQ.
+ */
+static void
+bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_QRESUME:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
+ bfa_ioim_send_abort(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ /**
+ * IO is alraedy being cleaned up implicitly
+ */
+ ioim->io_cbfn = __bfa_cb_ioim_abort;
+ break;
+
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO bfa callback is pending.
+ */
+static void
+bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_trc_fp(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_HCB:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
+ bfa_ioim_free(ioim);
+ bfa_cb_ioim_resfree(ioim->bfa->bfad);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO bfa callback is pending. IO resource cannot be freed.
+ */
+static void
+bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_HCB:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_resfree);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_resfree_q);
+ break;
+
+ case BFA_IOIM_SM_FREE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is completed, waiting resource free from firmware.
+ */
+static void
+bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_FREE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
+ bfa_ioim_free(ioim);
+ bfa_cb_ioim_resfree(ioim->bfa->bfad);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_ioim_private
+ */
+
+static void
+__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_good_comp(ioim->bfa->bfad, ioim->dio);
+}
+
+static void
+__bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+ struct bfi_ioim_rsp_s *m;
+ u8 *snsinfo = NULL;
+ u8 sns_len = 0;
+ s32 residue = 0;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
+ if (m->io_status == BFI_IOIM_STS_OK) {
+ /**
+ * setup sense information, if present
+ */
+ if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION
+ && m->sns_len) {
+ sns_len = m->sns_len;
+ snsinfo = ioim->iosp->snsinfo;
+ }
+
+ /**
+ * setup residue value correctly for normal completions
+ */
+ if (m->resid_flags == FCP_RESID_UNDER)
+ residue = bfa_os_ntohl(m->residue);
+ if (m->resid_flags == FCP_RESID_OVER) {
+ residue = bfa_os_ntohl(m->residue);
+ residue = -residue;
+ }
+ }
+
+ bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, m->io_status,
+ m->scsi_status, sns_len, snsinfo, residue);
+}
+
+static void
+__bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED,
+ 0, 0, NULL, 0);
+}
+
+static void
+__bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV,
+ 0, 0, NULL, 0);
+}
+
+static void
+__bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio);
+}
+
+static void
+bfa_ioim_sgpg_alloced(void *cbarg)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
+ list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q);
+ bfa_ioim_sgpg_setup(ioim);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED);
+}
+
+/**
+ * Send I/O request to firmware.
+ */
+static bfa_boolean_t
+bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
+{
+ struct bfa_itnim_s *itnim = ioim->itnim;
+ struct bfi_ioim_req_s *m;
+ static struct fcp_cmnd_s cmnd_z0 = { 0 };
+ struct bfi_sge_s *sge;
+ u32 pgdlen = 0;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+ if (!m) {
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ /**
+ * build i/o request message next
+ */
+ m->io_tag = bfa_os_htons(ioim->iotag);
+ m->rport_hdl = ioim->itnim->rport->fw_handle;
+ m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio);
+
+ /**
+ * build inline IO SG element here
+ */
+ sge = &m->sges[0];
+ if (ioim->nsges) {
+ sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0);
+ pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0);
+ sge->sg_len = pgdlen;
+ sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
+ BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
+ bfa_sge_to_be(sge);
+ sge++;
+ }
+
+ if (ioim->nsges > BFI_SGE_INLINE) {
+ sge->sga = ioim->sgpg->sgpg_pa;
+ } else {
+ sge->sga.a32.addr_lo = 0;
+ sge->sga.a32.addr_hi = 0;
+ }
+ sge->sg_len = pgdlen;
+ sge->flags = BFI_SGE_PGDLEN;
+ bfa_sge_to_be(sge);
+
+ /**
+ * set up I/O command parameters
+ */
+ bfa_os_assign(m->cmnd, cmnd_z0);
+ m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio);
+ m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio);
+ bfa_os_assign(m->cmnd.cdb,
+ *(struct scsi_cdb_s *)bfa_cb_ioim_get_cdb(ioim->dio));
+ m->cmnd.fcp_dl = bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
+
+ /**
+ * set up I/O message header
+ */
+ switch (m->cmnd.iodir) {
+ case FCP_IODIR_READ:
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa));
+ bfa_stats(itnim, input_reqs);
+ break;
+ case FCP_IODIR_WRITE:
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa));
+ bfa_stats(itnim, output_reqs);
+ break;
+ case FCP_IODIR_RW:
+ bfa_stats(itnim, input_reqs);
+ bfa_stats(itnim, output_reqs);
+ default:
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
+ }
+ if (itnim->seq_rec ||
+ (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1)))
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
+
+#ifdef IOIM_ADVANCED
+ m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio);
+ m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio);
+ m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio);
+
+ /**
+ * Handle large CDB (>16 bytes).
+ */
+ m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) -
+ FCP_CMND_CDB_LEN) / sizeof(u32);
+ if (m->cmnd.addl_cdb_len) {
+ bfa_os_memcpy(&m->cmnd.cdb + 1, (struct scsi_cdb_s *)
+ bfa_cb_ioim_get_cdb(ioim->dio) + 1,
+ m->cmnd.addl_cdb_len * sizeof(u32));
+ fcp_cmnd_fcpdl(&m->cmnd) =
+ bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
+ }
+#endif
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(ioim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Setup any additional SG pages needed.Inline SG element is setup
+ * at queuing time.
+ */
+static bfa_boolean_t
+bfa_ioim_sge_setup(struct bfa_ioim_s *ioim)
+{
+ u16 nsgpgs;
+
+ bfa_assert(ioim->nsges > BFI_SGE_INLINE);
+
+ /**
+ * allocate SG pages needed
+ */
+ nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
+ if (!nsgpgs)
+ return BFA_TRUE;
+
+ if (bfa_sgpg_malloc(ioim->bfa, &ioim->sgpg_q, nsgpgs)
+ != BFA_STATUS_OK) {
+ bfa_sgpg_wait(ioim->bfa, &ioim->iosp->sgpg_wqe, nsgpgs);
+ return BFA_FALSE;
+ }
+
+ ioim->nsgpgs = nsgpgs;
+ bfa_ioim_sgpg_setup(ioim);
+
+ return BFA_TRUE;
+}
+
+static void
+bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
+{
+ int sgeid, nsges, i;
+ struct bfi_sge_s *sge;
+ struct bfa_sgpg_s *sgpg;
+ u32 pgcumsz;
+
+ sgeid = BFI_SGE_INLINE;
+ ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
+
+ do {
+ sge = sgpg->sgpg->sges;
+ nsges = ioim->nsges - sgeid;
+ if (nsges > BFI_SGPG_DATA_SGES)
+ nsges = BFI_SGPG_DATA_SGES;
+
+ pgcumsz = 0;
+ for (i = 0; i < nsges; i++, sge++, sgeid++) {
+ sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid);
+ sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid);
+ pgcumsz += sge->sg_len;
+
+ /**
+ * set flags
+ */
+ if (i < (nsges - 1))
+ sge->flags = BFI_SGE_DATA;
+ else if (sgeid < (ioim->nsges - 1))
+ sge->flags = BFI_SGE_DATA_CPL;
+ else
+ sge->flags = BFI_SGE_DATA_LAST;
+ }
+
+ sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
+
+ /**
+ * set the link element of each page
+ */
+ if (sgeid == ioim->nsges) {
+ sge->flags = BFI_SGE_PGDLEN;
+ sge->sga.a32.addr_lo = 0;
+ sge->sga.a32.addr_hi = 0;
+ } else {
+ sge->flags = BFI_SGE_LINK;
+ sge->sga = sgpg->sgpg_pa;
+ }
+ sge->sg_len = pgcumsz;
+ } while (sgeid < ioim->nsges);
+}
+
+/**
+ * Send I/O abort request to firmware.
+ */
+static bfa_boolean_t
+bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
+{
+ struct bfa_itnim_s *itnim = ioim->itnim;
+ struct bfi_ioim_abort_req_s *m;
+ enum bfi_ioim_h2i msgop;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+ if (!m)
+ return BFA_FALSE;
+
+ /**
+ * build i/o request message next
+ */
+ if (ioim->iosp->abort_explicit)
+ msgop = BFI_IOIM_H2I_IOABORT_REQ;
+ else
+ msgop = BFI_IOIM_H2I_IOCLEANUP_REQ;
+
+ bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa));
+ m->io_tag = bfa_os_htons(ioim->iotag);
+ m->abort_tag = ++ioim->abort_tag;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(ioim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Call to resume any I/O requests waiting for room in request queue.
+ */
+static void
+bfa_ioim_qresume(void *cbarg)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ bfa_fcpim_stats(ioim->fcpim, qresumes);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_QRESUME);
+}
+
+
+static void
+bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim)
+{
+ /**
+ * Move IO from itnim queue to fcpim global queue since itnim will be
+ * freed.
+ */
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+
+ if (!ioim->iosp->tskim) {
+ if (ioim->fcpim->delay_comp && ioim->itnim->iotov_active) {
+ bfa_cb_dequeue(&ioim->hcb_qe);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->itnim->delay_comp_q);
+ }
+ bfa_itnim_iodone(ioim->itnim);
+ } else
+ bfa_tskim_iodone(ioim->iosp->tskim);
+}
+
+/**
+ * or after the link comes back.
+ */
+void
+bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
+{
+ /**
+ * If path tov timer expired, failback with PATHTOV status - these
+ * IO requests are not normally retried by IO stack.
+ *
+ * Otherwise device cameback online and fail it with normal failed
+ * status so that IO stack retries these failed IO requests.
+ */
+ if (iotov)
+ ioim->io_cbfn = __bfa_cb_ioim_pathtov;
+ else
+ ioim->io_cbfn = __bfa_cb_ioim_failed;
+
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+
+ /**
+ * Move IO to fcpim global queue since itnim will be
+ * freed.
+ */
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+}
+
+
+
+/**
+ * bfa_ioim_friend
+ */
+
+/**
+ * Memory allocation and initialization.
+ */
+void
+bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
+{
+ struct bfa_ioim_s *ioim;
+ struct bfa_ioim_sp_s *iosp;
+ u16 i;
+ u8 *snsinfo;
+ u32 snsbufsz;
+
+ /**
+ * claim memory first
+ */
+ ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo);
+ fcpim->ioim_arr = ioim;
+ bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs);
+
+ iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo);
+ fcpim->ioim_sp_arr = iosp;
+ bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs);
+
+ /**
+ * Claim DMA memory for per IO sense data.
+ */
+ snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN;
+ fcpim->snsbase.pa = bfa_meminfo_dma_phys(minfo);
+ bfa_meminfo_dma_phys(minfo) += snsbufsz;
+
+ fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo);
+ bfa_meminfo_dma_virt(minfo) += snsbufsz;
+ snsinfo = fcpim->snsbase.kva;
+ bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa);
+
+ /**
+ * Initialize ioim free queues
+ */
+ INIT_LIST_HEAD(&fcpim->ioim_free_q);
+ INIT_LIST_HEAD(&fcpim->ioim_resfree_q);
+ INIT_LIST_HEAD(&fcpim->ioim_comp_q);
+
+ for (i = 0; i < fcpim->num_ioim_reqs;
+ i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) {
+ /*
+ * initialize IOIM
+ */
+ bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s));
+ ioim->iotag = i;
+ ioim->bfa = fcpim->bfa;
+ ioim->fcpim = fcpim;
+ ioim->iosp = iosp;
+ iosp->snsinfo = snsinfo;
+ INIT_LIST_HEAD(&ioim->sgpg_q);
+ bfa_reqq_winit(&ioim->iosp->reqq_wait,
+ bfa_ioim_qresume, ioim);
+ bfa_sgpg_winit(&ioim->iosp->sgpg_wqe,
+ bfa_ioim_sgpg_alloced, ioim);
+ bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
+
+ list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
+ }
+}
+
+/**
+ * Driver detach time call.
+ */
+void
+bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim)
+{
+}
+
+void
+bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m;
+ struct bfa_ioim_s *ioim;
+ u16 iotag;
+ enum bfa_ioim_event evt = BFA_IOIM_SM_COMP;
+
+ iotag = bfa_os_ntohs(rsp->io_tag);
+
+ ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
+ bfa_assert(ioim->iotag == iotag);
+
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, rsp->io_status);
+ bfa_trc(ioim->bfa, rsp->reuse_io_tag);
+
+ if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active))
+ bfa_os_assign(ioim->iosp->comp_rspmsg, *m);
+
+ switch (rsp->io_status) {
+ case BFI_IOIM_STS_OK:
+ bfa_fcpim_stats(fcpim, iocomp_ok);
+ if (rsp->reuse_io_tag == 0)
+ evt = BFA_IOIM_SM_DONE;
+ else
+ evt = BFA_IOIM_SM_COMP;
+ break;
+
+ case BFI_IOIM_STS_TIMEDOUT:
+ case BFI_IOIM_STS_ABORTED:
+ rsp->io_status = BFI_IOIM_STS_ABORTED;
+ bfa_fcpim_stats(fcpim, iocomp_aborted);
+ if (rsp->reuse_io_tag == 0)
+ evt = BFA_IOIM_SM_DONE;
+ else
+ evt = BFA_IOIM_SM_COMP;
+ break;
+
+ case BFI_IOIM_STS_PROTO_ERR:
+ bfa_fcpim_stats(fcpim, iocom_proto_err);
+ bfa_assert(rsp->reuse_io_tag);
+ evt = BFA_IOIM_SM_COMP;
+ break;
+
+ case BFI_IOIM_STS_SQER_NEEDED:
+ bfa_fcpim_stats(fcpim, iocom_sqer_needed);
+ bfa_assert(rsp->reuse_io_tag == 0);
+ evt = BFA_IOIM_SM_SQRETRY;
+ break;
+
+ case BFI_IOIM_STS_RES_FREE:
+ bfa_fcpim_stats(fcpim, iocom_res_free);
+ evt = BFA_IOIM_SM_FREE;
+ break;
+
+ case BFI_IOIM_STS_HOST_ABORTED:
+ bfa_fcpim_stats(fcpim, iocom_hostabrts);
+ if (rsp->abort_tag != ioim->abort_tag) {
+ bfa_trc(ioim->bfa, rsp->abort_tag);
+ bfa_trc(ioim->bfa, ioim->abort_tag);
+ return;
+ }
+
+ if (rsp->reuse_io_tag)
+ evt = BFA_IOIM_SM_ABORT_COMP;
+ else
+ evt = BFA_IOIM_SM_ABORT_DONE;
+ break;
+
+ case BFI_IOIM_STS_UTAG:
+ bfa_fcpim_stats(fcpim, iocom_utags);
+ evt = BFA_IOIM_SM_COMP_UTAG;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+
+ bfa_sm_send_event(ioim, evt);
+}
+
+void
+bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m;
+ struct bfa_ioim_s *ioim;
+ u16 iotag;
+
+ iotag = bfa_os_ntohs(rsp->io_tag);
+
+ ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
+ bfa_assert(ioim->iotag == iotag);
+
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+}
+
+/**
+ * Called by itnim to clean up IO while going offline.
+ */
+void
+bfa_ioim_cleanup(struct bfa_ioim_s *ioim)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_fcpim_stats(ioim->fcpim, io_cleanups);
+
+ ioim->iosp->tskim = NULL;
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
+}
+
+void
+bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_fcpim_stats(ioim->fcpim, io_tmaborts);
+
+ ioim->iosp->tskim = tskim;
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
+}
+
+/**
+ * IOC failure handling.
+ */
+void
+bfa_ioim_iocdisable(struct bfa_ioim_s *ioim)
+{
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL);
+}
+
+/**
+ * IO offline TOV popped. Fail the pending IO.
+ */
+void
+bfa_ioim_tov(struct bfa_ioim_s *ioim)
+{
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_IOTOV);
+}
+
+
+
+/**
+ * bfa_ioim_api
+ */
+
+/**
+ * Allocate IOIM resource for initiator mode I/O request.
+ */
+struct bfa_ioim_s *
+bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio,
+ struct bfa_itnim_s *itnim, u16 nsges)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_ioim_s *ioim;
+
+ /**
+ * alocate IOIM resource
+ */
+ bfa_q_deq(&fcpim->ioim_free_q, &ioim);
+ if (!ioim) {
+ bfa_fcpim_stats(fcpim, no_iotags);
+ return NULL;
+ }
+
+ ioim->dio = dio;
+ ioim->itnim = itnim;
+ ioim->nsges = nsges;
+ ioim->nsgpgs = 0;
+
+ bfa_stats(fcpim, total_ios);
+ bfa_stats(itnim, ios);
+ fcpim->ios_active++;
+
+ list_add_tail(&ioim->qe, &itnim->io_q);
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+
+ return ioim;
+}
+
+void
+bfa_ioim_free(struct bfa_ioim_s *ioim)
+{
+ struct bfa_fcpim_mod_s *fcpim = ioim->fcpim;
+
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_assert_fp(bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit));
+
+ bfa_assert_fp(list_empty(&ioim->sgpg_q)
+ || (ioim->nsges > BFI_SGE_INLINE));
+
+ if (ioim->nsgpgs > 0)
+ bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs);
+
+ bfa_stats(ioim->itnim, io_comps);
+ fcpim->ios_active--;
+
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
+}
+
+void
+bfa_ioim_start(struct bfa_ioim_s *ioim)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
+}
+
+/**
+ * Driver I/O abort request.
+ */
+void
+bfa_ioim_abort(struct bfa_ioim_s *ioim)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_fcpim_stats(ioim->fcpim, io_aborts);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_ABORT);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_itnim.c b/drivers/scsi/bfa/bfa_itnim.c
new file mode 100644
index 000000000000..4d5c61a4f85c
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_itnim.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_fcpim.h>
+#include "bfa_fcpim_priv.h"
+
+BFA_TRC_FILE(HAL, ITNIM);
+
+#define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \
+ ((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1)))
+
+#define bfa_fcpim_additn(__itnim) \
+ list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q)
+#define bfa_fcpim_delitn(__itnim) do { \
+ bfa_assert(bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \
+ list_del(&(__itnim)->qe); \
+ bfa_assert(list_empty(&(__itnim)->io_q)); \
+ bfa_assert(list_empty(&(__itnim)->io_cleanup_q)); \
+ bfa_assert(list_empty(&(__itnim)->pending_q)); \
+} while (0)
+
+#define bfa_itnim_online_cb(__itnim) do { \
+ if ((__itnim)->bfa->fcs) \
+ bfa_cb_itnim_online((__itnim)->ditn); \
+ else { \
+ bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
+ __bfa_cb_itnim_online, (__itnim)); \
+ } \
+} while (0)
+
+#define bfa_itnim_offline_cb(__itnim) do { \
+ if ((__itnim)->bfa->fcs) \
+ bfa_cb_itnim_offline((__itnim)->ditn); \
+ else { \
+ bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
+ __bfa_cb_itnim_offline, (__itnim)); \
+ } \
+} while (0)
+
+#define bfa_itnim_sler_cb(__itnim) do { \
+ if ((__itnim)->bfa->fcs) \
+ bfa_cb_itnim_sler((__itnim)->ditn); \
+ else { \
+ bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
+ __bfa_cb_itnim_sler, (__itnim)); \
+ } \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static void bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim);
+static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim);
+static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim);
+static void bfa_itnim_cleanp_comp(void *itnim_cbarg);
+static void bfa_itnim_cleanup(struct bfa_itnim_s *itnim);
+static void __bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete);
+static void bfa_itnim_iotov_online(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov(void *itnim_arg);
+static void bfa_itnim_iotov_start(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim);
+
+/**
+ * bfa_itnim_sm BFA itnim state machine
+ */
+
+
+enum bfa_itnim_event {
+ BFA_ITNIM_SM_CREATE = 1, /* itnim is created */
+ BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */
+ BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */
+ BFA_ITNIM_SM_FWRSP = 4, /* firmware response */
+ BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */
+ BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */
+ BFA_ITNIM_SM_SLER = 7, /* second level error recovery */
+ BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */
+ BFA_ITNIM_SM_QRESUME = 9, /* queue space available */
+};
+
+static void bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_created(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_online(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_sler(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_offline(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+
+/**
+ * Beginning/unallocated state - no events expected.
+ */
+static void
+bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_CREATE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_created);
+ itnim->is_online = BFA_FALSE;
+ bfa_fcpim_additn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Beginning state, only online event expected.
+ */
+static void
+bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_ONLINE:
+ if (bfa_itnim_send_fwcreate(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for itnim create response from firmware.
+ */
+static void
+bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_online);
+ itnim->is_online = BFA_TRUE;
+ bfa_itnim_iotov_online(itnim);
+ bfa_itnim_online_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_delete_pending);
+ break;
+
+ case BFA_ITNIM_SM_OFFLINE:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_QRESUME:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ bfa_itnim_send_fwcreate(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_offline);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for itnim create response from firmware, a delete is pending.
+ */
+static void
+bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Online state - normal parking state.
+ */
+static void
+bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_iotov_start(itnim);
+ bfa_itnim_cleanup(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_cleanup(itnim);
+ break;
+
+ case BFA_ITNIM_SM_SLER:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_sler);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_iotov_start(itnim);
+ bfa_itnim_sler_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_iotov_start(itnim);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Second level error recovery need.
+ */
+static void
+bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline);
+ bfa_itnim_cleanup(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
+ bfa_itnim_cleanup(itnim);
+ bfa_itnim_iotov_delete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Going offline. Waiting for active IO cleanup.
+ */
+static void
+bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_CLEANUP:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
+ bfa_itnim_iotov_delete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_SLER:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Deleting itnim. Waiting for active IO cleanup.
+ */
+static void
+bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_CLEANUP:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport offline. Fimrware itnim is being deleted - awaiting f/w response.
+ */
+static void
+bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_offline);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_QRESUME:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
+ bfa_itnim_send_fwdelete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Offline state.
+ */
+static void
+bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_itnim_iotov_delete(itnim);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_ONLINE:
+ if (bfa_itnim_send_fwcreate(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IOC h/w failed state.
+ */
+static void
+bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_itnim_iotov_delete(itnim);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_ONLINE:
+ if (bfa_itnim_send_fwcreate(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Itnim is deleted, waiting for firmware response to delete.
+ */
+static void
+bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_QRESUME:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ bfa_itnim_send_fwdelete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_itnim_private
+ */
+
+/**
+ * Initiate cleanup of all IOs on an IOC failure.
+ */
+static void
+bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
+{
+ struct bfa_tskim_s *tskim;
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &itnim->tsk_q) {
+ tskim = (struct bfa_tskim_s *) qe;
+ bfa_tskim_iocdisable(tskim);
+ }
+
+ list_for_each_safe(qe, qen, &itnim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_iocdisable(ioim);
+ }
+
+ /**
+ * For IO request in pending queue, we pretend an early timeout.
+ */
+ list_for_each_safe(qe, qen, &itnim->pending_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_tov(ioim);
+ }
+
+ list_for_each_safe(qe, qen, &itnim->io_cleanup_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_iocdisable(ioim);
+ }
+}
+
+/**
+ * IO cleanup completion
+ */
+static void
+bfa_itnim_cleanp_comp(void *itnim_cbarg)
+{
+ struct bfa_itnim_s *itnim = itnim_cbarg;
+
+ bfa_stats(itnim, cleanup_comps);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP);
+}
+
+/**
+ * Initiate cleanup of all IOs.
+ */
+static void
+bfa_itnim_cleanup(struct bfa_itnim_s *itnim)
+{
+ struct bfa_ioim_s *ioim;
+ struct bfa_tskim_s *tskim;
+ struct list_head *qe, *qen;
+
+ bfa_wc_init(&itnim->wc, bfa_itnim_cleanp_comp, itnim);
+
+ list_for_each_safe(qe, qen, &itnim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+
+ /**
+ * Move IO to a cleanup queue from active queue so that a later
+ * TM will not pickup this IO.
+ */
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &itnim->io_cleanup_q);
+
+ bfa_wc_up(&itnim->wc);
+ bfa_ioim_cleanup(ioim);
+ }
+
+ list_for_each_safe(qe, qen, &itnim->tsk_q) {
+ tskim = (struct bfa_tskim_s *) qe;
+ bfa_wc_up(&itnim->wc);
+ bfa_tskim_cleanup(tskim);
+ }
+
+ bfa_wc_wait(&itnim->wc);
+}
+
+static void
+__bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ if (complete)
+ bfa_cb_itnim_online(itnim->ditn);
+}
+
+static void
+__bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ if (complete)
+ bfa_cb_itnim_offline(itnim->ditn);
+}
+
+static void
+__bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ if (complete)
+ bfa_cb_itnim_sler(itnim->ditn);
+}
+
+/**
+ * Call to resume any I/O requests waiting for room in request queue.
+ */
+static void
+bfa_itnim_qresume(void *cbarg)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME);
+}
+
+
+
+
+/**
+ * bfa_itnim_public
+ */
+
+void
+bfa_itnim_iodone(struct bfa_itnim_s *itnim)
+{
+ bfa_wc_down(&itnim->wc);
+}
+
+void
+bfa_itnim_tskdone(struct bfa_itnim_s *itnim)
+{
+ bfa_wc_down(&itnim->wc);
+}
+
+void
+bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ /**
+ * ITN memory
+ */
+ *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s);
+}
+
+void
+bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
+{
+ struct bfa_s *bfa = fcpim->bfa;
+ struct bfa_itnim_s *itnim;
+ int i;
+
+ INIT_LIST_HEAD(&fcpim->itnim_q);
+
+ itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo);
+ fcpim->itnim_arr = itnim;
+
+ for (i = 0; i < fcpim->num_itnims; i++, itnim++) {
+ bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s));
+ itnim->bfa = bfa;
+ itnim->fcpim = fcpim;
+ itnim->reqq = BFA_REQQ_QOS_LO;
+ itnim->rport = BFA_RPORT_FROM_TAG(bfa, i);
+ itnim->iotov_active = BFA_FALSE;
+ bfa_reqq_winit(&itnim->reqq_wait, bfa_itnim_qresume, itnim);
+
+ INIT_LIST_HEAD(&itnim->io_q);
+ INIT_LIST_HEAD(&itnim->io_cleanup_q);
+ INIT_LIST_HEAD(&itnim->pending_q);
+ INIT_LIST_HEAD(&itnim->tsk_q);
+ INIT_LIST_HEAD(&itnim->delay_comp_q);
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ }
+
+ bfa_meminfo_kva(minfo) = (u8 *) itnim;
+}
+
+void
+bfa_itnim_iocdisable(struct bfa_itnim_s *itnim)
+{
+ bfa_stats(itnim, ioc_disabled);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_HWFAIL);
+}
+
+static bfa_boolean_t
+bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim)
+{
+ struct bfi_itnim_create_req_s *m;
+
+ itnim->msg_no++;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(itnim->bfa, itnim->reqq);
+ if (!m) {
+ bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ,
+ bfa_lpuid(itnim->bfa));
+ m->fw_handle = itnim->rport->fw_handle;
+ m->class = FC_CLASS_3;
+ m->seq_rec = itnim->seq_rec;
+ m->msg_no = itnim->msg_no;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(itnim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+static bfa_boolean_t
+bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim)
+{
+ struct bfi_itnim_delete_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(itnim->bfa, itnim->reqq);
+ if (!m) {
+ bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ,
+ bfa_lpuid(itnim->bfa));
+ m->fw_handle = itnim->rport->fw_handle;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(itnim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Cleanup all pending failed inflight requests.
+ */
+static void
+bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov)
+{
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &itnim->delay_comp_q) {
+ ioim = (struct bfa_ioim_s *)qe;
+ bfa_ioim_delayed_comp(ioim, iotov);
+ }
+}
+
+/**
+ * Start all pending IO requests.
+ */
+static void
+bfa_itnim_iotov_online(struct bfa_itnim_s *itnim)
+{
+ struct bfa_ioim_s *ioim;
+
+ bfa_itnim_iotov_stop(itnim);
+
+ /**
+ * Abort all inflight IO requests in the queue
+ */
+ bfa_itnim_delayed_comp(itnim, BFA_FALSE);
+
+ /**
+ * Start all pending IO requests.
+ */
+ while (!list_empty(&itnim->pending_q)) {
+ bfa_q_deq(&itnim->pending_q, &ioim);
+ list_add_tail(&ioim->qe, &itnim->io_q);
+ bfa_ioim_start(ioim);
+ }
+}
+
+/**
+ * Fail all pending IO requests
+ */
+static void
+bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim)
+{
+ struct bfa_ioim_s *ioim;
+
+ /**
+ * Fail all inflight IO requests in the queue
+ */
+ bfa_itnim_delayed_comp(itnim, BFA_TRUE);
+
+ /**
+ * Fail any pending IO requests.
+ */
+ while (!list_empty(&itnim->pending_q)) {
+ bfa_q_deq(&itnim->pending_q, &ioim);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+ bfa_ioim_tov(ioim);
+ }
+}
+
+/**
+ * IO TOV timer callback. Fail any pending IO requests.
+ */
+static void
+bfa_itnim_iotov(void *itnim_arg)
+{
+ struct bfa_itnim_s *itnim = itnim_arg;
+
+ itnim->iotov_active = BFA_FALSE;
+
+ bfa_cb_itnim_tov_begin(itnim->ditn);
+ bfa_itnim_iotov_cleanup(itnim);
+ bfa_cb_itnim_tov(itnim->ditn);
+}
+
+/**
+ * Start IO TOV timer for failing back pending IO requests in offline state.
+ */
+static void
+bfa_itnim_iotov_start(struct bfa_itnim_s *itnim)
+{
+ if (itnim->fcpim->path_tov > 0) {
+
+ itnim->iotov_active = BFA_TRUE;
+ bfa_assert(bfa_itnim_hold_io(itnim));
+ bfa_timer_start(itnim->bfa, &itnim->timer,
+ bfa_itnim_iotov, itnim, itnim->fcpim->path_tov);
+ }
+}
+
+/**
+ * Stop IO TOV timer.
+ */
+static void
+bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim)
+{
+ if (itnim->iotov_active) {
+ itnim->iotov_active = BFA_FALSE;
+ bfa_timer_stop(&itnim->timer);
+ }
+}
+
+/**
+ * Stop IO TOV timer.
+ */
+static void
+bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim)
+{
+ bfa_boolean_t pathtov_active = BFA_FALSE;
+
+ if (itnim->iotov_active)
+ pathtov_active = BFA_TRUE;
+
+ bfa_itnim_iotov_stop(itnim);
+ if (pathtov_active)
+ bfa_cb_itnim_tov_begin(itnim->ditn);
+ bfa_itnim_iotov_cleanup(itnim);
+ if (pathtov_active)
+ bfa_cb_itnim_tov(itnim->ditn);
+}
+
+
+
+/**
+ * bfa_itnim_public
+ */
+
+/**
+ * Itnim interrupt processing.
+ */
+void
+bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ union bfi_itnim_i2h_msg_u msg;
+ struct bfa_itnim_s *itnim;
+
+ bfa_trc(bfa, m->mhdr.msg_id);
+
+ msg.msg = m;
+
+ switch (m->mhdr.msg_id) {
+ case BFI_ITNIM_I2H_CREATE_RSP:
+ itnim = BFA_ITNIM_FROM_TAG(fcpim,
+ msg.create_rsp->bfa_handle);
+ bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
+ bfa_stats(itnim, create_comps);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
+ break;
+
+ case BFI_ITNIM_I2H_DELETE_RSP:
+ itnim = BFA_ITNIM_FROM_TAG(fcpim,
+ msg.delete_rsp->bfa_handle);
+ bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
+ bfa_stats(itnim, delete_comps);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
+ break;
+
+ case BFI_ITNIM_I2H_SLER_EVENT:
+ itnim = BFA_ITNIM_FROM_TAG(fcpim,
+ msg.sler_event->bfa_handle);
+ bfa_stats(itnim, sler_events);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_SLER);
+ break;
+
+ default:
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_itnim_api
+ */
+
+struct bfa_itnim_s *
+bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_itnim_s *itnim;
+
+ itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag);
+ bfa_assert(itnim->rport == rport);
+
+ itnim->ditn = ditn;
+
+ bfa_stats(itnim, creates);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE);
+
+ return (itnim);
+}
+
+void
+bfa_itnim_delete(struct bfa_itnim_s *itnim)
+{
+ bfa_stats(itnim, deletes);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_DELETE);
+}
+
+void
+bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec)
+{
+ itnim->seq_rec = seq_rec;
+ bfa_stats(itnim, onlines);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_ONLINE);
+}
+
+void
+bfa_itnim_offline(struct bfa_itnim_s *itnim)
+{
+ bfa_stats(itnim, offlines);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE);
+}
+
+/**
+ * Return true if itnim is considered offline for holding off IO request.
+ * IO is not held if itnim is being deleted.
+ */
+bfa_boolean_t
+bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
+{
+ return (
+ itnim->fcpim->path_tov && itnim->iotov_active &&
+ (bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) ||
+ bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) ||
+ bfa_sm_cmp_state(itnim, bfa_itnim_sm_cleanup_offline) ||
+ bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) ||
+ bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) ||
+ bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable))
+);
+}
+
+void
+bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
+ struct bfa_itnim_hal_stats_s *stats)
+{
+ *stats = itnim->stats;
+}
+
+void
+bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
+{
+ bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats));
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_log.c b/drivers/scsi/bfa/bfa_log.c
new file mode 100644
index 000000000000..c2735e55cf03
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_log.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_log.c BFA log library
+ */
+
+#include <bfa_os_inc.h>
+#include <cs/bfa_log.h>
+
+/*
+ * global log info structure
+ */
+struct bfa_log_info_s {
+ u32 start_idx; /* start index for a module */
+ u32 total_count; /* total count for a module */
+ enum bfa_log_severity level; /* global log level */
+ bfa_log_cb_t cbfn; /* callback function */
+};
+
+static struct bfa_log_info_s bfa_log_info[BFA_LOG_MODULE_ID_MAX + 1];
+static u32 bfa_log_msg_total_count;
+static int bfa_log_initialized;
+
+static char *bfa_log_severity[] =
+ { "[none]", "[critical]", "[error]", "[warn]", "[info]", "" };
+
+/**
+ * BFA log library initialization
+ *
+ * The log library initialization includes the following,
+ * - set log instance name and callback function
+ * - read the message array generated from xml files
+ * - calculate start index for each module
+ * - calculate message count for each module
+ * - perform error checking
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] instance_name - instance name
+ * @param[in] cbfn - callback function
+ *
+ * It return 0 on success, or -1 on failure
+ */
+int
+bfa_log_init(struct bfa_log_mod_s *log_mod, char *instance_name,
+ bfa_log_cb_t cbfn)
+{
+ struct bfa_log_msgdef_s *msg;
+ u32 pre_mod_id = 0;
+ u32 cur_mod_id = 0;
+ u32 i, pre_idx, idx, msg_id;
+
+ /*
+ * set instance name
+ */
+ if (log_mod) {
+ strncpy(log_mod->instance_info, instance_name,
+ sizeof(log_mod->instance_info));
+ log_mod->cbfn = cbfn;
+ for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++)
+ log_mod->log_level[i] = BFA_LOG_WARNING;
+ }
+
+ if (bfa_log_initialized)
+ return 0;
+
+ for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++) {
+ bfa_log_info[i].start_idx = 0;
+ bfa_log_info[i].total_count = 0;
+ bfa_log_info[i].level = BFA_LOG_WARNING;
+ bfa_log_info[i].cbfn = cbfn;
+ }
+
+ pre_idx = 0;
+ idx = 0;
+ msg = bfa_log_msg_array;
+ msg_id = BFA_LOG_GET_MSG_ID(msg);
+ pre_mod_id = BFA_LOG_GET_MOD_ID(msg_id);
+ while (msg_id != 0) {
+ cur_mod_id = BFA_LOG_GET_MOD_ID(msg_id);
+
+ if (cur_mod_id > BFA_LOG_MODULE_ID_MAX) {
+ cbfn(log_mod, msg_id,
+ "%s%s log: module id %u out of range\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_ERROR],
+ cur_mod_id);
+ return -1;
+ }
+
+ if (pre_mod_id > BFA_LOG_MODULE_ID_MAX) {
+ cbfn(log_mod, msg_id,
+ "%s%s log: module id %u out of range\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_ERROR],
+ pre_mod_id);
+ return -1;
+ }
+
+ if (cur_mod_id != pre_mod_id) {
+ bfa_log_info[pre_mod_id].start_idx = pre_idx;
+ bfa_log_info[pre_mod_id].total_count = idx - pre_idx;
+ pre_mod_id = cur_mod_id;
+ pre_idx = idx;
+ }
+
+ idx++;
+ msg++;
+ msg_id = BFA_LOG_GET_MSG_ID(msg);
+ }
+
+ bfa_log_info[cur_mod_id].start_idx = pre_idx;
+ bfa_log_info[cur_mod_id].total_count = idx - pre_idx;
+ bfa_log_msg_total_count = idx;
+
+ cbfn(log_mod, msg_id, "%s%s log: init OK, msg total count %u\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_INFO], bfa_log_msg_total_count);
+
+ bfa_log_initialized = 1;
+
+ return 0;
+}
+
+/**
+ * BFA log set log level for a module
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] mod_id - module id
+ * @param[in] log_level - log severity level
+ *
+ * It return BFA_STATUS_OK on success, or > 0 on failure
+ */
+bfa_status_t
+bfa_log_set_level(struct bfa_log_mod_s *log_mod, int mod_id,
+ enum bfa_log_severity log_level)
+{
+ if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX)
+ return BFA_STATUS_EINVAL;
+
+ if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX)
+ return BFA_STATUS_EINVAL;
+
+ if (log_mod)
+ log_mod->log_level[mod_id] = log_level;
+ else
+ bfa_log_info[mod_id].level = log_level;
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * BFA log set log level for all modules
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] log_level - log severity level
+ *
+ * It return BFA_STATUS_OK on success, or > 0 on failure
+ */
+bfa_status_t
+bfa_log_set_level_all(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level)
+{
+ int mod_id = BFA_LOG_UNUSED_ID + 1;
+
+ if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX)
+ return BFA_STATUS_EINVAL;
+
+ if (log_mod) {
+ for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++)
+ log_mod->log_level[mod_id] = log_level;
+ } else {
+ for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++)
+ bfa_log_info[mod_id].level = log_level;
+ }
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * BFA log set log level for all aen sub-modules
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] log_level - log severity level
+ *
+ * It return BFA_STATUS_OK on success, or > 0 on failure
+ */
+bfa_status_t
+bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level)
+{
+ int mod_id = BFA_LOG_AEN_MIN + 1;
+
+ if (log_mod) {
+ for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++)
+ log_mod->log_level[mod_id] = log_level;
+ } else {
+ for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++)
+ bfa_log_info[mod_id].level = log_level;
+ }
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * BFA log get log level for a module
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] mod_id - module id
+ *
+ * It returns log level or -1 on error
+ */
+enum bfa_log_severity
+bfa_log_get_level(struct bfa_log_mod_s *log_mod, int mod_id)
+{
+ if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX)
+ return BFA_LOG_INVALID;
+
+ if (log_mod)
+ return (log_mod->log_level[mod_id]);
+ else
+ return (bfa_log_info[mod_id].level);
+}
+
+enum bfa_log_severity
+bfa_log_get_msg_level(struct bfa_log_mod_s *log_mod, u32 msg_id)
+{
+ struct bfa_log_msgdef_s *msg;
+ u32 mod = BFA_LOG_GET_MOD_ID(msg_id);
+ u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1;
+
+ if (!bfa_log_initialized)
+ return BFA_LOG_INVALID;
+
+ if (mod > BFA_LOG_MODULE_ID_MAX)
+ return BFA_LOG_INVALID;
+
+ if (idx >= bfa_log_info[mod].total_count) {
+ bfa_log_info[mod].cbfn(log_mod, msg_id,
+ "%s%s log: inconsistent idx %u vs. total count %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx,
+ bfa_log_info[mod].total_count);
+ return BFA_LOG_INVALID;
+ }
+
+ msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx;
+ if (msg_id != BFA_LOG_GET_MSG_ID(msg)) {
+ bfa_log_info[mod].cbfn(log_mod, msg_id,
+ "%s%s log: inconsistent msg id %u array msg id %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR],
+ msg_id, BFA_LOG_GET_MSG_ID(msg));
+ return BFA_LOG_INVALID;
+ }
+
+ return BFA_LOG_GET_SEVERITY(msg);
+}
+
+/**
+ * BFA log message handling
+ *
+ * BFA log message handling finds the message based on message id and prints
+ * out the message based on its format and arguments. It also does prefix
+ * the severity etc.
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] msg_id - message id
+ * @param[in] ... - message arguments
+ *
+ * It return 0 on success, or -1 on errors
+ */
+int
+bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...)
+{
+ va_list ap;
+ char buf[256];
+ struct bfa_log_msgdef_s *msg;
+ int log_level;
+ u32 mod = BFA_LOG_GET_MOD_ID(msg_id);
+ u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1;
+
+ if (!bfa_log_initialized)
+ return -1;
+
+ if (mod > BFA_LOG_MODULE_ID_MAX)
+ return -1;
+
+ if (idx >= bfa_log_info[mod].total_count) {
+ bfa_log_info[mod].
+ cbfn
+ (log_mod, msg_id,
+ "%s%s log: inconsistent idx %u vs. total count %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx,
+ bfa_log_info[mod].total_count);
+ return -1;
+ }
+
+ msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx;
+ if (msg_id != BFA_LOG_GET_MSG_ID(msg)) {
+ bfa_log_info[mod].
+ cbfn
+ (log_mod, msg_id,
+ "%s%s log: inconsistent msg id %u array msg id %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR],
+ msg_id, BFA_LOG_GET_MSG_ID(msg));
+ return -1;
+ }
+
+ log_level = log_mod ? log_mod->log_level[mod] : bfa_log_info[mod].level;
+ if ((BFA_LOG_GET_SEVERITY(msg) > log_level) &&
+ (msg->attributes != BFA_LOG_ATTR_NONE))
+ return 0;
+
+ va_start(ap, msg_id);
+ bfa_os_vsprintf(buf, BFA_LOG_GET_MSG_FMT_STRING(msg), ap);
+ va_end(ap);
+
+ if (log_mod)
+ log_mod->cbfn(log_mod, msg_id, "%s[%s]%s%s %s: %s\n",
+ BFA_LOG_CAT_NAME, log_mod->instance_info,
+ bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)],
+ (msg->attributes & BFA_LOG_ATTR_AUDIT)
+ ? " (audit) " : "", msg->msg_value, buf);
+ else
+ bfa_log_info[mod].cbfn(log_mod, msg_id, "%s%s%s %s: %s\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)],
+ (msg->attributes & BFA_LOG_ATTR_AUDIT) ?
+ " (audit) " : "", msg->msg_value, buf);
+
+ return 0;
+}
+
diff --git a/drivers/scsi/bfa/bfa_log_module.c b/drivers/scsi/bfa/bfa_log_module.c
new file mode 100644
index 000000000000..5c154d341d69
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_log_module.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2005-2009 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 <cs/bfa_log.h>
+#include <aen/bfa_aen_adapter.h>
+#include <aen/bfa_aen_audit.h>
+#include <aen/bfa_aen_ethport.h>
+#include <aen/bfa_aen_ioc.h>
+#include <aen/bfa_aen_itnim.h>
+#include <aen/bfa_aen_lport.h>
+#include <aen/bfa_aen_port.h>
+#include <aen/bfa_aen_rport.h>
+#include <log/bfa_log_fcs.h>
+#include <log/bfa_log_hal.h>
+#include <log/bfa_log_linux.h>
+#include <log/bfa_log_wdrv.h>
+
+struct bfa_log_msgdef_s bfa_log_msg_array[] = {
+
+
+/* messages define for BFA_AEN_CAT_ADAPTER Module */
+{BFA_AEN_ADAPTER_ADD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ADAPTER_ADD",
+ "New adapter found: SN = %s, base port WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_ADAPTER_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_ADAPTER_REMOVE",
+ "Adapter removed: SN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_AUDIT Module */
+{BFA_AEN_AUDIT_AUTH_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_ENABLE",
+ "Authentication enabled for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_AUDIT_AUTH_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_DISABLE",
+ "Authentication disabled for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_ETHPORT Module */
+{BFA_AEN_ETHPORT_LINKUP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_LINKUP",
+ "Base port ethernet linkup: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_ETHPORT_LINKDOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_LINKDOWN",
+ "Base port ethernet linkdown: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_ETHPORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_ENABLE",
+ "Base port ethernet interface enabled: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_ETHPORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_DISABLE",
+ "Base port ethernet interface disabled: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_IOC Module */
+{BFA_AEN_IOC_HBGOOD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_IOC_HBGOOD",
+ "Heart Beat of IOC %d is good.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_HBFAIL, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_CRITICAL,
+ "BFA_AEN_IOC_HBFAIL",
+ "Heart Beat of IOC %d has failed.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_IOC_ENABLE",
+ "IOC %d is enabled.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_IOC_DISABLE",
+ "IOC %d is disabled.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_FWMISMATCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_CRITICAL, "BFA_AEN_IOC_FWMISMATCH",
+ "Running firmware version is incompatible with the driver version.",
+ (0), 0},
+
+
+
+
+/* messages define for BFA_AEN_CAT_ITNIM Module */
+{BFA_AEN_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ITNIM_ONLINE",
+ "Target (WWN = %s) is online for initiator (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ITNIM_OFFLINE",
+ "Target (WWN = %s) offlined by initiator (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_ITNIM_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_ITNIM_DISCONNECT",
+ "Target (WWN = %s) connectivity lost for initiator (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+
+
+
+/* messages define for BFA_AEN_CAT_LPORT Module */
+{BFA_AEN_LPORT_NEW, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_NEW",
+ "New logical port created: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DELETE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_DELETE",
+ "Logical port deleted: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_ONLINE",
+ "Logical port online: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_OFFLINE",
+ "Logical port taken offline: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_LPORT_DISCONNECT",
+ "Logical port lost fabric connectivity: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_NEW_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_NEW_PROP",
+ "New virtual port created using proprietary interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DELETE_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_PROP",
+ "Virtual port deleted using proprietary interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_NEW_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_LPORT_NEW_STANDARD",
+ "New virtual port created using standard interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DELETE_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_STANDARD",
+ "Virtual port deleted using standard interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_NPIV_DUP_WWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_DUP_WWN",
+ "Virtual port login failed. Duplicate WWN = %s reported by fabric.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_LPORT_NPIV_FABRIC_MAX, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_FABRIC_MAX",
+ "Virtual port (WWN = %s) login failed. Max NPIV ports already exist in"
+ " fabric/fport.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_LPORT_NPIV_UNKNOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_UNKNOWN",
+ "Virtual port (WWN = %s) login failed.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_PORT Module */
+{BFA_AEN_PORT_ONLINE, BFA_LOG_ATTR_NONE, BFA_LOG_INFO, "BFA_AEN_PORT_ONLINE",
+ "Base port online: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
+ "BFA_AEN_PORT_OFFLINE",
+ "Base port offline: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_RLIR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_RLIR",
+ "RLIR event not supported.",
+ (0), 0},
+
+{BFA_AEN_PORT_SFP_INSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_SFP_INSERT",
+ "New SFP found: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_SFP_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_REMOVE",
+ "SFP removed: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_SFP_POM, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
+ "BFA_AEN_PORT_SFP_POM",
+ "SFP POM level to %s: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_PORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_ENABLE",
+ "Base port enabled: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_DISABLE",
+ "Base port disabled: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_AUTH_ON, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_AUTH_ON",
+ "Authentication successful for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_AUTH_OFF, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "BFA_AEN_PORT_AUTH_OFF",
+ "Authentication unsuccessful for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "BFA_AEN_PORT_DISCONNECT",
+ "Base port (WWN = %s) lost fabric connectivity.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_QOS_NEG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
+ "BFA_AEN_PORT_QOS_NEG",
+ "QOS negotiation failed for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_FABRIC_NAME_CHANGE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_FABRIC_NAME_CHANGE",
+ "Base port WWN = %s, Fabric WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_PORT_SFP_ACCESS_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_ACCESS_ERROR",
+ "SFP access error: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_SFP_UNSUPPORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_UNSUPPORT",
+ "Unsupported SFP found: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_RPORT Module */
+{BFA_AEN_RPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_ONLINE",
+ "Remote port (WWN = %s) online for logical port (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_RPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_OFFLINE",
+ "Remote port (WWN = %s) offlined by logical port (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_RPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_RPORT_DISCONNECT",
+ "Remote port (WWN = %s) connectivity lost for logical port (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_RPORT_QOS_PRIO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_QOS_PRIO",
+ "QOS priority changed to %s: RPWWN = %s and LPWWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_AEN_RPORT_QOS_FLOWID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_QOS_FLOWID",
+ "QOS flow ID changed to %d: RPWWN = %s and LPWWN = %s.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for FCS Module */
+{BFA_LOG_FCS_FABRIC_NOSWITCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "FCS_FABRIC_NOSWITCH",
+ "No switched fabric presence is detected.",
+ (0), 0},
+
+{BFA_LOG_FCS_FABRIC_ISOLATED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "FCS_FABRIC_ISOLATED",
+ "Port is isolated due to VF_ID mismatch. PWWN: %s, Port VF_ID: %04x and"
+ " switch port VF_ID: %04x.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_X << BFA_LOG_ARG1) |
+ (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for HAL Module */
+{BFA_LOG_HAL_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "HAL_ASSERT",
+ "Assertion failure: %s:%d: %s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_LOG_HAL_HEARTBEAT_FAILURE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_CRITICAL, "HAL_HEARTBEAT_FAILURE",
+ "Firmware heartbeat failure at %d",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_HAL_FCPIM_PARM_INVALID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "HAL_FCPIM_PARM_INVALID",
+ "Driver configuration %s value %d is invalid. Value should be within"
+ " %d and %d.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_D << BFA_LOG_ARG2) | (BFA_LOG_D << BFA_LOG_ARG3) | 0), 4},
+
+{BFA_LOG_HAL_SM_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "HAL_SM_ASSERT",
+ "SM Assertion failure: %s:%d: event = %d",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_D << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for LINUX Module */
+{BFA_LOG_LINUX_DEVICE_CLAIMED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DEVICE_CLAIMED",
+ "bfa device at %s claimed.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_HASH_INIT_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_HASH_INIT_FAILED",
+ "Hash table initialization failure for the port %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_SYSFS_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_SYSFS_FAILED",
+ "sysfs file creation failure for the port %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_MEM_ALLOC_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_MEM_ALLOC_FAILED",
+ "Memory allocation failed: %s. ",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_DRIVER_REGISTRATION_FAILED",
+ "%s. ",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_ITNIM_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_ITNIM_FREE",
+ "scsi%d: FCID: %s WWPN: %s",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_LOG_LINUX_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_ITNIM_ONLINE",
+ "Target: %d:0:%d FCID: %s WWPN: %s",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4},
+
+{BFA_LOG_LINUX_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_ITNIM_OFFLINE",
+ "Target: %d:0:%d FCID: %s WWPN: %s",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4},
+
+{BFA_LOG_LINUX_SCSI_HOST_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_SCSI_HOST_FREE",
+ "Free scsi%d",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_SCSI_ABORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_SCSI_ABORT",
+ "scsi%d: abort cmnd %p, iotag %x",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
+ (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_LOG_LINUX_SCSI_ABORT_COMP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_SCSI_ABORT_COMP",
+ "scsi%d: complete abort 0x%p, iotag 0x%x",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
+ (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for WDRV Module */
+{BFA_LOG_WDRV_IOC_INIT_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_INIT_ERROR",
+ "IOC initialization has failed.",
+ (0), 0},
+
+{BFA_LOG_WDRV_IOC_INTERNAL_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_INTERNAL_ERROR",
+ "IOC internal error. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_IOC_START_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_START_ERROR",
+ "IOC could not be started. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_IOC_STOP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_STOP_ERROR",
+ "IOC could not be stopped. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_INSUFFICIENT_RESOURCES, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_INSUFFICIENT_RESOURCES",
+ "Insufficient memory. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_BASE_ADDRESS_MAP_ERROR",
+ "Unable to map the IOC onto the system address space. ",
+ (0), 0},
+
+
+{0, 0, 0, "", "", 0, 0},
+};
diff --git a/drivers/scsi/bfa/bfa_lps.c b/drivers/scsi/bfa/bfa_lps.c
new file mode 100644
index 000000000000..9844b45412b6
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_lps.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfi/bfi_lps.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, LPS);
+BFA_MODULE(lps);
+
+#define BFA_LPS_MIN_LPORTS (1)
+#define BFA_LPS_MAX_LPORTS (256)
+
+/**
+ * forward declarations
+ */
+static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
+ u32 *dm_len);
+static void bfa_lps_attach(struct bfa_s *bfa, void *bfad,
+ struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+static void bfa_lps_initdone(struct bfa_s *bfa);
+static void bfa_lps_detach(struct bfa_s *bfa);
+static void bfa_lps_start(struct bfa_s *bfa);
+static void bfa_lps_stop(struct bfa_s *bfa);
+static void bfa_lps_iocdisable(struct bfa_s *bfa);
+static void bfa_lps_login_rsp(struct bfa_s *bfa,
+ struct bfi_lps_login_rsp_s *rsp);
+static void bfa_lps_logout_rsp(struct bfa_s *bfa,
+ struct bfi_lps_logout_rsp_s *rsp);
+static void bfa_lps_reqq_resume(void *lps_arg);
+static void bfa_lps_free(struct bfa_lps_s *lps);
+static void bfa_lps_send_login(struct bfa_lps_s *lps);
+static void bfa_lps_send_logout(struct bfa_lps_s *lps);
+static void bfa_lps_login_comp(struct bfa_lps_s *lps);
+static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
+
+
+/**
+ * lps_pvt BFA LPS private functions
+ */
+
+enum bfa_lps_event {
+ BFA_LPS_SM_LOGIN = 1, /* login request from user */
+ BFA_LPS_SM_LOGOUT = 2, /* logout request from user */
+ BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */
+ BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */
+ BFA_LPS_SM_DELETE = 5, /* lps delete from user */
+ BFA_LPS_SM_OFFLINE = 6, /* Link is offline */
+};
+
+static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps,
+ enum bfa_lps_event event);
+static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_logowait(struct bfa_lps_s *lps,
+ enum bfa_lps_event event);
+
+/**
+ * Init state -- no login
+ */
+static void
+bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_LOGIN:
+ if (bfa_reqq_full(lps->bfa, lps->reqq)) {
+ bfa_sm_set_state(lps, bfa_lps_sm_loginwait);
+ bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
+ } else {
+ bfa_sm_set_state(lps, bfa_lps_sm_login);
+ bfa_lps_send_login(lps);
+ }
+ break;
+
+ case BFA_LPS_SM_LOGOUT:
+ bfa_lps_logout_comp(lps);
+ break;
+
+ case BFA_LPS_SM_DELETE:
+ bfa_lps_free(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ break;
+
+ case BFA_LPS_SM_FWRSP:
+ /* Could happen when fabric detects loopback and discards
+ * the lps request. Fw will eventually sent out the timeout
+ * Just ignore
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * login is in progress -- awaiting response from firmware
+ */
+static void
+bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_FWRSP:
+ if (lps->status == BFA_STATUS_OK)
+ bfa_sm_set_state(lps, bfa_lps_sm_online);
+ else
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_lps_login_comp(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * login pending - awaiting space in request queue
+ */
+static void
+bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_RESUME:
+ bfa_sm_set_state(lps, bfa_lps_sm_login);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * login complete
+ */
+static void
+bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_LOGOUT:
+ if (bfa_reqq_full(lps->bfa, lps->reqq)) {
+ bfa_sm_set_state(lps, bfa_lps_sm_logowait);
+ bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
+ } else {
+ bfa_sm_set_state(lps, bfa_lps_sm_logout);
+ bfa_lps_send_logout(lps);
+ }
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ case BFA_LPS_SM_DELETE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * logout in progress - awaiting firmware response
+ */
+static void
+bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_FWRSP:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_lps_logout_comp(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * logout pending -- awaiting space in request queue
+ */
+static void
+bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_RESUME:
+ bfa_sm_set_state(lps, bfa_lps_sm_logout);
+ bfa_lps_send_logout(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * lps_pvt BFA LPS private functions
+ */
+
+/**
+ * return memory requirement
+ */
+static void
+bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len)
+{
+ if (cfg->drvcfg.min_cfg)
+ *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS;
+ else
+ *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS;
+}
+
+/**
+ * bfa module attach at initialization time
+ */
+static void
+bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+ int i;
+
+ bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s));
+ mod->num_lps = BFA_LPS_MAX_LPORTS;
+ if (cfg->drvcfg.min_cfg)
+ mod->num_lps = BFA_LPS_MIN_LPORTS;
+ else
+ mod->num_lps = BFA_LPS_MAX_LPORTS;
+ mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo);
+
+ bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s);
+
+ INIT_LIST_HEAD(&mod->lps_free_q);
+ INIT_LIST_HEAD(&mod->lps_active_q);
+
+ for (i = 0; i < mod->num_lps; i++, lps++) {
+ lps->bfa = bfa;
+ lps->lp_tag = (u8) i;
+ lps->reqq = BFA_REQQ_LPS;
+ bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps);
+ list_add_tail(&lps->qe, &mod->lps_free_q);
+ }
+}
+
+static void
+bfa_lps_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_lps_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_lps_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_lps_stop(struct bfa_s *bfa)
+{
+}
+
+/**
+ * IOC in disabled state -- consider all lps offline
+ */
+static void
+bfa_lps_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &mod->lps_active_q) {
+ lps = (struct bfa_lps_s *) qe;
+ bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
+ }
+}
+
+/**
+ * Firmware login response
+ */
+static void
+bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+
+ bfa_assert(rsp->lp_tag < mod->num_lps);
+ lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
+
+ lps->status = rsp->status;
+ switch (rsp->status) {
+ case BFA_STATUS_OK:
+ lps->fport = rsp->f_port;
+ lps->npiv_en = rsp->npiv_en;
+ lps->lp_pid = rsp->lp_pid;
+ lps->pr_bbcred = bfa_os_ntohs(rsp->bb_credit);
+ lps->pr_pwwn = rsp->port_name;
+ lps->pr_nwwn = rsp->node_name;
+ lps->auth_req = rsp->auth_req;
+ lps->lp_mac = rsp->lp_mac;
+ lps->brcd_switch = rsp->brcd_switch;
+ lps->fcf_mac = rsp->fcf_mac;
+
+ break;
+
+ case BFA_STATUS_FABRIC_RJT:
+ lps->lsrjt_rsn = rsp->lsrjt_rsn;
+ lps->lsrjt_expl = rsp->lsrjt_expl;
+
+ break;
+
+ case BFA_STATUS_EPROTOCOL:
+ lps->ext_status = rsp->ext_status;
+
+ break;
+
+ default:
+ /* Nothing to do with other status */
+ break;
+ }
+
+ bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
+}
+
+/**
+ * Firmware logout response
+ */
+static void
+bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+
+ bfa_assert(rsp->lp_tag < mod->num_lps);
+ lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
+
+ bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
+}
+
+/**
+ * Space is available in request queue, resume queueing request to firmware.
+ */
+static void
+bfa_lps_reqq_resume(void *lps_arg)
+{
+ struct bfa_lps_s *lps = lps_arg;
+
+ bfa_sm_send_event(lps, BFA_LPS_SM_RESUME);
+}
+
+/**
+ * lps is freed -- triggered by vport delete
+ */
+static void
+bfa_lps_free(struct bfa_lps_s *lps)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa);
+
+ list_del(&lps->qe);
+ list_add_tail(&lps->qe, &mod->lps_free_q);
+}
+
+/**
+ * send login request to firmware
+ */
+static void
+bfa_lps_send_login(struct bfa_lps_s *lps)
+{
+ struct bfi_lps_login_req_s *m;
+
+ m = bfa_reqq_next(lps->bfa, lps->reqq);
+ bfa_assert(m);
+
+ bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ,
+ bfa_lpuid(lps->bfa));
+
+ m->lp_tag = lps->lp_tag;
+ m->alpa = lps->alpa;
+ m->pdu_size = bfa_os_htons(lps->pdusz);
+ m->pwwn = lps->pwwn;
+ m->nwwn = lps->nwwn;
+ m->fdisc = lps->fdisc;
+ m->auth_en = lps->auth_en;
+
+ bfa_reqq_produce(lps->bfa, lps->reqq);
+}
+
+/**
+ * send logout request to firmware
+ */
+static void
+bfa_lps_send_logout(struct bfa_lps_s *lps)
+{
+ struct bfi_lps_logout_req_s *m;
+
+ m = bfa_reqq_next(lps->bfa, lps->reqq);
+ bfa_assert(m);
+
+ bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ,
+ bfa_lpuid(lps->bfa));
+
+ m->lp_tag = lps->lp_tag;
+ m->port_name = lps->pwwn;
+ bfa_reqq_produce(lps->bfa, lps->reqq);
+}
+
+/**
+ * Indirect login completion handler for non-fcs
+ */
+static void
+bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete)
+{
+ struct bfa_lps_s *lps = arg;
+
+ if (!complete)
+ return;
+
+ if (lps->fdisc)
+ bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
+ else
+ bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
+}
+
+/**
+ * Login completion handler -- direct call for fcs, queue for others
+ */
+static void
+bfa_lps_login_comp(struct bfa_lps_s *lps)
+{
+ if (!lps->bfa->fcs) {
+ bfa_cb_queue(lps->bfa, &lps->hcb_qe,
+ bfa_lps_login_comp_cb, lps);
+ return;
+ }
+
+ if (lps->fdisc)
+ bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
+ else
+ bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
+}
+
+/**
+ * Indirect logout completion handler for non-fcs
+ */
+static void
+bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete)
+{
+ struct bfa_lps_s *lps = arg;
+
+ if (!complete)
+ return;
+
+ if (lps->fdisc)
+ bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
+ else
+ bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
+}
+
+/**
+ * Logout completion handler -- direct call for fcs, queue for others
+ */
+static void
+bfa_lps_logout_comp(struct bfa_lps_s *lps)
+{
+ if (!lps->bfa->fcs) {
+ bfa_cb_queue(lps->bfa, &lps->hcb_qe,
+ bfa_lps_logout_comp_cb, lps);
+ return;
+ }
+ if (lps->fdisc)
+ bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
+ else
+ bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
+}
+
+
+
+/**
+ * lps_public BFA LPS public functions
+ */
+
+/**
+ * Allocate a lport srvice tag.
+ */
+struct bfa_lps_s *
+bfa_lps_alloc(struct bfa_s *bfa)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps = NULL;
+
+ bfa_q_deq(&mod->lps_free_q, &lps);
+
+ if (lps == NULL)
+ return NULL;
+
+ list_add_tail(&lps->qe, &mod->lps_active_q);
+
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ return lps;
+}
+
+/**
+ * Free lport service tag. This can be called anytime after an alloc.
+ * No need to wait for any pending login/logout completions.
+ */
+void
+bfa_lps_delete(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_DELETE);
+}
+
+/**
+ * Initiate a lport login.
+ */
+void
+bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
+ wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en)
+{
+ lps->uarg = uarg;
+ lps->alpa = alpa;
+ lps->pdusz = pdusz;
+ lps->pwwn = pwwn;
+ lps->nwwn = nwwn;
+ lps->fdisc = BFA_FALSE;
+ lps->auth_en = auth_en;
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
+}
+
+/**
+ * Initiate a lport fdisc login.
+ */
+void
+bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
+ wwn_t nwwn)
+{
+ lps->uarg = uarg;
+ lps->alpa = 0;
+ lps->pdusz = pdusz;
+ lps->pwwn = pwwn;
+ lps->nwwn = nwwn;
+ lps->fdisc = BFA_TRUE;
+ lps->auth_en = BFA_FALSE;
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
+}
+
+/**
+ * Initiate a lport logout (flogi).
+ */
+void
+bfa_lps_flogo(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
+}
+
+/**
+ * Initiate a lport FDSIC logout.
+ */
+void
+bfa_lps_fdisclogo(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
+}
+
+/**
+ * Discard a pending login request -- should be called only for
+ * link down handling.
+ */
+void
+bfa_lps_discard(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
+}
+
+/**
+ * Return lport services tag
+ */
+u8
+bfa_lps_get_tag(struct bfa_lps_s *lps)
+{
+ return lps->lp_tag;
+}
+
+/**
+ * Return lport services tag given the pid
+ */
+u8
+bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+ int i;
+
+ for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) {
+ if (lps->lp_pid == pid)
+ return lps->lp_tag;
+ }
+
+ /* Return base port tag anyway */
+ return 0;
+}
+
+/**
+ * return if fabric login indicates support for NPIV
+ */
+bfa_boolean_t
+bfa_lps_is_npiv_en(struct bfa_lps_s *lps)
+{
+ return lps->npiv_en;
+}
+
+/**
+ * Return TRUE if attached to F-Port, else return FALSE
+ */
+bfa_boolean_t
+bfa_lps_is_fport(struct bfa_lps_s *lps)
+{
+ return lps->fport;
+}
+
+/**
+ * Return TRUE if attached to a Brocade Fabric
+ */
+bfa_boolean_t
+bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps)
+{
+ return lps->brcd_switch;
+}
+/**
+ * return TRUE if authentication is required
+ */
+bfa_boolean_t
+bfa_lps_is_authreq(struct bfa_lps_s *lps)
+{
+ return lps->auth_req;
+}
+
+bfa_eproto_status_t
+bfa_lps_get_extstatus(struct bfa_lps_s *lps)
+{
+ return lps->ext_status;
+}
+
+/**
+ * return port id assigned to the lport
+ */
+u32
+bfa_lps_get_pid(struct bfa_lps_s *lps)
+{
+ return lps->lp_pid;
+}
+
+/**
+ * Return bb_credit assigned in FLOGI response
+ */
+u16
+bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps)
+{
+ return lps->pr_bbcred;
+}
+
+/**
+ * Return peer port name
+ */
+wwn_t
+bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps)
+{
+ return lps->pr_pwwn;
+}
+
+/**
+ * Return peer node name
+ */
+wwn_t
+bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps)
+{
+ return lps->pr_nwwn;
+}
+
+/**
+ * return reason code if login request is rejected
+ */
+u8
+bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps)
+{
+ return lps->lsrjt_rsn;
+}
+
+/**
+ * return explanation code if login request is rejected
+ */
+u8
+bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps)
+{
+ return lps->lsrjt_expl;
+}
+
+
+/**
+ * LPS firmware message class handler.
+ */
+void
+bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ union bfi_lps_i2h_msg_u msg;
+
+ bfa_trc(bfa, m->mhdr.msg_id);
+ msg.msg = m;
+
+ switch (m->mhdr.msg_id) {
+ case BFI_LPS_H2I_LOGIN_RSP:
+ bfa_lps_login_rsp(bfa, msg.login_rsp);
+ break;
+
+ case BFI_LPS_H2I_LOGOUT_RSP:
+ bfa_lps_logout_rsp(bfa, msg.logout_rsp);
+ break;
+
+ default:
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_lps_priv.h b/drivers/scsi/bfa/bfa_lps_priv.h
new file mode 100644
index 000000000000..d16c6ce995df
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_lps_priv.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_LPS_PRIV_H__
+#define __BFA_LPS_PRIV_H__
+
+#include <bfa_svc.h>
+
+struct bfa_lps_mod_s {
+ struct list_head lps_free_q;
+ struct list_head lps_active_q;
+ struct bfa_lps_s *lps_arr;
+ int num_lps;
+};
+
+#define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod)
+#define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag])
+
+/*
+ * external functions
+ */
+void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+
+#endif /* __BFA_LPS_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_module.c b/drivers/scsi/bfa/bfa_module.c
new file mode 100644
index 000000000000..32eda8e1ec65
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_module.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <defs/bfa_defs_pci.h>
+#include <cs/bfa_debug.h>
+#include <bfa_iocfc.h>
+
+/**
+ * BFA module list terminated by NULL
+ */
+struct bfa_module_s *hal_mods[] = {
+ &hal_mod_sgpg,
+ &hal_mod_pport,
+ &hal_mod_fcxp,
+ &hal_mod_lps,
+ &hal_mod_uf,
+ &hal_mod_rport,
+ &hal_mod_fcpim,
+#ifdef BFA_CFG_PBIND
+ &hal_mod_pbind,
+#endif
+ NULL
+};
+
+/**
+ * Message handlers for various modules.
+ */
+bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
+ bfa_isr_unhandled, /* NONE */
+ bfa_isr_unhandled, /* BFI_MC_IOC */
+ bfa_isr_unhandled, /* BFI_MC_DIAG */
+ bfa_isr_unhandled, /* BFI_MC_FLASH */
+ bfa_isr_unhandled, /* BFI_MC_CEE */
+ bfa_pport_isr, /* BFI_MC_PORT */
+ bfa_isr_unhandled, /* BFI_MC_IOCFC */
+ bfa_isr_unhandled, /* BFI_MC_LL */
+ bfa_uf_isr, /* BFI_MC_UF */
+ bfa_fcxp_isr, /* BFI_MC_FCXP */
+ bfa_lps_isr, /* BFI_MC_LPS */
+ bfa_rport_isr, /* BFI_MC_RPORT */
+ bfa_itnim_isr, /* BFI_MC_ITNIM */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_READ */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_IO */
+ bfa_ioim_isr, /* BFI_MC_IOIM */
+ bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */
+ bfa_tskim_isr, /* BFI_MC_TSKIM */
+ bfa_isr_unhandled, /* BFI_MC_SBOOT */
+ bfa_isr_unhandled, /* BFI_MC_IPFC */
+ bfa_isr_unhandled, /* BFI_MC_PORT */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+};
+
+/**
+ * Message handlers for mailbox command classes
+ */
+bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
+ NULL,
+ NULL, /* BFI_MC_IOC */
+ NULL, /* BFI_MC_DIAG */
+ NULL, /* BFI_MC_FLASH */
+ NULL, /* BFI_MC_CEE */
+ NULL, /* BFI_MC_PORT */
+ bfa_iocfc_isr, /* BFI_MC_IOCFC */
+ NULL,
+};
+
diff --git a/drivers/scsi/bfa/bfa_modules_priv.h b/drivers/scsi/bfa/bfa_modules_priv.h
new file mode 100644
index 000000000000..96f70534593c
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_modules_priv.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_MODULES_PRIV_H__
+#define __BFA_MODULES_PRIV_H__
+
+#include "bfa_uf_priv.h"
+#include "bfa_port_priv.h"
+#include "bfa_rport_priv.h"
+#include "bfa_fcxp_priv.h"
+#include "bfa_lps_priv.h"
+#include "bfa_fcpim_priv.h"
+#include <cee/bfa_cee.h>
+#include <port/bfa_port.h>
+
+
+struct bfa_modules_s {
+ struct bfa_pport_s pport; /* physical port module */
+ struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */
+ struct bfa_lps_mod_s lps_mod; /* fcxp module */
+ struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */
+ struct bfa_rport_mod_s rport_mod; /* remote port module */
+ struct bfa_fcpim_mod_s fcpim_mod; /* FCP initiator module */
+ struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */
+ struct bfa_cee_s cee; /* CEE Module */
+ struct bfa_port_s port; /* Physical port module */
+};
+
+#endif /* __BFA_MODULES_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_os_inc.h b/drivers/scsi/bfa/bfa_os_inc.h
new file mode 100644
index 000000000000..10a89f75fa94
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_os_inc.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * Contains declarations all OS Specific files needed for BFA layer
+ */
+
+#ifndef __BFA_OS_INC_H__
+#define __BFA_OS_INC_H__
+
+#ifndef __KERNEL__
+#include <stdint.h>
+#else
+#include <linux/types.h>
+
+#include <linux/version.h>
+#include <linux/pci.h>
+
+#include <linux/dma-mapping.h>
+#define SET_MODULE_VERSION(VER)
+
+#include <linux/idr.h>
+
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+
+#include <linux/workqueue.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
+
+#define BFA_ERR KERN_ERR
+#define BFA_WARNING KERN_WARNING
+#define BFA_NOTICE KERN_NOTICE
+#define BFA_INFO KERN_INFO
+#define BFA_DEBUG KERN_DEBUG
+
+#define LOG_BFAD_INIT 0x00000001
+#define LOG_FCP_IO 0x00000002
+
+#ifdef DEBUG
+#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...) \
+ BFA_LOG(bfad, level, mask, fmt, ## arg)
+#define BFA_DEV_TRACE(bfad, level, fmt, arg...) \
+ BFA_DEV_PRINTF(bfad, level, fmt, ## arg)
+#define BFA_TRACE(level, fmt, arg...) \
+ BFA_PRINTF(level, fmt, ## arg)
+#else
+#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...)
+#define BFA_DEV_TRACE(bfad, level, fmt, arg...)
+#define BFA_TRACE(level, fmt, arg...)
+#endif
+
+#define BFA_ASSERT(p) do { \
+ if (!(p)) { \
+ printk(KERN_ERR "assert(%s) failed at %s:%d\n", \
+ #p, __FILE__, __LINE__); \
+ BUG(); \
+ } \
+} while (0)
+
+
+#define BFA_LOG(bfad, level, mask, fmt, arg...) \
+do { \
+ if (((mask) & (((struct bfad_s *)(bfad))-> \
+ cfg_data[cfg_log_mask])) || (level[1] <= '3')) \
+ dev_printk(level, &(((struct bfad_s *) \
+ (bfad))->pcidev->dev), fmt, ##arg); \
+} while (0)
+
+#ifndef BFA_DEV_PRINTF
+#define BFA_DEV_PRINTF(bfad, level, fmt, arg...) \
+ dev_printk(level, &(((struct bfad_s *) \
+ (bfad))->pcidev->dev), fmt, ##arg);
+#endif
+
+#define BFA_PRINTF(level, fmt, arg...) \
+ printk(level fmt, ##arg);
+
+int bfa_os_MWB(void *);
+
+#define bfa_os_mmiowb() mmiowb()
+
+#define bfa_swap_3b(_x) \
+ ((((_x) & 0xff) << 16) | \
+ ((_x) & 0x00ff00) | \
+ (((_x) & 0xff0000) >> 16))
+
+#define bfa_swap_8b(_x) \
+ ((((_x) & 0xff00000000000000ull) >> 56) \
+ | (((_x) & 0x00ff000000000000ull) >> 40) \
+ | (((_x) & 0x0000ff0000000000ull) >> 24) \
+ | (((_x) & 0x000000ff00000000ull) >> 8) \
+ | (((_x) & 0x00000000ff000000ull) << 8) \
+ | (((_x) & 0x0000000000ff0000ull) << 24) \
+ | (((_x) & 0x000000000000ff00ull) << 40) \
+ | (((_x) & 0x00000000000000ffull) << 56))
+
+#define bfa_os_swap32(_x) \
+ ((((_x) & 0xff) << 24) | \
+ (((_x) & 0x0000ff00) << 8) | \
+ (((_x) & 0x00ff0000) >> 8) | \
+ (((_x) & 0xff000000) >> 24))
+
+
+#ifndef __BIGENDIAN
+#define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
+ (((_x) & 0x00ff) << 8)))
+
+#define bfa_os_htonl(_x) bfa_os_swap32(_x)
+#define bfa_os_htonll(_x) bfa_swap_8b(_x)
+#define bfa_os_hton3b(_x) bfa_swap_3b(_x)
+
+#define bfa_os_wtole(_x) (_x)
+
+#else
+
+#define bfa_os_htons(_x) (_x)
+#define bfa_os_htonl(_x) (_x)
+#define bfa_os_hton3b(_x) (_x)
+#define bfa_os_htonll(_x) (_x)
+#define bfa_os_wtole(_x) bfa_os_swap32(_x)
+
+#endif
+
+#define bfa_os_ntohs(_x) bfa_os_htons(_x)
+#define bfa_os_ntohl(_x) bfa_os_htonl(_x)
+#define bfa_os_ntohll(_x) bfa_os_htonll(_x)
+#define bfa_os_ntoh3b(_x) bfa_os_hton3b(_x)
+
+#define bfa_os_u32(__pa64) ((__pa64) >> 32)
+
+#define bfa_os_memset memset
+#define bfa_os_memcpy memcpy
+#define bfa_os_udelay udelay
+#define bfa_os_vsprintf vsprintf
+
+#define bfa_os_assign(__t, __s) __t = __s
+
+#define bfa_os_addr_t char __iomem *
+#define bfa_os_panic()
+
+#define bfa_os_reg_read(_raddr) bfa_os_wtole(readl(_raddr))
+#define bfa_os_reg_write(_raddr, _val) writel(bfa_os_wtole((_val)), (_raddr))
+#define bfa_os_mem_read(_raddr, _off) \
+ bfa_os_ntohl(readl(((_raddr) + (_off))))
+#define bfa_os_mem_write(_raddr, _off, _val) \
+ writel(bfa_os_htonl((_val)), ((_raddr) + (_off)))
+
+#define BFA_TRC_TS(_trcm) \
+ ({ \
+ struct timeval tv; \
+ \
+ do_gettimeofday(&tv); \
+ (tv.tv_sec*1000000+tv.tv_usec); \
+ })
+
+struct bfa_log_mod_s;
+void bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id,
+ const char *fmt, ...);
+#endif
+
+#define boolean_t int
+
+/**
+ * For current time stamp, OS API will fill-in
+ */
+struct bfa_timeval_s {
+ u32 tv_sec; /* seconds */
+ u32 tv_usec; /* microseconds */
+};
+
+void bfa_os_gettimeofday(struct bfa_timeval_s *tv);
+
+static inline void
+wwn2str(char *wwn_str, u64 wwn)
+{
+ union {
+ u64 wwn;
+ u8 byte[8];
+ } w;
+
+ w.wwn = wwn;
+ sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0],
+ w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5],
+ w.byte[6], w.byte[7]);
+}
+
+static inline void
+fcid2str(char *fcid_str, u32 fcid)
+{
+ union {
+ u32 fcid;
+ u8 byte[4];
+ } f;
+
+ f.fcid = fcid;
+ sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]);
+}
+
+#endif /* __BFA_OS_INC_H__ */
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
new file mode 100644
index 000000000000..cab19028361a
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2005-2009 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 <defs/bfa_defs_port.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+#include <cs/bfa_debug.h>
+#include <port/bfa_port.h>
+#include <bfi/bfi.h>
+#include <bfi/bfi_port.h>
+#include <bfa_ioc.h>
+#include <cna/bfa_cna_trcmod.h>
+
+BFA_TRC_FILE(CNA, PORT);
+
+#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
+
+static void
+bfa_port_stats_swap(struct bfa_port_s *port, union bfa_pport_stats_u *stats)
+{
+ u32 *dip = (u32 *) stats;
+ u32 t0, t1;
+ int i;
+
+ for (i = 0; i < sizeof(union bfa_pport_stats_u) / sizeof(u32);
+ i += 2) {
+ t0 = dip[i];
+ t1 = dip[i + 1];
+#ifdef __BIGENDIAN
+ dip[i] = bfa_os_ntohl(t0);
+ dip[i + 1] = bfa_os_ntohl(t1);
+#else
+ dip[i] = bfa_os_ntohl(t1);
+ dip[i + 1] = bfa_os_ntohl(t0);
+#endif
+ }
+
+ /** todo
+ * QoS stats r also swapped as 64bit; that structure also
+ * has to use 64 bit counters
+ */
+}
+
+/**
+ * bfa_port_enable_isr()
+ *
+ *
+ * @param[in] port - Pointer to the port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ bfa_assert(0);
+}
+
+/**
+ * bfa_port_disable_isr()
+ *
+ *
+ * @param[in] port - Pointer to the port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ bfa_assert(0);
+}
+
+/**
+ * bfa_port_get_stats_isr()
+ *
+ *
+ * @param[in] port - Pointer to the Port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ port->stats_status = status;
+ port->stats_busy = BFA_FALSE;
+
+ if (status == BFA_STATUS_OK) {
+ memcpy(port->stats, port->stats_dma.kva,
+ sizeof(union bfa_pport_stats_u));
+ bfa_port_stats_swap(port, port->stats);
+ }
+
+ if (port->stats_cbfn) {
+ port->stats_cbfn(port->stats_cbarg, status);
+ port->stats_cbfn = NULL;
+ }
+}
+
+/**
+ * bfa_port_clear_stats_isr()
+ *
+ *
+ * @param[in] port - Pointer to the Port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ port->stats_status = status;
+ port->stats_busy = BFA_FALSE;
+
+ if (port->stats_cbfn) {
+ port->stats_cbfn(port->stats_cbarg, status);
+ port->stats_cbfn = NULL;
+ }
+}
+
+/**
+ * bfa_port_isr()
+ *
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return void
+ */
+static void
+bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m)
+{
+ struct bfa_port_s *port = (struct bfa_port_s *)cbarg;
+ union bfi_port_i2h_msg_u *i2hmsg;
+
+ i2hmsg = (union bfi_port_i2h_msg_u *)m;
+ bfa_trc(port, m->mh.msg_id);
+
+ switch (m->mh.msg_id) {
+ case BFI_PORT_I2H_ENABLE_RSP:
+ if (port->endis_pending == BFA_FALSE)
+ break;
+ bfa_port_enable_isr(port, i2hmsg->enable_rsp.status);
+ break;
+
+ case BFI_PORT_I2H_DISABLE_RSP:
+ if (port->endis_pending == BFA_FALSE)
+ break;
+ bfa_port_disable_isr(port, i2hmsg->disable_rsp.status);
+ break;
+
+ case BFI_PORT_I2H_GET_STATS_RSP:
+ /*
+ * Stats busy flag is still set? (may be cmd timed out)
+ */
+ if (port->stats_busy == BFA_FALSE)
+ break;
+ bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status);
+ break;
+
+ case BFI_PORT_I2H_CLEAR_STATS_RSP:
+ if (port->stats_busy == BFA_FALSE)
+ break;
+ bfa_port_clear_stats_isr(port, i2hmsg->clearstats_rsp.status);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * bfa_port_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+u32
+bfa_port_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_port_mem_claim()
+ *
+ *
+ * @param[in] port Port module pointer
+ * dma_kva Kernel Virtual Address of Port DMA Memory
+ * dma_pa Physical Address of Port DMA Memory
+ *
+ * @return void
+ */
+void
+bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa)
+{
+ port->stats_dma.kva = dma_kva;
+ port->stats_dma.pa = dma_pa;
+}
+
+/**
+ * bfa_port_enable()
+ *
+ * Send the Port enable request to the f/w
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_port_generic_req_s *m;
+
+ /** todo Not implemented */
+ bfa_assert(0);
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->endis_pending) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_generic_req_s *)port->endis_mb.msg;
+
+ port->msgtag++;
+ port->endis_cbfn = cbfn;
+ port->endis_cbarg = cbarg;
+ port->endis_pending = BFA_TRUE;
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->endis_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_disable()
+ *
+ * Send the Port disable request to the f/w
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_port_generic_req_s *m;
+
+ /** todo Not implemented */
+ bfa_assert(0);
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->endis_pending) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_generic_req_s *)port->endis_mb.msg;
+
+ port->msgtag++;
+ port->endis_cbfn = cbfn;
+ port->endis_cbarg = cbarg;
+ port->endis_pending = BFA_TRUE;
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->endis_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_get_stats()
+ *
+ * Send the request to the f/w to fetch Port statistics.
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_get_stats(struct bfa_port_s *port, union bfa_pport_stats_u *stats,
+ bfa_port_stats_cbfn_t cbfn, void *cbarg)
+{
+ struct bfi_port_get_stats_req_s *m;
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->stats_busy) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_get_stats_req_s *)port->stats_mb.msg;
+
+ port->stats = stats;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+ port->stats_busy = BFA_TRUE;
+ bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa);
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->stats_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_clear_stats()
+ *
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_port_generic_req_s *m;
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->stats_busy) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_generic_req_s *)port->stats_mb.msg;
+
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+ port->stats_busy = BFA_TRUE;
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->stats_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_hbfail()
+ *
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return void
+ */
+void
+bfa_port_hbfail(void *arg)
+{
+ struct bfa_port_s *port = (struct bfa_port_s *)arg;
+
+ /*
+ * Fail any pending get_stats/clear_stats requests
+ */
+ if (port->stats_busy) {
+ if (port->stats_cbfn)
+ port->stats_cbfn(port->dev, BFA_STATUS_FAILED);
+ port->stats_cbfn = NULL;
+ port->stats_busy = BFA_FALSE;
+ }
+
+ /*
+ * Clear any enable/disable is pending
+ */
+ if (port->endis_pending) {
+ if (port->endis_cbfn)
+ port->endis_cbfn(port->dev, BFA_STATUS_FAILED);
+ port->endis_cbfn = NULL;
+ port->endis_pending = BFA_FALSE;
+ }
+}
+
+/**
+ * bfa_port_attach()
+ *
+ *
+ * @param[in] port - Pointer to the Port module data structure
+ * ioc - Pointer to the ioc module data structure
+ * dev - Pointer to the device driver module data structure
+ * The device driver specific mbox ISR functions have
+ * this pointer as one of the parameters.
+ * trcmod -
+ * logmod -
+ *
+ * @return void
+ */
+void
+bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev,
+ struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod)
+{
+ bfa_assert(port);
+
+ port->dev = dev;
+ port->ioc = ioc;
+ port->trcmod = trcmod;
+ port->logmod = logmod;
+
+ port->stats_busy = port->endis_pending = BFA_FALSE;
+ port->stats_cbfn = port->endis_cbfn = NULL;
+
+ bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
+ bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
+ bfa_ioc_hbfail_register(port->ioc, &port->hbfail);
+
+ bfa_trc(port, 0);
+}
+
+/**
+ * bfa_port_detach()
+ *
+ *
+ * @param[in] port - Pointer to the Port module data structure
+ *
+ * @return void
+ */
+void
+bfa_port_detach(struct bfa_port_s *port)
+{
+ bfa_trc(port, 0);
+}
diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h
new file mode 100644
index 000000000000..4b97e2759908
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_port_priv.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_PORT_PRIV_H__
+#define __BFA_PORT_PRIV_H__
+
+#include <defs/bfa_defs_pport.h>
+#include <bfi/bfi_pport.h>
+#include "bfa_intr_priv.h"
+
+/**
+ * BFA physical port data structure
+ */
+struct bfa_pport_s {
+ struct bfa_s *bfa; /* parent BFA instance */
+ bfa_sm_t sm; /* port state machine */
+ wwn_t nwwn; /* node wwn of physical port */
+ wwn_t pwwn; /* port wwn of physical oprt */
+ enum bfa_pport_speed speed_sup;
+ /* supported speeds */
+ enum bfa_pport_speed speed; /* current speed */
+ enum bfa_pport_topology topology; /* current topology */
+ u8 myalpa; /* my ALPA in LOOP topology */
+ u8 rsvd[3];
+ struct bfa_pport_cfg_s cfg; /* current port configuration */
+ struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
+ struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
+ struct bfa_reqq_wait_s reqq_wait;
+ /* to wait for room in reqq */
+ struct bfa_reqq_wait_s svcreq_wait;
+ /* to wait for room in reqq */
+ struct bfa_reqq_wait_s stats_reqq_wait;
+ /* to wait for room in reqq (stats) */
+ void *event_cbarg;
+ void (*event_cbfn) (void *cbarg,
+ bfa_pport_event_t event);
+ union {
+ union bfi_pport_i2h_msg_u i2hmsg;
+ } event_arg;
+ void *bfad; /* BFA driver handle */
+ struct bfa_cb_qe_s hcb_qe; /* BFA callback queue elem */
+ enum bfa_pport_linkstate hcb_event;
+ /* link event for callback */
+ u32 msgtag; /* fimrware msg tag for reply */
+ u8 *stats_kva;
+ u64 stats_pa;
+ union bfa_pport_stats_u *stats; /* pport stats */
+ u32 mypid : 24;
+ u32 rsvd_b : 8;
+ struct bfa_timer_s timer; /* timer */
+ union bfa_pport_stats_u *stats_ret;
+ /* driver stats location */
+ bfa_status_t stats_status;
+ /* stats/statsclr status */
+ bfa_boolean_t stats_busy;
+ /* outstanding stats/statsclr */
+ bfa_boolean_t stats_qfull;
+ bfa_boolean_t diag_busy;
+ /* diag busy status */
+ bfa_boolean_t beacon;
+ /* port beacon status */
+ bfa_boolean_t link_e2e_beacon;
+ /* link beacon status */
+ bfa_cb_pport_t stats_cbfn;
+ /* driver callback function */
+ void *stats_cbarg;
+ /* *!< user callback arg */
+};
+
+#define BFA_PORT_MOD(__bfa) (&(__bfa)->modules.pport)
+
+/*
+ * public functions
+ */
+void bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+#endif /* __BFA_PORT_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_priv.h b/drivers/scsi/bfa/bfa_priv.h
new file mode 100644
index 000000000000..0747a6b26f7b
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_priv.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_PRIV_H__
+#define __BFA_PRIV_H__
+
+#include "bfa_iocfc.h"
+#include "bfa_intr_priv.h"
+#include "bfa_trcmod_priv.h"
+#include "bfa_modules_priv.h"
+#include "bfa_fwimg_priv.h"
+#include <cs/bfa_log.h>
+#include <bfa_timer.h>
+
+/**
+ * Macro to define a new BFA module
+ */
+#define BFA_MODULE(__mod) \
+ static void bfa_ ## __mod ## _meminfo( \
+ struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, \
+ u32 *dm_len); \
+ static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \
+ void *bfad, struct bfa_iocfc_cfg_s *cfg, \
+ struct bfa_meminfo_s *meminfo, \
+ struct bfa_pcidev_s *pcidev); \
+ static void bfa_ ## __mod ## _initdone(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _stop(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _iocdisable(struct bfa_s *bfa); \
+ \
+ extern struct bfa_module_s hal_mod_ ## __mod; \
+ struct bfa_module_s hal_mod_ ## __mod = { \
+ bfa_ ## __mod ## _meminfo, \
+ bfa_ ## __mod ## _attach, \
+ bfa_ ## __mod ## _initdone, \
+ bfa_ ## __mod ## _detach, \
+ bfa_ ## __mod ## _start, \
+ bfa_ ## __mod ## _stop, \
+ bfa_ ## __mod ## _iocdisable, \
+ }
+
+#define BFA_CACHELINE_SZ (256)
+
+/**
+ * Structure used to interact between different BFA sub modules
+ *
+ * Each sub module needs to implement only the entry points relevant to it (and
+ * can leave entry points as NULL)
+ */
+struct bfa_module_s {
+ void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len);
+ void (*attach) (struct bfa_s *bfa, void *bfad,
+ struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+ void (*initdone) (struct bfa_s *bfa);
+ void (*detach) (struct bfa_s *bfa);
+ void (*start) (struct bfa_s *bfa);
+ void (*stop) (struct bfa_s *bfa);
+ void (*iocdisable) (struct bfa_s *bfa);
+};
+
+extern struct bfa_module_s *hal_mods[];
+
+struct bfa_s {
+ void *bfad; /* BFA driver instance */
+ struct bfa_aen_s *aen; /* AEN module */
+ struct bfa_plog_s *plog; /* portlog buffer */
+ struct bfa_log_mod_s *logm; /* driver logging modulen */
+ struct bfa_trc_mod_s *trcmod; /* driver tracing */
+ struct bfa_ioc_s ioc; /* IOC module */
+ struct bfa_iocfc_s iocfc; /* IOCFC module */
+ struct bfa_timer_mod_s timer_mod; /* timer module */
+ struct bfa_modules_s modules; /* BFA modules */
+ struct list_head comp_q; /* pending completions */
+ bfa_boolean_t rme_process; /* RME processing enabled */
+ struct list_head reqq_waitq[BFI_IOC_MAX_CQS];
+ bfa_boolean_t fcs; /* FCS is attached to BFA */
+ struct bfa_msix_s msix;
+};
+
+extern bfa_isr_func_t bfa_isrs[BFI_MC_MAX];
+extern bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[];
+extern bfa_boolean_t bfa_auto_recover;
+extern struct bfa_module_s hal_mod_flash;
+extern struct bfa_module_s hal_mod_fcdiag;
+extern struct bfa_module_s hal_mod_sgpg;
+extern struct bfa_module_s hal_mod_pport;
+extern struct bfa_module_s hal_mod_fcxp;
+extern struct bfa_module_s hal_mod_lps;
+extern struct bfa_module_s hal_mod_uf;
+extern struct bfa_module_s hal_mod_rport;
+extern struct bfa_module_s hal_mod_fcpim;
+extern struct bfa_module_s hal_mod_pbind;
+
+#endif /* __BFA_PRIV_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c
new file mode 100644
index 000000000000..16da77a8db28
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_rport.c
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_svc.h>
+#include <cs/bfa_debug.h>
+#include <bfi/bfi_rport.h>
+#include "bfa_intr_priv.h"
+
+BFA_TRC_FILE(HAL, RPORT);
+BFA_MODULE(rport);
+
+#define bfa_rport_offline_cb(__rp) do { \
+ if ((__rp)->bfa->fcs) \
+ bfa_cb_rport_offline((__rp)->rport_drv); \
+ else { \
+ bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \
+ __bfa_cb_rport_offline, (__rp)); \
+ } \
+} while (0)
+
+#define bfa_rport_online_cb(__rp) do { \
+ if ((__rp)->bfa->fcs) \
+ bfa_cb_rport_online((__rp)->rport_drv); \
+ else { \
+ bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \
+ __bfa_cb_rport_online, (__rp)); \
+ } \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod);
+static void bfa_rport_free(struct bfa_rport_s *rport);
+static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp);
+static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp);
+static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp);
+static void __bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete);
+
+/**
+ * bfa_rport_sm BFA rport state machine
+ */
+
+
+enum bfa_rport_event {
+ BFA_RPORT_SM_CREATE = 1, /* rport create event */
+ BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */
+ BFA_RPORT_SM_ONLINE = 3, /* rport is online */
+ BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */
+ BFA_RPORT_SM_FWRSP = 5, /* firmware response */
+ BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */
+ BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */
+ BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */
+ BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */
+};
+
+static void bfa_rport_sm_uninit(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_created(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwcreate(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_online(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwdelete(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_offline(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_deleting(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_iocdisable(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+
+/**
+ * Beginning state, only online event expected.
+ */
+static void
+bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_CREATE:
+ bfa_stats(rp, sm_un_cr);
+ bfa_sm_set_state(rp, bfa_rport_sm_created);
+ break;
+
+ default:
+ bfa_stats(rp, sm_un_unexp);
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_ONLINE:
+ bfa_stats(rp, sm_cr_on);
+ if (bfa_rport_send_fwcreate(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_cr_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_cr_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_cr_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for rport create response from firmware.
+ */
+static void
+bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_fwc_rsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_online);
+ bfa_rport_online_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwc_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_delete_pending);
+ break;
+
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_fwc_off);
+ bfa_sm_set_state(rp, bfa_rport_sm_offline_pending);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwc_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwc_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Request queue is full, awaiting queue resume to send create request.
+ */
+static void
+bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_QRESUME:
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ bfa_rport_send_fwcreate(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwc_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_fwc_off);
+ bfa_sm_set_state(rp, bfa_rport_sm_offline);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwc_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwc_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Online state - normal parking state.
+ */
+static void
+bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ struct bfi_rport_qos_scn_s *qos_scn;
+
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_on_off);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_on_del);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_on_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ case BFA_RPORT_SM_SET_SPEED:
+ bfa_rport_send_fwspeed(rp);
+ break;
+
+ case BFA_RPORT_SM_QOS_SCN:
+ qos_scn = (struct bfi_rport_qos_scn_s *) rp->event_arg.fw_msg;
+ rp->qos_attr = qos_scn->new_qos_attr;
+ bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_flow_id);
+ bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_flow_id);
+ bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_priority);
+ bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority);
+
+ qos_scn->old_qos_attr.qos_flow_id =
+ bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id);
+ qos_scn->new_qos_attr.qos_flow_id =
+ bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id);
+ qos_scn->old_qos_attr.qos_priority =
+ bfa_os_ntohl(qos_scn->old_qos_attr.qos_priority);
+ qos_scn->new_qos_attr.qos_priority =
+ bfa_os_ntohl(qos_scn->new_qos_attr.qos_priority);
+
+ if (qos_scn->old_qos_attr.qos_flow_id !=
+ qos_scn->new_qos_attr.qos_flow_id)
+ bfa_cb_rport_qos_scn_flowid(rp->rport_drv,
+ qos_scn->old_qos_attr,
+ qos_scn->new_qos_attr);
+ if (qos_scn->old_qos_attr.qos_priority !=
+ qos_scn->new_qos_attr.qos_priority)
+ bfa_cb_rport_qos_scn_prio(rp->rport_drv,
+ qos_scn->old_qos_attr,
+ qos_scn->new_qos_attr);
+ break;
+
+ default:
+ bfa_stats(rp, sm_on_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Firmware rport is being deleted - awaiting f/w response.
+ */
+static void
+bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_fwd_rsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_offline);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwd_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwd_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwd_unexp);
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_QRESUME:
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
+ bfa_rport_send_fwdelete(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwd_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwd_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwd_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Offline state.
+ */
+static void
+bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_off_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_ONLINE:
+ bfa_stats(rp, sm_off_on);
+ if (bfa_rport_send_fwcreate(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_off_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_off_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is deleted, waiting for firmware response to delete.
+ */
+static void
+bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_del_fwrsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_del_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_QRESUME:
+ bfa_stats(rp, sm_del_fwrsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ bfa_rport_send_fwdelete(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_del_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_free(rp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for rport create response from firmware. A delete is pending.
+ */
+static void
+bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_delp_fwrsp);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_delp_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ default:
+ bfa_stats(rp, sm_delp_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for rport create response from firmware. Rport offline is pending.
+ */
+static void
+bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_offp_fwrsp);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_offp_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_delete_pending);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_offp_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_offp_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IOC h/w failed.
+ */
+static void
+bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_iocd_off);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_iocd_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_ONLINE:
+ bfa_stats(rp, sm_iocd_on);
+ if (bfa_rport_send_fwcreate(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_stats(rp, sm_iocd_unexp);
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_rport_private BFA rport private functions
+ */
+
+static void
+__bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_rport_s *rp = cbarg;
+
+ if (complete)
+ bfa_cb_rport_online(rp->rport_drv);
+}
+
+static void
+__bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_rport_s *rp = cbarg;
+
+ if (complete)
+ bfa_cb_rport_offline(rp->rport_drv);
+}
+
+static void
+bfa_rport_qresume(void *cbarg)
+{
+ struct bfa_rport_s *rp = cbarg;
+
+ bfa_sm_send_event(rp, BFA_RPORT_SM_QRESUME);
+}
+
+static void
+bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ if (cfg->fwcfg.num_rports < BFA_RPORT_MIN)
+ cfg->fwcfg.num_rports = BFA_RPORT_MIN;
+
+ *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s);
+}
+
+static void
+bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa);
+ struct bfa_rport_s *rp;
+ u16 i;
+
+ INIT_LIST_HEAD(&mod->rp_free_q);
+ INIT_LIST_HEAD(&mod->rp_active_q);
+
+ rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo);
+ mod->rps_list = rp;
+ mod->num_rports = cfg->fwcfg.num_rports;
+
+ bfa_assert(mod->num_rports
+ && !(mod->num_rports & (mod->num_rports - 1)));
+
+ for (i = 0; i < mod->num_rports; i++, rp++) {
+ bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s));
+ rp->bfa = bfa;
+ rp->rport_tag = i;
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+
+ /**
+ * - is unused
+ */
+ if (i)
+ list_add_tail(&rp->qe, &mod->rp_free_q);
+
+ bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp);
+ }
+
+ /**
+ * consume memory
+ */
+ bfa_meminfo_kva(meminfo) = (u8 *) rp;
+}
+
+static void
+bfa_rport_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa);
+ struct bfa_rport_s *rport;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &mod->rp_active_q) {
+ rport = (struct bfa_rport_s *) qe;
+ bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL);
+ }
+}
+
+static struct bfa_rport_s *
+bfa_rport_alloc(struct bfa_rport_mod_s *mod)
+{
+ struct bfa_rport_s *rport;
+
+ bfa_q_deq(&mod->rp_free_q, &rport);
+ if (rport)
+ list_add_tail(&rport->qe, &mod->rp_active_q);
+
+ return (rport);
+}
+
+static void
+bfa_rport_free(struct bfa_rport_s *rport)
+{
+ struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa);
+
+ bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rport));
+ list_del(&rport->qe);
+ list_add_tail(&rport->qe, &mod->rp_free_q);
+}
+
+static bfa_boolean_t
+bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
+{
+ struct bfi_rport_create_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
+ if (!m) {
+ bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ,
+ bfa_lpuid(rp->bfa));
+ m->bfa_handle = rp->rport_tag;
+ m->max_frmsz = bfa_os_htons(rp->rport_info.max_frmsz);
+ m->pid = rp->rport_info.pid;
+ m->lp_tag = rp->rport_info.lp_tag;
+ m->local_pid = rp->rport_info.local_pid;
+ m->fc_class = rp->rport_info.fc_class;
+ m->vf_en = rp->rport_info.vf_en;
+ m->vf_id = rp->rport_info.vf_id;
+ m->cisc = rp->rport_info.cisc;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
+ return BFA_TRUE;
+}
+
+static bfa_boolean_t
+bfa_rport_send_fwdelete(struct bfa_rport_s *rp)
+{
+ struct bfi_rport_delete_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
+ if (!m) {
+ bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ,
+ bfa_lpuid(rp->bfa));
+ m->fw_handle = rp->fw_handle;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
+ return BFA_TRUE;
+}
+
+static bfa_boolean_t
+bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
+{
+ struct bfa_rport_speed_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
+ if (!m) {
+ bfa_trc(rp->bfa, rp->rport_info.speed);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ,
+ bfa_lpuid(rp->bfa));
+ m->fw_handle = rp->fw_handle;
+ m->speed = (u8)rp->rport_info.speed;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
+ return BFA_TRUE;
+}
+
+
+
+/**
+ * bfa_rport_public
+ */
+
+/**
+ * Rport interrupt processing.
+ */
+void
+bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ union bfi_rport_i2h_msg_u msg;
+ struct bfa_rport_s *rp;
+
+ bfa_trc(bfa, m->mhdr.msg_id);
+
+ msg.msg = m;
+
+ switch (m->mhdr.msg_id) {
+ case BFI_RPORT_I2H_CREATE_RSP:
+ rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle);
+ rp->fw_handle = msg.create_rsp->fw_handle;
+ rp->qos_attr = msg.create_rsp->qos_attr;
+ bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
+ bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
+ break;
+
+ case BFI_RPORT_I2H_DELETE_RSP:
+ rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle);
+ bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
+ bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
+ break;
+
+ case BFI_RPORT_I2H_QOS_SCN:
+ rp = BFA_RPORT_FROM_TAG(bfa, msg.qos_scn_evt->bfa_handle);
+ rp->event_arg.fw_msg = msg.qos_scn_evt;
+ bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN);
+ break;
+
+ default:
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_rport_api
+ */
+
+struct bfa_rport_s *
+bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
+{
+ struct bfa_rport_s *rp;
+
+ rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa));
+
+ if (rp == NULL)
+ return (NULL);
+
+ rp->bfa = bfa;
+ rp->rport_drv = rport_drv;
+ bfa_rport_clear_stats(rp);
+
+ bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
+ bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE);
+
+ return (rp);
+}
+
+void
+bfa_rport_delete(struct bfa_rport_s *rport)
+{
+ bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE);
+}
+
+void
+bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
+{
+ bfa_assert(rport_info->max_frmsz != 0);
+
+ /**
+ * Some JBODs are seen to be not setting PDU size correctly in PLOGI
+ * responses. Default to minimum size.
+ */
+ if (rport_info->max_frmsz == 0) {
+ bfa_trc(rport->bfa, rport->rport_tag);
+ rport_info->max_frmsz = FC_MIN_PDUSZ;
+ }
+
+ bfa_os_assign(rport->rport_info, *rport_info);
+ bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE);
+}
+
+void
+bfa_rport_offline(struct bfa_rport_s *rport)
+{
+ bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE);
+}
+
+void
+bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed)
+{
+ bfa_assert(speed != 0);
+ bfa_assert(speed != BFA_PPORT_SPEED_AUTO);
+
+ rport->rport_info.speed = speed;
+ bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED);
+}
+
+void
+bfa_rport_get_stats(struct bfa_rport_s *rport,
+ struct bfa_rport_hal_stats_s *stats)
+{
+ *stats = rport->stats;
+}
+
+void
+bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
+ struct bfa_rport_qos_attr_s *qos_attr)
+{
+ qos_attr->qos_priority = bfa_os_ntohl(rport->qos_attr.qos_priority);
+ qos_attr->qos_flow_id = bfa_os_ntohl(rport->qos_attr.qos_flow_id);
+
+}
+
+void
+bfa_rport_clear_stats(struct bfa_rport_s *rport)
+{
+ bfa_os_memset(&rport->stats, 0, sizeof(rport->stats));
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_rport_priv.h b/drivers/scsi/bfa/bfa_rport_priv.h
new file mode 100644
index 000000000000..6490ce2e990d
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_rport_priv.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_RPORT_PRIV_H__
+#define __BFA_RPORT_PRIV_H__
+
+#include <bfa_svc.h>
+
+#define BFA_RPORT_MIN 4
+
+struct bfa_rport_mod_s {
+ struct bfa_rport_s *rps_list; /* list of rports */
+ struct list_head rp_free_q; /* free bfa_rports */
+ struct list_head rp_active_q; /* free bfa_rports */
+ u16 num_rports; /* number of rports */
+};
+
+#define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod)
+
+/**
+ * Convert rport tag to RPORT
+ */
+#define BFA_RPORT_FROM_TAG(__bfa, _tag) \
+ (BFA_RPORT_MOD(__bfa)->rps_list + \
+ ((_tag) & (BFA_RPORT_MOD(__bfa)->num_rports - 1)))
+
+/*
+ * external functions
+ */
+void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+#endif /* __BFA_RPORT_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c
new file mode 100644
index 000000000000..279d8f9b8907
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_sgpg.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+
+BFA_TRC_FILE(HAL, SGPG);
+BFA_MODULE(sgpg);
+
+/**
+ * bfa_sgpg_mod BFA SGPG Mode module
+ */
+
+/**
+ * Compute and return memory needed by FCP(im) module.
+ */
+static void
+bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN)
+ cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
+
+ *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s);
+ *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s);
+}
+
+
+static void
+bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+ int i;
+ struct bfa_sgpg_s *hsgpg;
+ struct bfi_sgpg_s *sgpg;
+ u64 align_len;
+
+ union {
+ u64 pa;
+ union bfi_addr_u addr;
+ } sgpg_pa;
+
+ INIT_LIST_HEAD(&mod->sgpg_q);
+ INIT_LIST_HEAD(&mod->sgpg_wait_q);
+
+ bfa_trc(bfa, cfg->drvcfg.num_sgpgs);
+
+ mod->num_sgpgs = cfg->drvcfg.num_sgpgs;
+ mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo);
+ align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa);
+ mod->sgpg_arr_pa += align_len;
+ mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) +
+ align_len);
+ mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) +
+ align_len);
+
+ hsgpg = mod->hsgpg_arr;
+ sgpg = mod->sgpg_arr;
+ sgpg_pa.pa = mod->sgpg_arr_pa;
+ mod->free_sgpgs = mod->num_sgpgs;
+
+ bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
+
+ for (i = 0; i < mod->num_sgpgs; i++) {
+ bfa_os_memset(hsgpg, 0, sizeof(*hsgpg));
+ bfa_os_memset(sgpg, 0, sizeof(*sgpg));
+
+ hsgpg->sgpg = sgpg;
+ hsgpg->sgpg_pa = sgpg_pa.addr;
+ list_add_tail(&hsgpg->qe, &mod->sgpg_q);
+
+ hsgpg++;
+ sgpg++;
+ sgpg_pa.pa += sizeof(struct bfi_sgpg_s);
+ }
+
+ bfa_meminfo_kva(minfo) = (u8 *) hsgpg;
+ bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg;
+ bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa;
+}
+
+static void
+bfa_sgpg_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_iocdisable(struct bfa_s *bfa)
+{
+}
+
+
+
+/**
+ * bfa_sgpg_public BFA SGPG public functions
+ */
+
+bfa_status_t
+bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+ struct bfa_sgpg_s *hsgpg;
+ int i;
+
+ bfa_trc_fp(bfa, nsgpgs);
+
+ if (mod->free_sgpgs < nsgpgs)
+ return BFA_STATUS_ENOMEM;
+
+ for (i = 0; i < nsgpgs; i++) {
+ bfa_q_deq(&mod->sgpg_q, &hsgpg);
+ bfa_assert(hsgpg);
+ list_add_tail(&hsgpg->qe, sgpg_q);
+ }
+
+ mod->free_sgpgs -= nsgpgs;
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+ struct bfa_sgpg_wqe_s *wqe;
+
+ bfa_trc_fp(bfa, nsgpg);
+
+ mod->free_sgpgs += nsgpg;
+ bfa_assert(mod->free_sgpgs <= mod->num_sgpgs);
+
+ list_splice_tail_init(sgpg_q, &mod->sgpg_q);
+
+ if (list_empty(&mod->sgpg_wait_q))
+ return;
+
+ /**
+ * satisfy as many waiting requests as possible
+ */
+ do {
+ wqe = bfa_q_first(&mod->sgpg_wait_q);
+ if (mod->free_sgpgs < wqe->nsgpg)
+ nsgpg = mod->free_sgpgs;
+ else
+ nsgpg = wqe->nsgpg;
+ bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg);
+ wqe->nsgpg -= nsgpg;
+ if (wqe->nsgpg == 0) {
+ list_del(&wqe->qe);
+ wqe->cbfn(wqe->cbarg);
+ }
+ } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q));
+}
+
+void
+bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+
+ bfa_assert(nsgpg > 0);
+ bfa_assert(nsgpg > mod->free_sgpgs);
+
+ wqe->nsgpg_total = wqe->nsgpg = nsgpg;
+
+ /**
+ * allocate any left to this one first
+ */
+ if (mod->free_sgpgs) {
+ /**
+ * no one else is waiting for SGPG
+ */
+ bfa_assert(list_empty(&mod->sgpg_wait_q));
+ list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q);
+ wqe->nsgpg -= mod->free_sgpgs;
+ mod->free_sgpgs = 0;
+ }
+
+ list_add_tail(&wqe->qe, &mod->sgpg_wait_q);
+}
+
+void
+bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+
+ bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
+ list_del(&wqe->qe);
+
+ if (wqe->nsgpg_total != wqe->nsgpg)
+ bfa_sgpg_mfree(bfa, &wqe->sgpg_q,
+ wqe->nsgpg_total - wqe->nsgpg);
+}
+
+void
+bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
+ void *cbarg)
+{
+ INIT_LIST_HEAD(&wqe->sgpg_q);
+ wqe->cbfn = cbfn;
+ wqe->cbarg = cbarg;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_sgpg_priv.h b/drivers/scsi/bfa/bfa_sgpg_priv.h
new file mode 100644
index 000000000000..9c2a8cbe7522
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_sgpg_priv.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * hal_sgpg.h BFA SG page module
+ */
+
+#ifndef __BFA_SGPG_PRIV_H__
+#define __BFA_SGPG_PRIV_H__
+
+#include <cs/bfa_q.h>
+
+#define BFA_SGPG_MIN (16)
+
+/**
+ * Alignment macro for SG page allocation
+ */
+#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \
+ & ~(sizeof(struct bfi_sgpg_s) - 1))
+
+struct bfa_sgpg_wqe_s {
+ struct list_head qe; /* queue sg page element */
+ int nsgpg; /* pages to be allocated */
+ int nsgpg_total; /* total pages required */
+ void (*cbfn) (void *cbarg);
+ /* callback function */
+ void *cbarg; /* callback arg */
+ struct list_head sgpg_q; /* queue of alloced sgpgs */
+};
+
+struct bfa_sgpg_s {
+ struct list_head qe; /* queue sg page element */
+ struct bfi_sgpg_s *sgpg; /* va of SG page */
+ union bfi_addr_u sgpg_pa;/* pa of SG page */
+};
+
+/**
+ * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of
+ * SG pages required.
+ */
+#define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1)
+
+struct bfa_sgpg_mod_s {
+ struct bfa_s *bfa;
+ int num_sgpgs; /* number of SG pages */
+ int free_sgpgs; /* number of free SG pages */
+ struct bfa_sgpg_s *hsgpg_arr; /* BFA SG page array */
+ struct bfi_sgpg_s *sgpg_arr; /* actual SG page array */
+ u64 sgpg_arr_pa; /* SG page array DMA addr */
+ struct list_head sgpg_q; /* queue of free SG pages */
+ struct list_head sgpg_wait_q; /* wait queue for SG pages */
+};
+#define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod)
+
+bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q,
+ int nsgpgs);
+void bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q,
+ int nsgpgs);
+void bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe,
+ void (*cbfn) (void *cbarg), void *cbarg);
+void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe,
+ int nsgpgs);
+void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe);
+
+#endif /* __BFA_SGPG_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_sm.c b/drivers/scsi/bfa/bfa_sm.c
new file mode 100644
index 000000000000..5420f4f45e58
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_sm.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfasm.c BFA State machine utility functions
+ */
+
+#include <cs/bfa_sm.h>
+
+/**
+ * cs_sm_api
+ */
+
+int
+bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm)
+{
+ int i = 0;
+
+ while (smt[i].sm && smt[i].sm != sm)
+ i++;
+ return smt[i].state;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_timer.c b/drivers/scsi/bfa/bfa_timer.c
new file mode 100644
index 000000000000..cb76481f5cb1
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_timer.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa_timer.h>
+#include <cs/bfa_debug.h>
+
+void
+bfa_timer_init(struct bfa_timer_mod_s *mod)
+{
+ INIT_LIST_HEAD(&mod->timer_q);
+}
+
+void
+bfa_timer_beat(struct bfa_timer_mod_s *mod)
+{
+ struct list_head *qh = &mod->timer_q;
+ struct list_head *qe, *qe_next;
+ struct bfa_timer_s *elem;
+ struct list_head timedout_q;
+
+ INIT_LIST_HEAD(&timedout_q);
+
+ qe = bfa_q_next(qh);
+
+ while (qe != qh) {
+ qe_next = bfa_q_next(qe);
+
+ elem = (struct bfa_timer_s *) qe;
+ if (elem->timeout <= BFA_TIMER_FREQ) {
+ elem->timeout = 0;
+ list_del(&elem->qe);
+ list_add_tail(&elem->qe, &timedout_q);
+ } else {
+ elem->timeout -= BFA_TIMER_FREQ;
+ }
+
+ qe = qe_next; /* go to next elem */
+ }
+
+ /*
+ * Pop all the timeout entries
+ */
+ while (!list_empty(&timedout_q)) {
+ bfa_q_deq(&timedout_q, &elem);
+ elem->timercb(elem->arg);
+ }
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
+ void (*timercb) (void *), void *arg, unsigned int timeout)
+{
+
+ bfa_assert(timercb != NULL);
+ bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer));
+
+ timer->timeout = timeout;
+ timer->timercb = timercb;
+ timer->arg = arg;
+
+ list_add_tail(&timer->qe, &mod->timer_q);
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_stop(struct bfa_timer_s *timer)
+{
+ bfa_assert(!list_empty(&timer->qe));
+
+ list_del(&timer->qe);
+}
diff --git a/drivers/scsi/bfa/bfa_trcmod_priv.h b/drivers/scsi/bfa/bfa_trcmod_priv.h
new file mode 100644
index 000000000000..b3562dce7e9f
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_trcmod_priv.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * hal_trcmod.h BFA trace modules
+ */
+
+#ifndef __BFA_TRCMOD_PRIV_H__
+#define __BFA_TRCMOD_PRIV_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ BFA_TRC_HAL_IOC = 1,
+ BFA_TRC_HAL_INTR = 2,
+ BFA_TRC_HAL_FCXP = 3,
+ BFA_TRC_HAL_UF = 4,
+ BFA_TRC_HAL_DIAG = 5,
+ BFA_TRC_HAL_RPORT = 6,
+ BFA_TRC_HAL_FCPIM = 7,
+ BFA_TRC_HAL_IOIM = 8,
+ BFA_TRC_HAL_TSKIM = 9,
+ BFA_TRC_HAL_ITNIM = 10,
+ BFA_TRC_HAL_PPORT = 11,
+ BFA_TRC_HAL_SGPG = 12,
+ BFA_TRC_HAL_FLASH = 13,
+ BFA_TRC_HAL_DEBUG = 14,
+ BFA_TRC_HAL_WWN = 15,
+ BFA_TRC_HAL_FLASH_RAW = 16,
+ BFA_TRC_HAL_SBOOT = 17,
+ BFA_TRC_HAL_SBOOT_IO = 18,
+ BFA_TRC_HAL_SBOOT_INTR = 19,
+ BFA_TRC_HAL_SBTEST = 20,
+ BFA_TRC_HAL_IPFC = 21,
+ BFA_TRC_HAL_IOCFC = 22,
+ BFA_TRC_HAL_FCPTM = 23,
+ BFA_TRC_HAL_IOTM = 24,
+ BFA_TRC_HAL_TSKTM = 25,
+ BFA_TRC_HAL_TIN = 26,
+ BFA_TRC_HAL_LPS = 27,
+ BFA_TRC_HAL_FCDIAG = 28,
+ BFA_TRC_HAL_PBIND = 29,
+ BFA_TRC_HAL_IOCFC_CT = 30,
+ BFA_TRC_HAL_IOCFC_CB = 31,
+ BFA_TRC_HAL_IOCFC_Q = 32,
+};
+
+#endif /* __BFA_TRCMOD_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_tskim.c b/drivers/scsi/bfa/bfa_tskim.c
new file mode 100644
index 000000000000..010d40d1e5d3
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_tskim.c
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_cb_ioim_macros.h>
+
+BFA_TRC_FILE(HAL, TSKIM);
+
+/**
+ * task management completion handling
+ */
+#define bfa_tskim_qcomp(__tskim, __cbfn) do { \
+ bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, __cbfn, (__tskim)); \
+ bfa_tskim_notify_comp(__tskim); \
+} while (0)
+
+#define bfa_tskim_notify_comp(__tskim) do { \
+ if ((__tskim)->notify) \
+ bfa_itnim_tskdone((__tskim)->itnim); \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete);
+static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim,
+ lun_t lun);
+static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim);
+static void bfa_tskim_cleanp_comp(void *tskim_cbarg);
+static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim);
+static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim);
+static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim);
+static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim);
+
+/**
+ * bfa_tskim_sm
+ */
+
+enum bfa_tskim_event {
+ BFA_TSKIM_SM_START = 1, /* TM command start */
+ BFA_TSKIM_SM_DONE = 2, /* TM completion */
+ BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */
+ BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */
+ BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */
+ BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */
+ BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */
+ BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */
+};
+
+static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_active(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+
+/**
+ * Task management command beginning state.
+ */
+static void
+bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_START:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_active);
+ bfa_tskim_gather_ios(tskim);
+
+ /**
+ * If device is offline, do not send TM on wire. Just cleanup
+ * any pending IO requests and complete TM request.
+ */
+ if (!bfa_itnim_is_online(tskim->itnim)) {
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ tskim->tsk_status = BFI_TSKIM_STS_OK;
+ bfa_tskim_cleanup_ios(tskim);
+ return;
+ }
+
+ if (!bfa_tskim_send(tskim)) {
+ bfa_sm_set_state(tskim, bfa_tskim_sm_qfull);
+ bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq,
+ &tskim->reqq_wait);
+ }
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * brief
+ * TM command is active, awaiting completion from firmware to
+ * cleanup IO requests in TM scope.
+ */
+static void
+bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_DONE:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ bfa_tskim_cleanup_ios(tskim);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
+ if (!bfa_tskim_send_abort(tskim)) {
+ bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup_qfull);
+ bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq,
+ &tskim->reqq_wait);
+ }
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An active TM is being cleaned up since ITN is offline. Awaiting cleanup
+ * completion event from firmware.
+ */
+static void
+bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_DONE:
+ /**
+ * Ignore and wait for ABORT completion from firmware.
+ */
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP_DONE:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ bfa_tskim_cleanup_ios(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_IOS_DONE:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_done);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ /**
+ * Ignore, TM command completed on wire.
+ * Notify TM conmpletion on IO cleanup completion.
+ */
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Task management command is waiting for room in request CQ
+ */
+static void
+bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_QRESUME:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_active);
+ bfa_tskim_send(tskim);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ /**
+ * No need to send TM on wire since ITN is offline.
+ */
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ bfa_tskim_cleanup_ios(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Task management command is active, awaiting for room in request CQ
+ * to send clean up request.
+ */
+static void
+bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_DONE:
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ /**
+ *
+ * Fall through !!!
+ */
+
+ case BFA_TSKIM_SM_QRESUME:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
+ bfa_tskim_send_abort(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * BFA callback is pending
+ */
+static void
+bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_HCB:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_uninit);
+ bfa_tskim_free(tskim);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ bfa_tskim_notify_comp(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_tskim_private
+ */
+
+static void
+__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_tskim_s *tskim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB);
+ return;
+ }
+
+ bfa_stats(tskim->itnim, tm_success);
+ bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, tskim->tsk_status);
+}
+
+static void
+__bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_tskim_s *tskim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB);
+ return;
+ }
+
+ bfa_stats(tskim->itnim, tm_failures);
+ bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk,
+ BFI_TSKIM_STS_FAILED);
+}
+
+static bfa_boolean_t
+bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun)
+{
+ switch (tskim->tm_cmnd) {
+ case FCP_TM_TARGET_RESET:
+ return BFA_TRUE;
+
+ case FCP_TM_ABORT_TASK_SET:
+ case FCP_TM_CLEAR_TASK_SET:
+ case FCP_TM_LUN_RESET:
+ case FCP_TM_CLEAR_ACA:
+ return (tskim->lun == lun);
+
+ default:
+ bfa_assert(0);
+ }
+
+ return BFA_FALSE;
+}
+
+/**
+ * Gather affected IO requests and task management commands.
+ */
+static void
+bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
+{
+ struct bfa_itnim_s *itnim = tskim->itnim;
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ INIT_LIST_HEAD(&tskim->io_q);
+
+ /**
+ * Gather any active IO requests first.
+ */
+ list_for_each_safe(qe, qen, &itnim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ if (bfa_tskim_match_scope
+ (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &tskim->io_q);
+ }
+ }
+
+ /**
+ * Failback any pending IO requests immediately.
+ */
+ list_for_each_safe(qe, qen, &itnim->pending_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ if (bfa_tskim_match_scope
+ (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+ bfa_ioim_tov(ioim);
+ }
+ }
+}
+
+/**
+ * IO cleanup completion
+ */
+static void
+bfa_tskim_cleanp_comp(void *tskim_cbarg)
+{
+ struct bfa_tskim_s *tskim = tskim_cbarg;
+
+ bfa_stats(tskim->itnim, tm_io_comps);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE);
+}
+
+/**
+ * Gather affected IO requests and task management commands.
+ */
+static void
+bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim)
+{
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ bfa_wc_init(&tskim->wc, bfa_tskim_cleanp_comp, tskim);
+
+ list_for_each_safe(qe, qen, &tskim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_wc_up(&tskim->wc);
+ bfa_ioim_cleanup_tm(ioim, tskim);
+ }
+
+ bfa_wc_wait(&tskim->wc);
+}
+
+/**
+ * Send task management request to firmware.
+ */
+static bfa_boolean_t
+bfa_tskim_send(struct bfa_tskim_s *tskim)
+{
+ struct bfa_itnim_s *itnim = tskim->itnim;
+ struct bfi_tskim_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(tskim->bfa, itnim->reqq);
+ if (!m)
+ return BFA_FALSE;
+
+ /**
+ * build i/o request message next
+ */
+ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ,
+ bfa_lpuid(tskim->bfa));
+
+ m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
+ m->itn_fhdl = tskim->itnim->rport->fw_handle;
+ m->t_secs = tskim->tsecs;
+ m->lun = tskim->lun;
+ m->tm_flags = tskim->tm_cmnd;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(tskim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Send abort request to cleanup an active TM to firmware.
+ */
+static bfa_boolean_t
+bfa_tskim_send_abort(struct bfa_tskim_s *tskim)
+{
+ struct bfa_itnim_s *itnim = tskim->itnim;
+ struct bfi_tskim_abortreq_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(tskim->bfa, itnim->reqq);
+ if (!m)
+ return BFA_FALSE;
+
+ /**
+ * build i/o request message next
+ */
+ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ,
+ bfa_lpuid(tskim->bfa));
+
+ m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(tskim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Call to resume task management cmnd waiting for room in request queue.
+ */
+static void
+bfa_tskim_qresume(void *cbarg)
+{
+ struct bfa_tskim_s *tskim = cbarg;
+
+ bfa_fcpim_stats(tskim->fcpim, qresumes);
+ bfa_stats(tskim->itnim, tm_qresumes);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME);
+}
+
+/**
+ * Cleanup IOs associated with a task mangement command on IOC failures.
+ */
+static void
+bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim)
+{
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &tskim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_iocdisable(ioim);
+ }
+}
+
+
+
+/**
+ * bfa_tskim_friend
+ */
+
+/**
+ * Notification on completions from related ioim.
+ */
+void
+bfa_tskim_iodone(struct bfa_tskim_s *tskim)
+{
+ bfa_wc_down(&tskim->wc);
+}
+
+/**
+ * Handle IOC h/w failure notification from itnim.
+ */
+void
+bfa_tskim_iocdisable(struct bfa_tskim_s *tskim)
+{
+ tskim->notify = BFA_FALSE;
+ bfa_stats(tskim->itnim, tm_iocdowns);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL);
+}
+
+/**
+ * Cleanup TM command and associated IOs as part of ITNIM offline.
+ */
+void
+bfa_tskim_cleanup(struct bfa_tskim_s *tskim)
+{
+ tskim->notify = BFA_TRUE;
+ bfa_stats(tskim->itnim, tm_cleanups);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP);
+}
+
+/**
+ * Memory allocation and initialization.
+ */
+void
+bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
+{
+ struct bfa_tskim_s *tskim;
+ u16 i;
+
+ INIT_LIST_HEAD(&fcpim->tskim_free_q);
+
+ tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo);
+ fcpim->tskim_arr = tskim;
+
+ for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) {
+ /*
+ * initialize TSKIM
+ */
+ bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s));
+ tskim->tsk_tag = i;
+ tskim->bfa = fcpim->bfa;
+ tskim->fcpim = fcpim;
+ tskim->notify = BFA_FALSE;
+ bfa_reqq_winit(&tskim->reqq_wait, bfa_tskim_qresume,
+ tskim);
+ bfa_sm_set_state(tskim, bfa_tskim_sm_uninit);
+
+ list_add_tail(&tskim->qe, &fcpim->tskim_free_q);
+ }
+
+ bfa_meminfo_kva(minfo) = (u8 *) tskim;
+}
+
+void
+bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim)
+{
+ /**
+ * @todo
+ */
+}
+
+void
+bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m;
+ struct bfa_tskim_s *tskim;
+ u16 tsk_tag = bfa_os_ntohs(rsp->tsk_tag);
+
+ tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag);
+ bfa_assert(tskim->tsk_tag == tsk_tag);
+
+ tskim->tsk_status = rsp->tsk_status;
+
+ /**
+ * Firmware sends BFI_TSKIM_STS_ABORTED status for abort
+ * requests. All other statuses are for normal completions.
+ */
+ if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) {
+ bfa_stats(tskim->itnim, tm_cleanup_comps);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE);
+ } else {
+ bfa_stats(tskim->itnim, tm_fw_rsps);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE);
+ }
+}
+
+
+
+/**
+ * bfa_tskim_api
+ */
+
+
+struct bfa_tskim_s *
+bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_tskim_s *tskim;
+
+ bfa_q_deq(&fcpim->tskim_free_q, &tskim);
+
+ if (!tskim)
+ bfa_fcpim_stats(fcpim, no_tskims);
+ else
+ tskim->dtsk = dtsk;
+
+ return tskim;
+}
+
+void
+bfa_tskim_free(struct bfa_tskim_s *tskim)
+{
+ bfa_assert(bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe));
+ list_del(&tskim->qe);
+ list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q);
+}
+
+/**
+ * Start a task management command.
+ *
+ * @param[in] tskim BFA task management command instance
+ * @param[in] itnim i-t nexus for the task management command
+ * @param[in] lun lun, if applicable
+ * @param[in] tm_cmnd Task management command code.
+ * @param[in] t_secs Timeout in seconds
+ *
+ * @return None.
+ */
+void
+bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun,
+ enum fcp_tm_cmnd tm_cmnd, u8 tsecs)
+{
+ tskim->itnim = itnim;
+ tskim->lun = lun;
+ tskim->tm_cmnd = tm_cmnd;
+ tskim->tsecs = tsecs;
+ tskim->notify = BFA_FALSE;
+ bfa_stats(itnim, tm_cmnds);
+
+ list_add_tail(&tskim->qe, &itnim->tsk_q);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_START);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c
new file mode 100644
index 000000000000..ff5f9deb1b22
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_uf.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_uf.c BFA unsolicited frame receive implementation
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_uf.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, UF);
+BFA_MODULE(uf);
+
+/*
+ *****************************************************************************
+ * Internal functions
+ *****************************************************************************
+ */
+static void
+__bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_uf_s *uf = cbarg;
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa);
+
+ if (complete)
+ ufm->ufrecv(ufm->cbarg, uf);
+}
+
+static void
+claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ u32 uf_pb_tot_sz;
+
+ ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi);
+ ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi);
+ uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs),
+ BFA_DMA_ALIGN_SZ);
+
+ bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz;
+ bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz;
+
+ bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz);
+}
+
+static void
+claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ struct bfi_uf_buf_post_s *uf_bp_msg;
+ struct bfi_sge_s *sge;
+ union bfi_addr_u sga_zero = { {0} };
+ u16 i;
+ u16 buf_len;
+
+ ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi);
+ uf_bp_msg = ufm->uf_buf_posts;
+
+ for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs;
+ i++, uf_bp_msg++) {
+ bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s));
+
+ uf_bp_msg->buf_tag = i;
+ buf_len = sizeof(struct bfa_uf_buf_s);
+ uf_bp_msg->buf_len = bfa_os_htons(buf_len);
+ bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST,
+ bfa_lpuid(ufm->bfa));
+
+ sge = uf_bp_msg->sge;
+ sge[0].sg_len = buf_len;
+ sge[0].flags = BFI_SGE_DATA_LAST;
+ bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i));
+ bfa_sge_to_be(sge);
+
+ sge[1].sg_len = buf_len;
+ sge[1].flags = BFI_SGE_PGDLEN;
+ sge[1].sga = sga_zero;
+ bfa_sge_to_be(&sge[1]);
+ }
+
+ /**
+ * advance pointer beyond consumed memory
+ */
+ bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg;
+}
+
+static void
+claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ u16 i;
+ struct bfa_uf_s *uf;
+
+ /*
+ * Claim block of memory for UF list
+ */
+ ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi);
+
+ /*
+ * Initialize UFs and queue it in UF free queue
+ */
+ for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) {
+ bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s));
+ uf->bfa = ufm->bfa;
+ uf->uf_tag = i;
+ uf->pb_len = sizeof(struct bfa_uf_buf_s);
+ uf->buf_kva = (void *)&ufm->uf_pbs_kva[i];
+ uf->buf_pa = ufm_pbs_pa(ufm, i);
+ list_add_tail(&uf->qe, &ufm->uf_free_q);
+ }
+
+ /**
+ * advance memory pointer
+ */
+ bfa_meminfo_kva(mi) = (u8 *) uf;
+}
+
+static void
+uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ claim_uf_pbs(ufm, mi);
+ claim_ufs(ufm, mi);
+ claim_uf_post_msgs(ufm, mi);
+}
+
+static void
+bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len)
+{
+ u32 num_ufs = cfg->fwcfg.num_uf_bufs;
+
+ /*
+ * dma-able memory for UF posted bufs
+ */
+ *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs),
+ BFA_DMA_ALIGN_SZ);
+
+ /*
+ * kernel Virtual memory for UFs and UF buf post msg copies
+ */
+ *ndm_len += sizeof(struct bfa_uf_s) * num_ufs;
+ *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs;
+}
+
+static void
+bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+
+ bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s));
+ ufm->bfa = bfa;
+ ufm->num_ufs = cfg->fwcfg.num_uf_bufs;
+ INIT_LIST_HEAD(&ufm->uf_free_q);
+ INIT_LIST_HEAD(&ufm->uf_posted_q);
+
+ uf_mem_claim(ufm, meminfo);
+}
+
+static void
+bfa_uf_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_uf_detach(struct bfa_s *bfa)
+{
+}
+
+static struct bfa_uf_s *
+bfa_uf_get(struct bfa_uf_mod_s *uf_mod)
+{
+ struct bfa_uf_s *uf;
+
+ bfa_q_deq(&uf_mod->uf_free_q, &uf);
+ return (uf);
+}
+
+static void
+bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf)
+{
+ list_add_tail(&uf->qe, &uf_mod->uf_free_q);
+}
+
+static bfa_status_t
+bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf)
+{
+ struct bfi_uf_buf_post_s *uf_post_msg;
+
+ uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP);
+ if (!uf_post_msg)
+ return BFA_STATUS_FAILED;
+
+ bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag],
+ sizeof(struct bfi_uf_buf_post_s));
+ bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP);
+
+ bfa_trc(ufm->bfa, uf->uf_tag);
+
+ list_add_tail(&uf->qe, &ufm->uf_posted_q);
+ return BFA_STATUS_OK;
+}
+
+static void
+bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod)
+{
+ struct bfa_uf_s *uf;
+
+ while ((uf = bfa_uf_get(uf_mod)) != NULL) {
+ if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK)
+ break;
+ }
+}
+
+static void
+uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+ u16 uf_tag = m->buf_tag;
+ struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag];
+ struct bfa_uf_s *uf = &ufm->uf_list[uf_tag];
+ u8 *buf = &uf_buf->d[0];
+ struct fchs_s *fchs;
+
+ m->frm_len = bfa_os_ntohs(m->frm_len);
+ m->xfr_len = bfa_os_ntohs(m->xfr_len);
+
+ fchs = (struct fchs_s *) uf_buf;
+
+ list_del(&uf->qe); /* dequeue from posted queue */
+
+ uf->data_ptr = buf;
+ uf->data_len = m->xfr_len;
+
+ bfa_assert(uf->data_len >= sizeof(struct fchs_s));
+
+ if (uf->data_len == sizeof(struct fchs_s)) {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX,
+ uf->data_len, (struct fchs_s *) buf);
+ } else {
+ u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s)));
+ bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF,
+ BFA_PL_EID_RX, uf->data_len,
+ (struct fchs_s *) buf, pld_w0);
+ }
+
+ bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf);
+}
+
+static void
+bfa_uf_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_uf_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+ struct bfa_uf_s *uf;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &ufm->uf_posted_q) {
+ uf = (struct bfa_uf_s *) qe;
+ list_del(&uf->qe);
+ bfa_uf_put(ufm, uf);
+ }
+}
+
+static void
+bfa_uf_start(struct bfa_s *bfa)
+{
+ bfa_uf_post_all(BFA_UF_MOD(bfa));
+}
+
+
+
+/**
+ * bfa_uf_api
+ */
+
+/**
+ * Register handler for all unsolicted recieve frames.
+ *
+ * @param[in] bfa BFA instance
+ * @param[in] ufrecv receive handler function
+ * @param[in] cbarg receive handler arg
+ */
+void
+bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+
+ ufm->ufrecv = ufrecv;
+ ufm->cbarg = cbarg;
+}
+
+/**
+ * Free an unsolicited frame back to BFA.
+ *
+ * @param[in] uf unsolicited frame to be freed
+ *
+ * @return None
+ */
+void
+bfa_uf_free(struct bfa_uf_s *uf)
+{
+ bfa_uf_put(BFA_UF_MOD(uf->bfa), uf);
+ bfa_uf_post_all(BFA_UF_MOD(uf->bfa));
+}
+
+
+
+/**
+ * uf_pub BFA uf module public functions
+ */
+
+void
+bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
+{
+ bfa_trc(bfa, msg->mhdr.msg_id);
+
+ switch (msg->mhdr.msg_id) {
+ case BFI_UF_I2H_FRM_RCVD:
+ uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg);
+ break;
+
+ default:
+ bfa_trc(bfa, msg->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_uf_priv.h b/drivers/scsi/bfa/bfa_uf_priv.h
new file mode 100644
index 000000000000..bcb490f834f3
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_uf_priv.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_UF_PRIV_H__
+#define __BFA_UF_PRIV_H__
+
+#include <cs/bfa_sm.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_uf.h>
+
+#define BFA_UF_MIN (4)
+
+struct bfa_uf_mod_s {
+ struct bfa_s *bfa; /* back pointer to BFA */
+ struct bfa_uf_s *uf_list; /* array of UFs */
+ u16 num_ufs; /* num unsolicited rx frames */
+ struct list_head uf_free_q; /* free UFs */
+ struct list_head uf_posted_q; /* UFs posted to IOC */
+ struct bfa_uf_buf_s *uf_pbs_kva; /* list UF bufs request pld */
+ u64 uf_pbs_pa; /* phy addr for UF bufs */
+ struct bfi_uf_buf_post_s *uf_buf_posts;
+ /* pre-built UF post msgs */
+ bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */
+ void *cbarg; /* uf receive handler arg */
+};
+
+#define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod)
+
+#define ufm_pbs_pa(_ufmod, _uftag) \
+ ((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag))
+
+void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+
+#endif /* __BFA_UF_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
new file mode 100644
index 000000000000..6f2be5abf561
--- /dev/null
+++ b/drivers/scsi/bfa/bfad.c
@@ -0,0 +1,1182 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfad.c Linux driver PCI interface module.
+ */
+
+#include <linux/module.h>
+#include "bfad_drv.h"
+#include "bfad_im.h"
+#include "bfad_tm.h"
+#include "bfad_ipfc.h"
+#include "bfad_trcmod.h"
+#include <fcb/bfa_fcb_vf.h>
+#include <fcb/bfa_fcb_rport.h>
+#include <fcb/bfa_fcb_port.h>
+#include <fcb/bfa_fcb.h>
+
+BFA_TRC_FILE(LDRV, BFAD);
+static DEFINE_MUTEX(bfad_mutex);
+LIST_HEAD(bfad_list);
+static int bfad_inst;
+int bfad_supported_fc4s;
+
+static char *host_name;
+static char *os_name;
+static char *os_patch;
+static int num_rports;
+static int num_ios;
+static int num_tms;
+static int num_fcxps;
+static int num_ufbufs;
+static int reqq_size;
+static int rspq_size;
+static int num_sgpgs;
+static int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT;
+static int bfa_io_max_sge = BFAD_IO_MAX_SGE;
+static int log_level = BFA_LOG_WARNING;
+static int ioc_auto_recover = BFA_TRUE;
+static int ipfc_enable = BFA_FALSE;
+static int ipfc_mtu = -1;
+int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
+int bfa_linkup_delay = -1;
+
+module_param(os_name, charp, S_IRUGO | S_IWUSR);
+module_param(os_patch, charp, S_IRUGO | S_IWUSR);
+module_param(host_name, charp, S_IRUGO | S_IWUSR);
+module_param(num_rports, int, S_IRUGO | S_IWUSR);
+module_param(num_ios, int, S_IRUGO | S_IWUSR);
+module_param(num_tms, int, S_IRUGO | S_IWUSR);
+module_param(num_fcxps, int, S_IRUGO | S_IWUSR);
+module_param(num_ufbufs, int, S_IRUGO | S_IWUSR);
+module_param(reqq_size, int, S_IRUGO | S_IWUSR);
+module_param(rspq_size, int, S_IRUGO | S_IWUSR);
+module_param(num_sgpgs, int, S_IRUGO | S_IWUSR);
+module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR);
+module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR);
+module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
+module_param(log_level, int, S_IRUGO | S_IWUSR);
+module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
+module_param(ipfc_enable, int, S_IRUGO | S_IWUSR);
+module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR);
+module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR);
+
+/*
+ * Stores the module parm num_sgpgs value;
+ * used to reset for bfad next instance.
+ */
+static int num_sgpgs_parm;
+
+static bfa_status_t
+bfad_fc4_probe(struct bfad_s *bfad)
+{
+ int rc;
+
+ rc = bfad_im_probe(bfad);
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ bfad_tm_probe(bfad);
+
+ if (ipfc_enable)
+ bfad_ipfc_probe(bfad);
+ext:
+ return rc;
+}
+
+static void
+bfad_fc4_probe_undo(struct bfad_s *bfad)
+{
+ bfad_im_probe_undo(bfad);
+ bfad_tm_probe_undo(bfad);
+ if (ipfc_enable)
+ bfad_ipfc_probe_undo(bfad);
+}
+
+static void
+bfad_fc4_probe_post(struct bfad_s *bfad)
+{
+ if (bfad->im)
+ bfad_im_probe_post(bfad->im);
+
+ bfad_tm_probe_post(bfad);
+ if (ipfc_enable)
+ bfad_ipfc_probe_post(bfad);
+}
+
+static bfa_status_t
+bfad_fc4_port_new(struct bfad_s *bfad, struct bfad_port_s *port, int roles)
+{
+ int rc = BFA_STATUS_FAILED;
+
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ rc = bfad_im_port_new(bfad, port);
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ rc = bfad_tm_port_new(bfad, port);
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ rc = bfad_ipfc_port_new(bfad, port, port->pvb_type);
+ext:
+ return rc;
+}
+
+static void
+bfad_fc4_port_delete(struct bfad_s *bfad, struct bfad_port_s *port, int roles)
+{
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ bfad_im_port_delete(bfad, port);
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ bfad_tm_port_delete(bfad, port);
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ bfad_ipfc_port_delete(bfad, port);
+}
+
+/**
+ * BFA callbacks
+ */
+void
+bfad_hcb_comp(void *arg, bfa_status_t status)
+{
+ struct bfad_hal_comp *fcomp = (struct bfad_hal_comp *)arg;
+
+ fcomp->status = status;
+ complete(&fcomp->comp);
+}
+
+/**
+ * bfa_init callback
+ */
+void
+bfa_cb_init(void *drv, bfa_status_t init_status)
+{
+ struct bfad_s *bfad = drv;
+
+ if (init_status == BFA_STATUS_OK)
+ bfad->bfad_flags |= BFAD_HAL_INIT_DONE;
+
+ complete(&bfad->comp);
+}
+
+
+
+/**
+ * BFA_FCS callbacks
+ */
+static struct bfad_port_s *
+bfad_get_drv_port(struct bfad_s *bfad, struct bfad_vf_s *vf_drv,
+ struct bfad_vport_s *vp_drv)
+{
+ return ((vp_drv) ? (&(vp_drv)->drv_port)
+ : ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport)));
+}
+
+struct bfad_port_s *
+bfa_fcb_port_new(struct bfad_s *bfad, struct bfa_fcs_port_s *port,
+ enum bfa_port_role roles, struct bfad_vf_s *vf_drv,
+ struct bfad_vport_s *vp_drv)
+{
+ bfa_status_t rc;
+ struct bfad_port_s *port_drv;
+
+ if (!vp_drv && !vf_drv) {
+ port_drv = &bfad->pport;
+ port_drv->pvb_type = BFAD_PORT_PHYS_BASE;
+ } else if (!vp_drv && vf_drv) {
+ port_drv = &vf_drv->base_port;
+ port_drv->pvb_type = BFAD_PORT_VF_BASE;
+ } else if (vp_drv && !vf_drv) {
+ port_drv = &vp_drv->drv_port;
+ port_drv->pvb_type = BFAD_PORT_PHYS_VPORT;
+ } else {
+ port_drv = &vp_drv->drv_port;
+ port_drv->pvb_type = BFAD_PORT_VF_VPORT;
+ }
+
+ port_drv->fcs_port = port;
+ port_drv->roles = roles;
+ rc = bfad_fc4_port_new(bfad, port_drv, roles);
+ if (rc != BFA_STATUS_OK) {
+ bfad_fc4_port_delete(bfad, port_drv, roles);
+ port_drv = NULL;
+ }
+
+ return port_drv;
+}
+
+void
+bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
+{
+ struct bfad_port_s *port_drv;
+
+ /*
+ * this will be only called from rmmod context
+ */
+ if (vp_drv && !vp_drv->comp_del) {
+ port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv);
+ bfa_trc(bfad, roles);
+ bfad_fc4_port_delete(bfad, port_drv, roles);
+ }
+}
+
+void
+bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
+{
+ struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ bfad_im_port_online(bfad, port_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ bfad_tm_port_online(bfad, port_drv);
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ bfad_ipfc_port_online(bfad, port_drv);
+
+ bfad->bfad_flags |= BFAD_PORT_ONLINE;
+}
+
+void
+bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
+{
+ struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ bfad_im_port_offline(bfad, port_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ bfad_tm_port_offline(bfad, port_drv);
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ bfad_ipfc_port_offline(bfad, port_drv);
+}
+
+void
+bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv)
+{
+ if (vport_drv->comp_del) {
+ complete(vport_drv->comp_del);
+ return;
+ }
+
+ kfree(vport_drv);
+}
+
+/**
+ * FCS RPORT alloc callback, after successful PLOGI by FCS
+ */
+bfa_status_t
+bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport,
+ struct bfad_rport_s **rport_drv)
+{
+ bfa_status_t rc = BFA_STATUS_OK;
+
+ *rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC);
+ if (*rport_drv == NULL) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+
+ *rport = &(*rport_drv)->fcs_rport;
+
+ext:
+ return rc;
+}
+
+
+
+void
+bfad_hal_mem_release(struct bfad_s *bfad)
+{
+ int i;
+ struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo;
+ struct bfa_mem_elem_s *meminfo_elem;
+
+ for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
+ meminfo_elem = &hal_meminfo->meminfo[i];
+ if (meminfo_elem->kva != NULL) {
+ switch (meminfo_elem->mem_type) {
+ case BFA_MEM_TYPE_KVA:
+ vfree(meminfo_elem->kva);
+ break;
+ case BFA_MEM_TYPE_DMA:
+ dma_free_coherent(&bfad->pcidev->dev,
+ meminfo_elem->mem_len,
+ meminfo_elem->kva,
+ (dma_addr_t) meminfo_elem->dma);
+ break;
+ default:
+ bfa_assert(0);
+ break;
+ }
+ }
+ }
+
+ memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s));
+}
+
+void
+bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg)
+{
+ if (num_rports > 0)
+ bfa_cfg->fwcfg.num_rports = num_rports;
+ if (num_ios > 0)
+ bfa_cfg->fwcfg.num_ioim_reqs = num_ios;
+ if (num_tms > 0)
+ bfa_cfg->fwcfg.num_tskim_reqs = num_tms;
+ if (num_fcxps > 0)
+ bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps;
+ if (num_ufbufs > 0)
+ bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs;
+ if (reqq_size > 0)
+ bfa_cfg->drvcfg.num_reqq_elems = reqq_size;
+ if (rspq_size > 0)
+ bfa_cfg->drvcfg.num_rspq_elems = rspq_size;
+ if (num_sgpgs > 0)
+ bfa_cfg->drvcfg.num_sgpgs = num_sgpgs;
+
+ /*
+ * populate the hal values back to the driver for sysfs use.
+ * otherwise, the default values will be shown as 0 in sysfs
+ */
+ num_rports = bfa_cfg->fwcfg.num_rports;
+ num_ios = bfa_cfg->fwcfg.num_ioim_reqs;
+ num_tms = bfa_cfg->fwcfg.num_tskim_reqs;
+ num_fcxps = bfa_cfg->fwcfg.num_fcxp_reqs;
+ num_ufbufs = bfa_cfg->fwcfg.num_uf_bufs;
+ reqq_size = bfa_cfg->drvcfg.num_reqq_elems;
+ rspq_size = bfa_cfg->drvcfg.num_rspq_elems;
+ num_sgpgs = bfa_cfg->drvcfg.num_sgpgs;
+}
+
+bfa_status_t
+bfad_hal_mem_alloc(struct bfad_s *bfad)
+{
+ struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo;
+ struct bfa_mem_elem_s *meminfo_elem;
+ bfa_status_t rc = BFA_STATUS_OK;
+ dma_addr_t phys_addr;
+ int retry_count = 0;
+ int reset_value = 1;
+ int min_num_sgpgs = 512;
+ void *kva;
+ int i;
+
+ bfa_cfg_get_default(&bfad->ioc_cfg);
+
+retry:
+ bfad_update_hal_cfg(&bfad->ioc_cfg);
+ bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs;
+ bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo);
+
+ for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
+ meminfo_elem = &hal_meminfo->meminfo[i];
+ switch (meminfo_elem->mem_type) {
+ case BFA_MEM_TYPE_KVA:
+ kva = vmalloc(meminfo_elem->mem_len);
+ if (kva == NULL) {
+ bfad_hal_mem_release(bfad);
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+ memset(kva, 0, meminfo_elem->mem_len);
+ meminfo_elem->kva = kva;
+ break;
+ case BFA_MEM_TYPE_DMA:
+ kva = dma_alloc_coherent(&bfad->pcidev->dev,
+ meminfo_elem->mem_len,
+ &phys_addr, GFP_KERNEL);
+ if (kva == NULL) {
+ bfad_hal_mem_release(bfad);
+ /*
+ * If we cannot allocate with default
+ * num_sgpages try with half the value.
+ */
+ if (num_sgpgs > min_num_sgpgs) {
+ printk(KERN_INFO "bfad[%d]: memory"
+ " allocation failed with"
+ " num_sgpgs: %d\n",
+ bfad->inst_no, num_sgpgs);
+ nextLowerInt(&num_sgpgs);
+ printk(KERN_INFO "bfad[%d]: trying to"
+ " allocate memory with"
+ " num_sgpgs: %d\n",
+ bfad->inst_no, num_sgpgs);
+ retry_count++;
+ goto retry;
+ } else {
+ if (num_sgpgs_parm > 0)
+ num_sgpgs = num_sgpgs_parm;
+ else {
+ reset_value =
+ (1 << retry_count);
+ num_sgpgs *= reset_value;
+ }
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+ }
+
+ if (num_sgpgs_parm > 0)
+ num_sgpgs = num_sgpgs_parm;
+ else {
+ reset_value = (1 << retry_count);
+ num_sgpgs *= reset_value;
+ }
+
+ memset(kva, 0, meminfo_elem->mem_len);
+ meminfo_elem->kva = kva;
+ meminfo_elem->dma = phys_addr;
+ break;
+ default:
+ break;
+
+ }
+ }
+ext:
+ return rc;
+}
+
+/**
+ * Create a vport under a vf.
+ */
+bfa_status_t
+bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg)
+{
+ struct bfad_vport_s *vport;
+ int rc = BFA_STATUS_OK;
+ unsigned long flags;
+ struct completion fcomp;
+
+ vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL);
+ if (!vport) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+
+ vport->drv_port.bfad = bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id,
+ port_cfg, vport);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (rc != BFA_STATUS_OK)
+ goto ext_free_vport;
+
+ if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) {
+ rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port);
+ if (rc != BFA_STATUS_OK)
+ goto ext_free_fcs_vport;
+ }
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcs_vport_start(&vport->fcs_vport);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ return BFA_STATUS_OK;
+
+ext_free_fcs_vport:
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ vport->comp_del = &fcomp;
+ init_completion(vport->comp_del);
+ bfa_fcs_vport_delete(&vport->fcs_vport);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(vport->comp_del);
+ext_free_vport:
+ kfree(vport);
+ext:
+ return rc;
+}
+
+/**
+ * Create a vf and its base vport implicitely.
+ */
+bfa_status_t
+bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg)
+{
+ struct bfad_vf_s *vf;
+ int rc = BFA_STATUS_OK;
+
+ vf = kzalloc(sizeof(struct bfad_vf_s), GFP_KERNEL);
+ if (!vf) {
+ rc = BFA_STATUS_FAILED;
+ goto ext;
+ }
+
+ rc = bfa_fcs_vf_create(&vf->fcs_vf, &bfad->bfa_fcs, vf_id, port_cfg,
+ vf);
+ if (rc != BFA_STATUS_OK)
+ kfree(vf);
+ext:
+ return rc;
+}
+
+void
+bfad_bfa_tmo(unsigned long data)
+{
+ struct bfad_s *bfad = (struct bfad_s *)data;
+ unsigned long flags;
+ struct list_head doneq;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ bfa_timer_tick(&bfad->bfa);
+
+ bfa_comp_deq(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (!list_empty(&doneq)) {
+ bfa_comp_process(&bfad->bfa, &doneq);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_comp_free(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ }
+
+ mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ));
+}
+
+void
+bfad_init_timer(struct bfad_s *bfad)
+{
+ init_timer(&bfad->hal_tmo);
+ bfad->hal_tmo.function = bfad_bfa_tmo;
+ bfad->hal_tmo.data = (unsigned long)bfad;
+
+ mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ));
+}
+
+int
+bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
+{
+ unsigned long bar0_len;
+ int rc = -ENODEV;
+
+ if (pci_enable_device(pdev)) {
+ BFA_PRINTF(BFA_ERR, "pci_enable_device fail %p\n", pdev);
+ goto out;
+ }
+
+ if (pci_request_regions(pdev, BFAD_DRIVER_NAME))
+ goto out_disable_device;
+
+ pci_set_master(pdev);
+
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
+ BFA_PRINTF(BFA_ERR, "pci_set_dma_mask fail %p\n", pdev);
+ goto out_release_region;
+ }
+
+ bfad->pci_bar0_map = pci_resource_start(pdev, 0);
+ bar0_len = pci_resource_len(pdev, 0);
+ bfad->pci_bar0_kva = ioremap(bfad->pci_bar0_map, bar0_len);
+
+ if (bfad->pci_bar0_kva == NULL) {
+ BFA_PRINTF(BFA_ERR, "Fail to map bar0\n");
+ goto out_release_region;
+ }
+
+ bfad->hal_pcidev.pci_slot = PCI_SLOT(pdev->devfn);
+ bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn);
+ bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva;
+ bfad->hal_pcidev.device_id = pdev->device;
+ bfad->pci_name = pci_name(pdev);
+
+ bfad->pci_attr.vendor_id = pdev->vendor;
+ bfad->pci_attr.device_id = pdev->device;
+ bfad->pci_attr.ssid = pdev->subsystem_device;
+ bfad->pci_attr.ssvid = pdev->subsystem_vendor;
+ bfad->pci_attr.pcifn = PCI_FUNC(pdev->devfn);
+
+ bfad->pcidev = pdev;
+ return 0;
+
+out_release_region:
+ pci_release_regions(pdev);
+out_disable_device:
+ pci_disable_device(pdev);
+out:
+ return rc;
+}
+
+void
+bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
+{
+#if defined(__ia64__)
+ pci_iounmap(pdev, bfad->pci_bar0_kva);
+#else
+ iounmap(bfad->pci_bar0_kva);
+#endif
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+void
+bfad_fcs_port_cfg(struct bfad_s *bfad)
+{
+ struct bfa_port_cfg_s port_cfg;
+ struct bfa_pport_attr_s attr;
+ char symname[BFA_SYMNAME_MAXLEN];
+
+ sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no);
+ memcpy(port_cfg.sym_name.symname, symname, strlen(symname));
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+ port_cfg.nwwn = attr.nwwn;
+ port_cfg.pwwn = attr.pwwn;
+
+ bfa_fcs_cfg_base_port(&bfad->bfa_fcs, &port_cfg);
+}
+
+bfa_status_t
+bfad_drv_init(struct bfad_s *bfad)
+{
+ bfa_status_t rc;
+ unsigned long flags;
+ struct bfa_fcs_driver_info_s driver_info;
+ int i;
+
+ bfad->cfg_data.rport_del_timeout = rport_del_timeout;
+ bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth;
+ bfad->cfg_data.io_max_sge = bfa_io_max_sge;
+ bfad->cfg_data.binding_method = FCP_PWWN_BINDING;
+
+ rc = bfad_hal_mem_alloc(bfad);
+ if (rc != BFA_STATUS_OK) {
+ printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n",
+ bfad->inst_no);
+ printk(KERN_WARNING
+ "Not enough memory to attach all Brocade HBA ports,"
+ " System may need more memory.\n");
+ goto out_hal_mem_alloc_failure;
+ }
+
+ bfa_init_log(&bfad->bfa, bfad->logmod);
+ bfa_init_trc(&bfad->bfa, bfad->trcmod);
+ bfa_init_aen(&bfad->bfa, bfad->aen);
+ INIT_LIST_HEAD(&bfad->file_q);
+ INIT_LIST_HEAD(&bfad->file_free_q);
+ for (i = 0; i < BFAD_AEN_MAX_APPS; i++) {
+ bfa_q_qe_init(&bfad->file_buf[i].qe);
+ list_add_tail(&bfad->file_buf[i].qe, &bfad->file_free_q);
+ }
+ bfa_init_plog(&bfad->bfa, &bfad->plog_buf);
+ bfa_plog_init(&bfad->plog_buf);
+ bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START,
+ 0, "Driver Attach");
+
+ bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, &bfad->meminfo,
+ &bfad->hal_pcidev);
+
+ init_completion(&bfad->comp);
+
+ /*
+ * Enable Interrupt and wait bfa_init completion
+ */
+ if (bfad_setup_intr(bfad)) {
+ printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n",
+ bfad->inst_no);
+ goto out_setup_intr_failure;
+ }
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_init(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ /*
+ * Set up interrupt handler for each vectors
+ */
+ if ((bfad->bfad_flags & BFAD_MSIX_ON)
+ && bfad_install_msix_handler(bfad)) {
+ printk(KERN_WARNING "%s: install_msix failed, bfad%d\n",
+ __FUNCTION__, bfad->inst_no);
+ }
+
+ bfad_init_timer(bfad);
+
+ wait_for_completion(&bfad->comp);
+
+ memset(&driver_info, 0, sizeof(driver_info));
+ strncpy(driver_info.version, BFAD_DRIVER_VERSION,
+ sizeof(driver_info.version) - 1);
+ if (host_name)
+ strncpy(driver_info.host_machine_name, host_name,
+ sizeof(driver_info.host_machine_name) - 1);
+ if (os_name)
+ strncpy(driver_info.host_os_name, os_name,
+ sizeof(driver_info.host_os_name) - 1);
+ if (os_patch)
+ strncpy(driver_info.host_os_patch, os_patch,
+ sizeof(driver_info.host_os_patch) - 1);
+
+ strncpy(driver_info.os_device_name, bfad->pci_name,
+ sizeof(driver_info.os_device_name - 1));
+
+ /*
+ * FCS INIT
+ */
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcs_log_init(&bfad->bfa_fcs, bfad->logmod);
+ bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod);
+ bfa_fcs_aen_init(&bfad->bfa_fcs, bfad->aen);
+ bfa_fcs_init(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE);
+ bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ bfad->bfad_flags |= BFAD_DRV_INIT_DONE;
+ return BFA_STATUS_OK;
+
+out_setup_intr_failure:
+ bfa_detach(&bfad->bfa);
+ bfad_hal_mem_release(bfad);
+out_hal_mem_alloc_failure:
+ return BFA_STATUS_FAILED;
+}
+
+void
+bfad_drv_uninit(struct bfad_s *bfad)
+{
+ del_timer_sync(&bfad->hal_tmo);
+ bfa_isr_disable(&bfad->bfa);
+ bfa_detach(&bfad->bfa);
+ bfad_remove_intr(bfad);
+ bfa_assert(list_empty(&bfad->file_q));
+ bfad_hal_mem_release(bfad);
+}
+
+void
+bfad_drv_start(struct bfad_s *bfad)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_start(&bfad->bfa);
+ bfa_fcs_start(&bfad->bfa_fcs);
+ bfad->bfad_flags |= BFAD_HAL_START_DONE;
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ bfad_fc4_probe_post(bfad);
+}
+
+void
+bfad_drv_stop(struct bfad_s *bfad)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ init_completion(&bfad->comp);
+ bfad->pport.flags |= BFAD_PORT_DELETE;
+ bfa_fcs_exit(&bfad->bfa_fcs);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(&bfad->comp);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ init_completion(&bfad->comp);
+ bfa_stop(&bfad->bfa);
+ bfad->bfad_flags &= ~BFAD_HAL_START_DONE;
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(&bfad->comp);
+}
+
+bfa_status_t
+bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role)
+{
+ int rc = BFA_STATUS_OK;
+
+ /*
+ * Allocate scsi_host for the physical port
+ */
+ if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM)
+ && (role & BFA_PORT_ROLE_FCP_IM)) {
+ if (bfad->pport.im_port == NULL) {
+ rc = BFA_STATUS_FAILED;
+ goto out;
+ }
+
+ rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port);
+ if (rc != BFA_STATUS_OK)
+ goto out;
+
+ bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM;
+ }
+
+ bfad->bfad_flags |= BFAD_CFG_PPORT_DONE;
+
+out:
+ return rc;
+}
+
+void
+bfad_uncfg_pport(struct bfad_s *bfad)
+{
+ if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) {
+ bfad_ipfc_port_delete(bfad, &bfad->pport);
+ bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC;
+ }
+
+ if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM)
+ && (bfad->pport.roles & BFA_PORT_ROLE_FCP_IM)) {
+ bfad_im_scsi_host_free(bfad, bfad->pport.im_port);
+ bfad_im_port_clean(bfad->pport.im_port);
+ kfree(bfad->pport.im_port);
+ bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IM;
+ }
+
+ bfad->bfad_flags &= ~BFAD_CFG_PPORT_DONE;
+}
+
+void
+bfad_drv_log_level_set(struct bfad_s *bfad)
+{
+ if (log_level > BFA_LOG_INVALID && log_level <= BFA_LOG_LEVEL_MAX)
+ bfa_log_set_level_all(&bfad->log_data, log_level);
+}
+
+ /*
+ * PCI_entry PCI driver entries * {
+ */
+
+/**
+ * PCI probe entry.
+ */
+int
+bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+ struct bfad_s *bfad;
+ int error = -ENODEV, retval;
+ char buf[16];
+
+ /*
+ * For single port cards - only claim function 0
+ */
+ if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P)
+ && (PCI_FUNC(pdev->devfn) != 0))
+ return -ENODEV;
+
+ BFA_TRACE(BFA_INFO, "bfad_pci_probe entry");
+
+ bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL);
+ if (!bfad) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ bfad->trcmod = kzalloc(sizeof(struct bfa_trc_mod_s), GFP_KERNEL);
+ if (!bfad->trcmod) {
+ printk(KERN_WARNING "Error alloc trace buffer!\n");
+ error = -ENOMEM;
+ goto out_alloc_trace_failure;
+ }
+
+ /*
+ * LOG/TRACE INIT
+ */
+ bfa_trc_init(bfad->trcmod);
+ bfa_trc(bfad, bfad_inst);
+
+ bfad->logmod = &bfad->log_data;
+ sprintf(buf, "%d", bfad_inst);
+ bfa_log_init(bfad->logmod, buf, bfa_os_printf);
+
+ bfad_drv_log_level_set(bfad);
+
+ bfad->aen = &bfad->aen_buf;
+
+ if (!(bfad_load_fwimg(pdev))) {
+ printk(KERN_WARNING "bfad_load_fwimg failure!\n");
+ kfree(bfad->trcmod);
+ goto out_alloc_trace_failure;
+ }
+
+ retval = bfad_pci_init(pdev, bfad);
+ if (retval) {
+ printk(KERN_WARNING "bfad_pci_init failure!\n");
+ error = retval;
+ goto out_pci_init_failure;
+ }
+
+ mutex_lock(&bfad_mutex);
+ bfad->inst_no = bfad_inst++;
+ list_add_tail(&bfad->list_entry, &bfad_list);
+ mutex_unlock(&bfad_mutex);
+
+ spin_lock_init(&bfad->bfad_lock);
+ pci_set_drvdata(pdev, bfad);
+
+ bfad->ref_count = 0;
+ bfad->pport.bfad = bfad;
+
+ retval = bfad_drv_init(bfad);
+ if (retval != BFA_STATUS_OK)
+ goto out_drv_init_failure;
+ if (!(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
+ printk(KERN_WARNING "bfad%d: hal init failed\n", bfad->inst_no);
+ goto ok;
+ }
+
+ /*
+ * PPORT FCS config
+ */
+ bfad_fcs_port_cfg(bfad);
+
+ retval = bfad_cfg_pport(bfad, BFA_PORT_ROLE_FCP_IM);
+ if (retval != BFA_STATUS_OK)
+ goto out_cfg_pport_failure;
+
+ /*
+ * BFAD level FC4 (IM/TM/IPFC) specific resource allocation
+ */
+ retval = bfad_fc4_probe(bfad);
+ if (retval != BFA_STATUS_OK) {
+ printk(KERN_WARNING "bfad_fc4_probe failed\n");
+ goto out_fc4_probe_failure;
+ }
+
+ bfad_drv_start(bfad);
+
+ /*
+ * If bfa_linkup_delay is set to -1 default; try to retrive the
+ * value using the bfad_os_get_linkup_delay(); else use the
+ * passed in module param value as the bfa_linkup_delay.
+ */
+ if (bfa_linkup_delay < 0) {
+ bfa_linkup_delay = bfad_os_get_linkup_delay(bfad);
+ bfad_os_rport_online_wait(bfad);
+ bfa_linkup_delay = -1;
+ } else {
+ bfad_os_rport_online_wait(bfad);
+ }
+
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_DEVICE_CLAIMED, bfad->pci_name);
+ok:
+ return 0;
+
+out_fc4_probe_failure:
+ bfad_fc4_probe_undo(bfad);
+ bfad_uncfg_pport(bfad);
+out_cfg_pport_failure:
+ bfad_drv_uninit(bfad);
+out_drv_init_failure:
+ mutex_lock(&bfad_mutex);
+ bfad_inst--;
+ list_del(&bfad->list_entry);
+ mutex_unlock(&bfad_mutex);
+ bfad_pci_uninit(pdev, bfad);
+out_pci_init_failure:
+ kfree(bfad->trcmod);
+out_alloc_trace_failure:
+ kfree(bfad);
+out:
+ return error;
+}
+
+/**
+ * PCI remove entry.
+ */
+void
+bfad_pci_remove(struct pci_dev *pdev)
+{
+ struct bfad_s *bfad = pci_get_drvdata(pdev);
+ unsigned long flags;
+
+ bfa_trc(bfad, bfad->inst_no);
+
+ if ((bfad->bfad_flags & BFAD_DRV_INIT_DONE)
+ && !(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ init_completion(&bfad->comp);
+ bfa_stop(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(&bfad->comp);
+
+ bfad_remove_intr(bfad);
+ del_timer_sync(&bfad->hal_tmo);
+ goto hal_detach;
+ } else if (!(bfad->bfad_flags & BFAD_DRV_INIT_DONE)) {
+ goto remove_sysfs;
+ }
+
+ if (bfad->bfad_flags & BFAD_HAL_START_DONE)
+ bfad_drv_stop(bfad);
+
+ bfad_remove_intr(bfad);
+
+ del_timer_sync(&bfad->hal_tmo);
+ bfad_fc4_probe_undo(bfad);
+
+ if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE)
+ bfad_uncfg_pport(bfad);
+
+hal_detach:
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_detach(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ bfad_hal_mem_release(bfad);
+remove_sysfs:
+
+ mutex_lock(&bfad_mutex);
+ bfad_inst--;
+ list_del(&bfad->list_entry);
+ mutex_unlock(&bfad_mutex);
+ bfad_pci_uninit(pdev, bfad);
+
+ kfree(bfad->trcmod);
+ kfree(bfad);
+}
+
+
+static struct pci_device_id bfad_id_table[] = {
+ {
+ .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+ .device = BFA_PCI_DEVICE_ID_FC_8G2P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+ .device = BFA_PCI_DEVICE_ID_FC_8G1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+ .device = BFA_PCI_DEVICE_ID_CT,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_SERIAL_FIBER << 8),
+ .class_mask = ~0,
+ },
+
+ {0, 0},
+};
+
+MODULE_DEVICE_TABLE(pci, bfad_id_table);
+
+static struct pci_driver bfad_pci_driver = {
+ .name = BFAD_DRIVER_NAME,
+ .id_table = bfad_id_table,
+ .probe = bfad_pci_probe,
+ .remove = __devexit_p(bfad_pci_remove),
+};
+
+/**
+ * Linux driver module functions
+ */
+bfa_status_t
+bfad_fc4_module_init(void)
+{
+ int rc;
+
+ rc = bfad_im_module_init();
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ bfad_tm_module_init();
+ if (ipfc_enable)
+ bfad_ipfc_module_init();
+ext:
+ return rc;
+}
+
+void
+bfad_fc4_module_exit(void)
+{
+ if (ipfc_enable)
+ bfad_ipfc_module_exit();
+ bfad_tm_module_exit();
+ bfad_im_module_exit();
+}
+
+/**
+ * Driver module init.
+ */
+static int __init
+bfad_init(void)
+{
+ int error = 0;
+
+ printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n",
+ BFAD_DRIVER_VERSION);
+
+ if (num_sgpgs > 0)
+ num_sgpgs_parm = num_sgpgs;
+
+ error = bfad_fc4_module_init();
+ if (error) {
+ error = -ENOMEM;
+ printk(KERN_WARNING "bfad_fc4_module_init failure\n");
+ goto ext;
+ }
+
+ if (!strcmp(FCPI_NAME, " fcpim"))
+ bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IM;
+ if (!strcmp(FCPT_NAME, " fcptm"))
+ bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_TM;
+ if (!strcmp(IPFC_NAME, " ipfc"))
+ bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IPFC;
+
+ bfa_ioc_auto_recover(ioc_auto_recover);
+ bfa_fcs_rport_set_del_timeout(rport_del_timeout);
+ error = pci_register_driver(&bfad_pci_driver);
+
+ if (error) {
+ printk(KERN_WARNING "bfad pci_register_driver failure\n");
+ goto ext;
+ }
+
+ return 0;
+
+ext:
+ bfad_fc4_module_exit();
+ return error;
+}
+
+/**
+ * Driver module exit.
+ */
+static void __exit
+bfad_exit(void)
+{
+ pci_unregister_driver(&bfad_pci_driver);
+ bfad_fc4_module_exit();
+ bfad_free_fwimg();
+}
+
+#define BFAD_PROTO_NAME FCPI_NAME FCPT_NAME IPFC_NAME
+
+module_init(bfad_init);
+module_exit(bfad_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME);
+MODULE_AUTHOR("Brocade Communications Systems, Inc.");
+MODULE_VERSION(BFAD_DRIVER_VERSION);
+
+
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
new file mode 100644
index 000000000000..9129ae3040ff
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_attr.c Linux driver configuration interface module.
+ */
+
+#include "bfad_drv.h"
+#include "bfad_im.h"
+#include "bfad_trcmod.h"
+#include "bfad_attr.h"
+
+/**
+ * FC_transport_template FC transport template
+ */
+
+/**
+ * FC transport template entry, get SCSI target port ID.
+ */
+void
+bfad_im_get_starget_port_id(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost;
+ struct bfad_im_port_s *im_port;
+ struct bfad_s *bfad;
+ struct bfad_itnim_s *itnim = NULL;
+ u32 fc_id = -1;
+ unsigned long flags;
+
+ shost = bfad_os_starget_to_shost(starget);
+ im_port = (struct bfad_im_port_s *) shost->hostdata[0];
+ bfad = im_port->bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ itnim = bfad_os_get_itnim(im_port, starget->id);
+ if (itnim)
+ fc_id = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
+
+ fc_starget_port_id(starget) = fc_id;
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, get SCSI target nwwn.
+ */
+void
+bfad_im_get_starget_node_name(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost;
+ struct bfad_im_port_s *im_port;
+ struct bfad_s *bfad;
+ struct bfad_itnim_s *itnim = NULL;
+ u64 node_name = 0;
+ unsigned long flags;
+
+ shost = bfad_os_starget_to_shost(starget);
+ im_port = (struct bfad_im_port_s *) shost->hostdata[0];
+ bfad = im_port->bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ itnim = bfad_os_get_itnim(im_port, starget->id);
+ if (itnim)
+ node_name = bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim);
+
+ fc_starget_node_name(starget) = bfa_os_htonll(node_name);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, get SCSI target pwwn.
+ */
+void
+bfad_im_get_starget_port_name(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost;
+ struct bfad_im_port_s *im_port;
+ struct bfad_s *bfad;
+ struct bfad_itnim_s *itnim = NULL;
+ u64 port_name = 0;
+ unsigned long flags;
+
+ shost = bfad_os_starget_to_shost(starget);
+ im_port = (struct bfad_im_port_s *) shost->hostdata[0];
+ bfad = im_port->bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ itnim = bfad_os_get_itnim(im_port, starget->id);
+ if (itnim)
+ port_name = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
+
+ fc_starget_port_name(starget) = bfa_os_htonll(port_name);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, get SCSI host port ID.
+ */
+void
+bfad_im_get_host_port_id(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+
+ fc_host_port_id(shost) =
+ bfa_os_hton3b(bfa_fcs_port_get_fcid(port->fcs_port));
+}
+
+
+
+
+
+struct Scsi_Host *
+bfad_os_starget_to_shost(struct scsi_target *starget)
+{
+ return dev_to_shost(starget->dev.parent);
+}
+
+/**
+ * FC transport template entry, get SCSI host port type.
+ */
+static void
+bfad_im_get_host_port_type(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_pport_attr_s attr;
+
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+
+ switch (attr.port_type) {
+ case BFA_PPORT_TYPE_NPORT:
+ fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+ break;
+ case BFA_PPORT_TYPE_NLPORT:
+ fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+ break;
+ case BFA_PPORT_TYPE_P2P:
+ fc_host_port_type(shost) = FC_PORTTYPE_PTP;
+ break;
+ case BFA_PPORT_TYPE_LPORT:
+ fc_host_port_type(shost) = FC_PORTTYPE_LPORT;
+ break;
+ default:
+ fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
+ break;
+ }
+}
+
+/**
+ * FC transport template entry, get SCSI host port state.
+ */
+static void
+bfad_im_get_host_port_state(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_pport_attr_s attr;
+
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+
+ switch (attr.port_state) {
+ case BFA_PPORT_ST_LINKDOWN:
+ fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
+ break;
+ case BFA_PPORT_ST_LINKUP:
+ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+ break;
+ case BFA_PPORT_ST_UNINIT:
+ case BFA_PPORT_ST_ENABLING_QWAIT:
+ case BFA_PPORT_ST_ENABLING:
+ case BFA_PPORT_ST_DISABLING_QWAIT:
+ case BFA_PPORT_ST_DISABLING:
+ case BFA_PPORT_ST_DISABLED:
+ case BFA_PPORT_ST_STOPPED:
+ case BFA_PPORT_ST_IOCDOWN:
+ default:
+ fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+ break;
+ }
+}
+
+/**
+ * FC transport template entry, get SCSI host active fc4s.
+ */
+static void
+bfad_im_get_host_active_fc4s(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+
+ memset(fc_host_active_fc4s(shost), 0,
+ sizeof(fc_host_active_fc4s(shost)));
+
+ if (port->supported_fc4s &
+ (BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM))
+ fc_host_active_fc4s(shost)[2] = 1;
+
+ if (port->supported_fc4s & BFA_PORT_ROLE_FCP_IPFC)
+ fc_host_active_fc4s(shost)[3] = 0x20;
+
+ fc_host_active_fc4s(shost)[7] = 1;
+}
+
+/**
+ * FC transport template entry, get SCSI host link speed.
+ */
+static void
+bfad_im_get_host_speed(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_pport_attr_s attr;
+
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+ switch (attr.speed) {
+ case BFA_PPORT_SPEED_8GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+ break;
+ case BFA_PPORT_SPEED_4GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
+ break;
+ case BFA_PPORT_SPEED_2GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
+ break;
+ case BFA_PPORT_SPEED_1GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
+ break;
+ default:
+ fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+ break;
+ }
+}
+
+/**
+ * FC transport template entry, get SCSI host port type.
+ */
+static void
+bfad_im_get_host_fabric_name(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+ wwn_t fabric_nwwn = 0;
+
+ fabric_nwwn = bfa_fcs_port_get_fabric_name(port->fcs_port);
+
+ fc_host_fabric_name(shost) = bfa_os_htonll(fabric_nwwn);
+
+}
+
+/**
+ * FC transport template entry, get BFAD statistics.
+ */
+static struct fc_host_statistics *
+bfad_im_get_stats(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_hal_comp fcomp;
+ struct fc_host_statistics *hstats;
+ bfa_status_t rc;
+ unsigned long flags;
+
+ hstats = &bfad->link_stats;
+ init_completion(&fcomp.comp);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ memset(hstats, 0, sizeof(struct fc_host_statistics));
+ rc = bfa_pport_get_stats(&bfad->bfa,
+ (union bfa_pport_stats_u *) hstats,
+ bfad_hcb_comp, &fcomp);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ if (rc != BFA_STATUS_OK)
+ return NULL;
+
+ wait_for_completion(&fcomp.comp);
+
+ return hstats;
+}
+
+/**
+ * FC transport template entry, reset BFAD statistics.
+ */
+static void
+bfad_im_reset_stats(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_hal_comp fcomp;
+ unsigned long flags;
+ bfa_status_t rc;
+
+ init_completion(&fcomp.comp);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_pport_clear_stats(&bfad->bfa, bfad_hcb_comp, &fcomp);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (rc != BFA_STATUS_OK)
+ return;
+
+ wait_for_completion(&fcomp.comp);
+
+ return;
+}
+
+/**
+ * FC transport template entry, get rport loss timeout.
+ */
+static void
+bfad_im_get_rport_loss_tmo(struct fc_rport *rport)
+{
+ struct bfad_itnim_data_s *itnim_data = rport->dd_data;
+ struct bfad_itnim_s *itnim = itnim_data->itnim;
+ struct bfad_s *bfad = itnim->im->bfad;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, set rport loss timeout.
+ */
+static void
+bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
+{
+ struct bfad_itnim_data_s *itnim_data = rport->dd_data;
+ struct bfad_itnim_s *itnim = itnim_data->itnim;
+ struct bfad_s *bfad = itnim->im->bfad;
+ unsigned long flags;
+
+ if (timeout > 0) {
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcpim_path_tov_set(&bfad->bfa, timeout);
+ rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ }
+
+}
+
+struct fc_function_template bfad_im_fc_function_template = {
+
+ /* Target dynamic attributes */
+ .get_starget_port_id = bfad_im_get_starget_port_id,
+ .show_starget_port_id = 1,
+ .get_starget_node_name = bfad_im_get_starget_node_name,
+ .show_starget_node_name = 1,
+ .get_starget_port_name = bfad_im_get_starget_port_name,
+ .show_starget_port_name = 1,
+
+ /* Host dynamic attribute */
+ .get_host_port_id = bfad_im_get_host_port_id,
+ .show_host_port_id = 1,
+
+ /* Host fixed attributes */
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+
+ /* More host dynamic attributes */
+ .show_host_port_type = 1,
+ .get_host_port_type = bfad_im_get_host_port_type,
+ .show_host_port_state = 1,
+ .get_host_port_state = bfad_im_get_host_port_state,
+ .show_host_active_fc4s = 1,
+ .get_host_active_fc4s = bfad_im_get_host_active_fc4s,
+ .show_host_speed = 1,
+ .get_host_speed = bfad_im_get_host_speed,
+ .show_host_fabric_name = 1,
+ .get_host_fabric_name = bfad_im_get_host_fabric_name,
+
+ .show_host_symbolic_name = 1,
+
+ /* Statistics */
+ .get_fc_host_stats = bfad_im_get_stats,
+ .reset_fc_host_stats = bfad_im_reset_stats,
+
+ /* Allocation length for host specific data */
+ .dd_fcrport_size = sizeof(struct bfad_itnim_data_s *),
+
+ /* Remote port fixed attributes */
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+ .show_rport_dev_loss_tmo = 1,
+ .get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
+ .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
+};
+
+/**
+ * Scsi_Host_attrs SCSI host attributes
+ */
+static ssize_t
+bfad_im_serial_num_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ioc_attr.adapter_attr.serial_num);
+}
+
+static ssize_t
+bfad_im_model_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.model);
+}
+
+static ssize_t
+bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ioc_attr.adapter_attr.model_descr);
+}
+
+static ssize_t
+bfad_im_node_name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+ u64 nwwn;
+
+ nwwn = bfa_fcs_port_get_nwwn(port->fcs_port);
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n", bfa_os_htonll(nwwn));
+}
+
+static ssize_t
+bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+
+ return snprintf(buf, PAGE_SIZE, "Brocade %s FV%s DV%s\n",
+ ioc_attr.adapter_attr.model,
+ ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION);
+}
+
+static ssize_t
+bfad_im_hw_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.hw_ver);
+}
+
+static ssize_t
+bfad_im_drv_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_VERSION);
+}
+
+static ssize_t
+bfad_im_optionrom_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ioc_attr.adapter_attr.optrom_ver);
+}
+
+static ssize_t
+bfad_im_fw_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.fw_ver);
+}
+
+static ssize_t
+bfad_im_num_of_ports_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc_attr.adapter_attr.nports);
+}
+
+static ssize_t
+bfad_im_drv_name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_NAME);
+}
+
+static ssize_t
+bfad_im_num_of_discovered_ports_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+ struct bfad_s *bfad = im_port->bfad;
+ int nrports = 2048;
+ wwn_t *rports = NULL;
+ unsigned long flags;
+
+ rports = kzalloc(sizeof(wwn_t) * nrports , GFP_ATOMIC);
+ if (rports == NULL)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcs_port_get_rports(port->fcs_port, rports, &nrports);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ kfree(rports);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", nrports);
+}
+
+static DEVICE_ATTR(serial_number, S_IRUGO,
+ bfad_im_serial_num_show, NULL);
+static DEVICE_ATTR(model, S_IRUGO, bfad_im_model_show, NULL);
+static DEVICE_ATTR(model_description, S_IRUGO,
+ bfad_im_model_desc_show, NULL);
+static DEVICE_ATTR(node_name, S_IRUGO, bfad_im_node_name_show, NULL);
+static DEVICE_ATTR(symbolic_name, S_IRUGO,
+ bfad_im_symbolic_name_show, NULL);
+static DEVICE_ATTR(hardware_version, S_IRUGO,
+ bfad_im_hw_version_show, NULL);
+static DEVICE_ATTR(driver_version, S_IRUGO,
+ bfad_im_drv_version_show, NULL);
+static DEVICE_ATTR(option_rom_version, S_IRUGO,
+ bfad_im_optionrom_version_show, NULL);
+static DEVICE_ATTR(firmware_version, S_IRUGO,
+ bfad_im_fw_version_show, NULL);
+static DEVICE_ATTR(number_of_ports, S_IRUGO,
+ bfad_im_num_of_ports_show, NULL);
+static DEVICE_ATTR(driver_name, S_IRUGO, bfad_im_drv_name_show, NULL);
+static DEVICE_ATTR(number_of_discovered_ports, S_IRUGO,
+ bfad_im_num_of_discovered_ports_show, NULL);
+
+struct device_attribute *bfad_im_host_attrs[] = {
+ &dev_attr_serial_number,
+ &dev_attr_model,
+ &dev_attr_model_description,
+ &dev_attr_node_name,
+ &dev_attr_symbolic_name,
+ &dev_attr_hardware_version,
+ &dev_attr_driver_version,
+ &dev_attr_option_rom_version,
+ &dev_attr_firmware_version,
+ &dev_attr_number_of_ports,
+ &dev_attr_driver_name,
+ &dev_attr_number_of_discovered_ports,
+ NULL,
+};
+
+struct device_attribute *bfad_im_vport_attrs[] = {
+ &dev_attr_serial_number,
+ &dev_attr_model,
+ &dev_attr_model_description,
+ &dev_attr_node_name,
+ &dev_attr_symbolic_name,
+ &dev_attr_hardware_version,
+ &dev_attr_driver_version,
+ &dev_attr_option_rom_version,
+ &dev_attr_firmware_version,
+ &dev_attr_number_of_ports,
+ &dev_attr_driver_name,
+ &dev_attr_number_of_discovered_ports,
+ NULL,
+};
+
+
diff --git a/drivers/scsi/bfa/bfad_attr.h b/drivers/scsi/bfa/bfad_attr.h
new file mode 100644
index 000000000000..4d3312da6a81
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_attr.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFAD_ATTR_H__
+#define __BFAD_ATTR_H__
+/**
+ * bfad_attr.h VMware driver configuration interface module.
+ */
+
+/**
+ * FC_transport_template FC transport template
+ */
+
+struct Scsi_Host*
+bfad_os_dev_to_shost(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI target port ID.
+ */
+void
+bfad_im_get_starget_port_id(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI target nwwn.
+ */
+void
+bfad_im_get_starget_node_name(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI target pwwn.
+ */
+void
+bfad_im_get_starget_port_name(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI host port ID.
+ */
+void
+bfad_im_get_host_port_id(struct Scsi_Host *shost);
+
+/**
+ * FC transport template entry, issue a LIP.
+ */
+int
+bfad_im_issue_fc_host_lip(struct Scsi_Host *shost);
+
+struct Scsi_Host*
+bfad_os_starget_to_shost(struct scsi_target *starget);
+
+
+#endif /* __BFAD_ATTR_H__ */
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
new file mode 100644
index 000000000000..172c81e25c1c
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * Contains base driver definitions.
+ */
+
+/**
+ * bfa_drv.h Linux driver data structures.
+ */
+
+#ifndef __BFAD_DRV_H__
+#define __BFAD_DRV_H__
+
+#include "bfa_os_inc.h"
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs.h>
+#include <defs/bfa_defs_pci.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_rport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <defs/bfa_defs_vport.h>
+#include <fcs/bfa_fcs_vport.h>
+
+#include <cs/bfa_plog.h>
+#include "aen/bfa_aen.h"
+#include <log/bfa_log_linux.h>
+
+#define BFAD_DRIVER_NAME "bfa"
+#ifdef BFA_DRIVER_VERSION
+#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
+#else
+#define BFAD_DRIVER_VERSION "2.0.0.0"
+#endif
+
+
+#define BFAD_IRQ_FLAGS IRQF_SHARED
+
+/*
+ * BFAD flags
+ */
+#define BFAD_MSIX_ON 0x00000001
+#define BFAD_HAL_INIT_DONE 0x00000002
+#define BFAD_DRV_INIT_DONE 0x00000004
+#define BFAD_CFG_PPORT_DONE 0x00000008
+#define BFAD_HAL_START_DONE 0x00000010
+#define BFAD_PORT_ONLINE 0x00000020
+#define BFAD_RPORT_ONLINE 0x00000040
+
+#define BFAD_PORT_DELETE 0x00000001
+
+/*
+ * BFAD related definition
+ */
+#define SCSI_SCAN_DELAY HZ
+#define BFAD_STOP_TIMEOUT 30
+#define BFAD_SUSPEND_TIMEOUT BFAD_STOP_TIMEOUT
+
+/*
+ * BFAD configuration parameter default values
+ */
+#define BFAD_LUN_QUEUE_DEPTH 32
+#define BFAD_IO_MAX_SGE SG_ALL
+
+#define bfad_isr_t irq_handler_t
+
+#define MAX_MSIX_ENTRY 22
+
+struct bfad_msix_s {
+ struct bfad_s *bfad;
+ struct msix_entry msix;
+};
+
+enum bfad_port_pvb_type {
+ BFAD_PORT_PHYS_BASE = 0,
+ BFAD_PORT_PHYS_VPORT = 1,
+ BFAD_PORT_VF_BASE = 2,
+ BFAD_PORT_VF_VPORT = 3,
+};
+
+/*
+ * PORT data structure
+ */
+struct bfad_port_s {
+ struct list_head list_entry;
+ struct bfad_s *bfad;
+ struct bfa_fcs_port_s *fcs_port;
+ u32 roles;
+ s32 flags;
+ u32 supported_fc4s;
+ u8 ipfc_flags;
+ enum bfad_port_pvb_type pvb_type;
+ struct bfad_im_port_s *im_port; /* IM specific data */
+ struct bfad_tm_port_s *tm_port; /* TM specific data */
+ struct bfad_ipfc_port_s *ipfc_port; /* IPFC specific data */
+};
+
+/*
+ * VPORT data structure
+ */
+struct bfad_vport_s {
+ struct bfad_port_s drv_port;
+ struct bfa_fcs_vport_s fcs_vport;
+ struct completion *comp_del;
+};
+
+/*
+ * VF data structure
+ */
+struct bfad_vf_s {
+ bfa_fcs_vf_t fcs_vf;
+ struct bfad_port_s base_port; /* base port for vf */
+ struct bfad_s *bfad;
+};
+
+struct bfad_cfg_param_s {
+ u32 rport_del_timeout;
+ u32 ioc_queue_depth;
+ u32 lun_queue_depth;
+ u32 io_max_sge;
+ u32 binding_method;
+};
+
+#define BFAD_AEN_MAX_APPS 8
+struct bfad_aen_file_s {
+ struct list_head qe;
+ struct bfad_s *bfad;
+ s32 ri;
+ s32 app_id;
+};
+
+/*
+ * BFAD (PCI function) data structure
+ */
+struct bfad_s {
+ struct list_head list_entry;
+ struct bfa_s bfa;
+ struct bfa_fcs_s bfa_fcs;
+ struct pci_dev *pcidev;
+ const char *pci_name;
+ struct bfa_pcidev_s hal_pcidev;
+ struct bfa_ioc_pci_attr_s pci_attr;
+ unsigned long pci_bar0_map;
+ void __iomem *pci_bar0_kva;
+ struct completion comp;
+ struct completion suspend;
+ struct completion disable_comp;
+ bfa_boolean_t disable_active;
+ struct bfad_port_s pport; /* physical port of the BFAD */
+ struct bfa_meminfo_s meminfo;
+ struct bfa_iocfc_cfg_s ioc_cfg;
+ u32 inst_no; /* BFAD instance number */
+ u32 bfad_flags;
+ spinlock_t bfad_lock;
+ struct bfad_cfg_param_s cfg_data;
+ struct bfad_msix_s msix_tab[MAX_MSIX_ENTRY];
+ int nvec;
+ char adapter_name[BFA_ADAPTER_SYM_NAME_LEN];
+ char port_name[BFA_ADAPTER_SYM_NAME_LEN];
+ struct timer_list hal_tmo;
+ unsigned long hs_start;
+ struct bfad_im_s *im; /* IM specific data */
+ struct bfad_tm_s *tm; /* TM specific data */
+ struct bfad_ipfc_s *ipfc; /* IPFC specific data */
+ struct bfa_log_mod_s log_data;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_log_mod_s *logmod;
+ struct bfa_aen_s *aen;
+ struct bfa_aen_s aen_buf;
+ struct bfad_aen_file_s file_buf[BFAD_AEN_MAX_APPS];
+ struct list_head file_q;
+ struct list_head file_free_q;
+ struct bfa_plog_s plog_buf;
+ int ref_count;
+ bfa_boolean_t ipfc_enabled;
+ struct fc_host_statistics link_stats;
+
+ struct kobject *bfa_kobj;
+ struct kobject *ioc_kobj;
+ struct kobject *pport_kobj;
+ struct kobject *lport_kobj;
+};
+
+/*
+ * RPORT data structure
+ */
+struct bfad_rport_s {
+ struct bfa_fcs_rport_s fcs_rport;
+};
+
+struct bfad_buf_info {
+ void *virt;
+ dma_addr_t phys;
+ u32 size;
+};
+
+struct bfad_fcxp {
+ struct bfad_port_s *port;
+ struct bfa_rport_s *bfa_rport;
+ bfa_status_t req_status;
+ u16 tag;
+ u16 rsp_len;
+ u16 rsp_maxlen;
+ u8 use_ireqbuf;
+ u8 use_irspbuf;
+ u32 num_req_sgles;
+ u32 num_rsp_sgles;
+ struct fchs_s fchs;
+ void *reqbuf_info;
+ void *rspbuf_info;
+ struct bfa_sge_s *req_sge;
+ struct bfa_sge_s *rsp_sge;
+ fcxp_send_cb_t send_cbfn;
+ void *send_cbarg;
+ void *bfa_fcxp;
+ struct completion comp;
+};
+
+struct bfad_hal_comp {
+ bfa_status_t status;
+ struct completion comp;
+};
+
+/*
+ * Macro to obtain the immediate lower power
+ * of two for the integer.
+ */
+#define nextLowerInt(x) \
+do { \
+ int j; \
+ (*x)--; \
+ for (j = 1; j < (sizeof(int) * 8); j <<= 1) \
+ (*x) = (*x) | (*x) >> j; \
+ (*x)++; \
+ (*x) = (*x) >> 1; \
+} while (0)
+
+
+bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg);
+bfa_status_t bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg);
+bfa_status_t bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role);
+bfa_status_t bfad_drv_init(struct bfad_s *bfad);
+void bfad_drv_start(struct bfad_s *bfad);
+void bfad_uncfg_pport(struct bfad_s *bfad);
+void bfad_drv_stop(struct bfad_s *bfad);
+void bfad_remove_intr(struct bfad_s *bfad);
+void bfad_hal_mem_release(struct bfad_s *bfad);
+void bfad_hcb_comp(void *arg, bfa_status_t status);
+
+int bfad_setup_intr(struct bfad_s *bfad);
+void bfad_remove_intr(struct bfad_s *bfad);
+
+void bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg);
+bfa_status_t bfad_hal_mem_alloc(struct bfad_s *bfad);
+void bfad_bfa_tmo(unsigned long data);
+void bfad_init_timer(struct bfad_s *bfad);
+int bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad);
+void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad);
+void bfad_fcs_port_cfg(struct bfad_s *bfad);
+void bfad_drv_uninit(struct bfad_s *bfad);
+void bfad_drv_log_level_set(struct bfad_s *bfad);
+bfa_status_t bfad_fc4_module_init(void);
+void bfad_fc4_module_exit(void);
+
+void bfad_pci_remove(struct pci_dev *pdev);
+int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid);
+void bfad_os_rport_online_wait(struct bfad_s *bfad);
+int bfad_os_get_linkup_delay(struct bfad_s *bfad);
+int bfad_install_msix_handler(struct bfad_s *bfad);
+
+extern struct idr bfad_im_port_index;
+extern struct list_head bfad_list;
+extern int bfa_lun_queue_depth;
+extern int bfad_supported_fc4s;
+extern int bfa_linkup_delay;
+
+#endif /* __BFAD_DRV_H__ */
diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c
new file mode 100644
index 000000000000..bd34b0db2d6b
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_fwimg.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfad_fwimg.c Linux driver PCI interface module.
+ */
+#include <bfa_os_inc.h>
+#include <bfad_drv.h>
+#include <bfad_im_compat.h>
+#include <defs/bfa_defs_version.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/fcntl.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <bfa_fwimg_priv.h>
+#include <bfa.h>
+
+u32 bfi_image_ct_size;
+u32 bfi_image_cb_size;
+u32 *bfi_image_ct;
+u32 *bfi_image_cb;
+
+
+#define BFAD_FW_FILE_CT "ctfw.bin"
+#define BFAD_FW_FILE_CB "cbfw.bin"
+MODULE_FIRMWARE(BFAD_FW_FILE_CT);
+MODULE_FIRMWARE(BFAD_FW_FILE_CB);
+
+u32 *
+bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+ u32 *bfi_image_size, char *fw_name)
+{
+ const struct firmware *fw;
+
+ if (request_firmware(&fw, fw_name, &pdev->dev)) {
+ printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
+ goto error;
+ }
+
+ *bfi_image = vmalloc(fw->size);
+ if (NULL == *bfi_image) {
+ printk(KERN_ALERT "Fail to allocate buffer for fw image "
+ "size=%x!\n", (u32) fw->size);
+ goto error;
+ }
+
+ memcpy(*bfi_image, fw->data, fw->size);
+ *bfi_image_size = fw->size/sizeof(u32);
+
+ return(*bfi_image);
+
+error:
+ return(NULL);
+}
+
+u32 *
+bfad_get_firmware_buf(struct pci_dev *pdev)
+{
+ if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
+ if (bfi_image_ct_size == 0)
+ bfad_read_firmware(pdev, &bfi_image_ct,
+ &bfi_image_ct_size, BFAD_FW_FILE_CT);
+ return(bfi_image_ct);
+ } else {
+ if (bfi_image_cb_size == 0)
+ bfad_read_firmware(pdev, &bfi_image_cb,
+ &bfi_image_cb_size, BFAD_FW_FILE_CB);
+ return(bfi_image_cb);
+ }
+}
+
+u32 *
+bfi_image_ct_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct + off); }
+
+u32 *
+bfi_image_cb_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_cb + off); }
+
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
new file mode 100644
index 000000000000..55d012a9a668
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfad_im.c Linux driver IM module.
+ */
+
+#include "bfad_drv.h"
+#include "bfad_im.h"
+#include "bfad_trcmod.h"
+#include "bfa_cb_ioim_macros.h"
+#include <fcb/bfa_fcb_fcpim.h>
+
+BFA_TRC_FILE(LDRV, IM);
+
+DEFINE_IDR(bfad_im_port_index);
+struct scsi_transport_template *bfad_im_scsi_transport_template;
+static void bfad_im_itnim_work_handler(struct work_struct *work);
+static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
+ void (*done)(struct scsi_cmnd *));
+static int bfad_im_slave_alloc(struct scsi_device *sdev);
+
+void
+bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
+ enum bfi_ioim_status io_status, u8 scsi_status,
+ int sns_len, u8 *sns_info, s32 residue)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct bfad_s *bfad = drv;
+ struct bfad_itnim_data_s *itnim_data;
+ struct bfad_itnim_s *itnim;
+
+ switch (io_status) {
+ case BFI_IOIM_STS_OK:
+ bfa_trc(bfad, scsi_status);
+ cmnd->result = ScsiResult(DID_OK, scsi_status);
+ scsi_set_resid(cmnd, 0);
+
+ if (sns_len > 0) {
+ bfa_trc(bfad, sns_len);
+ if (sns_len > SCSI_SENSE_BUFFERSIZE)
+ sns_len = SCSI_SENSE_BUFFERSIZE;
+ memcpy(cmnd->sense_buffer, sns_info, sns_len);
+ }
+ if (residue > 0)
+ scsi_set_resid(cmnd, residue);
+ break;
+
+ case BFI_IOIM_STS_ABORTED:
+ case BFI_IOIM_STS_TIMEDOUT:
+ case BFI_IOIM_STS_PATHTOV:
+ default:
+ cmnd->result = ScsiResult(DID_ERROR, 0);
+ }
+
+ /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
+ if (cmnd->device->host != NULL)
+ scsi_dma_unmap(cmnd);
+
+ cmnd->host_scribble = NULL;
+ bfa_trc(bfad, cmnd->result);
+
+ itnim_data = cmnd->device->hostdata;
+ if (itnim_data) {
+ itnim = itnim_data->itnim;
+ if (!cmnd->result && itnim &&
+ (bfa_lun_queue_depth > cmnd->device->queue_depth)) {
+ /* Queue depth adjustment for good status completion */
+ bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ } else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) {
+ /* qfull handling */
+ bfad_os_handle_qfull(itnim, cmnd->device);
+ }
+ }
+
+ cmnd->scsi_done(cmnd);
+}
+
+void
+bfa_cb_ioim_good_comp(void *drv, struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct bfad_itnim_data_s *itnim_data;
+ struct bfad_itnim_s *itnim;
+
+ cmnd->result = ScsiResult(DID_OK, SCSI_STATUS_GOOD);
+
+ /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
+ if (cmnd->device->host != NULL)
+ scsi_dma_unmap(cmnd);
+
+ cmnd->host_scribble = NULL;
+
+ /* Queue depth adjustment */
+ if (bfa_lun_queue_depth > cmnd->device->queue_depth) {
+ itnim_data = cmnd->device->hostdata;
+ if (itnim_data) {
+ itnim = itnim_data->itnim;
+ if (itnim)
+ bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ }
+ }
+
+ cmnd->scsi_done(cmnd);
+}
+
+void
+bfa_cb_ioim_abort(void *drv, struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct bfad_s *bfad = drv;
+
+ cmnd->result = ScsiResult(DID_ERROR, 0);
+
+ /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
+ if (cmnd->device->host != NULL)
+ scsi_dma_unmap(cmnd);
+
+ bfa_trc(bfad, cmnd->result);
+ cmnd->host_scribble = NULL;
+}
+
+void
+bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
+ enum bfi_tskim_status tsk_status)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dtsk;
+ wait_queue_head_t *wq;
+
+ cmnd->SCp.Status |= tsk_status << 1;
+ set_bit(IO_DONE_BIT, (unsigned long *)&cmnd->SCp.Status);
+ wq = (wait_queue_head_t *) cmnd->SCp.ptr;
+ cmnd->SCp.ptr = NULL;
+
+ if (wq)
+ wake_up(wq);
+}
+
+void
+bfa_cb_ioim_resfree(void *drv)
+{
+}
+
+/**
+ * Scsi_Host_template SCSI host template
+ */
+/**
+ * Scsi_Host template entry, returns BFAD PCI info.
+ */
+static const char *
+bfad_im_info(struct Scsi_Host *shost)
+{
+ static char bfa_buf[256];
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfa_ioc_attr_s ioc_attr;
+ struct bfad_s *bfad = im_port->bfad;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+
+ memset(bfa_buf, 0, sizeof(bfa_buf));
+ snprintf(bfa_buf, sizeof(bfa_buf),
+ "Brocade FC/FCOE Adapter, " "model: %s hwpath: %s driver: %s",
+ ioc_attr.adapter_attr.model, bfad->pci_name,
+ BFAD_DRIVER_VERSION);
+ return bfa_buf;
+}
+
+/**
+ * Scsi_Host template entry, aborts the specified SCSI command.
+ *
+ * Returns: SUCCESS or FAILED.
+ */
+static int
+bfad_im_abort_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioim_s *hal_io;
+ unsigned long flags;
+ u32 timeout;
+ int rc = FAILED;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ hal_io = (struct bfa_ioim_s *) cmnd->host_scribble;
+ if (!hal_io) {
+ /* IO has been completed, retrun success */
+ rc = SUCCESS;
+ goto out;
+ }
+ if (hal_io->dio != (struct bfad_ioim_s *) cmnd) {
+ rc = FAILED;
+ goto out;
+ }
+
+ bfa_trc(bfad, hal_io->iotag);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT,
+ im_port->shost->host_no, cmnd, hal_io->iotag);
+ bfa_ioim_abort(hal_io);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ /* Need to wait until the command get aborted */
+ timeout = 10;
+ while ((struct bfa_ioim_s *) cmnd->host_scribble == hal_io) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(timeout);
+ if (timeout < 4 * HZ)
+ timeout *= 2;
+ }
+
+ cmnd->scsi_done(cmnd);
+ bfa_trc(bfad, hal_io->iotag);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT_COMP,
+ im_port->shost->host_no, cmnd, hal_io->iotag);
+ return SUCCESS;
+out:
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ return rc;
+}
+
+static bfa_status_t
+bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
+ struct bfad_itnim_s *itnim)
+{
+ struct bfa_tskim_s *tskim;
+ struct bfa_itnim_s *bfa_itnim;
+ bfa_status_t rc = BFA_STATUS_OK;
+
+ bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
+ if (!tskim) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR,
+ "target reset, fail to allocate tskim\n");
+ rc = BFA_STATUS_FAILED;
+ goto out;
+ }
+
+ /*
+ * Set host_scribble to NULL to avoid aborting a task command if
+ * happens.
+ */
+ cmnd->host_scribble = NULL;
+ cmnd->SCp.Status = 0;
+ bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ bfa_tskim_start(tskim, bfa_itnim, (lun_t)0,
+ FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
+out:
+ return rc;
+}
+
+/**
+ * Scsi_Host template entry, resets a LUN and abort its all commands.
+ *
+ * Returns: SUCCESS or FAILED.
+ *
+ */
+static int
+bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata;
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_tskim_s *tskim;
+ struct bfad_itnim_s *itnim;
+ struct bfa_itnim_s *bfa_itnim;
+ DECLARE_WAIT_QUEUE_HEAD(wq);
+ int rc = SUCCESS;
+ unsigned long flags;
+ enum bfi_tskim_status task_status;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ itnim = itnim_data->itnim;
+ if (!itnim) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ rc = FAILED;
+ goto out;
+ }
+
+ tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
+ if (!tskim) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR,
+ "LUN reset, fail to allocate tskim");
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ rc = FAILED;
+ goto out;
+ }
+
+ /**
+ * Set host_scribble to NULL to avoid aborting a task command
+ * if happens.
+ */
+ cmnd->host_scribble = NULL;
+ cmnd->SCp.ptr = (char *)&wq;
+ cmnd->SCp.Status = 0;
+ bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ bfa_tskim_start(tskim, bfa_itnim,
+ bfad_int_to_lun(cmnd->device->lun),
+ FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ wait_event(wq, test_bit(IO_DONE_BIT,
+ (unsigned long *)&cmnd->SCp.Status));
+
+ task_status = cmnd->SCp.Status >> 1;
+ if (task_status != BFI_TSKIM_STS_OK) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR, "LUN reset failure, status: %d\n",
+ task_status);
+ rc = FAILED;
+ }
+
+out:
+ return rc;
+}
+
+/**
+ * Scsi_Host template entry, resets the bus and abort all commands.
+ */
+static int
+bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_itnim_s *itnim;
+ unsigned long flags;
+ u32 i, rc, err_cnt = 0;
+ DECLARE_WAIT_QUEUE_HEAD(wq);
+ enum bfi_tskim_status task_status;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ for (i = 0; i < MAX_FCP_TARGET; i++) {
+ itnim = bfad_os_get_itnim(im_port, i);
+ if (itnim) {
+ cmnd->SCp.ptr = (char *)&wq;
+ rc = bfad_im_target_reset_send(bfad, cmnd, itnim);
+ if (rc != BFA_STATUS_OK) {
+ err_cnt++;
+ continue;
+ }
+
+ /* wait target reset to complete */
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_event(wq, test_bit(IO_DONE_BIT,
+ (unsigned long *)&cmnd->SCp.Status));
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ task_status = cmnd->SCp.Status >> 1;
+ if (task_status != BFI_TSKIM_STS_OK) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR,
+ "target reset failure,"
+ " status: %d\n", task_status);
+ err_cnt++;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (err_cnt)
+ return FAILED;
+
+ return SUCCESS;
+}
+
+/**
+ * Scsi_Host template entry slave_destroy.
+ */
+static void
+bfad_im_slave_destroy(struct scsi_device *sdev)
+{
+ sdev->hostdata = NULL;
+ return;
+}
+
+/**
+ * BFA FCS itnim callbacks
+ */
+
+/**
+ * BFA FCS itnim alloc callback, after successful PRLI
+ * Context: Interrupt
+ */
+void
+bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
+ struct bfad_itnim_s **itnim_drv)
+{
+ *itnim_drv = kzalloc(sizeof(struct bfad_itnim_s), GFP_ATOMIC);
+ if (*itnim_drv == NULL)
+ return;
+
+ (*itnim_drv)->im = bfad->im;
+ *itnim = &(*itnim_drv)->fcs_itnim;
+ (*itnim_drv)->state = ITNIM_STATE_NONE;
+
+ /*
+ * Initiaze the itnim_work
+ */
+ INIT_WORK(&(*itnim_drv)->itnim_work, bfad_im_itnim_work_handler);
+ bfad->bfad_flags |= BFAD_RPORT_ONLINE;
+}
+
+/**
+ * BFA FCS itnim free callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void
+bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_port_s *port;
+ wwn_t wwpn;
+ u32 fcid;
+ char wwpn_str[32], fcid_str[16];
+
+ /* online to free state transtion should not happen */
+ bfa_assert(itnim_drv->state != ITNIM_STATE_ONLINE);
+
+ itnim_drv->queue_work = 1;
+ /* offline request is not yet done, use the same request to free */
+ if (itnim_drv->state == ITNIM_STATE_OFFLINE_PENDING)
+ itnim_drv->queue_work = 0;
+
+ itnim_drv->state = ITNIM_STATE_FREE;
+ port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
+ itnim_drv->im_port = port->im_port;
+ wwpn = bfa_fcs_itnim_get_pwwn(&itnim_drv->fcs_itnim);
+ fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim);
+ wwn2str(wwpn_str, wwpn);
+ fcid2str(fcid_str, fcid);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_FREE,
+ port->im_port->shost->host_no,
+ fcid_str, wwpn_str);
+ bfad_os_itnim_process(itnim_drv);
+}
+
+/**
+ * BFA FCS itnim online callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void
+bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_port_s *port;
+
+ itnim_drv->bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim_drv->fcs_itnim);
+ port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
+ itnim_drv->state = ITNIM_STATE_ONLINE;
+ itnim_drv->queue_work = 1;
+ itnim_drv->im_port = port->im_port;
+ bfad_os_itnim_process(itnim_drv);
+}
+
+/**
+ * BFA FCS itnim offline callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void
+bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_port_s *port;
+ struct bfad_s *bfad;
+
+ port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
+ bfad = port->bfad;
+ if ((bfad->pport.flags & BFAD_PORT_DELETE) ||
+ (port->flags & BFAD_PORT_DELETE)) {
+ itnim_drv->state = ITNIM_STATE_OFFLINE;
+ return;
+ }
+ itnim_drv->im_port = port->im_port;
+ itnim_drv->state = ITNIM_STATE_OFFLINE_PENDING;
+ itnim_drv->queue_work = 1;
+ bfad_os_itnim_process(itnim_drv);
+}
+
+/**
+ * BFA FCS itnim timeout callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim)
+{
+ itnim->state = ITNIM_STATE_TIMEOUT;
+}
+
+/**
+ * Path TOV processing begin notification -- dummy for linux
+ */
+void
+bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim)
+{
+}
+
+
+
+/**
+ * Allocate a Scsi_Host for a port.
+ */
+int
+bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+{
+ int error = 1;
+
+ if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) {
+ printk(KERN_WARNING "idr_pre_get failure\n");
+ goto out;
+ }
+
+ error = idr_get_new(&bfad_im_port_index, im_port,
+ &im_port->idr_id);
+ if (error) {
+ printk(KERN_WARNING "idr_get_new failure\n");
+ goto out;
+ }
+
+ im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
+ if (!im_port->shost) {
+ error = 1;
+ goto out_free_idr;
+ }
+
+ im_port->shost->hostdata[0] = (unsigned long)im_port;
+ im_port->shost->unique_id = im_port->idr_id;
+ im_port->shost->this_id = -1;
+ im_port->shost->max_id = MAX_FCP_TARGET;
+ im_port->shost->max_lun = MAX_FCP_LUN;
+ im_port->shost->max_cmd_len = 16;
+ im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth;
+ im_port->shost->transportt = bfad_im_scsi_transport_template;
+
+ error = bfad_os_scsi_add_host(im_port->shost, im_port, bfad);
+ if (error) {
+ printk(KERN_WARNING "bfad_os_scsi_add_host failure %d\n",
+ error);
+ goto out_fc_rel;
+ }
+
+ /* setup host fixed attribute if the lk supports */
+ bfad_os_fc_host_init(im_port);
+
+ return 0;
+
+out_fc_rel:
+ scsi_host_put(im_port->shost);
+out_free_idr:
+ idr_remove(&bfad_im_port_index, im_port->idr_id);
+out:
+ return error;
+}
+
+void
+bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+{
+ unsigned long flags;
+
+ bfa_trc(bfad, bfad->inst_no);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE,
+ im_port->shost->host_no);
+
+ fc_remove_host(im_port->shost);
+
+ scsi_remove_host(im_port->shost);
+ scsi_host_put(im_port->shost);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ idr_remove(&bfad_im_port_index, im_port->idr_id);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+static void
+bfad_im_port_delete_handler(struct work_struct *work)
+{
+ struct bfad_im_port_s *im_port =
+ container_of(work, struct bfad_im_port_s, port_delete_work);
+
+ bfad_im_scsi_host_free(im_port->bfad, im_port);
+ bfad_im_port_clean(im_port);
+ kfree(im_port);
+}
+
+bfa_status_t
+bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+ int rc = BFA_STATUS_OK;
+ struct bfad_im_port_s *im_port;
+
+ im_port = kzalloc(sizeof(struct bfad_im_port_s), GFP_ATOMIC);
+ if (im_port == NULL) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+ port->im_port = im_port;
+ im_port->port = port;
+ im_port->bfad = bfad;
+
+ INIT_WORK(&im_port->port_delete_work, bfad_im_port_delete_handler);
+ INIT_LIST_HEAD(&im_port->itnim_mapped_list);
+ INIT_LIST_HEAD(&im_port->binding_list);
+
+ext:
+ return rc;
+}
+
+void
+bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+ struct bfad_im_port_s *im_port = port->im_port;
+
+ queue_work(bfad->im->drv_workq,
+ &im_port->port_delete_work);
+}
+
+void
+bfad_im_port_clean(struct bfad_im_port_s *im_port)
+{
+ struct bfad_fcp_binding *bp, *bp_new;
+ unsigned long flags;
+ struct bfad_s *bfad = im_port->bfad;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ list_for_each_entry_safe(bp, bp_new, &im_port->binding_list,
+ list_entry) {
+ list_del(&bp->list_entry);
+ kfree(bp);
+ }
+
+ /* the itnim_mapped_list must be empty at this time */
+ bfa_assert(list_empty(&im_port->itnim_mapped_list));
+
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+void
+bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+}
+
+void
+bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+}
+
+bfa_status_t
+bfad_im_probe(struct bfad_s *bfad)
+{
+ struct bfad_im_s *im;
+ bfa_status_t rc = BFA_STATUS_OK;
+
+ im = kzalloc(sizeof(struct bfad_im_s), GFP_KERNEL);
+ if (im == NULL) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+
+ bfad->im = im;
+ im->bfad = bfad;
+
+ if (bfad_os_thread_workq(bfad) != BFA_STATUS_OK) {
+ kfree(im);
+ rc = BFA_STATUS_FAILED;
+ }
+
+ext:
+ return rc;
+}
+
+void
+bfad_im_probe_undo(struct bfad_s *bfad)
+{
+ if (bfad->im) {
+ bfad_os_destroy_workq(bfad->im);
+ kfree(bfad->im);
+ bfad->im = NULL;
+ }
+}
+
+
+
+
+int
+bfad_os_scsi_add_host(struct Scsi_Host *shost, struct bfad_im_port_s *im_port,
+ struct bfad_s *bfad)
+{
+ struct device *dev;
+
+ if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
+ dev = &bfad->pcidev->dev;
+ else
+ dev = &bfad->pport.im_port->shost->shost_gendev;
+
+ return scsi_add_host(shost, dev);
+}
+
+struct Scsi_Host *
+bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
+{
+ struct scsi_host_template *sht;
+
+ if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
+ sht = &bfad_im_scsi_host_template;
+ else
+ sht = &bfad_im_vport_template;
+
+ sht->sg_tablesize = bfad->cfg_data.io_max_sge;
+
+ return scsi_host_alloc(sht, sizeof(unsigned long));
+}
+
+void
+bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+{
+ flush_workqueue(bfad->im->drv_workq);
+ bfad_im_scsi_host_free(im_port->bfad, im_port);
+ bfad_im_port_clean(im_port);
+ kfree(im_port);
+}
+
+void
+bfad_os_destroy_workq(struct bfad_im_s *im)
+{
+ if (im && im->drv_workq) {
+ destroy_workqueue(im->drv_workq);
+ im->drv_workq = NULL;
+ }
+}
+
+bfa_status_t
+bfad_os_thread_workq(struct bfad_s *bfad)
+{
+ struct bfad_im_s *im = bfad->im;
+
+ bfa_trc(bfad, 0);
+ snprintf(im->drv_workq_name, BFAD_KOBJ_NAME_LEN, "bfad_wq_%d",
+ bfad->inst_no);
+ im->drv_workq = create_singlethread_workqueue(im->drv_workq_name);
+ if (!im->drv_workq)
+ return BFA_STATUS_FAILED;
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Scsi_Host template entry.
+ *
+ * Description:
+ * OS entry point to adjust the queue_depths on a per-device basis.
+ * Called once per device during the bus scan.
+ * Return non-zero if fails.
+ */
+static int
+bfad_im_slave_configure(struct scsi_device *sdev)
+{
+ if (sdev->tagged_supported)
+ scsi_activate_tcq(sdev, bfa_lun_queue_depth);
+ else
+ scsi_deactivate_tcq(sdev, bfa_lun_queue_depth);
+
+ return 0;
+}
+
+struct scsi_host_template bfad_im_scsi_host_template = {
+ .module = THIS_MODULE,
+ .name = BFAD_DRIVER_NAME,
+ .info = bfad_im_info,
+ .queuecommand = bfad_im_queuecommand,
+ .eh_abort_handler = bfad_im_abort_handler,
+ .eh_device_reset_handler = bfad_im_reset_lun_handler,
+ .eh_bus_reset_handler = bfad_im_reset_bus_handler,
+
+ .slave_alloc = bfad_im_slave_alloc,
+ .slave_configure = bfad_im_slave_configure,
+ .slave_destroy = bfad_im_slave_destroy,
+
+ .this_id = -1,
+ .sg_tablesize = BFAD_IO_MAX_SGE,
+ .cmd_per_lun = 3,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = bfad_im_host_attrs,
+ .max_sectors = 0xFFFF,
+};
+
+struct scsi_host_template bfad_im_vport_template = {
+ .module = THIS_MODULE,
+ .name = BFAD_DRIVER_NAME,
+ .info = bfad_im_info,
+ .queuecommand = bfad_im_queuecommand,
+ .eh_abort_handler = bfad_im_abort_handler,
+ .eh_device_reset_handler = bfad_im_reset_lun_handler,
+ .eh_bus_reset_handler = bfad_im_reset_bus_handler,
+
+ .slave_alloc = bfad_im_slave_alloc,
+ .slave_configure = bfad_im_slave_configure,
+ .slave_destroy = bfad_im_slave_destroy,
+
+ .this_id = -1,
+ .sg_tablesize = BFAD_IO_MAX_SGE,
+ .cmd_per_lun = 3,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = bfad_im_vport_attrs,
+ .max_sectors = 0xFFFF,
+};
+
+void
+bfad_im_probe_post(struct bfad_im_s *im)
+{
+ flush_workqueue(im->drv_workq);
+}
+
+bfa_status_t
+bfad_im_module_init(void)
+{
+ bfad_im_scsi_transport_template =
+ fc_attach_transport(&bfad_im_fc_function_template);
+ if (!bfad_im_scsi_transport_template)
+ return BFA_STATUS_ENOMEM;
+
+ return BFA_STATUS_OK;
+}
+
+void
+bfad_im_module_exit(void)
+{
+ if (bfad_im_scsi_transport_template)
+ fc_release_transport(bfad_im_scsi_transport_template);
+}
+
+void
+bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_im_s *im = itnim_drv->im;
+
+ if (itnim_drv->queue_work)
+ queue_work(im->drv_workq, &itnim_drv->itnim_work);
+}
+
+void
+bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+{
+ struct scsi_device *tmp_sdev;
+
+ if (((jiffies - itnim->last_ramp_up_time) >
+ BFA_QUEUE_FULL_RAMP_UP_TIME * HZ) &&
+ ((jiffies - itnim->last_queue_full_time) >
+ BFA_QUEUE_FULL_RAMP_UP_TIME * HZ)) {
+ shost_for_each_device(tmp_sdev, sdev->host) {
+ if (bfa_lun_queue_depth > tmp_sdev->queue_depth) {
+ if (tmp_sdev->id != sdev->id)
+ continue;
+ if (tmp_sdev->ordered_tags)
+ scsi_adjust_queue_depth(tmp_sdev,
+ MSG_ORDERED_TAG,
+ tmp_sdev->queue_depth + 1);
+ else
+ scsi_adjust_queue_depth(tmp_sdev,
+ MSG_SIMPLE_TAG,
+ tmp_sdev->queue_depth + 1);
+
+ itnim->last_ramp_up_time = jiffies;
+ }
+ }
+ }
+}
+
+void
+bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+{
+ struct scsi_device *tmp_sdev;
+
+ itnim->last_queue_full_time = jiffies;
+
+ shost_for_each_device(tmp_sdev, sdev->host) {
+ if (tmp_sdev->id != sdev->id)
+ continue;
+ scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1);
+ }
+}
+
+
+
+
+struct bfad_itnim_s *
+bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id)
+{
+ struct bfad_itnim_s *itnim = NULL;
+
+ /* Search the mapped list for this target ID */
+ list_for_each_entry(itnim, &im_port->itnim_mapped_list, list_entry) {
+ if (id == itnim->scsi_tgt_id)
+ return itnim;
+ }
+
+ return NULL;
+}
+
+/**
+ * Scsi_Host template entry slave_alloc
+ */
+static int
+bfad_im_slave_alloc(struct scsi_device *sdev)
+{
+ struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+
+ if (!rport || fc_remote_port_chkready(rport))
+ return -ENXIO;
+
+ sdev->hostdata = rport->dd_data;
+
+ return 0;
+}
+
+void
+bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
+{
+ struct Scsi_Host *host = im_port->shost;
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_port_s *port = im_port->port;
+ union attr {
+ struct bfa_pport_attr_s pattr;
+ struct bfa_ioc_attr_s ioc_attr;
+ } attr;
+
+ fc_host_node_name(host) =
+ bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port)));
+ fc_host_port_name(host) =
+ bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port)));
+
+ fc_host_supported_classes(host) = FC_COS_CLASS3;
+
+ memset(fc_host_supported_fc4s(host), 0,
+ sizeof(fc_host_supported_fc4s(host)));
+ if (bfad_supported_fc4s & (BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM))
+ /* For FCP type 0x08 */
+ fc_host_supported_fc4s(host)[2] = 1;
+ if (bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IPFC)
+ /* For LLC/SNAP type 0x05 */
+ fc_host_supported_fc4s(host)[3] = 0x20;
+ /* For fibre channel services type 0x20 */
+ fc_host_supported_fc4s(host)[7] = 1;
+
+ memset(&attr.ioc_attr, 0, sizeof(attr.ioc_attr));
+ bfa_get_attr(&bfad->bfa, &attr.ioc_attr);
+ sprintf(fc_host_symbolic_name(host), "Brocade %s FV%s DV%s",
+ attr.ioc_attr.adapter_attr.model,
+ attr.ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION);
+
+ fc_host_supported_speeds(host) = 0;
+ fc_host_supported_speeds(host) |=
+ FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
+ FC_PORTSPEED_1GBIT;
+
+ memset(&attr.pattr, 0, sizeof(attr.pattr));
+ bfa_pport_get_attr(&bfad->bfa, &attr.pattr);
+ fc_host_maxframe_size(host) = attr.pattr.pport_cfg.maxfrsize;
+}
+
+static void
+bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
+{
+ struct fc_rport_identifiers rport_ids;
+ struct fc_rport *fc_rport;
+ struct bfad_itnim_data_s *itnim_data;
+
+ rport_ids.node_name =
+ bfa_os_htonll(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim));
+ rport_ids.port_name =
+ bfa_os_htonll(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
+ rport_ids.port_id =
+ bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
+ rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
+
+ itnim->fc_rport = fc_rport =
+ fc_remote_port_add(im_port->shost, 0, &rport_ids);
+
+ if (!fc_rport)
+ return;
+
+ fc_rport->maxframe_size =
+ bfa_fcs_itnim_get_maxfrsize(&itnim->fcs_itnim);
+ fc_rport->supported_classes = bfa_fcs_itnim_get_cos(&itnim->fcs_itnim);
+
+ itnim_data = fc_rport->dd_data;
+ itnim_data->itnim = itnim;
+
+ rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
+
+ if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN)
+ fc_remote_port_rolechg(fc_rport, rport_ids.roles);
+
+ if ((fc_rport->scsi_target_id != -1)
+ && (fc_rport->scsi_target_id < MAX_FCP_TARGET))
+ itnim->scsi_tgt_id = fc_rport->scsi_target_id;
+
+ return;
+}
+
+/**
+ * Work queue handler using FC transport service
+* Context: kernel
+ */
+static void
+bfad_im_itnim_work_handler(struct work_struct *work)
+{
+ struct bfad_itnim_s *itnim = container_of(work, struct bfad_itnim_s,
+ itnim_work);
+ struct bfad_im_s *im = itnim->im;
+ struct bfad_s *bfad = im->bfad;
+ struct bfad_im_port_s *im_port;
+ unsigned long flags;
+ struct fc_rport *fc_rport;
+ wwn_t wwpn;
+ u32 fcid;
+ char wwpn_str[32], fcid_str[16];
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ im_port = itnim->im_port;
+ bfa_trc(bfad, itnim->state);
+ switch (itnim->state) {
+ case ITNIM_STATE_ONLINE:
+ if (!itnim->fc_rport) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ bfad_im_fc_rport_add(im_port, itnim);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
+ fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
+ wwn2str(wwpn_str, wwpn);
+ fcid2str(fcid_str, fcid);
+ list_add_tail(&itnim->list_entry,
+ &im_port->itnim_mapped_list);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_ONLINE,
+ im_port->shost->host_no,
+ itnim->scsi_tgt_id,
+ fcid_str, wwpn_str);
+ } else {
+ printk(KERN_WARNING
+ "%s: itnim %llx is already in online state\n",
+ __FUNCTION__,
+ bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
+ }
+
+ break;
+ case ITNIM_STATE_OFFLINE_PENDING:
+ itnim->state = ITNIM_STATE_OFFLINE;
+ if (itnim->fc_rport) {
+ fc_rport = itnim->fc_rport;
+ ((struct bfad_itnim_data_s *)
+ fc_rport->dd_data)->itnim = NULL;
+ itnim->fc_rport = NULL;
+ if (!(im_port->port->flags & BFAD_PORT_DELETE)) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ fc_rport->dev_loss_tmo =
+ bfa_fcpim_path_tov_get(&bfad->bfa) + 1;
+ fc_remote_port_delete(fc_rport);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ }
+ wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
+ fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
+ wwn2str(wwpn_str, wwpn);
+ fcid2str(fcid_str, fcid);
+ list_del(&itnim->list_entry);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_OFFLINE,
+ im_port->shost->host_no,
+ itnim->scsi_tgt_id,
+ fcid_str, wwpn_str);
+ }
+ break;
+ case ITNIM_STATE_FREE:
+ if (itnim->fc_rport) {
+ fc_rport = itnim->fc_rport;
+ ((struct bfad_itnim_data_s *)
+ fc_rport->dd_data)->itnim = NULL;
+ itnim->fc_rport = NULL;
+ if (!(im_port->port->flags & BFAD_PORT_DELETE)) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ fc_rport->dev_loss_tmo =
+ bfa_fcpim_path_tov_get(&bfad->bfa) + 1;
+ fc_remote_port_delete(fc_rport);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ }
+ list_del(&itnim->list_entry);
+ }
+
+ kfree(itnim);
+ break;
+ default:
+ bfa_assert(0);
+ break;
+ }
+
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * Scsi_Host template entry, queue a SCSI command to the BFAD.
+ */
+static int
+bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) cmnd->device->host->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata;
+ struct bfad_itnim_s *itnim;
+ struct bfa_ioim_s *hal_io;
+ unsigned long flags;
+ int rc;
+ s16 sg_cnt = 0;
+ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+
+ rc = fc_remote_port_chkready(rport);
+ if (rc) {
+ cmnd->result = rc;
+ done(cmnd);
+ return 0;
+ }
+
+ sg_cnt = scsi_dma_map(cmnd);
+
+ if (sg_cnt < 0)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ cmnd->scsi_done = done;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ if (!(bfad->bfad_flags & BFAD_HAL_START_DONE)) {
+ printk(KERN_WARNING
+ "bfad%d, queuecommand %p %x failed, BFA stopped\n",
+ bfad->inst_no, cmnd, cmnd->cmnd[0]);
+ cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
+ goto out_fail_cmd;
+ }
+
+ itnim = itnim_data->itnim;
+ if (!itnim) {
+ cmnd->result = ScsiResult(DID_IMM_RETRY, 0);
+ goto out_fail_cmd;
+ }
+
+ hal_io = bfa_ioim_alloc(&bfad->bfa, (struct bfad_ioim_s *) cmnd,
+ itnim->bfa_itnim, sg_cnt);
+ if (!hal_io) {
+ printk(KERN_WARNING "hal_io failure\n");
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ scsi_dma_unmap(cmnd);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ cmnd->host_scribble = (char *)hal_io;
+ bfa_trc_fp(bfad, hal_io->iotag);
+ bfa_ioim_start(hal_io);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ return 0;
+
+out_fail_cmd:
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ scsi_dma_unmap(cmnd);
+ if (done)
+ done(cmnd);
+
+ return 0;
+}
+
+void
+bfad_os_rport_online_wait(struct bfad_s *bfad)
+{
+ int i;
+ int rport_delay = 10;
+
+ for (i = 0; !(bfad->bfad_flags & BFAD_PORT_ONLINE)
+ && i < bfa_linkup_delay; i++)
+ schedule_timeout_uninterruptible(HZ);
+
+ if (bfad->bfad_flags & BFAD_PORT_ONLINE) {
+ rport_delay = rport_delay < bfa_linkup_delay ?
+ rport_delay : bfa_linkup_delay;
+ for (i = 0; !(bfad->bfad_flags & BFAD_RPORT_ONLINE)
+ && i < rport_delay; i++)
+ schedule_timeout_uninterruptible(HZ);
+
+ if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE))
+ schedule_timeout_uninterruptible(rport_delay * HZ);
+ }
+}
+
+int
+bfad_os_get_linkup_delay(struct bfad_s *bfad)
+{
+
+ u8 nwwns = 0;
+ wwn_t *wwns;
+ int ldelay;
+
+ /*
+ * Querying for the boot target port wwns
+ * -- read from boot information in flash.
+ * If nwwns > 0 => boot over SAN and set bfa_linkup_delay = 30
+ * else => local boot machine set bfa_linkup_delay = 10
+ */
+
+ bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, &wwns);
+
+ if (nwwns > 0) {
+ /* If boot over SAN; linkup_delay = 30sec */
+ ldelay = 30;
+ } else {
+ /* If local boot; linkup_delay = 10sec */
+ ldelay = 0;
+ }
+
+ return ldelay;
+}
+
+
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
new file mode 100644
index 000000000000..189a5b29e21a
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFAD_IM_H__
+#define __BFAD_IM_H__
+
+#include "fcs/bfa_fcs_fcpim.h"
+#include "bfad_im_compat.h"
+
+#define FCPI_NAME " fcpim"
+
+void bfad_flags_set(struct bfad_s *bfad, u32 flags);
+bfa_status_t bfad_im_module_init(void);
+void bfad_im_module_exit(void);
+bfa_status_t bfad_im_probe(struct bfad_s *bfad);
+void bfad_im_probe_undo(struct bfad_s *bfad);
+void bfad_im_probe_post(struct bfad_im_s *im);
+bfa_status_t bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_clean(struct bfad_im_port_s *im_port);
+int bfad_im_scsi_host_alloc(struct bfad_s *bfad,
+ struct bfad_im_port_s *im_port);
+void bfad_im_scsi_host_free(struct bfad_s *bfad,
+ struct bfad_im_port_s *im_port);
+
+#define MAX_FCP_TARGET 1024
+#define MAX_FCP_LUN 16384
+#define BFAD_TARGET_RESET_TMO 60
+#define BFAD_LUN_RESET_TMO 60
+#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
+#define BFA_QUEUE_FULL_RAMP_UP_TIME 120
+#define BFAD_KOBJ_NAME_LEN 20
+
+/*
+ * itnim flags
+ */
+#define ITNIM_MAPPED 0x00000001
+
+#define SCSI_TASK_MGMT 0x00000001
+#define IO_DONE_BIT 0
+
+struct bfad_itnim_data_s {
+ struct bfad_itnim_s *itnim;
+};
+
+struct bfad_im_port_s {
+ struct bfad_s *bfad;
+ struct bfad_port_s *port;
+ struct work_struct port_delete_work;
+ int idr_id;
+ u16 cur_scsi_id;
+ struct list_head binding_list;
+ struct Scsi_Host *shost;
+ struct list_head itnim_mapped_list;
+};
+
+enum bfad_itnim_state {
+ ITNIM_STATE_NONE,
+ ITNIM_STATE_ONLINE,
+ ITNIM_STATE_OFFLINE_PENDING,
+ ITNIM_STATE_OFFLINE,
+ ITNIM_STATE_TIMEOUT,
+ ITNIM_STATE_FREE,
+};
+
+/*
+ * Per itnim data structure
+ */
+struct bfad_itnim_s {
+ struct list_head list_entry;
+ struct bfa_fcs_itnim_s fcs_itnim;
+ struct work_struct itnim_work;
+ u32 flags;
+ enum bfad_itnim_state state;
+ struct bfad_im_s *im;
+ struct bfad_im_port_s *im_port;
+ struct bfad_rport_s *drv_rport;
+ struct fc_rport *fc_rport;
+ struct bfa_itnim_s *bfa_itnim;
+ u16 scsi_tgt_id;
+ u16 queue_work;
+ unsigned long last_ramp_up_time;
+ unsigned long last_queue_full_time;
+};
+
+enum bfad_binding_type {
+ FCP_PWWN_BINDING = 0x1,
+ FCP_NWWN_BINDING = 0x2,
+ FCP_FCID_BINDING = 0x3,
+};
+
+struct bfad_fcp_binding {
+ struct list_head list_entry;
+ enum bfad_binding_type binding_type;
+ u16 scsi_target_id;
+ u32 fc_id;
+ wwn_t nwwn;
+ wwn_t pwwn;
+};
+
+struct bfad_im_s {
+ struct bfad_s *bfad;
+ struct workqueue_struct *drv_workq;
+ char drv_workq_name[BFAD_KOBJ_NAME_LEN];
+};
+
+struct Scsi_Host *bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port,
+ struct bfad_s *);
+bfa_status_t bfad_os_thread_workq(struct bfad_s *bfad);
+void bfad_os_destroy_workq(struct bfad_im_s *im);
+void bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv);
+void bfad_os_fc_host_init(struct bfad_im_port_s *im_port);
+void bfad_os_init_work(struct bfad_im_port_s *im_port);
+void bfad_os_scsi_host_free(struct bfad_s *bfad,
+ struct bfad_im_port_s *im_port);
+void bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim,
+ struct scsi_device *sdev);
+void bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev);
+struct bfad_itnim_s *bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id);
+int bfad_os_scsi_add_host(struct Scsi_Host *shost,
+ struct bfad_im_port_s *im_port, struct bfad_s *bfad);
+
+/*
+ * scsi_host_template entries
+ */
+void bfad_im_itnim_unmap(struct bfad_im_port_s *im_port,
+ struct bfad_itnim_s *itnim);
+
+extern struct scsi_host_template bfad_im_scsi_host_template;
+extern struct scsi_host_template bfad_im_vport_template;
+extern struct fc_function_template bfad_im_fc_function_template;
+extern struct scsi_transport_template *bfad_im_scsi_transport_template;
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h
new file mode 100644
index 000000000000..1d3e74ec338c
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_im_compat.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFAD_IM_COMPAT_H__
+#define __BFAD_IM_COMPAT_H__
+
+extern u32 *bfi_image_buf;
+extern u32 bfi_image_size;
+
+extern struct device_attribute *bfad_im_host_attrs[];
+extern struct device_attribute *bfad_im_vport_attrs[];
+
+u32 *bfad_get_firmware_buf(struct pci_dev *pdev);
+u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+ u32 *bfi_image_size, char *fw_name);
+
+static inline u32 *
+bfad_load_fwimg(struct pci_dev *pdev)
+{
+ return(bfad_get_firmware_buf(pdev));
+}
+
+static inline void
+bfad_free_fwimg(void)
+{
+ if (bfi_image_ct_size && bfi_image_ct)
+ vfree(bfi_image_ct);
+ if (bfi_image_cb_size && bfi_image_cb)
+ vfree(bfi_image_cb);
+}
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c
new file mode 100644
index 000000000000..f104e029cac9
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_intr.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2005-2009 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_trcmod.h"
+
+BFA_TRC_FILE(LDRV, INTR);
+
+/**
+ * bfa_isr BFA driver interrupt functions
+ */
+irqreturn_t bfad_intx(int irq, void *dev_id);
+static int msix_disable;
+module_param(msix_disable, int, S_IRUGO | S_IWUSR);
+/**
+ * Line based interrupt handler.
+ */
+irqreturn_t
+bfad_intx(int irq, void *dev_id)
+{
+ struct bfad_s *bfad = dev_id;
+ struct list_head doneq;
+ unsigned long flags;
+ bfa_boolean_t rc;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_intx(&bfad->bfa);
+ if (!rc) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ return IRQ_NONE;
+ }
+
+ bfa_comp_deq(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (!list_empty(&doneq)) {
+ bfa_comp_process(&bfad->bfa, &doneq);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_comp_free(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ bfa_trc_fp(bfad, irq);
+ }
+
+ return IRQ_HANDLED;
+
+}
+
+static irqreturn_t
+bfad_msix(int irq, void *dev_id)
+{
+ struct bfad_msix_s *vec = dev_id;
+ struct bfad_s *bfad = vec->bfad;
+ struct list_head doneq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ bfa_msix(&bfad->bfa, vec->msix.entry);
+ bfa_comp_deq(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (!list_empty(&doneq)) {
+ bfa_comp_process(&bfad->bfa, &doneq);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_comp_free(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * Initialize the MSIX entry table.
+ */
+static void
+bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries,
+ int mask, int max_bit)
+{
+ int i;
+ int match = 0x00000001;
+
+ for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) {
+ if (mask & match) {
+ bfad->msix_tab[bfad->nvec].msix.entry = i;
+ bfad->msix_tab[bfad->nvec].bfad = bfad;
+ msix_entries[bfad->nvec].entry = i;
+ bfad->nvec++;
+ }
+
+ match <<= 1;
+ }
+
+}
+
+int
+bfad_install_msix_handler(struct bfad_s *bfad)
+{
+ int i, error = 0;
+
+ for (i = 0; i < bfad->nvec; i++) {
+ error = request_irq(bfad->msix_tab[i].msix.vector,
+ (irq_handler_t) bfad_msix, 0,
+ BFAD_DRIVER_NAME, &bfad->msix_tab[i]);
+ bfa_trc(bfad, i);
+ bfa_trc(bfad, bfad->msix_tab[i].msix.vector);
+ if (error) {
+ int j;
+
+ for (j = 0; j < i; j++)
+ free_irq(bfad->msix_tab[j].msix.vector,
+ &bfad->msix_tab[j]);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Setup MSIX based interrupt.
+ */
+int
+bfad_setup_intr(struct bfad_s *bfad)
+{
+ int error = 0;
+ u32 mask = 0, i, num_bit = 0, max_bit = 0;
+ struct msix_entry msix_entries[MAX_MSIX_ENTRY];
+
+ /* Call BFA to get the msix map for this PCI function. */
+ bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit);
+
+ /* Set up the msix entry table */
+ bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
+
+ if (!msix_disable) {
+ error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec);
+ if (error) {
+ /*
+ * Only error number of vector is available.
+ * We don't have a mechanism to map multiple
+ * interrupts into one vector, so even if we
+ * can try to request less vectors, we don't
+ * know how to associate interrupt events to
+ * vectors. Linux doesn't dupicate vectors
+ * in the MSIX table for this case.
+ */
+
+ printk(KERN_WARNING "bfad%d: "
+ "pci_enable_msix failed (%d),"
+ " use line based.\n", bfad->inst_no, error);
+
+ goto line_based;
+ }
+
+ /* Save the vectors */
+ for (i = 0; i < bfad->nvec; i++) {
+ bfa_trc(bfad, msix_entries[i].vector);
+ bfad->msix_tab[i].msix.vector = msix_entries[i].vector;
+ }
+
+ bfa_msix_init(&bfad->bfa, bfad->nvec);
+
+ bfad->bfad_flags |= BFAD_MSIX_ON;
+
+ return error;
+ }
+
+line_based:
+ error = 0;
+ if (request_irq
+ (bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS,
+ BFAD_DRIVER_NAME, bfad) != 0) {
+ /* Enable interrupt handler failed */
+ return 1;
+ }
+
+ return error;
+}
+
+void
+bfad_remove_intr(struct bfad_s *bfad)
+{
+ int i;
+
+ if (bfad->bfad_flags & BFAD_MSIX_ON) {
+ for (i = 0; i < bfad->nvec; i++)
+ free_irq(bfad->msix_tab[i].msix.vector,
+ &bfad->msix_tab[i]);
+
+ pci_disable_msix(bfad->pcidev);
+ bfad->bfad_flags &= ~BFAD_MSIX_ON;
+ } else {
+ free_irq(bfad->pcidev->irq, bfad);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/bfad_ipfc.h b/drivers/scsi/bfa/bfad_ipfc.h
new file mode 100644
index 000000000000..718bc5227671
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_ipfc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DRV_IPFC_H__
+#define __BFA_DRV_IPFC_H__
+
+
+#define IPFC_NAME ""
+
+#define bfad_ipfc_module_init(x) do {} while (0)
+#define bfad_ipfc_module_exit(x) do {} while (0)
+#define bfad_ipfc_probe(x) do {} while (0)
+#define bfad_ipfc_probe_undo(x) do {} while (0)
+#define bfad_ipfc_port_config(x, y) BFA_STATUS_OK
+#define bfad_ipfc_port_unconfig(x, y) do {} while (0)
+
+#define bfad_ipfc_probe_post(x) do {} while (0)
+#define bfad_ipfc_port_new(x, y, z) BFA_STATUS_OK
+#define bfad_ipfc_port_delete(x, y) do {} while (0)
+#define bfad_ipfc_port_online(x, y) do {} while (0)
+#define bfad_ipfc_port_offline(x, y) do {} while (0)
+
+#define bfad_ip_get_attr(x) BFA_STATUS_FAILED
+#define bfad_ip_reset_drv_stats(x) BFA_STATUS_FAILED
+#define bfad_ip_get_drv_stats(x, y) BFA_STATUS_FAILED
+#define bfad_ip_enable_ipfc(x, y, z) BFA_STATUS_FAILED
+
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_os.c b/drivers/scsi/bfa/bfad_os.c
new file mode 100644
index 000000000000..faf47b4f1a38
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_os.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfad_os.c Linux driver OS specific calls.
+ */
+
+#include "bfa_os_inc.h"
+#include "bfad_drv.h"
+
+void
+bfa_os_gettimeofday(struct bfa_timeval_s *tv)
+{
+ struct timeval tmp_tv;
+
+ do_gettimeofday(&tmp_tv);
+ tv->tv_sec = (u32) tmp_tv.tv_sec;
+ tv->tv_usec = (u32) tmp_tv.tv_usec;
+}
+
+void
+bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id,
+ const char *fmt, ...)
+{
+ va_list ap;
+ #define BFA_STRING_256 256
+ char tmp[BFA_STRING_256];
+
+ va_start(ap, fmt);
+ vsprintf(tmp, fmt, ap);
+ va_end(ap);
+
+ printk(tmp);
+}
+
+
diff --git a/drivers/scsi/bfa/bfad_tm.h b/drivers/scsi/bfa/bfad_tm.h
new file mode 100644
index 000000000000..4901b1b7df02
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_tm.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/*
+ * Brocade Fibre Channel HBA Linux Target Mode Driver
+ */
+
+/**
+ * tm/dummy/bfad_tm.h BFA callback dummy header file for BFA Linux target mode PCI interface module.
+ */
+
+#ifndef __BFAD_TM_H__
+#define __BFAD_TM_H__
+
+#include <defs/bfa_defs_status.h>
+
+#define FCPT_NAME ""
+
+/*
+ * Called from base Linux driver on (De)Init events
+ */
+
+/* attach tgt template with scst */
+#define bfad_tm_module_init() do {} while (0)
+
+/* detach/release tgt template */
+#define bfad_tm_module_exit() do {} while (0)
+
+#define bfad_tm_probe(x) do {} while (0)
+#define bfad_tm_probe_undo(x) do {} while (0)
+#define bfad_tm_probe_post(x) do {} while (0)
+
+/*
+ * Called by base Linux driver but triggered by BFA FCS on config events
+ */
+#define bfad_tm_port_new(x, y) BFA_STATUS_OK
+#define bfad_tm_port_delete(x, y) do {} while (0)
+
+/*
+ * Called by base Linux driver but triggered by BFA FCS on PLOGI/O events
+ */
+#define bfad_tm_port_online(x, y) do {} while (0)
+#define bfad_tm_port_offline(x, y) do {} while (0)
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_trcmod.h b/drivers/scsi/bfa/bfad_trcmod.h
new file mode 100644
index 000000000000..2827b2acd041
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_trcmod.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfad_trcmod.h Linux driver trace modules
+ */
+
+
+#ifndef __BFAD_TRCMOD_H__
+#define __BFAD_TRCMOD_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ /* 2.6 Driver */
+ BFA_TRC_LDRV_BFAD = 1,
+ BFA_TRC_LDRV_BFAD_2_6 = 2,
+ BFA_TRC_LDRV_BFAD_2_6_9 = 3,
+ BFA_TRC_LDRV_BFAD_2_6_10 = 4,
+ BFA_TRC_LDRV_INTR = 5,
+ BFA_TRC_LDRV_IOCTL = 6,
+ BFA_TRC_LDRV_OS = 7,
+ BFA_TRC_LDRV_IM = 8,
+ BFA_TRC_LDRV_IM_2_6 = 9,
+ BFA_TRC_LDRV_IM_2_6_9 = 10,
+ BFA_TRC_LDRV_IM_2_6_10 = 11,
+ BFA_TRC_LDRV_TM = 12,
+ BFA_TRC_LDRV_IPFC = 13,
+ BFA_TRC_LDRV_IM_2_4 = 14,
+ BFA_TRC_LDRV_IM_VMW = 15,
+ BFA_TRC_LDRV_IM_LT_2_6_10 = 16,
+};
+
+#endif /* __BFAD_TRCMOD_H__ */
diff --git a/drivers/scsi/bfa/fab.c b/drivers/scsi/bfa/fab.c
new file mode 100644
index 000000000000..7e3a4d5d7bb4
--- /dev/null
+++ b/drivers/scsi/bfa/fab.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "lport_priv.h"
+
+/**
+ * fab.c port fab implementation.
+ */
+
+/**
+ * bfa_fcs_port_fab_public port fab public functions
+ */
+
+/**
+ * Called by port to initialize fabric services of the base port.
+ */
+void
+bfa_fcs_port_fab_init(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_ns_init(port);
+ bfa_fcs_port_scn_init(port);
+ bfa_fcs_port_ms_init(port);
+}
+
+/**
+ * Called by port to notify transition to online state.
+ */
+void
+bfa_fcs_port_fab_online(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_ns_online(port);
+ bfa_fcs_port_scn_online(port);
+}
+
+/**
+ * Called by port to notify transition to offline state.
+ */
+void
+bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_ns_offline(port);
+ bfa_fcs_port_scn_offline(port);
+ bfa_fcs_port_ms_offline(port);
+}
diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c
new file mode 100644
index 000000000000..a8b14c47b009
--- /dev/null
+++ b/drivers/scsi/bfa/fabric.c
@@ -0,0 +1,1278 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fabric.c Fabric module implementation.
+ */
+
+#include "fcs_fabric.h"
+#include "fcs_lport.h"
+#include "fcs_vport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs_auth.h"
+#include "fcs.h"
+#include "fcbuild.h"
+#include <log/bfa_log_fcs.h>
+#include <aen/bfa_aen_port.h>
+#include <bfa_svc.h>
+
+BFA_TRC_FILE(FCS, FABRIC);
+
+#define BFA_FCS_FABRIC_RETRY_DELAY (2000) /* Milliseconds */
+#define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */
+
+#define bfa_fcs_fabric_set_opertype(__fabric) do { \
+ if (bfa_pport_get_topology((__fabric)->fcs->bfa) \
+ == BFA_PPORT_TOPOLOGY_P2P) \
+ (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT; \
+ else \
+ (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT; \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_delay(void *cbarg);
+static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_delete_comp(void *cbarg);
+static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len);
+static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len);
+static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg,
+ struct bfa_fcxp_s *fcxp,
+ void *cbarg, bfa_status_t status,
+ u32 rsp_len,
+ u32 resid_len,
+ struct fchs_s *rspfchs);
+/**
+ * fcs_fabric_sm fabric state machine functions
+ */
+
+/**
+ * Fabric state machine events
+ */
+enum bfa_fcs_fabric_event {
+ BFA_FCS_FABRIC_SM_CREATE = 1, /* fabric create from driver */
+ BFA_FCS_FABRIC_SM_DELETE = 2, /* fabric delete from driver */
+ BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */
+ BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */
+ BFA_FCS_FABRIC_SM_CONT_OP = 5, /* continue op from flogi/auth */
+ BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* continue op from flogi/auth */
+ BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* no fabric from flogi/auth
+ */
+ BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* perform EVFP from
+ *flogi/auth */
+ BFA_FCS_FABRIC_SM_ISOLATE = 9, /* isolate from EVFP processing */
+ BFA_FCS_FABRIC_SM_NO_TAGGING = 10,/* no VFT tagging from EVFP */
+ BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */
+ BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* authentication failed */
+ BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* authentication successful
+ */
+ BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */
+ BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */
+ BFA_FCS_FABRIC_SM_START = 16, /* fabric delete from driver */
+};
+
+static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+/**
+ * Beginning state before fabric creation.
+ */
+static void
+bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_CREATE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created);
+ bfa_fcs_fabric_init(fabric);
+ bfa_fcs_lport_init(&fabric->bport, fabric->fcs, FC_VF_ID_NULL,
+ &fabric->bport.port_cfg, NULL);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Beginning state before fabric creation.
+ */
+static void
+bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_START:
+ if (bfa_pport_is_linkup(fabric->fcs->bfa)) {
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
+ bfa_fcs_fabric_login(fabric);
+ } else
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
+ bfa_fcs_modexit_comp(fabric->fcs);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Link is down, awaiting LINK UP event from port. This is also the
+ * first state at fabric creation.
+ */
+static void
+bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
+ bfa_fcs_fabric_login(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_RETRY_OP:
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * FLOGI is in progress, awaiting FLOGI reply.
+ */
+static void
+bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_CONT_OP:
+
+ bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+ fabric->fab_type = BFA_FCS_FABRIC_SWITCHED;
+
+ if (fabric->auth_reqd && fabric->is_auth) {
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth);
+ bfa_trc(fabric->fcs, event);
+ } else {
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
+ bfa_fcs_fabric_notify_online(fabric);
+ }
+ break;
+
+ case BFA_FCS_FABRIC_SM_RETRY_OP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry);
+ bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer,
+ bfa_fcs_fabric_delay, fabric,
+ BFA_FCS_FABRIC_RETRY_DELAY);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LOOPBACK:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_set_opertype(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_NO_FABRIC:
+ fabric->fab_type = BFA_FCS_FABRIC_N2N;
+ bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+ bfa_fcs_fabric_notify_online(fabric);
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+
+static void
+bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_DELAYED:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
+ bfa_fcs_fabric_login(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_timer_stop(&fabric->delay_timer);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_timer_stop(&fabric->delay_timer);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Authentication is in progress, awaiting authentication results.
+ */
+static void
+bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_AUTH_FAILED:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
+ bfa_fcs_fabric_notify_online(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_PERF_EVFP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Authentication failed
+ */
+static void
+bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Port is in loopback mode.
+ */
+static void
+bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * There is no attached fabric - private loop or NPort-to-NPort topology.
+ */
+static void
+bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_NO_FABRIC:
+ bfa_trc(fabric->fcs, fabric->bb_credit);
+ bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Fabric is online - normal operating state.
+ */
+static void
+bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_AUTH_FAILED:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Exchanging virtual fabric parameters.
+ */
+static void
+bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_CONT_OP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done);
+ break;
+
+ case BFA_FCS_FABRIC_SM_ISOLATE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * EVFP exchange complete and VFT tagging is enabled.
+ */
+static void
+bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+}
+
+/**
+ * Port is isolated after EVFP exchange due to VF_ID mismatch (N and F).
+ */
+static void
+bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ bfa_log(fabric->fcs->logm, BFA_LOG_FCS_FABRIC_ISOLATED,
+ fabric->bport.port_cfg.pwwn, fabric->fcs->port_vfid,
+ fabric->event_arg.swp_vfid);
+}
+
+/**
+ * Fabric is being deleted, awaiting vport delete completions.
+ */
+static void
+bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_DELCOMP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
+ bfa_fcs_modexit_comp(fabric->fcs);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+
+
+/**
+ * fcs_fabric_private fabric private functions
+ */
+
+static void
+bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg;
+
+ port_cfg->roles = BFA_PORT_ROLE_FCP_IM;
+ port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->fcs->bfa->ioc);
+ port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc);
+}
+
+/**
+ * Port Symbolic Name Creation for base port.
+ */
+void
+bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg;
+ struct bfa_adapter_attr_s adapter_attr;
+ struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info;
+
+ bfa_os_memset((void *)&adapter_attr, 0,
+ sizeof(struct bfa_adapter_attr_s));
+ bfa_ioc_get_adapter_attr(&fabric->fcs->bfa->ioc, &adapter_attr);
+
+ /*
+ * Model name/number
+ */
+ strncpy((char *)&port_cfg->sym_name, adapter_attr.model,
+ BFA_FCS_PORT_SYMBNAME_MODEL_SZ);
+ strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Driver Version
+ */
+ strncat((char *)&port_cfg->sym_name, (char *)driver_info->version,
+ BFA_FCS_PORT_SYMBNAME_VERSION_SZ);
+ strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Host machine name
+ */
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_machine_name,
+ BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ);
+ strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Host OS Info :
+ * If OS Patch Info is not there, do not truncate any bytes from the
+ * OS name string and instead copy the entire OS info string (64 bytes).
+ */
+ if (driver_info->host_os_patch[0] == '\0') {
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_os_name, BFA_FCS_OS_STR_LEN);
+ strncat((char *)&port_cfg->sym_name,
+ BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+ } else {
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_os_name,
+ BFA_FCS_PORT_SYMBNAME_OSINFO_SZ);
+ strncat((char *)&port_cfg->sym_name,
+ BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Append host OS Patch Info
+ */
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_os_patch,
+ BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ);
+ }
+
+ /*
+ * null terminate
+ */
+ port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
+}
+
+/**
+ * bfa lps login completion callback
+ */
+void
+bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
+{
+ struct bfa_fcs_fabric_s *fabric = uarg;
+
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, status);
+
+ switch (status) {
+ case BFA_STATUS_OK:
+ fabric->stats.flogi_accepts++;
+ break;
+
+ case BFA_STATUS_INVALID_MAC:
+ /*
+ * Only for CNA
+ */
+ fabric->stats.flogi_acc_err++;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+
+ return;
+
+ case BFA_STATUS_EPROTOCOL:
+ switch (bfa_lps_get_extstatus(fabric->lps)) {
+ case BFA_EPROTO_BAD_ACCEPT:
+ fabric->stats.flogi_acc_err++;
+ break;
+
+ case BFA_EPROTO_UNKNOWN_RSP:
+ fabric->stats.flogi_unknown_rsp++;
+ break;
+
+ default:
+ break;
+ }
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+
+ return;
+
+ case BFA_STATUS_FABRIC_RJT:
+ fabric->stats.flogi_rejects++;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+ return;
+
+ default:
+ fabric->stats.flogi_rsp_err++;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+ return;
+ }
+
+ fabric->bb_credit = bfa_lps_get_peer_bbcredit(fabric->lps);
+ bfa_trc(fabric->fcs, fabric->bb_credit);
+
+ if (!bfa_lps_is_brcd_fabric(fabric->lps))
+ fabric->fabric_name = bfa_lps_get_peer_nwwn(fabric->lps);
+
+ /*
+ * Check port type. It should be 1 = F-port.
+ */
+ if (bfa_lps_is_fport(fabric->lps)) {
+ fabric->bport.pid = bfa_lps_get_pid(fabric->lps);
+ fabric->is_npiv = bfa_lps_is_npiv_en(fabric->lps);
+ fabric->is_auth = bfa_lps_is_authreq(fabric->lps);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP);
+ } else {
+ /*
+ * Nport-2-Nport direct attached
+ */
+ fabric->bport.port_topo.pn2n.rem_port_wwn =
+ bfa_lps_get_peer_pwwn(fabric->lps);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
+ }
+
+ bfa_trc(fabric->fcs, fabric->bport.pid);
+ bfa_trc(fabric->fcs, fabric->is_npiv);
+ bfa_trc(fabric->fcs, fabric->is_auth);
+}
+
+/**
+ * Allocate and send FLOGI.
+ */
+static void
+bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_s *bfa = fabric->fcs->bfa;
+ struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg;
+ u8 alpa = 0;
+
+ if (bfa_pport_get_topology(bfa) == BFA_PPORT_TOPOLOGY_LOOP)
+ alpa = bfa_pport_get_myalpa(bfa);
+
+ bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_pport_get_maxfrsize(bfa),
+ pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd);
+
+ fabric->stats.flogi_sent++;
+}
+
+static void
+bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe, *qen;
+
+ bfa_trc(fabric->fcs, fabric->fabric_name);
+
+ bfa_fcs_fabric_set_opertype(fabric);
+ fabric->stats.fabric_onlines++;
+
+ /**
+ * notify online event to base and then virtual ports
+ */
+ bfa_fcs_port_online(&fabric->bport);
+
+ list_for_each_safe(qe, qen, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ bfa_fcs_vport_online(vport);
+ }
+}
+
+static void
+bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe, *qen;
+
+ bfa_trc(fabric->fcs, fabric->fabric_name);
+ fabric->stats.fabric_offlines++;
+
+ /**
+ * notify offline event first to vports and then base port.
+ */
+ list_for_each_safe(qe, qen, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ bfa_fcs_vport_offline(vport);
+ }
+
+ bfa_fcs_port_offline(&fabric->bport);
+
+ fabric->fabric_name = 0;
+ fabric->fabric_ip_addr[0] = 0;
+}
+
+static void
+bfa_fcs_fabric_delay(void *cbarg)
+{
+ struct bfa_fcs_fabric_s *fabric = cbarg;
+
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED);
+}
+
+/**
+ * Delete all vports and wait for vport delete completions.
+ */
+static void
+bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ bfa_fcs_vport_delete(vport);
+ }
+
+ bfa_fcs_port_delete(&fabric->bport);
+ bfa_wc_wait(&fabric->wc);
+}
+
+static void
+bfa_fcs_fabric_delete_comp(void *cbarg)
+{
+ struct bfa_fcs_fabric_s *fabric = cbarg;
+
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP);
+}
+
+
+
+/**
+ * fcs_fabric_public fabric public functions
+ */
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_fabric_s *fabric;
+
+ fabric = &fcs->fabric;
+ bfa_os_memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
+
+ /**
+ * Initialize base fabric.
+ */
+ fabric->fcs = fcs;
+ INIT_LIST_HEAD(&fabric->vport_q);
+ INIT_LIST_HEAD(&fabric->vf_q);
+ fabric->lps = bfa_lps_alloc(fcs->bfa);
+ bfa_assert(fabric->lps);
+
+ /**
+ * Initialize fabric delete completion handler. Fabric deletion is complete
+ * when the last vport delete is complete.
+ */
+ bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric);
+ bfa_wc_up(&fabric->wc); /* For the base port */
+
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CREATE);
+ bfa_trc(fcs, 0);
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_fabric_s *fabric;
+
+ bfa_trc(fcs, 0);
+
+ /**
+ * Cleanup base fabric.
+ */
+ fabric = &fcs->fabric;
+ bfa_lps_delete(fabric->lps);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE);
+}
+
+/**
+ * Fabric module start -- kick starts FCS actions
+ */
+void
+bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_fabric_s *fabric;
+
+ bfa_trc(fcs, 0);
+ fabric = &fcs->fabric;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START);
+}
+
+/**
+ * Suspend fabric activity as part of driver suspend.
+ */
+void
+bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs)
+{
+}
+
+bfa_boolean_t
+bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric)
+{
+ return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback));
+}
+
+enum bfa_pport_type
+bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric)
+{
+ return fabric->oper_type;
+}
+
+/**
+ * Link up notification from BFA physical port module.
+ */
+void
+bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP);
+}
+
+/**
+ * Link down notification from BFA physical port module.
+ */
+void
+bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN);
+}
+
+/**
+ * A child vport is being created in the fabric.
+ *
+ * Call from vport module at vport creation. A list of base port and vports
+ * belonging to a fabric is maintained to propagate link events.
+ *
+ * param[in] fabric - Fabric instance. This can be a base fabric or vf.
+ * param[in] vport - Vport being created.
+ *
+ * @return None (always succeeds)
+ */
+void
+bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport)
+{
+ /**
+ * - add vport to fabric's vport_q
+ */
+ bfa_trc(fabric->fcs, fabric->vf_id);
+
+ list_add_tail(&vport->qe, &fabric->vport_q);
+ fabric->num_vports++;
+ bfa_wc_up(&fabric->wc);
+}
+
+/**
+ * A child vport is being deleted from fabric.
+ *
+ * Vport is being deleted.
+ */
+void
+bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport)
+{
+ list_del(&vport->qe);
+ fabric->num_vports--;
+ bfa_wc_down(&fabric->wc);
+}
+
+/**
+ * Base port is deleted.
+ */
+void
+bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric)
+{
+ bfa_wc_down(&fabric->wc);
+}
+
+/**
+ * Check if fabric is online.
+ *
+ * param[in] fabric - Fabric instance. This can be a base fabric or vf.
+ *
+ * @return TRUE/FALSE
+ */
+int
+bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric)
+{
+ return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online));
+}
+
+
+bfa_status_t
+bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs,
+ struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vf_s *vf_drv)
+{
+ bfa_sm_set_state(vf, bfa_fcs_fabric_sm_uninit);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Lookup for a vport withing a fabric given its pwwn
+ */
+struct bfa_fcs_vport_s *
+bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe;
+
+ list_for_each(qe, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ if (bfa_fcs_port_get_pwwn(&vport->lport) == pwwn)
+ return vport;
+ }
+
+ return NULL;
+}
+
+/**
+ * In a given fabric, return the number of lports.
+ *
+ * param[in] fabric - Fabric instance. This can be a base fabric or vf.
+ *
+* @return : 1 or more.
+ */
+u16
+bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric)
+{
+ return (fabric->num_vports);
+}
+
+/**
+ * Unsolicited frame receive handling.
+ */
+void
+bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
+ u16 len)
+{
+ u32 pid = fchs->d_id;
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe;
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+ struct fc_logi_s *flogi = (struct fc_logi_s *) els_cmd;
+
+ bfa_trc(fabric->fcs, len);
+ bfa_trc(fabric->fcs, pid);
+
+ /**
+ * Look for our own FLOGI frames being looped back. This means an
+ * external loopback cable is in place. Our own FLOGI frames are
+ * sometimes looped back when switch port gets temporarily bypassed.
+ */
+ if ((pid == bfa_os_ntoh3b(FC_FABRIC_PORT))
+ && (els_cmd->els_code == FC_ELS_FLOGI)
+ && (flogi->port_name == bfa_fcs_port_get_pwwn(&fabric->bport))) {
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK);
+ return;
+ }
+
+ /**
+ * FLOGI/EVFP exchanges should be consumed by base fabric.
+ */
+ if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) {
+ bfa_trc(fabric->fcs, pid);
+ bfa_fcs_fabric_process_uf(fabric, fchs, len);
+ return;
+ }
+
+ if (fabric->bport.pid == pid) {
+ /**
+ * All authentication frames should be routed to auth
+ */
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+ if (els_cmd->els_code == FC_ELS_AUTH) {
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+ fabric->auth.response = (u8 *) els_cmd;
+ return;
+ }
+
+ bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs));
+ bfa_fcs_port_uf_recv(&fabric->bport, fchs, len);
+ return;
+ }
+
+ /**
+ * look for a matching local port ID
+ */
+ list_for_each(qe, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ if (vport->lport.pid == pid) {
+ bfa_fcs_port_uf_recv(&vport->lport, fchs, len);
+ return;
+ }
+ }
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+ bfa_fcs_port_uf_recv(&fabric->bport, fchs, len);
+}
+
+/**
+ * Unsolicited frames to be processed by fabric.
+ */
+static void
+bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
+ u16 len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_FLOGI:
+ bfa_fcs_fabric_process_flogi(fabric, fchs, len);
+ break;
+
+ default:
+ /*
+ * need to generate a LS_RJT
+ */
+ break;
+ }
+}
+
+/**
+ * Process incoming FLOGI
+ */
+static void
+bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len)
+{
+ struct fc_logi_s *flogi = (struct fc_logi_s *) (fchs + 1);
+ struct bfa_fcs_port_s *bport = &fabric->bport;
+
+ bfa_trc(fabric->fcs, fchs->s_id);
+
+ fabric->stats.flogi_rcvd++;
+ /*
+ * Check port type. It should be 0 = n-port.
+ */
+ if (flogi->csp.port_type) {
+ /*
+ * @todo: may need to send a LS_RJT
+ */
+ bfa_trc(fabric->fcs, flogi->port_name);
+ fabric->stats.flogi_rejected++;
+ return;
+ }
+
+ fabric->bb_credit = bfa_os_ntohs(flogi->csp.bbcred);
+ bport->port_topo.pn2n.rem_port_wwn = flogi->port_name;
+ bport->port_topo.pn2n.reply_oxid = fchs->ox_id;
+
+ /*
+ * Send a Flogi Acc
+ */
+ bfa_fcs_fabric_send_flogi_acc(fabric);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
+}
+
+static void
+bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg;
+ struct bfa_fcs_port_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n;
+ struct bfa_s *bfa = fabric->fcs->bfa;
+ struct bfa_fcxp_s *fcxp;
+ u16 reqlen;
+ struct fchs_s fchs;
+
+ fcxp = bfa_fcs_fcxp_alloc(fabric->fcs);
+ /**
+ * Do not expect this failure -- expect remote node to retry
+ */
+ if (!fcxp)
+ return;
+
+ reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_os_hton3b(FC_FABRIC_PORT),
+ n2n_port->reply_oxid, pcfg->pwwn,
+ pcfg->nwwn, bfa_pport_get_maxfrsize(bfa),
+ bfa_pport_get_rx_bbcredit(bfa));
+
+ bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps),
+ BFA_FALSE, FC_CLASS_3, reqlen, &fchs,
+ bfa_fcs_fabric_flogiacc_comp, fabric,
+ FC_MAX_PDUSZ, 0); /* Timeout 0 indicates no
+ * response expected
+ */
+}
+
+/**
+ * Flogi Acc completion callback.
+ */
+static void
+bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
+ bfa_status_t status, u32 rsp_len,
+ u32 resid_len, struct fchs_s *rspfchs)
+{
+ struct bfa_fcs_fabric_s *fabric = cbarg;
+
+ bfa_trc(fabric->fcs, status);
+}
+
+/*
+ *
+ * @param[in] fabric - fabric
+ * @param[in] result - 1
+ *
+ * @return - none
+ */
+void
+bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, enum auth_status status)
+{
+ bfa_trc(fabric->fcs, status);
+
+ if (status == FC_AUTH_STATE_SUCCESS)
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_SUCCESS);
+ else
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_FAILED);
+}
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_fcs_fabric_aen_post(struct bfa_fcs_port_s *port,
+ enum bfa_port_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = port->fcs->logm;
+ wwn_t pwwn = bfa_fcs_port_get_pwwn(port);
+ wwn_t fwwn = bfa_fcs_port_get_fabric_name(port);
+ char pwwn_ptr[BFA_STRING_32];
+ char fwwn_ptr[BFA_STRING_32];
+
+ wwn2str(pwwn_ptr, pwwn);
+ wwn2str(fwwn_ptr, fwwn);
+
+ switch (event) {
+ case BFA_PORT_AEN_FABRIC_NAME_CHANGE:
+ bfa_log(logmod, BFA_AEN_PORT_FABRIC_NAME_CHANGE, pwwn_ptr,
+ fwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.port.pwwn = pwwn;
+ aen_data.port.fwwn = fwwn;
+}
+
+/*
+ *
+ * @param[in] fabric - fabric
+ * @param[in] wwn_t - new fabric name
+ *
+ * @return - none
+ */
+void
+bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
+ wwn_t fabric_name)
+{
+ bfa_trc(fabric->fcs, fabric_name);
+
+ if (fabric->fabric_name == 0) {
+ /*
+ * With BRCD switches, we don't get Fabric Name in FLOGI.
+ * Don't generate a fabric name change event in this case.
+ */
+ fabric->fabric_name = fabric_name;
+ } else {
+ fabric->fabric_name = fabric_name;
+ /*
+ * Generate a Event
+ */
+ bfa_fcs_fabric_aen_post(&fabric->bport,
+ BFA_PORT_AEN_FABRIC_NAME_CHANGE);
+ }
+
+}
+
+/**
+ * Not used by FCS.
+ */
+void
+bfa_cb_lps_flogo_comp(void *bfad, void *uarg)
+{
+}
+
+
diff --git a/drivers/scsi/bfa/fcbuild.c b/drivers/scsi/bfa/fcbuild.c
new file mode 100644
index 000000000000..d174706b9caa
--- /dev/null
+++ b/drivers/scsi/bfa/fcbuild.c
@@ -0,0 +1,1449 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+/*
+ * fcbuild.c - FC link service frame building and parsing routines
+ */
+
+#include <bfa_os_inc.h>
+#include "fcbuild.h"
+
+/*
+ * static build functions
+ */
+static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id);
+static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id);
+static struct fchs_s fc_els_req_tmpl;
+static struct fchs_s fc_els_rsp_tmpl;
+static struct fchs_s fc_bls_req_tmpl;
+static struct fchs_s fc_bls_rsp_tmpl;
+static struct fc_ba_acc_s ba_acc_tmpl;
+static struct fc_logi_s plogi_tmpl;
+static struct fc_prli_s prli_tmpl;
+static struct fc_rrq_s rrq_tmpl;
+static struct fchs_s fcp_fchs_tmpl;
+
+void
+fcbuild_init(void)
+{
+ /*
+ * fc_els_req_tmpl
+ */
+ fc_els_req_tmpl.routing = FC_RTG_EXT_LINK;
+ fc_els_req_tmpl.cat_info = FC_CAT_LD_REQUEST;
+ fc_els_req_tmpl.type = FC_TYPE_ELS;
+ fc_els_req_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ FCTL_SI_XFER);
+ fc_els_req_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * fc_els_rsp_tmpl
+ */
+ fc_els_rsp_tmpl.routing = FC_RTG_EXT_LINK;
+ fc_els_rsp_tmpl.cat_info = FC_CAT_LD_REPLY;
+ fc_els_rsp_tmpl.type = FC_TYPE_ELS;
+ fc_els_rsp_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_els_rsp_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * fc_bls_req_tmpl
+ */
+ fc_bls_req_tmpl.routing = FC_RTG_BASIC_LINK;
+ fc_bls_req_tmpl.type = FC_TYPE_BLS;
+ fc_bls_req_tmpl.f_ctl = bfa_os_hton3b(FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_bls_req_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * fc_bls_rsp_tmpl
+ */
+ fc_bls_rsp_tmpl.routing = FC_RTG_BASIC_LINK;
+ fc_bls_rsp_tmpl.cat_info = FC_CAT_BA_ACC;
+ fc_bls_rsp_tmpl.type = FC_TYPE_BLS;
+ fc_bls_rsp_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_bls_rsp_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * ba_acc_tmpl
+ */
+ ba_acc_tmpl.seq_id_valid = 0;
+ ba_acc_tmpl.low_seq_cnt = 0;
+ ba_acc_tmpl.high_seq_cnt = 0xFFFF;
+
+ /*
+ * plogi_tmpl
+ */
+ plogi_tmpl.csp.verhi = FC_PH_VER_PH_3;
+ plogi_tmpl.csp.verlo = FC_PH_VER_4_3;
+ plogi_tmpl.csp.bbcred = bfa_os_htons(0x0004);
+ plogi_tmpl.csp.ciro = 0x1;
+ plogi_tmpl.csp.cisc = 0x0;
+ plogi_tmpl.csp.altbbcred = 0x0;
+ plogi_tmpl.csp.conseq = bfa_os_htons(0x00FF);
+ plogi_tmpl.csp.ro_bitmap = bfa_os_htons(0x0002);
+ plogi_tmpl.csp.e_d_tov = bfa_os_htonl(2000);
+
+ plogi_tmpl.class3.class_valid = 1;
+ plogi_tmpl.class3.sequential = 1;
+ plogi_tmpl.class3.conseq = 0xFF;
+ plogi_tmpl.class3.ospx = 1;
+
+ /*
+ * prli_tmpl
+ */
+ prli_tmpl.command = FC_ELS_PRLI;
+ prli_tmpl.pglen = 0x10;
+ prli_tmpl.pagebytes = bfa_os_htons(0x0014);
+ prli_tmpl.parampage.type = FC_TYPE_FCP;
+ prli_tmpl.parampage.imagepair = 1;
+ prli_tmpl.parampage.servparams.rxrdisab = 1;
+
+ /*
+ * rrq_tmpl
+ */
+ rrq_tmpl.els_cmd.els_code = FC_ELS_RRQ;
+
+ /*
+ * fcp_fchs_tmpl
+ */
+ fcp_fchs_tmpl.routing = FC_RTG_FC4_DEV_DATA;
+ fcp_fchs_tmpl.cat_info = FC_CAT_UNSOLICIT_CMD;
+ fcp_fchs_tmpl.type = FC_TYPE_FCP;
+ fcp_fchs_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER);
+ fcp_fchs_tmpl.seq_id = 1;
+ fcp_fchs_tmpl.rx_id = FC_RXID_ANY;
+}
+
+static void
+fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u32 ox_id)
+{
+ bfa_os_memset(fchs, 0, sizeof(struct fchs_s));
+
+ fchs->routing = FC_RTG_FC4_DEV_DATA;
+ fchs->cat_info = FC_CAT_UNSOLICIT_CTRL;
+ fchs->type = FC_TYPE_SERVICES;
+ fchs->f_ctl =
+ bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ FCTL_SI_XFER);
+ fchs->rx_id = FC_RXID_ANY;
+ fchs->d_id = (d_id);
+ fchs->s_id = (s_id);
+ fchs->ox_id = bfa_os_htons(ox_id);
+
+ /**
+ * @todo no need to set ox_id for request
+ * no need to set rx_id for response
+ */
+}
+
+void
+fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s));
+ fchs->d_id = (d_id);
+ fchs->s_id = (s_id);
+ fchs->ox_id = bfa_os_htons(ox_id);
+}
+
+static void
+fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s));
+ fchs->d_id = d_id;
+ fchs->s_id = s_id;
+ fchs->ox_id = ox_id;
+}
+
+enum fc_parse_status
+fc_els_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+ struct fc_ls_rjt_s *ls_rjt = (struct fc_ls_rjt_s *) els_cmd;
+
+ len = len;
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_LS_RJT:
+ if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY)
+ return (FC_PARSE_BUSY);
+ else
+ return (FC_PARSE_FAILURE);
+
+ case FC_ELS_ACC:
+ return (FC_PARSE_OK);
+ }
+ return (FC_PARSE_OK);
+}
+
+static void
+fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s));
+ fchs->d_id = d_id;
+ fchs->s_id = s_id;
+ fchs->ox_id = ox_id;
+}
+
+static u16
+fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size, u8 els_code)
+{
+ struct fc_logi_s *plogi = (struct fc_logi_s *) (pld);
+
+ bfa_os_memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ plogi->els_cmd.els_code = els_code;
+ if (els_code == FC_ELS_PLOGI)
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ else
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ plogi->csp.rxsz = plogi->class3.rxsz = bfa_os_htons(pdu_size);
+
+ bfa_os_memcpy(&plogi->port_name, &port_name, sizeof(wwn_t));
+ bfa_os_memcpy(&plogi->node_name, &node_name, sizeof(wwn_t));
+
+ return (sizeof(struct fc_logi_s));
+}
+
+u16
+fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size, u8 set_npiv, u8 set_auth,
+ u16 local_bb_credits)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
+ u32 *vvl_info;
+
+ bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ flogi->els_cmd.els_code = FC_ELS_FLOGI;
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->port_name = port_name;
+ flogi->node_name = node_name;
+
+ /*
+ * Set the NPIV Capability Bit ( word 1, bit 31) of Common
+ * Service Parameters.
+ */
+ flogi->csp.ciro = set_npiv;
+
+ /* set AUTH capability */
+ flogi->csp.security = set_auth;
+
+ flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+
+ /* Set brcd token in VVL */
+ vvl_info = (u32 *)&flogi->vvl[0];
+
+ /* set the flag to indicate the presence of VVL */
+ flogi->csp.npiv_supp = 1; /* @todo. field name is not correct */
+ vvl_info[0] = bfa_os_htonl(FLOGI_VVL_BRCD);
+
+ return (sizeof(struct fc_logi_s));
+}
+
+u16
+fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size, u16 local_bb_credits)
+{
+ u32 d_id = 0;
+
+ bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ flogi->els_cmd.els_code = FC_ELS_ACC;
+ flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->port_name = port_name;
+ flogi->node_name = node_name;
+
+ flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+
+ return (sizeof(struct fc_logi_s));
+}
+
+u16
+fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
+
+ bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ flogi->els_cmd.els_code = FC_ELS_FDISC;
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->port_name = port_name;
+ flogi->node_name = node_name;
+
+ return (sizeof(struct fc_logi_s));
+}
+
+u16
+fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name,
+ node_name, pdu_size, FC_ELS_PLOGI);
+}
+
+u16
+fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name,
+ node_name, pdu_size, FC_ELS_ACC);
+}
+
+enum fc_parse_status
+fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+ struct fc_logi_s *plogi;
+ struct fc_ls_rjt_s *ls_rjt;
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_LS_RJT:
+ ls_rjt = (struct fc_ls_rjt_s *) (fchs + 1);
+ if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY)
+ return (FC_PARSE_BUSY);
+ else
+ return (FC_PARSE_FAILURE);
+ case FC_ELS_ACC:
+ plogi = (struct fc_logi_s *) (fchs + 1);
+ if (len < sizeof(struct fc_logi_s))
+ return (FC_PARSE_FAILURE);
+
+ if (!wwn_is_equal(plogi->port_name, port_name))
+ return (FC_PARSE_FAILURE);
+
+ if (!plogi->class3.class_valid)
+ return (FC_PARSE_FAILURE);
+
+ if (bfa_os_ntohs(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
+ return (FC_PARSE_FAILURE);
+
+ return (FC_PARSE_OK);
+ default:
+ return (FC_PARSE_FAILURE);
+ }
+}
+
+enum fc_parse_status
+fc_plogi_parse(struct fchs_s *fchs)
+{
+ struct fc_logi_s *plogi = (struct fc_logi_s *) (fchs + 1);
+
+ if (plogi->class3.class_valid != 1)
+ return FC_PARSE_FAILURE;
+
+ if ((bfa_os_ntohs(plogi->class3.rxsz) < FC_MIN_PDUSZ)
+ || (bfa_os_ntohs(plogi->class3.rxsz) > FC_MAX_PDUSZ)
+ || (plogi->class3.rxsz == 0))
+ return (FC_PARSE_FAILURE);
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+
+ prli->command = FC_ELS_PRLI;
+ prli->parampage.servparams.initiator = 1;
+ prli->parampage.servparams.retry = 1;
+ prli->parampage.servparams.rec_support = 1;
+ prli->parampage.servparams.task_retry_id = 0;
+ prli->parampage.servparams.confirm = 1;
+
+ return (sizeof(struct fc_prli_s));
+}
+
+u16
+fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, enum bfa_port_role role)
+{
+ struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+ bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+
+ prli->command = FC_ELS_ACC;
+
+ if ((role & BFA_PORT_ROLE_FCP_TM) == BFA_PORT_ROLE_FCP_TM)
+ prli->parampage.servparams.target = 1;
+ else
+ prli->parampage.servparams.initiator = 1;
+
+ prli->parampage.rspcode = FC_PRLI_ACC_XQTD;
+
+ return (sizeof(struct fc_prli_s));
+}
+
+enum fc_parse_status
+fc_prli_rsp_parse(struct fc_prli_s *prli, int len)
+{
+ if (len < sizeof(struct fc_prli_s))
+ return (FC_PARSE_FAILURE);
+
+ if (prli->command != FC_ELS_ACC)
+ return (FC_PARSE_FAILURE);
+
+ if ((prli->parampage.rspcode != FC_PRLI_ACC_XQTD)
+ && (prli->parampage.rspcode != FC_PRLI_ACC_PREDEF_IMG))
+ return (FC_PARSE_FAILURE);
+
+ if (prli->parampage.servparams.target != 1)
+ return (FC_PARSE_FAILURE);
+
+ return (FC_PARSE_OK);
+}
+
+enum fc_parse_status
+fc_prli_parse(struct fc_prli_s *prli)
+{
+ if (prli->parampage.type != FC_TYPE_FCP)
+ return (FC_PARSE_FAILURE);
+
+ if (!prli->parampage.imagepair)
+ return (FC_PARSE_FAILURE);
+
+ if (!prli->parampage.servparams.initiator)
+ return (FC_PARSE_FAILURE);
+
+ return (FC_PARSE_OK);
+}
+
+u16
+fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ memset(logo, '\0', sizeof(struct fc_logo_s));
+ logo->els_cmd.els_code = FC_ELS_LOGO;
+ logo->nport_id = (s_id);
+ logo->orig_port_name = port_name;
+
+ return (sizeof(struct fc_logo_s));
+}
+
+static u16
+fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u8 els_code)
+{
+ memset(adisc, '\0', sizeof(struct fc_adisc_s));
+
+ adisc->els_cmd.els_code = els_code;
+
+ if (els_code == FC_ELS_ADISC)
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ else
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ adisc->orig_HA = 0;
+ adisc->orig_port_name = port_name;
+ adisc->orig_node_name = node_name;
+ adisc->nport_id = (s_id);
+
+ return (sizeof(struct fc_adisc_s));
+}
+
+u16
+fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name)
+{
+ return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
+ node_name, FC_ELS_ADISC);
+}
+
+u16
+fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name)
+{
+ return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
+ node_name, FC_ELS_ACC);
+}
+
+enum fc_parse_status
+fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name,
+ wwn_t node_name)
+{
+
+ if (len < sizeof(struct fc_adisc_s))
+ return (FC_PARSE_FAILURE);
+
+ if (adisc->els_cmd.els_code != FC_ELS_ACC)
+ return (FC_PARSE_FAILURE);
+
+ if (!wwn_is_equal(adisc->orig_port_name, port_name))
+ return (FC_PARSE_FAILURE);
+
+ return (FC_PARSE_OK);
+}
+
+enum fc_parse_status
+fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap,
+ wwn_t node_name, wwn_t port_name)
+{
+ struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld;
+
+ if (adisc->els_cmd.els_code != FC_ELS_ACC)
+ return (FC_PARSE_FAILURE);
+
+ if ((adisc->nport_id == (host_dap))
+ && wwn_is_equal(adisc->orig_port_name, port_name)
+ && wwn_is_equal(adisc->orig_node_name, node_name))
+ return (FC_PARSE_OK);
+
+ return (FC_PARSE_FAILURE);
+}
+
+enum fc_parse_status
+fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
+{
+ struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
+
+ if (pdisc->class3.class_valid != 1)
+ return FC_PARSE_FAILURE;
+
+ if ((bfa_os_ntohs(pdisc->class3.rxsz) <
+ (FC_MIN_PDUSZ - sizeof(struct fchs_s)))
+ || (pdisc->class3.rxsz == 0))
+ return (FC_PARSE_FAILURE);
+
+ if (!wwn_is_equal(pdisc->port_name, port_name))
+ return (FC_PARSE_FAILURE);
+
+ if (!wwn_is_equal(pdisc->node_name, node_name))
+ return (FC_PARSE_FAILURE);
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s));
+ fchs->cat_info = FC_CAT_ABTS;
+ fchs->d_id = (d_id);
+ fchs->s_id = (s_id);
+ fchs->ox_id = bfa_os_htons(ox_id);
+
+ return (sizeof(struct fchs_s));
+}
+
+enum fc_parse_status
+fc_abts_rsp_parse(struct fchs_s *fchs, int len)
+{
+ if ((fchs->cat_info == FC_CAT_BA_ACC)
+ || (fchs->cat_info == FC_CAT_BA_RJT))
+ return (FC_PARSE_OK);
+
+ return (FC_PARSE_FAILURE);
+}
+
+u16
+fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id,
+ u32 s_id, u16 ox_id, u16 rrq_oxid)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ /*
+ * build rrq payload
+ */
+ bfa_os_memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s));
+ rrq->s_id = (s_id);
+ rrq->ox_id = bfa_os_htons(rrq_oxid);
+ rrq->rx_id = FC_RXID_ANY;
+
+ return (sizeof(struct fc_rrq_s));
+}
+
+u16
+fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ struct fc_els_cmd_s *acc = pld;
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ memset(acc, 0, sizeof(struct fc_els_cmd_s));
+ acc->els_code = FC_ELS_ACC;
+
+ return (sizeof(struct fc_els_cmd_s));
+}
+
+u16
+fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
+ u32 s_id, u16 ox_id, u8 reason_code,
+ u8 reason_code_expl)
+{
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+ memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s));
+
+ ls_rjt->els_cmd.els_code = FC_ELS_LS_RJT;
+ ls_rjt->reason_code = reason_code;
+ ls_rjt->reason_code_expl = reason_code_expl;
+ ls_rjt->vendor_unique = 0x00;
+
+ return (sizeof(struct fc_ls_rjt_s));
+}
+
+u16
+fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
+ u32 s_id, u16 ox_id, u16 rx_id)
+{
+ fc_bls_rsp_build(fchs, d_id, s_id, ox_id);
+
+ bfa_os_memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s));
+
+ fchs->rx_id = rx_id;
+
+ ba_acc->ox_id = fchs->ox_id;
+ ba_acc->rx_id = fchs->rx_id;
+
+ return (sizeof(struct fc_ba_acc_s));
+}
+
+u16
+fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
+ u32 d_id, u32 s_id, u16 ox_id)
+{
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+ memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
+ els_cmd->els_code = FC_ELS_ACC;
+
+ return (sizeof(struct fc_els_cmd_s));
+}
+
+int
+fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code)
+{
+ int num_pages = 0;
+ struct fc_prlo_s *prlo;
+ struct fc_tprlo_s *tprlo;
+
+ if (els_code == FC_ELS_PRLO) {
+ prlo = (struct fc_prlo_s *) (fc_frame + 1);
+ num_pages = (bfa_os_ntohs(prlo->payload_len) - 4) / 16;
+ } else {
+ tprlo = (struct fc_tprlo_s *) (fc_frame + 1);
+ num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
+ }
+ return num_pages;
+}
+
+u16
+fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages)
+{
+ int page;
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ memset(tprlo_acc, 0, (num_pages * 16) + 4);
+ tprlo_acc->command = FC_ELS_ACC;
+
+ tprlo_acc->page_len = 0x10;
+ tprlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ tprlo_acc->tprlo_acc_params[page].opa_valid = 0;
+ tprlo_acc->tprlo_acc_params[page].rpa_valid = 0;
+ tprlo_acc->tprlo_acc_params[page].fc4type_csp = FC_TYPE_FCP;
+ tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0;
+ tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0;
+ }
+ return (bfa_os_ntohs(tprlo_acc->payload_len));
+}
+
+u16
+fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages)
+{
+ int page;
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ memset(prlo_acc, 0, (num_pages * 16) + 4);
+ prlo_acc->command = FC_ELS_ACC;
+ prlo_acc->page_len = 0x10;
+ prlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ prlo_acc->prlo_acc_params[page].opa_valid = 0;
+ prlo_acc->prlo_acc_params[page].rpa_valid = 0;
+ prlo_acc->prlo_acc_params[page].fc4type_csp = FC_TYPE_FCP;
+ prlo_acc->prlo_acc_params[page].orig_process_assc = 0;
+ prlo_acc->prlo_acc_params[page].resp_process_assc = 0;
+ }
+
+ return (bfa_os_ntohs(prlo_acc->payload_len));
+}
+
+u16
+fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id,
+ u32 s_id, u16 ox_id, u32 data_format)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ memset(rnid, 0, sizeof(struct fc_rnid_cmd_s));
+
+ rnid->els_cmd.els_code = FC_ELS_RNID;
+ rnid->node_id_data_format = data_format;
+
+ return (sizeof(struct fc_rnid_cmd_s));
+}
+
+u16
+fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u32 data_format,
+ struct fc_rnid_common_id_data_s *common_id_data,
+ struct fc_rnid_general_topology_data_s *gen_topo_data)
+{
+ memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s));
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ rnid_acc->els_cmd.els_code = FC_ELS_ACC;
+ rnid_acc->node_id_data_format = data_format;
+ rnid_acc->common_id_data_length =
+ sizeof(struct fc_rnid_common_id_data_s);
+ rnid_acc->common_id_data = *common_id_data;
+
+ if (data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
+ rnid_acc->specific_id_data_length =
+ sizeof(struct fc_rnid_general_topology_data_s);
+ bfa_os_assign(rnid_acc->gen_topology_data, *gen_topo_data);
+ return (sizeof(struct fc_rnid_acc_s));
+ } else {
+ return (sizeof(struct fc_rnid_acc_s) -
+ sizeof(struct fc_rnid_general_topology_data_s));
+ }
+
+}
+
+u16
+fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id,
+ u32 s_id, u16 ox_id)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s));
+
+ rpsc->els_cmd.els_code = FC_ELS_RPSC;
+ return (sizeof(struct fc_rpsc_cmd_s));
+}
+
+u16
+fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2,
+ u32 d_id, u32 s_id, u32 *pid_list,
+ u16 npids)
+{
+ u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_os_hton3b(d_id));
+ int i = 0;
+
+ fc_els_req_build(fchs, bfa_os_hton3b(dctlr_id), s_id, 0);
+
+ memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s));
+
+ rpsc2->els_cmd.els_code = FC_ELS_RPSC;
+ rpsc2->token = bfa_os_htonl(FC_BRCD_TOKEN);
+ rpsc2->num_pids = bfa_os_htons(npids);
+ for (i = 0; i < npids; i++)
+ rpsc2->pid_list[i].pid = pid_list[i];
+
+ return (sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) *
+ (sizeof(u32))));
+}
+
+u16
+fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ struct fc_rpsc_speed_info_s *oper_speed)
+{
+ memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s));
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ rpsc_acc->command = FC_ELS_ACC;
+ rpsc_acc->num_entries = bfa_os_htons(1);
+
+ rpsc_acc->speed_info[0].port_speed_cap =
+ bfa_os_htons(oper_speed->port_speed_cap);
+
+ rpsc_acc->speed_info[0].port_op_speed =
+ bfa_os_htons(oper_speed->port_op_speed);
+
+ return (sizeof(struct fc_rpsc_acc_s));
+
+}
+
+/*
+ * TBD -
+ * . get rid of unnecessary memsets
+ */
+
+u16
+fc_logo_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ len = len;
+ if (els_cmd->els_code != FC_ELS_ACC)
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
+
+ bfa_os_memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ pdisc->els_cmd.els_code = FC_ELS_PDISC;
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ pdisc->csp.rxsz = pdisc->class3.rxsz = bfa_os_htons(pdu_size);
+ pdisc->port_name = port_name;
+ pdisc->node_name = node_name;
+
+ return (sizeof(struct fc_logi_s));
+}
+
+u16
+fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
+{
+ struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
+
+ if (len < sizeof(struct fc_logi_s))
+ return (FC_PARSE_LEN_INVAL);
+
+ if (pdisc->els_cmd.els_code != FC_ELS_ACC)
+ return (FC_PARSE_ACC_INVAL);
+
+ if (!wwn_is_equal(pdisc->port_name, port_name))
+ return (FC_PARSE_PWWN_NOT_EQUAL);
+
+ if (!pdisc->class3.class_valid)
+ return (FC_PARSE_NWWN_NOT_EQUAL);
+
+ if (bfa_os_ntohs(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
+ return (FC_PARSE_RXSZ_INVAL);
+
+ return (FC_PARSE_OK);
+}
+
+u16
+fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages)
+{
+ struct fc_prlo_s *prlo = (struct fc_prlo_s *) (fchs + 1);
+ int page;
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ memset(prlo, 0, (num_pages * 16) + 4);
+ prlo->command = FC_ELS_PRLO;
+ prlo->page_len = 0x10;
+ prlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ prlo->prlo_params[page].type = FC_TYPE_FCP;
+ prlo->prlo_params[page].opa_valid = 0;
+ prlo->prlo_params[page].rpa_valid = 0;
+ prlo->prlo_params[page].orig_process_assc = 0;
+ prlo->prlo_params[page].resp_process_assc = 0;
+ }
+
+ return (bfa_os_ntohs(prlo->payload_len));
+}
+
+u16
+fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_prlo_acc_s *prlo = (struct fc_prlo_acc_s *) (fchs + 1);
+ int num_pages = 0;
+ int page = 0;
+
+ len = len;
+
+ if (prlo->command != FC_ELS_ACC)
+ return (FC_PARSE_FAILURE);
+
+ num_pages = ((bfa_os_ntohs(prlo->payload_len)) - 4) / 16;
+
+ for (page = 0; page < num_pages; page++) {
+ if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].opa_valid != 0)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].rpa_valid != 0)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].orig_process_assc != 0)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].resp_process_assc != 0)
+ return FC_PARSE_FAILURE;
+ }
+ return (FC_PARSE_OK);
+
+}
+
+u16
+fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, int num_pages,
+ enum fc_tprlo_type tprlo_type, u32 tpr_id)
+{
+ struct fc_tprlo_s *tprlo = (struct fc_tprlo_s *) (fchs + 1);
+ int page;
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ memset(tprlo, 0, (num_pages * 16) + 4);
+ tprlo->command = FC_ELS_TPRLO;
+ tprlo->page_len = 0x10;
+ tprlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ tprlo->tprlo_params[page].type = FC_TYPE_FCP;
+ tprlo->tprlo_params[page].opa_valid = 0;
+ tprlo->tprlo_params[page].rpa_valid = 0;
+ tprlo->tprlo_params[page].orig_process_assc = 0;
+ tprlo->tprlo_params[page].resp_process_assc = 0;
+ if (tprlo_type == FC_GLOBAL_LOGO) {
+ tprlo->tprlo_params[page].global_process_logout = 1;
+ } else if (tprlo_type == FC_TPR_LOGO) {
+ tprlo->tprlo_params[page].tpo_nport_valid = 1;
+ tprlo->tprlo_params[page].tpo_nport_id = (tpr_id);
+ }
+ }
+
+ return (bfa_os_ntohs(tprlo->payload_len));
+}
+
+u16
+fc_tprlo_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_tprlo_acc_s *tprlo = (struct fc_tprlo_acc_s *) (fchs + 1);
+ int num_pages = 0;
+ int page = 0;
+
+ len = len;
+
+ if (tprlo->command != FC_ELS_ACC)
+ return (FC_PARSE_ACC_INVAL);
+
+ num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
+
+ for (page = 0; page < num_pages; page++) {
+ if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP)
+ return (FC_PARSE_NOT_FCP);
+ if (tprlo->tprlo_acc_params[page].opa_valid != 0)
+ return (FC_PARSE_OPAFLAG_INVAL);
+ if (tprlo->tprlo_acc_params[page].rpa_valid != 0)
+ return (FC_PARSE_RPAFLAG_INVAL);
+ if (tprlo->tprlo_acc_params[page].orig_process_assc != 0)
+ return (FC_PARSE_OPA_INVAL);
+ if (tprlo->tprlo_acc_params[page].resp_process_assc != 0)
+ return (FC_PARSE_RPA_INVAL);
+ }
+ return (FC_PARSE_OK);
+}
+
+enum fc_parse_status
+fc_rrq_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ len = len;
+ if (els_cmd->els_code != FC_ELS_ACC)
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, u32 reason_code,
+ u32 reason_expl)
+{
+ struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1);
+
+ fc_bls_rsp_build(fchs, d_id, s_id, ox_id);
+
+ fchs->cat_info = FC_CAT_BA_RJT;
+ ba_rjt->reason_code = reason_code;
+ ba_rjt->reason_expl = reason_expl;
+ return (sizeof(struct fc_ba_rjt_s));
+}
+
+static void
+fc_gs_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
+{
+ bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ cthdr->rev_id = CT_GS3_REVISION;
+ cthdr->gs_type = CT_GSTYPE_DIRSERVICE;
+ cthdr->gs_sub_type = CT_GSSUBTYPE_NAMESERVER;
+ cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+}
+
+static void
+fc_gs_fdmi_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
+{
+ bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ cthdr->rev_id = CT_GS3_REVISION;
+ cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
+ cthdr->gs_sub_type = CT_GSSUBTYPE_HBA_MGMTSERVER;
+ cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+}
+
+static void
+fc_gs_ms_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code,
+ u8 sub_type)
+{
+ bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ cthdr->rev_id = CT_GS3_REVISION;
+ cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
+ cthdr->gs_sub_type = sub_type;
+ cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+}
+
+u16
+fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ wwn_t port_name)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_gidpn_req_s *gidpn =
+ (struct fcgs_gidpn_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GID_PN);
+
+ bfa_os_memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s));
+ gidpn->port_name = port_name;
+ return (sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u32 port_id)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gpnid_req_t *gpnid = (fcgs_gpnid_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GPN_ID);
+
+ bfa_os_memset(gpnid, 0, sizeof(fcgs_gpnid_req_t));
+ gpnid->dap = port_id;
+ return (sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u32 port_id)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GNN_ID);
+
+ bfa_os_memset(gnnid, 0, sizeof(fcgs_gnnid_req_t));
+ gnnid->dap = port_id;
+ return (sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_ct_rsp_parse(struct ct_hdr_s *cthdr)
+{
+ if (bfa_os_ntohs(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) {
+ if (cthdr->reason_code == CT_RSN_LOGICAL_BUSY)
+ return FC_PARSE_BUSY;
+ else
+ return FC_PARSE_FAILURE;
+ }
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg,
+ u32 s_id, u16 ox_id)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ bfa_os_memset(scr, 0, sizeof(struct fc_scr_s));
+ scr->command = FC_ELS_SCR;
+ scr->reg_func = FC_SCR_REG_FUNC_FULL;
+ if (set_br_reg)
+ scr->vu_reg_func = FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE;
+
+ return (sizeof(struct fc_scr_s));
+}
+
+u16
+fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id,
+ u16 ox_id)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+ u16 payldlen;
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ rscn->command = FC_ELS_RSCN;
+ rscn->pagelen = sizeof(rscn->event[0]);
+
+ payldlen = sizeof(u32) + rscn->pagelen;
+ rscn->payldlen = bfa_os_htons(payldlen);
+
+ rscn->event[0].format = FC_RSCN_FORMAT_PORTID;
+ rscn->event[0].portid = s_id;
+
+ return (sizeof(struct fc_rscn_pl_s));
+}
+
+u16
+fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ enum bfa_port_role roles)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rftid_req_s *rftid =
+ (struct fcgs_rftid_req_s *) (cthdr + 1);
+ u32 type_value, d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u8 index;
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
+
+ bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+
+ rftid->dap = s_id;
+
+ /* By default, FCP FC4 Type is registered */
+ index = FC_TYPE_FCP >> 5;
+ type_value = 1 << (FC_TYPE_FCP % 32);
+ rftid->fc4_type[index] = bfa_os_htonl(type_value);
+
+ if (roles & BFA_PORT_ROLE_FCP_IPFC) {
+ index = FC_TYPE_IP >> 5;
+ type_value = 1 << (FC_TYPE_IP % 32);
+ rftid->fc4_type[index] |= bfa_os_htonl(type_value);
+ }
+
+ return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u8 *fc4_bitmap,
+ u32 bitmap_size)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rftid_req_s *rftid =
+ (struct fcgs_rftid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
+
+ bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+
+ rftid->dap = s_id;
+ bfa_os_memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap,
+ (bitmap_size < 32 ? bitmap_size : 32));
+
+ return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u8 fc4_type, u8 fc4_ftrs)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rffid_req_s *rffid =
+ (struct fcgs_rffid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RFF_ID);
+
+ bfa_os_memset(rffid, 0, sizeof(struct fcgs_rffid_req_s));
+
+ rffid->dap = s_id;
+ rffid->fc4ftr_bits = fc4_ftrs;
+ rffid->fc4_type = fc4_type;
+
+ return (sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u8 *name)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rspnid_req_s *rspnid =
+ (struct fcgs_rspnid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RSPN_ID);
+
+ bfa_os_memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
+
+ rspnid->dap = s_id;
+ rspnid->spn_len = (u8) strlen((char *)name);
+ strncpy((char *)rspnid->spn, (char *)name, rspnid->spn_len);
+
+ return (sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u8 fc4_type)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_gidft_req_s *gidft =
+ (struct fcgs_gidft_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+
+ fc_gs_cthdr_build(cthdr, s_id, GS_GID_FT);
+
+ bfa_os_memset(gidft, 0, sizeof(struct fcgs_gidft_req_s));
+ gidft->fc4_type = fc4_type;
+ gidft->domain_id = 0;
+ gidft->area_id = 0;
+
+ return (sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ wwn_t port_name)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rpnid_req_s *rpnid =
+ (struct fcgs_rpnid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID);
+
+ bfa_os_memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s));
+ rpnid->port_id = port_id;
+ rpnid->port_name = port_name;
+
+ return (sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ wwn_t node_name)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rnnid_req_s *rnnid =
+ (struct fcgs_rnnid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RNN_ID);
+
+ bfa_os_memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s));
+ rnnid->port_id = port_id;
+ rnnid->node_name = node_name;
+
+ return (sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ u32 cos)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rcsid_req_s *rcsid =
+ (struct fcgs_rcsid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID);
+
+ bfa_os_memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s));
+ rcsid->port_id = port_id;
+ rcsid->cos = cos;
+
+ return (sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ u8 port_type)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rptid_req_s *rptid =
+ (struct fcgs_rptid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID);
+
+ bfa_os_memset(rptid, 0, sizeof(struct fcgs_rptid_req_s));
+ rptid->port_id = port_id;
+ rptid->port_type = port_type;
+
+ return (sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s));
+}
+
+u16
+fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_ganxt_req_s *ganxt =
+ (struct fcgs_ganxt_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT);
+
+ bfa_os_memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s));
+ ganxt->port_id = port_id;
+
+ return (sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s));
+}
+
+/*
+ * Builds fc hdr and ct hdr for FDMI requests.
+ */
+u16
+fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 cmd_code)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_fdmi_cthdr_build(cthdr, s_id, cmd_code);
+
+ return (sizeof(struct ct_hdr_s));
+}
+
+/*
+ * Given a FC4 Type, this function returns a fc4 type bitmask
+ */
+void
+fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask)
+{
+ u8 index;
+ u32 *ptr = (u32 *) bit_mask;
+ u32 type_value;
+
+ /*
+ * @todo : Check for bitmask size
+ */
+
+ index = fc4_type >> 5;
+ type_value = 1 << (fc4_type % 32);
+ ptr[index] = bfa_os_htonl(type_value);
+
+}
+
+/*
+ * GMAL Request
+ */
+u16
+fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gmal_req_t *gmal = (fcgs_gmal_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GMAL_CMD,
+ CT_GSSUBTYPE_CFGSERVER);
+
+ bfa_os_memset(gmal, 0, sizeof(fcgs_gmal_req_t));
+ gmal->wwn = wwn;
+
+ return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t));
+}
+
+/*
+ * GFN (Get Fabric Name) Request
+ */
+u16
+fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gfn_req_t *gfn = (fcgs_gfn_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GFN_CMD,
+ CT_GSSUBTYPE_CFGSERVER);
+
+ bfa_os_memset(gfn, 0, sizeof(fcgs_gfn_req_t));
+ gfn->wwn = wwn;
+
+ return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t));
+}
diff --git a/drivers/scsi/bfa/fcbuild.h b/drivers/scsi/bfa/fcbuild.h
new file mode 100644
index 000000000000..4d248424f7b3
--- /dev/null
+++ b/drivers/scsi/bfa/fcbuild.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+/*
+ * fcbuild.h - FC link service frame building and parsing routines
+ */
+
+#ifndef __FCBUILD_H__
+#define __FCBUILD_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/fc.h>
+#include <protocol/fcp.h>
+#include <protocol/ct.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_pport.h>
+
+/*
+ * Utility Macros/functions
+ */
+
+#define fcif_sof_set(_ifhdr, _sof) (_ifhdr)->sof = FC_ ## _sof
+#define fcif_eof_set(_ifhdr, _eof) (_ifhdr)->eof = FC_ ## _eof
+
+#define wwn_is_equal(_wwn1, _wwn2) \
+ (memcmp(&(_wwn1), &(_wwn2), sizeof(wwn_t)) == 0)
+
+#define fc_roundup(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1))
+
+/*
+ * Given the fc response length, this routine will return
+ * the length of the actual payload bytes following the CT header.
+ *
+ * Assumes the input response length does not include the crc, eof, etc.
+ */
+static inline u32
+fc_get_ctresp_pyld_len(u32 resp_len)
+{
+ return (resp_len - sizeof(struct ct_hdr_s));
+}
+
+/*
+ * Convert bfa speed to rpsc speed value.
+ */
+static inline enum bfa_pport_speed
+fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed_s speed)
+{
+ switch (speed) {
+
+ case RPSC_OP_SPEED_1G:
+ return BFA_PPORT_SPEED_1GBPS;
+
+ case RPSC_OP_SPEED_2G:
+ return BFA_PPORT_SPEED_2GBPS;
+
+ case RPSC_OP_SPEED_4G:
+ return BFA_PPORT_SPEED_4GBPS;
+
+ case RPSC_OP_SPEED_8G:
+ return BFA_PPORT_SPEED_8GBPS;
+
+ default:
+ return BFA_PPORT_SPEED_UNKNOWN;
+ }
+}
+
+/*
+ * Convert RPSC speed to bfa speed value.
+ */
+static inline enum fc_rpsc_op_speed_s
+fc_bfa_speed_to_rpsc_operspeed(enum bfa_pport_speed op_speed)
+{
+ switch (op_speed) {
+
+ case BFA_PPORT_SPEED_1GBPS:
+ return RPSC_OP_SPEED_1G;
+
+ case BFA_PPORT_SPEED_2GBPS:
+ return RPSC_OP_SPEED_2G;
+
+ case BFA_PPORT_SPEED_4GBPS:
+ return RPSC_OP_SPEED_4G;
+
+ case BFA_PPORT_SPEED_8GBPS:
+ return RPSC_OP_SPEED_8G;
+
+ default:
+ return RPSC_OP_SPEED_NOT_EST;
+ }
+}
+enum fc_parse_status {
+ FC_PARSE_OK = 0,
+ FC_PARSE_FAILURE = 1,
+ FC_PARSE_BUSY = 2,
+ FC_PARSE_LEN_INVAL,
+ FC_PARSE_ACC_INVAL,
+ FC_PARSE_PWWN_NOT_EQUAL,
+ FC_PARSE_NWWN_NOT_EQUAL,
+ FC_PARSE_RXSZ_INVAL,
+ FC_PARSE_NOT_FCP,
+ FC_PARSE_OPAFLAG_INVAL,
+ FC_PARSE_RPAFLAG_INVAL,
+ FC_PARSE_OPA_INVAL,
+ FC_PARSE_RPA_INVAL,
+
+};
+
+struct fc_templates_s {
+ struct fchs_s fc_els_req;
+ struct fchs_s fc_bls_req;
+ struct fc_logi_s plogi;
+ struct fc_rrq_s rrq;
+};
+
+void fcbuild_init(void);
+
+u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size, u8 set_npiv,
+ u8 set_auth, u16 local_bb_credits);
+u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size);
+u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size,
+ u16 local_bb_credits);
+u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size);
+enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs);
+u16 fc_abts_build(struct fchs_s *buf, u32 d_id, u32 s_id,
+ u16 ox_id);
+enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len);
+u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id,
+ u32 s_id, u16 ox_id, u16 rrq_oxid);
+enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len);
+u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u16 ox_id, u8 *name);
+u16 fc_rftid_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u16 ox_id, enum bfa_port_role role);
+u16 fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u8 *fc4_bitmap,
+ u32 bitmap_size);
+u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u8 fc4_type, u8 fc4_ftrs);
+u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, wwn_t port_name);
+u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u16 ox_id, u32 port_id);
+u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr,
+ u8 set_br_reg, u32 s_id, u16 ox_id);
+u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id,
+ wwn_t port_name, wwn_t node_name, u16 pdu_size);
+
+u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ wwn_t port_name, wwn_t node_name);
+enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld,
+ u32 host_dap,
+ wwn_t node_name, wwn_t port_name);
+enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len,
+ wwn_t port_name, wwn_t node_name);
+u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ wwn_t port_name, wwn_t node_name);
+u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u8 reason_code, u8 reason_code_expl);
+u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
+ u32 d_id, u32 s_id, u16 ox_id);
+u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id);
+enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len);
+
+u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id,
+ enum bfa_port_role role);
+u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u32 data_format);
+u16 fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u32 data_format,
+ struct fc_rnid_common_id_data_s *common_id_data,
+ struct fc_rnid_general_topology_data_s *
+ gen_topo_data);
+u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rps2c,
+ u32 d_id, u32 s_id,
+ u32 *pid_list, u16 npids);
+u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc,
+ u32 d_id, u32 s_id, u16 ox_id);
+u16 fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ struct fc_rpsc_speed_info_s *oper_speed);
+u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u8 fc4_type);
+u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, wwn_t port_name);
+u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, wwn_t node_name);
+u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, u32 cos);
+u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, u8 port_type);
+u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id);
+u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo,
+ u32 d_id, u32 s_id, u16 ox_id,
+ wwn_t port_name);
+u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id);
+u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 cmd_code);
+u16 fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ wwn_t wwn);
+u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ wwn_t wwn);
+void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask);
+void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id);
+enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len);
+enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len,
+ wwn_t port_name);
+enum fc_parse_status fc_prli_parse(struct fc_prli_s *prli);
+enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name,
+ wwn_t port_name);
+u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u16 rx_id);
+int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code);
+u16 fc_tprlo_acc_build(struct fchs_s *fchs,
+ struct fc_tprlo_acc_s *tprlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages);
+u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages);
+u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len);
+u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size);
+u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name);
+u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, int num_pages);
+u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len);
+u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, int num_pages,
+ enum fc_tprlo_type tprlo_type, u32 tpr_id);
+u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len);
+u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, u32 reason_code,
+ u32 reason_expl);
+u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u32 port_id);
+u16 fc_ct_rsp_parse(struct ct_hdr_s *cthdr);
+u16 fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn,
+ u32 s_id, u16 ox_id);
+#endif
diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c
new file mode 100644
index 000000000000..8ce5d8934677
--- /dev/null
+++ b/drivers/scsi/bfa/fcpim.c
@@ -0,0 +1,844 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcpim.c - FCP initiator mode i-t nexus state machine
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_fcpim.h"
+#include "fcs_rport.h"
+#include "fcs_lport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include <fcs/bfa_fcs_fcpim.h>
+#include <fcb/bfa_fcb_fcpim.h>
+#include <aen/bfa_aen_itnim.h>
+
+BFA_TRC_FILE(FCS, FCPIM);
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_itnim_timeout(void *arg);
+static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
+static void bfa_fcs_itnim_send_prli(void *itnim_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_itnim_prli_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_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_itnim_aen_event event);
+
+/**
+ * fcs_itnim_sm FCS itnim state machine events
+ */
+
+enum bfa_fcs_itnim_event {
+ BFA_FCS_ITNIM_SM_ONLINE = 1, /* rport online event */
+ BFA_FCS_ITNIM_SM_OFFLINE = 2, /* rport offline */
+ BFA_FCS_ITNIM_SM_FRMSENT = 3, /* prli frame is sent */
+ BFA_FCS_ITNIM_SM_RSP_OK = 4, /* good response */
+ BFA_FCS_ITNIM_SM_RSP_ERROR = 5, /* error response */
+ BFA_FCS_ITNIM_SM_TIMEOUT = 6, /* delay timeout */
+ BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */
+ BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */
+ BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */
+ BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */
+ BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */
+};
+
+static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+
+static struct bfa_sm_table_s itnim_sm_table[] = {
+ {BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND},
+ {BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT},
+ {BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY},
+ {BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
+};
+
+/**
+ * fcs_itnim_sm FCS itnim state machine
+ */
+
+static void
+bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_ONLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+ bfa_fcs_itnim_send_prli(itnim, NULL);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+
+}
+
+static void
+bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_FRMSENT:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_RSP_OK:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
+ bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
+ break;
+
+ case BFA_FCS_ITNIM_SM_RSP_ERROR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry);
+ bfa_timer_start(itnim->fcs->bfa, &itnim->timer,
+ bfa_fcs_itnim_timeout, itnim,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_discard(itnim->fcxp);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ /*
+ * dont discard fcxp. accept will reach same state
+ */
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_discard(itnim->fcxp);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_TIMEOUT:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+ bfa_fcs_itnim_send_prli(itnim, NULL);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_timer_stop(&itnim->timer);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ bfa_timer_stop(&itnim->timer);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_timer_stop(&itnim->timer);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_HCB_ONLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online);
+ bfa_fcb_itnim_online(itnim->itnim_drv);
+ bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_itnim_offline(itnim->bfa_itnim);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
+ bfa_fcb_itnim_offline(itnim->itnim_drv);
+ bfa_itnim_offline(itnim->bfa_itnim);
+ if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE) {
+ bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
+ } else {
+ bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
+ }
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/*
+ * This state is set when a discovered rport is also in intiator mode.
+ * This ITN is marked as no_op and is not active and will not be truned into
+ * online state.
+ */
+static void
+bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_RSP_ERROR:
+ case BFA_FCS_ITNIM_SM_ONLINE:
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * itnim_private FCS ITNIM private interfaces
+ */
+
+static void
+bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_itnim_aen_event event)
+{
+ struct bfa_fcs_rport_s *rport = itnim->rport;
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = rport->fcs->logm;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(rport->port);
+ wwn_t rpwwn = rport->pwwn;
+ char lpwwn_ptr[BFA_STRING_32];
+ char rpwwn_ptr[BFA_STRING_32];
+
+ /*
+ * Don't post events for well known addresses
+ */
+ if (BFA_FCS_PID_IS_WKA(rport->pid))
+ return;
+
+ wwn2str(lpwwn_ptr, lpwwn);
+ wwn2str(rpwwn_ptr, rpwwn);
+
+ switch (event) {
+ case BFA_ITNIM_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_ITNIM_ONLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_ITNIM_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_ITNIM_OFFLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_ITNIM_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_ITNIM_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.itnim.vf_id = rport->port->fabric->vf_id;
+ aen_data.itnim.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(itnim->fcs));
+ aen_data.itnim.lpwwn = lpwwn;
+ aen_data.itnim.rpwwn = rpwwn;
+}
+
+static void
+bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
+ struct bfa_fcs_rport_s *rport = itnim->rport;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ itnim->stats.fcxp_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
+ bfa_fcs_itnim_send_prli, itnim);
+ return;
+ }
+ itnim->fcxp = fcxp;
+
+ len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), itnim->rport->pid,
+ bfa_fcs_port_get_fcid(port), 0);
+
+ bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
+ BFA_FALSE, FC_CLASS_3, len, &fchs,
+ bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ,
+ FC_RA_TOV);
+
+ itnim->stats.prli_sent++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
+}
+
+static void
+bfa_fcs_itnim_prli_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_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
+ struct fc_els_cmd_s *els_cmd;
+ struct fc_prli_s *prli_resp;
+ struct fc_ls_rjt_s *ls_rjt;
+ struct fc_prli_params_s *sparams;
+
+ bfa_trc(itnim->fcs, req_status);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ itnim->stats.prli_rsp_err++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ if (els_cmd->els_code == FC_ELS_ACC) {
+ prli_resp = (struct fc_prli_s *) els_cmd;
+
+ if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
+ bfa_trc(itnim->fcs, rsp_len);
+ /*
+ * Check if this r-port is also in Initiator mode.
+ * If so, we need to set this ITN as a no-op.
+ */
+ if (prli_resp->parampage.servparams.initiator) {
+ bfa_trc(itnim->fcs, prli_resp->parampage.type);
+ itnim->rport->scsi_function =
+ BFA_RPORT_INITIATOR;
+ itnim->stats.prli_rsp_acc++;
+ bfa_sm_send_event(itnim,
+ BFA_FCS_ITNIM_SM_INITIATOR);
+ return;
+ }
+
+ itnim->stats.prli_rsp_parse_err++;
+ return;
+ }
+ itnim->rport->scsi_function = BFA_RPORT_TARGET;
+
+ sparams = &prli_resp->parampage.servparams;
+ itnim->seq_rec = sparams->retry;
+ itnim->rec_support = sparams->rec_support;
+ itnim->task_retry_id = sparams->task_retry_id;
+ itnim->conf_comp = sparams->confirm;
+
+ itnim->stats.prli_rsp_acc++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
+ } else {
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ bfa_trc(itnim->fcs, ls_rjt->reason_code);
+ bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
+
+ itnim->stats.prli_rsp_rjt++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
+ }
+}
+
+static void
+bfa_fcs_itnim_timeout(void *arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)arg;
+
+ itnim->stats.timeout++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
+}
+
+static void
+bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_itnim_delete(itnim->bfa_itnim);
+ bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
+}
+
+
+
+/**
+ * itnim_public FCS ITNIM public interfaces
+ */
+
+/**
+ * Called by rport when a new rport is created.
+ *
+ * @param[in] rport - remote port.
+ */
+struct bfa_fcs_itnim_s *
+bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct bfa_fcs_itnim_s *itnim;
+ struct bfad_itnim_s *itnim_drv;
+ struct bfa_itnim_s *bfa_itnim;
+
+ /*
+ * call bfad to allocate the itnim
+ */
+ bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
+ if (itnim == NULL) {
+ bfa_trc(port->fcs, rport->pwwn);
+ return NULL;
+ }
+
+ /*
+ * Initialize itnim
+ */
+ itnim->rport = rport;
+ itnim->fcs = rport->fcs;
+ itnim->itnim_drv = itnim_drv;
+
+ /*
+ * call BFA to create the itnim
+ */
+ bfa_itnim = bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim);
+
+ if (bfa_itnim == NULL) {
+ bfa_trc(port->fcs, rport->pwwn);
+ bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv);
+ bfa_assert(0);
+ return NULL;
+ }
+
+ itnim->bfa_itnim = bfa_itnim;
+ itnim->seq_rec = BFA_FALSE;
+ itnim->rec_support = BFA_FALSE;
+ itnim->conf_comp = BFA_FALSE;
+ itnim->task_retry_id = BFA_FALSE;
+
+ /*
+ * Set State machine
+ */
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+
+ return itnim;
+}
+
+/**
+ * Called by rport to delete the instance of FCPIM.
+ *
+ * @param[in] rport - remote port.
+ */
+void
+bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pid);
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
+}
+
+/**
+ * Notification from rport that PLOGI is complete to initiate FC-4 session.
+ */
+void
+bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim)
+{
+ itnim->stats.onlines++;
+
+ if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) {
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE);
+ } else {
+ /*
+ * For well known addresses, we set the itnim to initiator
+ * state
+ */
+ itnim->stats.initiator++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
+ }
+}
+
+/**
+ * Called by rport to handle a remote device offline.
+ */
+void
+bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
+{
+ itnim->stats.offlines++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
+}
+
+/**
+ * Called by rport when remote port is known to be an initiator from
+ * PRLI received.
+ */
+void
+bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pid);
+ itnim->stats.initiator++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
+}
+
+/**
+ * Called by rport to check if the itnim is online.
+ */
+bfa_status_t
+bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pid);
+ switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
+ case BFA_ITNIM_ONLINE:
+ case BFA_ITNIM_INITIATIOR:
+ return BFA_STATUS_OK;
+
+ default:
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ }
+}
+
+/**
+ * BFA completion callback for bfa_itnim_online().
+ */
+void
+bfa_cb_itnim_online(void *cbarg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
+}
+
+/**
+ * BFA completion callback for bfa_itnim_offline().
+ */
+void
+bfa_cb_itnim_offline(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
+}
+
+/**
+ * Mark the beginning of PATH TOV handling. IO completion callbacks
+ * are still pending.
+ */
+void
+bfa_cb_itnim_tov_begin(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_fcb_itnim_tov_begin(itnim->itnim_drv);
+}
+
+/**
+ * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
+ */
+void
+bfa_cb_itnim_tov(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_fcb_itnim_tov(itnim->itnim_drv);
+}
+
+/**
+ * BFA notification to FCS/driver for second level error recovery.
+ *
+ * Atleast one I/O request has timedout and target is unresponsive to
+ * repeated abort requests. Second level error recovery should be initiated
+ * by starting implicit logout and recovery procedures.
+ */
+void
+bfa_cb_itnim_sler(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ itnim->stats.sler++;
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_fcs_rport_logo_imp(itnim->rport);
+}
+
+struct bfa_fcs_itnim_s *
+bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+ rport = bfa_fcs_rport_lookup(port, rpwwn);
+
+ if (!rport)
+ return NULL;
+
+ bfa_assert(rport->itnim != NULL);
+ return (rport->itnim);
+}
+
+bfa_status_t
+bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_attr_s *attr)
+{
+ struct bfa_fcs_itnim_s *itnim = NULL;
+
+ itnim = bfa_fcs_itnim_lookup(port, rpwwn);
+
+ if (itnim == NULL)
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm);
+ attr->retry = itnim->seq_rec;
+ attr->rec_support = itnim->rec_support;
+ attr->conf_comp = itnim->conf_comp;
+ attr->task_retry_id = itnim->task_retry_id;
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_stats_s *stats)
+{
+ struct bfa_fcs_itnim_s *itnim = NULL;
+
+ bfa_assert(port != NULL);
+
+ itnim = bfa_fcs_itnim_lookup(port, rpwwn);
+
+ if (itnim == NULL)
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_itnim_s *itnim = NULL;
+
+ bfa_assert(port != NULL);
+
+ itnim = bfa_fcs_itnim_lookup(port, rpwwn);
+
+ if (itnim == NULL)
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
+ u16 len)
+{
+ struct fc_els_cmd_s *els_cmd;
+
+ bfa_trc(itnim->fcs, fchs->type);
+
+ if (fchs->type != FC_TYPE_ELS)
+ return;
+
+ els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ bfa_trc(itnim->fcs, els_cmd->els_code);
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_PRLO:
+ /* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+void
+bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim)
+{
+}
+
+void
+bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim)
+{
+}
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs)
+{
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+
diff --git a/drivers/scsi/bfa/fcptm.c b/drivers/scsi/bfa/fcptm.c
new file mode 100644
index 000000000000..8c8b08c72e7a
--- /dev/null
+++ b/drivers/scsi/bfa/fcptm.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * This file contains dummy FCPTM routines to aid in Initiator Mode only
+ * compilation of OS driver.
+ *
+ */
+
+#include "bfa_os_inc.h"
+#include "fcs_rport.h"
+#include "fcs_fcptm.h"
+#include "fcs/bfa_fcs_rport.h"
+
+struct bfa_fcs_tin_s *
+bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport)
+{
+ return NULL;
+}
+
+void
+bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len)
+{
+}
+
+void
+bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len)
+{
+}
+
+void
+bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin)
+{
+}
diff --git a/drivers/scsi/bfa/fcs.h b/drivers/scsi/bfa/fcs.h
new file mode 100644
index 000000000000..deee685e8478
--- /dev/null
+++ b/drivers/scsi/bfa/fcs.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs.h FCS module functions
+ */
+
+
+#ifndef __FCS_H__
+#define __FCS_H__
+
+#define __fcs_min_cfg(__fcs) (__fcs)->min_cfg
+
+void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_H__ */
diff --git a/drivers/scsi/bfa/fcs_auth.h b/drivers/scsi/bfa/fcs_auth.h
new file mode 100644
index 000000000000..65d155fea3d7
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_auth.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_uf.h FCS unsolicited frame receive
+ */
+
+
+#ifndef __FCS_AUTH_H__
+#define __FCS_AUTH_H__
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <fcs/bfa_fcs_lport.h>
+
+/*
+ * fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_auth_uf_recv(struct bfa_fcs_fabric_s *fabric, int len);
+void bfa_fcs_auth_start(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_auth_stop(struct bfa_fcs_fabric_s *fabric);
+
+#endif /* __FCS_UF_H__ */
diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h
new file mode 100644
index 000000000000..eee960820f86
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fabric.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_lport.h FCS logical port interfaces
+ */
+
+#ifndef __FCS_FABRIC_H__
+#define __FCS_FABRIC_H__
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <fcs/bfa_fcs_lport.h>
+
+/*
+* fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport);
+void bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport);
+int bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric);
+struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup(
+ struct bfa_fcs_fabric_s *fabric, wwn_t pwwn);
+void bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len);
+u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric);
+bfa_boolean_t bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric);
+enum bfa_pport_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric);
+
+bfa_status_t bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf,
+ struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vf_s *vf_drv);
+void bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric,
+ enum auth_status status);
+
+void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
+ wwn_t fabric_name);
+#endif /* __FCS_FABRIC_H__ */
diff --git a/drivers/scsi/bfa/fcs_fcpim.h b/drivers/scsi/bfa/fcs_fcpim.h
new file mode 100644
index 000000000000..61e9e2687de3
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fcpim.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __FCS_FCPIM_H__
+#define __FCS_FCPIM_H__
+
+#include <defs/bfa_defs_port.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+
+/*
+ * Following routines are from FCPIM and will be called by rport.
+ */
+struct bfa_fcs_itnim_s *bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim);
+bfa_status_t bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim);
+
+void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim);
+
+/*
+ * Modudle init/cleanup routines.
+ */
+void bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
+ u16 len);
+#endif /* __FCS_FCPIM_H__ */
diff --git a/drivers/scsi/bfa/fcs_fcptm.h b/drivers/scsi/bfa/fcs_fcptm.h
new file mode 100644
index 000000000000..ffff0829fd31
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fcptm.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __FCS_FCPTM_H__
+#define __FCS_FCPTM_H__
+
+#include <defs/bfa_defs_port.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+
+/*
+ * Following routines are from FCPTM and will be called by rport.
+ */
+struct bfa_fcs_tin_s *bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs,
+ u16 len);
+void bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin);
+
+/*
+ * Modudle init/cleanup routines.
+ */
+void bfa_fcs_fcptm_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcptm_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs,
+ u16 len);
+
+#endif /* __FCS_FCPTM_H__ */
diff --git a/drivers/scsi/bfa/fcs_fcxp.h b/drivers/scsi/bfa/fcs_fcxp.h
new file mode 100644
index 000000000000..8277fe9c2b70
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fcxp.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_fcxp.h FCXP helper macros for FCS
+ */
+
+
+#ifndef __FCS_FCXP_H__
+#define __FCS_FCXP_H__
+
+#define bfa_fcs_fcxp_alloc(__fcs) \
+ bfa_fcxp_alloc(NULL, (__fcs)->bfa, 0, 0, NULL, NULL, NULL, NULL)
+
+#endif /* __FCS_FCXP_H__ */
diff --git a/drivers/scsi/bfa/fcs_lport.h b/drivers/scsi/bfa/fcs_lport.h
new file mode 100644
index 000000000000..ae744ba35671
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_lport.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_lport.h FCS logical port interfaces
+ */
+
+#ifndef __FCS_LPORT_H__
+#define __FCS_LPORT_H__
+
+#define __VPORT_H__
+#include <defs/bfa_defs_port.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <fcs_fabric.h>
+#include <fcs_ms.h>
+#include <cs/bfa_q.h>
+#include <fcbuild.h>
+
+/*
+ * PID used in P2P/N2N ( In Big Endian)
+ */
+#define N2N_LOCAL_PID 0x010000
+#define N2N_REMOTE_PID 0x020000
+
+/*
+ * Misc Timeouts
+ */
+/*
+ * To be used when spawning a timer before retrying a failed command. Milli
+ * Secs.
+ */
+#define BFA_FCS_RETRY_TIMEOUT 2000
+
+/*
+ * Check for Port/Vport Mode/Role
+ */
+#define BFA_FCS_VPORT_IS_INITIATOR_MODE(port) \
+ (port->port_cfg.roles & BFA_PORT_ROLE_FCP_IM)
+
+#define BFA_FCS_VPORT_IS_TARGET_MODE(port) \
+ (port->port_cfg.roles & BFA_PORT_ROLE_FCP_TM)
+
+#define BFA_FCS_VPORT_IS_IPFC_MODE(port) \
+ (port->port_cfg.roles & BFA_PORT_ROLE_FCP_IPFC)
+
+/*
+ * Is this a Well Known Address
+ */
+#define BFA_FCS_PID_IS_WKA(pid) ((bfa_os_ntoh3b(pid) > 0xFFF000) ? 1 : 0)
+
+/*
+ * Pointer to elements within Port
+ */
+#define BFA_FCS_GET_HAL_FROM_PORT(port) (port->fcs->bfa)
+#define BFA_FCS_GET_NS_FROM_PORT(port) (&port->port_topo.pfab.ns)
+#define BFA_FCS_GET_SCN_FROM_PORT(port) (&port->port_topo.pfab.scn)
+#define BFA_FCS_GET_MS_FROM_PORT(port) (&port->port_topo.pfab.ms)
+#define BFA_FCS_GET_FDMI_FROM_PORT(port) (&port->port_topo.pfab.ms.fdmi)
+
+/*
+ * handler for unsolicied frames
+ */
+void bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs,
+ u16 len);
+
+/*
+ * Following routines will be called by Fabric to indicate port
+ * online/offline to vport.
+ */
+void bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
+ u16 vf_id, struct bfa_port_cfg_s *port_cfg,
+ struct bfa_fcs_vport_s *vport);
+void bfa_fcs_port_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_delete(struct bfa_fcs_port_s *port);
+bfa_boolean_t bfa_fcs_port_is_online(struct bfa_fcs_port_s *port);
+
+/*
+ * Lookup rport based on PID
+ */
+struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pid(
+ struct bfa_fcs_port_s *port, u32 pid);
+
+/*
+ * Lookup rport based on PWWN
+ */
+struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pwwn(
+ struct bfa_fcs_port_s *port, wwn_t pwwn);
+struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_nwwn(
+ struct bfa_fcs_port_s *port, wwn_t nwwn);
+void bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port,
+ struct bfa_fcs_rport_s *rport);
+void bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port,
+ struct bfa_fcs_rport_s *rport);
+
+void bfa_fcs_port_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_port_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_port_lip(struct bfa_fcs_port_s *port);
+
+#endif /* __FCS_LPORT_H__ */
diff --git a/drivers/scsi/bfa/fcs_ms.h b/drivers/scsi/bfa/fcs_ms.h
new file mode 100644
index 000000000000..b6a8c12876f4
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_ms.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_ms.h FCS ms interfaces
+ */
+#ifndef __FCS_MS_H__
+#define __FCS_MS_H__
+
+/* MS FCS routines */
+void bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port);
+
+/* FDMI FCS routines */
+void bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms);
+void bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms);
+void bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms);
+
+#endif
diff --git a/drivers/scsi/bfa/fcs_port.h b/drivers/scsi/bfa/fcs_port.h
new file mode 100644
index 000000000000..abb65191dd27
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_port.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_pport.h FCS physical port interfaces
+ */
+
+
+#ifndef __FCS_PPORT_H__
+#define __FCS_PPORT_H__
+
+/*
+ * fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_PPORT_H__ */
diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h
new file mode 100644
index 000000000000..f601e9d74236
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_rport.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_rport.h FCS rport interfaces and defines
+ */
+
+#ifndef __FCS_RPORT_H__
+#define __FCS_RPORT_H__
+
+#include <fcs/bfa_fcs_rport.h>
+
+void bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs);
+
+void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
+ u16 len);
+void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport);
+
+struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_port_s *port,
+ u32 pid);
+void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi_rsp);
+void bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi);
+void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
+ struct fc_logi_s *plogi);
+void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_fcptm_offline_done(struct bfa_fcs_rport_s *rport);
+int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport);
+struct bfa_fcs_rport_s *bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port,
+ wwn_t wwn);
+
+
+/* Rport Features */
+void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport);
+
+#endif /* __FCS_RPORT_H__ */
diff --git a/drivers/scsi/bfa/fcs_trcmod.h b/drivers/scsi/bfa/fcs_trcmod.h
new file mode 100644
index 000000000000..41b5ae8d7644
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_trcmod.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_trcmod.h BFA FCS trace modules
+ */
+
+#ifndef __FCS_TRCMOD_H__
+#define __FCS_TRCMOD_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ BFA_TRC_FCS_FABRIC = 1,
+ BFA_TRC_FCS_VFAPI = 2,
+ BFA_TRC_FCS_PORT = 3,
+ BFA_TRC_FCS_VPORT = 4,
+ BFA_TRC_FCS_VP_API = 5,
+ BFA_TRC_FCS_VPS = 6,
+ BFA_TRC_FCS_RPORT = 7,
+ BFA_TRC_FCS_FCPIM = 8,
+ BFA_TRC_FCS_FCPTM = 9,
+ BFA_TRC_FCS_NS = 10,
+ BFA_TRC_FCS_SCN = 11,
+ BFA_TRC_FCS_LOOP = 12,
+ BFA_TRC_FCS_UF = 13,
+ BFA_TRC_FCS_PPORT = 14,
+ BFA_TRC_FCS_FCPIP = 15,
+ BFA_TRC_FCS_PORT_API = 16,
+ BFA_TRC_FCS_RPORT_API = 17,
+ BFA_TRC_FCS_AUTH = 18,
+ BFA_TRC_FCS_N2N = 19,
+ BFA_TRC_FCS_MS = 20,
+ BFA_TRC_FCS_FDMI = 21,
+ BFA_TRC_FCS_RPORT_FTRS = 22,
+};
+
+#endif /* __FCS_TRCMOD_H__ */
diff --git a/drivers/scsi/bfa/fcs_uf.h b/drivers/scsi/bfa/fcs_uf.h
new file mode 100644
index 000000000000..96f1bdcb31ed
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_uf.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * fcs_uf.h FCS unsolicited frame receive
+ */
+
+
+#ifndef __FCS_UF_H__
+#define __FCS_UF_H__
+
+/*
+ * fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_UF_H__ */
diff --git a/drivers/scsi/bfa/fcs_vport.h b/drivers/scsi/bfa/fcs_vport.h
new file mode 100644
index 000000000000..9e80b6a97b7f
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_vport.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __FCS_VPORT_H__
+#define __FCS_VPORT_H__
+
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <defs/bfa_defs_pci.h>
+
+/*
+ * Modudle init/cleanup routines.
+ */
+
+void bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs);
+
+void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport);
+u32 bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_VPORT_H__ */
+
diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c
new file mode 100644
index 000000000000..b845eb272c78
--- /dev/null
+++ b/drivers/scsi/bfa/fdmi.c
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * port_api.c BFA FCS port
+ */
+
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "lport_priv.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include <fcs/bfa_fcs_fdmi.h>
+
+BFA_TRC_FILE(FCS, FDMI);
+
+#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_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_port_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_port_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_port_fdmi_timeout(void *arg);
+static u16 bfa_fcs_port_fdmi_build_rhba_pyld(
+ struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
+static u16 bfa_fcs_port_fdmi_build_rprt_pyld(
+ struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
+static u16 bfa_fcs_port_fdmi_build_rpa_pyld(
+ struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
+static u16 bfa_fcs_port_fdmi_build_portattr_block(
+ struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
+void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
+ struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
+void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
+ struct bfa_fcs_fdmi_port_attr_s *port_attr);
+/**
+ * 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_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+/**
+ * Start in offline state - awaiting MS to send start.
+ */
+static void
+bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_sending_rprt);
+ bfa_fcs_port_fdmi_send_rprt(fdmi, NULL);
+ } else {
+ /*
+ * For a base port, we should first register the HBA
+ * atribute. The HBA attribute also contains the base
+ * port registration.
+ */
+ bfa_sm_set_state(fdmi,
+ bfa_fcs_port_fdmi_sm_sending_rhba);
+ bfa_fcs_port_fdmi_send_rhba(fdmi, NULL);
+ }
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_rhba);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_rhba_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->timer, bfa_fcs_port_fdmi_timeout,
+ fdmi, BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ /*
+ * set state to offline
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ }
+ break;
+
+ case FDMISM_EVENT_RSP_OK:
+ /*
+ * Initiate Register Port Attributes
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa);
+ fdmi->retry_cnt = 0;
+ bfa_fcs_port_fdmi_send_rpa(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_fcxp_discard(fdmi->fcxp);
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_sending_rhba);
+ bfa_fcs_port_fdmi_send_rhba(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_timer_stop(&fdmi->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/*
+* RPRT : Register Port
+ */
+static void
+bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_rprt);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_rprt_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->timer, bfa_fcs_port_fdmi_timeout,
+ fdmi, BFA_FCS_RETRY_TIMEOUT);
+
+ } else {
+ /*
+ * set state to offline
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ fdmi->retry_cnt = 0;
+ }
+ break;
+
+ case FDMISM_EVENT_RSP_OK:
+ fdmi->retry_cnt = 0;
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_fcxp_discard(fdmi->fcxp);
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_sending_rprt);
+ bfa_fcs_port_fdmi_send_rprt(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_timer_stop(&fdmi->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/*
+ * Register Port Attributes
+ */
+static void
+bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_rpa);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_rpa_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->timer, bfa_fcs_port_fdmi_timeout,
+ fdmi, BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ /*
+ * set state to offline
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ fdmi->retry_cnt = 0;
+ }
+ break;
+
+ case FDMISM_EVENT_RSP_OK:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_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_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_sending_rpa);
+ bfa_fcs_port_fdmi_send_rpa(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_timer_stop(&fdmi->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_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_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+/**
+* RHBA : Register HBA Attributes.
+ */
+static void
+bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
+ bfa_fcs_port_fdmi_send_rhba, fdmi);
+ return;
+ }
+ fdmi->fcxp = fcxp;
+
+ pyld = bfa_fcxp_get_reqbuf(fcxp);
+ bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+
+ len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
+ FDMI_RHBA);
+
+ attr_len = bfa_fcs_port_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_port_fdmi_rhba_response, (void *)fdmi,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT);
+}
+
+static u16
+bfa_fcs_port_fdmi_build_rhba_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
+ u8 *pyld)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct bfa_fcs_fdmi_hba_attr_s hba_attr; /* @todo */
+ struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr; /* @todo */
+ struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld;
+ struct fdmi_attr_s *attr;
+ u8 *curr_ptr;
+ u16 len, count;
+
+ /*
+ * get hba attributes
+ */
+ bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr);
+
+ rhba->hba_id = bfa_fcs_port_get_pwwn(port);
+ rhba->port_list.num_ports = bfa_os_htonl(1);
+ rhba->port_list.port_entry = bfa_fcs_port_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 = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME);
+ attr->len = sizeof(wwn_t);
+ memcpy(attr->value, &bfa_fcs_port_get_nwwn(port), attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Manufacturer
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER);
+ attr->len = (u16) strlen(fcs_hba_attr->manufacturer);
+ memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Serial Number
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM);
+ attr->len = (u16) strlen(fcs_hba_attr->serial_num);
+ memcpy(attr->value, fcs_hba_attr->serial_num, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Model
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL);
+ attr->len = (u16) strlen(fcs_hba_attr->model);
+ memcpy(attr->value, fcs_hba_attr->model, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Model Desc
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC);
+ attr->len = (u16) strlen(fcs_hba_attr->model_desc);
+ memcpy(attr->value, fcs_hba_attr->model_desc, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * H/W Version
+ */
+ if (fcs_hba_attr->hw_version[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->hw_version);
+ memcpy(attr->value, fcs_hba_attr->hw_version, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+ }
+
+ /*
+ * Driver Version
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Option Rom Version
+ */
+ if (fcs_hba_attr->option_rom_ver[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver);
+ memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+ }
+
+ /*
+ * f/w Version = driver version
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * OS Name
+ */
+ if (fcs_hba_attr->os_name[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME);
+ attr->len = (u16) strlen(fcs_hba_attr->os_name);
+ memcpy(attr->value, fcs_hba_attr->os_name, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+ }
+
+ /*
+ * MAX_CT_PAYLOAD
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT);
+ attr->len = sizeof(fcs_hba_attr->max_ct_pyld);
+ memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len);
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Update size of payload
+ */
+ len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
+
+ rhba->hba_attr_blk.attr_count = bfa_os_htonl(count);
+ return len;
+}
+
+static void
+bfa_fcs_port_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_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
+ struct bfa_fcs_port_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 = bfa_os_ntohs(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_port_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
+ bfa_fcs_port_fdmi_send_rprt, fdmi);
+ return;
+ }
+ fdmi->fcxp = fcxp;
+
+ pyld = bfa_fcxp_get_reqbuf(fcxp);
+ bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+
+ len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
+ FDMI_RPRT);
+
+ attr_len = bfa_fcs_port_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_port_fdmi_rprt_response, (void *)fdmi,
+ FC_MAX_PDUSZ, FC_RA_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_port_fdmi_build_portattr_block(struct bfa_fcs_port_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;
+
+ /*
+ * 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 = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES);
+ attr->len = sizeof(fcs_port_attr.supp_fc4_types);
+ memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Supported Speed
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED);
+ attr->len = sizeof(fcs_port_attr.supp_speed);
+ memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * current Port Speed
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED);
+ attr->len = sizeof(fcs_port_attr.curr_speed);
+ memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * max frame size
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE);
+ attr->len = sizeof(fcs_port_attr.max_frm_size);
+ memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * OS Device Name
+ */
+ if (fcs_port_attr.os_device_name[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME);
+ attr->len = (u16) strlen(fcs_port_attr.os_device_name);
+ memcpy(attr->value, fcs_port_attr.os_device_name, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ }
+ /*
+ * Host Name
+ */
+ if (fcs_port_attr.host_name[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME);
+ attr->len = (u16) strlen(fcs_port_attr.host_name);
+ memcpy(attr->value, fcs_port_attr.host_name, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ }
+
+ /*
+ * Update size of payload
+ */
+ port_attrib->attr_count = bfa_os_htonl(count);
+ len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
+ return len;
+}
+
+static u16
+bfa_fcs_port_fdmi_build_rprt_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
+ u8 *pyld)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct fdmi_rprt_s *rprt = (struct fdmi_rprt_s *) pyld;
+ u16 len;
+
+ rprt->hba_id = bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
+ rprt->port_name = bfa_fcs_port_get_pwwn(port);
+
+ len = bfa_fcs_port_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_port_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_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
+ struct bfa_fcs_port_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 = bfa_os_ntohs(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_port_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
+ bfa_fcs_port_fdmi_send_rpa, fdmi);
+ return;
+ }
+ fdmi->fcxp = fcxp;
+
+ pyld = bfa_fcxp_get_reqbuf(fcxp);
+ bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+
+ len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
+ FDMI_RPA);
+
+ attr_len = bfa_fcs_port_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_port_fdmi_rpa_response, (void *)fdmi,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT);
+}
+
+static u16
+bfa_fcs_port_fdmi_build_rpa_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
+ u8 *pyld)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct fdmi_rpa_s *rpa = (struct fdmi_rpa_s *) pyld;
+ u16 len;
+
+ rpa->port_name = bfa_fcs_port_get_pwwn(port);
+
+ len = bfa_fcs_port_fdmi_build_portattr_block(fdmi,
+ (u8 *) &rpa->port_attr_blk);
+
+ len += sizeof(rpa->port_name);
+
+ return len;
+}
+
+static void
+bfa_fcs_port_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_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
+ struct bfa_fcs_port_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 = bfa_os_ntohs(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_port_fdmi_timeout(void *arg)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)arg;
+
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
+}
+
+void
+bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
+ struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
+ struct bfa_adapter_attr_s adapter_attr;
+
+ bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
+ bfa_os_memset(&adapter_attr, 0, sizeof(struct bfa_adapter_attr_s));
+
+ bfa_ioc_get_adapter_attr(&port->fcs->bfa->ioc, &adapter_attr);
+
+ strncpy(hba_attr->manufacturer, adapter_attr.manufacturer,
+ sizeof(adapter_attr.manufacturer));
+
+ strncpy(hba_attr->serial_num, adapter_attr.serial_num,
+ sizeof(adapter_attr.serial_num));
+
+ strncpy(hba_attr->model, adapter_attr.model, sizeof(hba_attr->model));
+
+ strncpy(hba_attr->model_desc, adapter_attr.model_descr,
+ sizeof(hba_attr->model_desc));
+
+ strncpy(hba_attr->hw_version, adapter_attr.hw_ver,
+ sizeof(hba_attr->hw_version));
+
+ strncpy(hba_attr->driver_version, (char *)driver_info->version,
+ sizeof(hba_attr->driver_version));
+
+ strncpy(hba_attr->option_rom_ver, adapter_attr.optrom_ver,
+ sizeof(hba_attr->option_rom_ver));
+
+ strncpy(hba_attr->fw_version, adapter_attr.fw_ver,
+ sizeof(hba_attr->fw_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 = bfa_os_htonl(FC_MAX_PDUSZ);
+
+}
+
+void
+bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
+ struct bfa_fcs_fdmi_port_attr_s *port_attr)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
+ struct bfa_pport_attr_s pport_attr;
+
+ bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));
+
+ /*
+ * get pport attributes from hal
+ */
+ bfa_pport_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
+ */
+ port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS);
+
+ /*
+ * Current Speed
+ */
+ port_attr->curr_speed = bfa_os_htonl(pport_attr.speed);
+
+ /*
+ * Max PDU Size.
+ */
+ port_attr->max_frm_size = bfa_os_htonl(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));
+
+}
+
+
+void
+bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
+
+ fdmi->ms = ms;
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+}
+
+void
+bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
+
+ fdmi->ms = ms;
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE);
+}
+
+void
+bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
+
+ fdmi->ms = ms;
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE);
+}
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen.h b/drivers/scsi/bfa/include/aen/bfa_aen.h
new file mode 100644
index 000000000000..da8cac093d3d
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_AEN_H__
+#define __BFA_AEN_H__
+
+#include "defs/bfa_defs_aen.h"
+
+#define BFA_AEN_MAX_ENTRY 512
+
+extern s32 bfa_aen_max_cfg_entry;
+struct bfa_aen_s {
+ void *bfad;
+ s32 max_entry;
+ s32 write_index;
+ s32 read_index;
+ u32 bfad_num;
+ u32 seq_num;
+ void (*aen_cb_notify)(void *bfad);
+ void (*gettimeofday)(struct bfa_timeval_s *tv);
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_aen_entry_s list[BFA_AEN_MAX_ENTRY]; /* Must be the last */
+};
+
+
+/**
+ * Public APIs
+ */
+static inline void
+bfa_aen_set_max_cfg_entry(int max_entry)
+{
+ bfa_aen_max_cfg_entry = max_entry;
+}
+
+static inline s32
+bfa_aen_get_max_cfg_entry(void)
+{
+ return bfa_aen_max_cfg_entry;
+}
+
+static inline s32
+bfa_aen_get_meminfo(void)
+{
+ return (sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry());
+}
+
+static inline s32
+bfa_aen_get_wi(struct bfa_aen_s *aen)
+{
+ return aen->write_index;
+}
+
+static inline s32
+bfa_aen_get_ri(struct bfa_aen_s *aen)
+{
+ return aen->read_index;
+}
+
+static inline s32
+bfa_aen_fetch_count(struct bfa_aen_s *aen, s32 read_index)
+{
+ return ((aen->write_index + aen->max_entry) - read_index)
+ % aen->max_entry;
+}
+
+s32 bfa_aen_init(struct bfa_aen_s *aen, struct bfa_trc_mod_s *trcmod,
+ void *bfad, u32 inst_id, void (*aen_cb_notify)(void *),
+ void (*gettimeofday)(struct bfa_timeval_s *));
+
+s32 bfa_aen_post(struct bfa_aen_s *aen, enum bfa_aen_category aen_category,
+ int aen_type, union bfa_aen_data_u *aen_data);
+
+s32 bfa_aen_fetch(struct bfa_aen_s *aen, struct bfa_aen_entry_s *aen_entry,
+ s32 entry_space, s32 rii, s32 *ri_arr,
+ s32 ri_arr_cnt);
+
+s32 bfa_aen_get_inst(struct bfa_aen_s *aen);
+
+#endif /* __BFA_AEN_H__ */
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h b/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h
new file mode 100644
index 000000000000..260d3ea1cab3
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_ADAPTER Module */
+#ifndef __bfa_aen_adapter_h__
+#define __bfa_aen_adapter_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_ADAPTER_ADD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_ADD)
+#define BFA_AEN_ADAPTER_REMOVE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_REMOVE)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_audit.h b/drivers/scsi/bfa/include/aen/bfa_aen_audit.h
new file mode 100644
index 000000000000..12cd7aab5d53
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_audit.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_AUDIT Module */
+#ifndef __bfa_aen_audit_h__
+#define __bfa_aen_audit_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_AUDIT_AUTH_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_ENABLE)
+#define BFA_AEN_AUDIT_AUTH_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_DISABLE)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h b/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h
new file mode 100644
index 000000000000..507d0b58d149
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_ETHPORT Module */
+#ifndef __bfa_aen_ethport_h__
+#define __bfa_aen_ethport_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_ETHPORT_LINKUP \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKUP)
+#define BFA_AEN_ETHPORT_LINKDOWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKDOWN)
+#define BFA_AEN_ETHPORT_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_ENABLE)
+#define BFA_AEN_ETHPORT_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_DISABLE)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
new file mode 100644
index 000000000000..71378b446b69
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_IOC Module */
+#ifndef __bfa_aen_ioc_h__
+#define __bfa_aen_ioc_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_IOC_HBGOOD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBGOOD)
+#define BFA_AEN_IOC_HBFAIL \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBFAIL)
+#define BFA_AEN_IOC_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_ENABLE)
+#define BFA_AEN_IOC_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_DISABLE)
+#define BFA_AEN_IOC_FWMISMATCH \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWMISMATCH)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h b/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h
new file mode 100644
index 000000000000..a7d8ddcfef99
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_ITNIM Module */
+#ifndef __bfa_aen_itnim_h__
+#define __bfa_aen_itnim_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_ITNIM_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_ONLINE)
+#define BFA_AEN_ITNIM_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_OFFLINE)
+#define BFA_AEN_ITNIM_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_DISCONNECT)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_lport.h b/drivers/scsi/bfa/include/aen/bfa_aen_lport.h
new file mode 100644
index 000000000000..5a8ebb65193f
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_lport.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_LPORT Module */
+#ifndef __bfa_aen_lport_h__
+#define __bfa_aen_lport_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_LPORT_NEW \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW)
+#define BFA_AEN_LPORT_DELETE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE)
+#define BFA_AEN_LPORT_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_ONLINE)
+#define BFA_AEN_LPORT_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_OFFLINE)
+#define BFA_AEN_LPORT_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DISCONNECT)
+#define BFA_AEN_LPORT_NEW_PROP \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_PROP)
+#define BFA_AEN_LPORT_DELETE_PROP \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_PROP)
+#define BFA_AEN_LPORT_NEW_STANDARD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_STANDARD)
+#define BFA_AEN_LPORT_DELETE_STANDARD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_STANDARD)
+#define BFA_AEN_LPORT_NPIV_DUP_WWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_DUP_WWN)
+#define BFA_AEN_LPORT_NPIV_FABRIC_MAX \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_FABRIC_MAX)
+#define BFA_AEN_LPORT_NPIV_UNKNOWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_UNKNOWN)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_port.h b/drivers/scsi/bfa/include/aen/bfa_aen_port.h
new file mode 100644
index 000000000000..9add905a622d
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_port.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_PORT Module */
+#ifndef __bfa_aen_port_h__
+#define __bfa_aen_port_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_PORT_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ONLINE)
+#define BFA_AEN_PORT_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_OFFLINE)
+#define BFA_AEN_PORT_RLIR \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_RLIR)
+#define BFA_AEN_PORT_SFP_INSERT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_INSERT)
+#define BFA_AEN_PORT_SFP_REMOVE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_REMOVE)
+#define BFA_AEN_PORT_SFP_POM \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_POM)
+#define BFA_AEN_PORT_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ENABLE)
+#define BFA_AEN_PORT_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISABLE)
+#define BFA_AEN_PORT_AUTH_ON \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_ON)
+#define BFA_AEN_PORT_AUTH_OFF \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_OFF)
+#define BFA_AEN_PORT_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISCONNECT)
+#define BFA_AEN_PORT_QOS_NEG \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_QOS_NEG)
+#define BFA_AEN_PORT_FABRIC_NAME_CHANGE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_FABRIC_NAME_CHANGE)
+#define BFA_AEN_PORT_SFP_ACCESS_ERROR \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_ACCESS_ERROR)
+#define BFA_AEN_PORT_SFP_UNSUPPORT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_UNSUPPORT)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_rport.h b/drivers/scsi/bfa/include/aen/bfa_aen_rport.h
new file mode 100644
index 000000000000..7e4be1fd5e15
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_rport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for BFA_AEN_CAT_RPORT Module */
+#ifndef __bfa_aen_rport_h__
+#define __bfa_aen_rport_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_RPORT_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_ONLINE)
+#define BFA_AEN_RPORT_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_OFFLINE)
+#define BFA_AEN_RPORT_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_DISCONNECT)
+#define BFA_AEN_RPORT_QOS_PRIO \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_PRIO)
+#define BFA_AEN_RPORT_QOS_FLOWID \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_FLOWID)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h
new file mode 100644
index 000000000000..64c1412c5703
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_H__
+#define __BFA_H__
+
+#include <bfa_os_inc.h>
+#include <cs/bfa_debug.h>
+#include <cs/bfa_q.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+#include <cs/bfa_plog.h>
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_ioc.h>
+#include <defs/bfa_defs_iocfc.h>
+#include <aen/bfa_aen.h>
+#include <bfi/bfi.h>
+
+struct bfa_s;
+#include <bfa_intr_priv.h>
+
+struct bfa_pcidev_s;
+
+/**
+ * PCI devices supported by the current BFA
+ */
+struct bfa_pciid_s {
+ u16 device_id;
+ u16 vendor_id;
+};
+
+extern char bfa_version[];
+
+/**
+ * BFA Power Mgmt Commands
+ */
+enum bfa_pm_cmd {
+ BFA_PM_CTL_D0 = 0,
+ BFA_PM_CTL_D1 = 1,
+ BFA_PM_CTL_D2 = 2,
+ BFA_PM_CTL_D3 = 3,
+};
+
+/**
+ * BFA memory resources
+ */
+enum bfa_mem_type {
+ BFA_MEM_TYPE_KVA = 1, /*! Kernel Virtual Memory *(non-dma-able) */
+ BFA_MEM_TYPE_DMA = 2, /*! DMA-able memory */
+ BFA_MEM_TYPE_MAX = BFA_MEM_TYPE_DMA,
+};
+
+struct bfa_mem_elem_s {
+ enum bfa_mem_type mem_type; /* see enum bfa_mem_type */
+ u32 mem_len; /* Total Length in Bytes */
+ u8 *kva; /* kernel virtual address */
+ u64 dma; /* dma address if DMA memory */
+ u8 *kva_curp; /* kva allocation cursor */
+ u64 dma_curp; /* dma allocation cursor */
+};
+
+struct bfa_meminfo_s {
+ struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX];
+};
+#define bfa_meminfo_kva(_m) \
+ (_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp
+#define bfa_meminfo_dma_virt(_m) \
+ (_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp
+#define bfa_meminfo_dma_phys(_m) \
+ (_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp
+
+/**
+ * Generic Scatter Gather Element used by driver
+ */
+struct bfa_sge_s {
+ u32 sg_len;
+ void *sg_addr;
+};
+
+#define bfa_sge_to_be(__sge) do { \
+ ((u32 *)(__sge))[0] = bfa_os_htonl(((u32 *)(__sge))[0]); \
+ ((u32 *)(__sge))[1] = bfa_os_htonl(((u32 *)(__sge))[1]); \
+ ((u32 *)(__sge))[2] = bfa_os_htonl(((u32 *)(__sge))[2]); \
+} while (0)
+
+
+/*
+ * bfa stats interfaces
+ */
+#define bfa_stats(_mod, _stats) (_mod)->stats._stats ++
+
+#define bfa_ioc_get_stats(__bfa, __ioc_stats) \
+ bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats)
+#define bfa_ioc_clear_stats(__bfa) \
+ bfa_ioc_clr_stats(&(__bfa)->ioc)
+
+/*
+ * bfa API functions
+ */
+void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids);
+void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg);
+void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg);
+void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo);
+void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+void bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod);
+void bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod);
+void bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen);
+void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog);
+void bfa_detach(struct bfa_s *bfa);
+void bfa_init(struct bfa_s *bfa);
+void bfa_start(struct bfa_s *bfa);
+void bfa_stop(struct bfa_s *bfa);
+void bfa_attach_fcs(struct bfa_s *bfa);
+void bfa_cb_init(void *bfad, bfa_status_t status);
+void bfa_cb_stop(void *bfad, bfa_status_t status);
+void bfa_cb_updateq(void *bfad, bfa_status_t status);
+
+bfa_boolean_t bfa_intx(struct bfa_s *bfa);
+void bfa_isr_enable(struct bfa_s *bfa);
+void bfa_isr_disable(struct bfa_s *bfa);
+void bfa_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
+ u32 *num_vecs, u32 *max_vec_bit);
+#define bfa_msix(__bfa, __vec) (__bfa)->msix.handler[__vec](__bfa, __vec)
+
+void bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q);
+void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q);
+void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q);
+
+typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status);
+void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr);
+bfa_status_t bfa_iocfc_get_stats(struct bfa_s *bfa,
+ struct bfa_iocfc_stats_s *stats,
+ bfa_cb_ioc_t cbfn, void *cbarg);
+bfa_status_t bfa_iocfc_clear_stats(struct bfa_s *bfa,
+ bfa_cb_ioc_t cbfn, void *cbarg);
+void bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr);
+
+void bfa_adapter_get_attr(struct bfa_s *bfa,
+ struct bfa_adapter_attr_s *ad_attr);
+u64 bfa_adapter_get_id(struct bfa_s *bfa);
+
+bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,
+ struct bfa_iocfc_intr_attr_s *attr);
+
+void bfa_iocfc_enable(struct bfa_s *bfa);
+void bfa_iocfc_disable(struct bfa_s *bfa);
+void bfa_ioc_auto_recover(bfa_boolean_t auto_recover);
+void bfa_cb_ioc_disable(void *bfad);
+void bfa_timer_tick(struct bfa_s *bfa);
+#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout) \
+ bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)
+
+/*
+ * BFA debug API functions
+ */
+bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen);
+bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen);
+
+#include "bfa_priv.h"
+
+#endif /* __BFA_H__ */
diff --git a/drivers/scsi/bfa/include/bfa_fcpim.h b/drivers/scsi/bfa/include/bfa_fcpim.h
new file mode 100644
index 000000000000..04789795fa53
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_fcpim.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCPIM_H__
+#define __BFA_FCPIM_H__
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_fcpim.h>
+#include <defs/bfa_defs_fcpim.h>
+
+/*
+ * forward declarations
+ */
+struct bfa_itnim_s;
+struct bfa_ioim_s;
+struct bfa_tskim_s;
+struct bfad_ioim_s;
+struct bfad_tskim_s;
+
+/*
+ * bfa fcpim module API functions
+ */
+void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov);
+u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa);
+void bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth);
+u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa);
+bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa,
+ struct bfa_fcpim_stats_s *modstats);
+bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa);
+
+/*
+ * bfa itnim API functions
+ */
+struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa,
+ struct bfa_rport_s *rport, void *itnim);
+void bfa_itnim_delete(struct bfa_itnim_s *itnim);
+void bfa_itnim_online(struct bfa_itnim_s *itnim,
+ bfa_boolean_t seq_rec);
+void bfa_itnim_offline(struct bfa_itnim_s *itnim);
+void bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
+ struct bfa_itnim_hal_stats_s *stats);
+void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
+
+
+/**
+ * BFA completion callback for bfa_itnim_online().
+ *
+ * @param[in] itnim FCS or driver itnim instance
+ *
+ * return None
+ */
+void bfa_cb_itnim_online(void *itnim);
+
+/**
+ * BFA completion callback for bfa_itnim_offline().
+ *
+ * @param[in] itnim FCS or driver itnim instance
+ *
+ * return None
+ */
+void bfa_cb_itnim_offline(void *itnim);
+void bfa_cb_itnim_tov_begin(void *itnim);
+void bfa_cb_itnim_tov(void *itnim);
+
+/**
+ * BFA notification to FCS/driver for second level error recovery.
+ *
+ * Atleast one I/O request has timedout and target is unresponsive to
+ * repeated abort requests. Second level error recovery should be initiated
+ * by starting implicit logout and recovery procedures.
+ *
+ * @param[in] itnim FCS or driver itnim instance
+ *
+ * return None
+ */
+void bfa_cb_itnim_sler(void *itnim);
+
+/*
+ * bfa ioim API functions
+ */
+struct bfa_ioim_s *bfa_ioim_alloc(struct bfa_s *bfa,
+ struct bfad_ioim_s *dio,
+ struct bfa_itnim_s *itnim,
+ u16 nsgles);
+
+void bfa_ioim_free(struct bfa_ioim_s *ioim);
+void bfa_ioim_start(struct bfa_ioim_s *ioim);
+void bfa_ioim_abort(struct bfa_ioim_s *ioim);
+void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim,
+ bfa_boolean_t iotov);
+
+
+/**
+ * I/O completion notification.
+ *
+ * @param[in] dio driver IO structure
+ * @param[in] io_status IO completion status
+ * @param[in] scsi_status SCSI status returned by target
+ * @param[in] sns_len SCSI sense length, 0 if none
+ * @param[in] sns_info SCSI sense data, if any
+ * @param[in] residue Residual length
+ *
+ * @return None
+ */
+void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
+ enum bfi_ioim_status io_status,
+ u8 scsi_status, int sns_len,
+ u8 *sns_info, s32 residue);
+
+/**
+ * I/O good completion notification.
+ *
+ * @param[in] dio driver IO structure
+ *
+ * @return None
+ */
+void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
+
+/**
+ * I/O abort completion notification
+ *
+ * @param[in] dio driver IO that was aborted
+ *
+ * @return None
+ */
+void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio);
+void bfa_cb_ioim_resfree(void *hcb_bfad);
+
+void bfa_cb_ioim_resfree(void *hcb_bfad);
+
+/*
+ * bfa tskim API functions
+ */
+struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa,
+ struct bfad_tskim_s *dtsk);
+void bfa_tskim_free(struct bfa_tskim_s *tskim);
+void bfa_tskim_start(struct bfa_tskim_s *tskim,
+ struct bfa_itnim_s *itnim, lun_t lun,
+ enum fcp_tm_cmnd tm, u8 t_secs);
+void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
+ enum bfi_tskim_status tsk_status);
+
+#endif /* __BFA_FCPIM_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfa_fcptm.h b/drivers/scsi/bfa/include/bfa_fcptm.h
new file mode 100644
index 000000000000..5f5ffe0bb1bb
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_fcptm.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCPTM_H__
+#define __BFA_FCPTM_H__
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_fcptm.h>
+
+/*
+ * forward declarations
+ */
+struct bfa_tin_s;
+struct bfa_iotm_s;
+struct bfa_tsktm_s;
+
+/*
+ * bfa fcptm module API functions
+ */
+void bfa_fcptm_path_tov_set(struct bfa_s *bfa, u16 path_tov);
+u16 bfa_fcptm_path_tov_get(struct bfa_s *bfa);
+void bfa_fcptm_qdepth_set(struct bfa_s *bfa, u16 q_depth);
+u16 bfa_fcptm_qdepth_get(struct bfa_s *bfa);
+
+/*
+ * bfa tin API functions
+ */
+void bfa_tin_get_stats(struct bfa_tin_s *tin, struct bfa_tin_stats_s *stats);
+void bfa_tin_clear_stats(struct bfa_tin_s *tin);
+
+#endif /* __BFA_FCPTM_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h
new file mode 100644
index 000000000000..0c80b74f72ef
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_svc.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_SVC_H__
+#define __BFA_SVC_H__
+
+/*
+ * forward declarations
+ */
+struct bfa_fcxp_s;
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_rport.h>
+#include <defs/bfa_defs_qos.h>
+#include <cs/bfa_sm.h>
+#include <bfa.h>
+
+/**
+ * BFA rport information.
+ */
+struct bfa_rport_info_s {
+ u16 max_frmsz; /* max rcv pdu size */
+ u32 pid : 24, /* remote port ID */
+ lp_tag : 8;
+ u32 local_pid : 24, /* local port ID */
+ cisc : 8; /* CIRO supported */
+ u8 fc_class; /* supported FC classes. enum fc_cos */
+ u8 vf_en; /* virtual fabric enable */
+ u16 vf_id; /* virtual fabric ID */
+ enum bfa_pport_speed speed; /* Rport's current speed */
+};
+
+/**
+ * BFA rport data structure
+ */
+struct bfa_rport_s {
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* state machine */
+ struct bfa_s *bfa; /* backpointer to BFA */
+ void *rport_drv; /* fcs/driver rport object */
+ u16 fw_handle; /* firmware rport handle */
+ u16 rport_tag; /* BFA rport tag */
+ struct bfa_rport_info_s rport_info; /* rport info from *fcs/driver */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct bfa_cb_qe_s hcb_qe; /* BFA callback qelem */
+ struct bfa_rport_hal_stats_s stats; /* BFA rport statistics */
+ struct bfa_rport_qos_attr_s qos_attr;
+ union a {
+ bfa_status_t status; /* f/w status */
+ void *fw_msg; /* QoS scn event */
+ } event_arg;
+};
+#define BFA_RPORT_FC_COS(_rport) ((_rport)->rport_info.fc_class)
+
+/**
+ * Send completion callback.
+ */
+typedef void (*bfa_cb_fcxp_send_t) (void *bfad_fcxp, struct bfa_fcxp_s *fcxp,
+ void *cbarg, enum bfa_status req_status,
+ u32 rsp_len, u32 resid_len,
+ struct fchs_s *rsp_fchs);
+
+/**
+ * BFA fcxp allocation (asynchronous)
+ */
+typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp);
+
+struct bfa_fcxp_wqe_s {
+ struct list_head qe;
+ bfa_fcxp_alloc_cbfn_t alloc_cbfn;
+ void *alloc_cbarg;
+};
+
+typedef u64 (*bfa_fcxp_get_sgaddr_t) (void *bfad_fcxp, int sgeid);
+typedef u32 (*bfa_fcxp_get_sglen_t) (void *bfad_fcxp, int sgeid);
+
+#define BFA_UF_BUFSZ (2 * 1024 + 256)
+
+/**
+ * @todo private
+ */
+struct bfa_uf_buf_s {
+ u8 d[BFA_UF_BUFSZ];
+};
+
+
+struct bfa_uf_s {
+ struct list_head qe; /* queue element */
+ struct bfa_s *bfa; /* bfa instance */
+ u16 uf_tag; /* identifying tag f/w messages */
+ u16 vf_id;
+ u16 src_rport_handle;
+ u16 rsvd;
+ u8 *data_ptr;
+ u16 data_len; /* actual receive length */
+ u16 pb_len; /* posted buffer length */
+ void *buf_kva; /* buffer virtual address */
+ u64 buf_pa; /* buffer physical address */
+ struct bfa_cb_qe_s hcb_qe; /* comp: BFA comp qelem */
+ struct bfa_sge_s sges[BFI_SGE_INLINE_MAX];
+};
+
+typedef void (*bfa_cb_pport_t) (void *cbarg, enum bfa_status status);
+
+/**
+ * bfa lport login/logout service interface
+ */
+struct bfa_lps_s {
+ struct list_head qe; /* queue element */
+ struct bfa_s *bfa; /* parent bfa instance */
+ bfa_sm_t sm; /* finite state machine */
+ u8 lp_tag; /* lport tag */
+ u8 reqq; /* lport request queue */
+ u8 alpa; /* ALPA for loop topologies */
+ u32 lp_pid; /* lport port ID */
+ bfa_boolean_t fdisc; /* send FDISC instead of FLOGI*/
+ bfa_boolean_t auth_en; /* enable authentication */
+ bfa_boolean_t auth_req; /* authentication required */
+ bfa_boolean_t npiv_en; /* NPIV is allowed by peer */
+ bfa_boolean_t fport; /* attached peer is F_PORT */
+ bfa_boolean_t brcd_switch;/* attached peer is brcd switch */
+ bfa_status_t status; /* login status */
+ u16 pdusz; /* max receive PDU size */
+ u16 pr_bbcred; /* BB_CREDIT from peer */
+ u8 lsrjt_rsn; /* LSRJT reason */
+ u8 lsrjt_expl; /* LSRJT explanation */
+ wwn_t pwwn; /* port wwn of lport */
+ wwn_t nwwn; /* node wwn of lport */
+ wwn_t pr_pwwn; /* port wwn of lport peer */
+ wwn_t pr_nwwn; /* node wwn of lport peer */
+ mac_t lp_mac; /* fpma/spma MAC for lport */
+ mac_t fcf_mac; /* FCF MAC of lport */
+ struct bfa_reqq_wait_s wqe; /* request wait queue element */
+ void *uarg; /* user callback arg */
+ struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */
+ struct bfi_lps_login_rsp_s *loginrsp;
+ bfa_eproto_status_t ext_status;
+};
+
+/*
+ * bfa pport API functions
+ */
+bfa_status_t bfa_pport_enable(struct bfa_s *bfa);
+bfa_status_t bfa_pport_disable(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_speed(struct bfa_s *bfa,
+ enum bfa_pport_speed speed);
+enum bfa_pport_speed bfa_pport_get_speed(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_topology(struct bfa_s *bfa,
+ enum bfa_pport_topology topo);
+enum bfa_pport_topology bfa_pport_get_topology(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa);
+bfa_boolean_t bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa);
+u8 bfa_pport_get_myalpa(struct bfa_s *bfa);
+bfa_status_t bfa_pport_clr_hardalpa(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize);
+u16 bfa_pport_get_maxfrsize(struct bfa_s *bfa);
+u32 bfa_pport_mypid(struct bfa_s *bfa);
+u8 bfa_pport_get_rx_bbcredit(struct bfa_s *bfa);
+bfa_status_t bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap);
+bfa_status_t bfa_pport_trunk_disable(struct bfa_s *bfa);
+bfa_boolean_t bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap);
+void bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr);
+wwn_t bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node);
+bfa_status_t bfa_pport_get_stats(struct bfa_s *bfa,
+ union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg);
+bfa_status_t bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
+ void *cbarg);
+void bfa_pport_event_register(struct bfa_s *bfa,
+ void (*event_cbfn) (void *cbarg,
+ bfa_pport_event_t event), void *event_cbarg);
+bfa_boolean_t bfa_pport_is_disabled(struct bfa_s *bfa);
+void bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off);
+void bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off);
+bfa_status_t bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa,
+ enum bfa_pport_speed speed);
+enum bfa_pport_speed bfa_pport_get_ratelim_speed(struct bfa_s *bfa);
+
+void bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit);
+void bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status);
+void bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
+ bfa_boolean_t link_e2e_beacon);
+void bfa_cb_pport_event(void *cbarg, bfa_pport_event_t event);
+void bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr);
+void bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
+ struct bfa_qos_vc_attr_s *qos_vc_attr);
+bfa_status_t bfa_pport_get_qos_stats(struct bfa_s *bfa,
+ union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg);
+bfa_status_t bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
+ void *cbarg);
+bfa_boolean_t bfa_pport_is_ratelim(struct bfa_s *bfa);
+bfa_boolean_t bfa_pport_is_linkup(struct bfa_s *bfa);
+
+/*
+ * bfa rport API functions
+ */
+struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv);
+void bfa_rport_delete(struct bfa_rport_s *rport);
+void bfa_rport_online(struct bfa_rport_s *rport,
+ struct bfa_rport_info_s *rport_info);
+void bfa_rport_offline(struct bfa_rport_s *rport);
+void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed);
+void bfa_rport_get_stats(struct bfa_rport_s *rport,
+ struct bfa_rport_hal_stats_s *stats);
+void bfa_rport_clear_stats(struct bfa_rport_s *rport);
+void bfa_cb_rport_online(void *rport);
+void bfa_cb_rport_offline(void *rport);
+void bfa_cb_rport_qos_scn_flowid(void *rport,
+ struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr);
+void bfa_cb_rport_qos_scn_prio(void *rport,
+ struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr);
+void bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
+ struct bfa_rport_qos_attr_s *qos_attr);
+
+/*
+ * bfa fcxp API functions
+ */
+struct bfa_fcxp_s *bfa_fcxp_alloc(void *bfad_fcxp, struct bfa_s *bfa,
+ int nreq_sgles, int nrsp_sgles,
+ bfa_fcxp_get_sgaddr_t get_req_sga,
+ bfa_fcxp_get_sglen_t get_req_sglen,
+ bfa_fcxp_get_sgaddr_t get_rsp_sga,
+ bfa_fcxp_get_sglen_t get_rsp_sglen);
+void bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe,
+ bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *cbarg);
+void bfa_fcxp_walloc_cancel(struct bfa_s *bfa,
+ struct bfa_fcxp_wqe_s *wqe);
+void bfa_fcxp_discard(struct bfa_fcxp_s *fcxp);
+
+void *bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp);
+void *bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp);
+
+void bfa_fcxp_free(struct bfa_fcxp_s *fcxp);
+
+void bfa_fcxp_send(struct bfa_fcxp_s *fcxp,
+ struct bfa_rport_s *rport, u16 vf_id, u8 lp_tag,
+ bfa_boolean_t cts, enum fc_cos cos,
+ u32 reqlen, struct fchs_s *fchs,
+ bfa_cb_fcxp_send_t cbfn,
+ void *cbarg,
+ u32 rsp_maxlen, u8 rsp_timeout);
+bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp);
+u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp);
+u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa);
+
+static inline void *
+bfa_uf_get_frmbuf(struct bfa_uf_s *uf)
+{
+ return uf->data_ptr;
+}
+
+static inline u16
+bfa_uf_get_frmlen(struct bfa_uf_s *uf)
+{
+ return uf->data_len;
+}
+
+/**
+ * Callback prototype for unsolicited frame receive handler.
+ *
+ * @param[in] cbarg callback arg for receive handler
+ * @param[in] uf unsolicited frame descriptor
+ *
+ * @return None
+ */
+typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf);
+
+/*
+ * bfa uf API functions
+ */
+void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv,
+ void *cbarg);
+void bfa_uf_free(struct bfa_uf_s *uf);
+
+/**
+ * bfa lport service api
+ */
+
+struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa);
+void bfa_lps_delete(struct bfa_lps_s *lps);
+void bfa_lps_discard(struct bfa_lps_s *lps);
+void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
+ wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en);
+void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
+ wwn_t nwwn);
+void bfa_lps_flogo(struct bfa_lps_s *lps);
+void bfa_lps_fdisclogo(struct bfa_lps_s *lps);
+u8 bfa_lps_get_tag(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_npiv_en(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_fport(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_authreq(struct bfa_lps_s *lps);
+bfa_eproto_status_t bfa_lps_get_extstatus(struct bfa_lps_s *lps);
+u32 bfa_lps_get_pid(struct bfa_lps_s *lps);
+u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid);
+u16 bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps);
+wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps);
+wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps);
+u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps);
+u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps);
+void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status);
+void bfa_cb_lps_flogo_comp(void *bfad, void *uarg);
+void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status);
+void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg);
+
+#endif /* __BFA_SVC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfa_timer.h b/drivers/scsi/bfa/include/bfa_timer.h
new file mode 100644
index 000000000000..e407103fa565
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_timer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_TIMER_H__
+#define __BFA_TIMER_H__
+
+#include <bfa_os_inc.h>
+#include <cs/bfa_q.h>
+
+struct bfa_s;
+
+typedef void (*bfa_timer_cbfn_t)(void *);
+
+/**
+ * BFA timer data structure
+ */
+struct bfa_timer_s {
+ struct list_head qe;
+ bfa_timer_cbfn_t timercb;
+ void *arg;
+ int timeout; /**< in millisecs. */
+};
+
+/**
+ * Timer module structure
+ */
+struct bfa_timer_mod_s {
+ struct list_head timer_q;
+};
+
+#define BFA_TIMER_FREQ 500 /**< specified in millisecs */
+
+void bfa_timer_beat(struct bfa_timer_mod_s *mod);
+void bfa_timer_init(struct bfa_timer_mod_s *mod);
+void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
+ bfa_timer_cbfn_t timercb, void *arg,
+ unsigned int timeout);
+void bfa_timer_stop(struct bfa_timer_s *timer);
+
+#endif /* __BFA_TIMER_H__ */
diff --git a/drivers/scsi/bfa/include/bfi/bfi.h b/drivers/scsi/bfa/include/bfi/bfi.h
new file mode 100644
index 000000000000..6cadfe0d4ba1
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_H__
+#define __BFI_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_status.h>
+
+#pragma pack(1)
+
+/**
+ * Msg header common to all msgs
+ */
+struct bfi_mhdr_s {
+ u8 msg_class; /* @ref bfi_mclass_t */
+ u8 msg_id; /* msg opcode with in the class */
+ union {
+ struct {
+ u8 rsvd;
+ u8 lpu_id; /* msg destination */
+ } h2i;
+ u16 i2htok; /* token in msgs to host */
+ } mtag;
+};
+
+#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \
+ (_mh).msg_class = (_mc); \
+ (_mh).msg_id = (_op); \
+ (_mh).mtag.h2i.lpu_id = (_lpuid); \
+} while (0)
+
+#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \
+ (_mh).msg_class = (_mc); \
+ (_mh).msg_id = (_op); \
+ (_mh).mtag.i2htok = (_i2htok); \
+} while (0)
+
+/*
+ * Message opcodes: 0-127 to firmware, 128-255 to host
+ */
+#define BFI_I2H_OPCODE_BASE 128
+#define BFA_I2HM(_x) ((_x) + BFI_I2H_OPCODE_BASE)
+
+/**
+ ****************************************************************************
+ *
+ * Scatter Gather Element and Page definition
+ *
+ ****************************************************************************
+ */
+
+#define BFI_SGE_INLINE 1
+#define BFI_SGE_INLINE_MAX (BFI_SGE_INLINE + 1)
+
+/**
+ * SG Flags
+ */
+enum {
+ BFI_SGE_DATA = 0, /* data address, not last */
+ BFI_SGE_DATA_CPL = 1, /* data addr, last in current page */
+ BFI_SGE_DATA_LAST = 3, /* data address, last */
+ BFI_SGE_LINK = 2, /* link address */
+ BFI_SGE_PGDLEN = 2, /* cumulative data length for page */
+};
+
+/**
+ * DMA addresses
+ */
+union bfi_addr_u {
+ struct {
+ u32 addr_lo;
+ u32 addr_hi;
+ } a32;
+};
+
+/**
+ * Scatter Gather Element
+ */
+struct bfi_sge_s {
+#ifdef __BIGENDIAN
+ u32 flags : 2,
+ rsvd : 2,
+ sg_len : 28;
+#else
+ u32 sg_len : 28,
+ rsvd : 2,
+ flags : 2;
+#endif
+ union bfi_addr_u sga;
+};
+
+/**
+ * Scatter Gather Page
+ */
+#define BFI_SGPG_DATA_SGES 7
+#define BFI_SGPG_SGES_MAX (BFI_SGPG_DATA_SGES + 1)
+#define BFI_SGPG_RSVD_WD_LEN 8
+struct bfi_sgpg_s {
+ struct bfi_sge_s sges[BFI_SGPG_SGES_MAX];
+ u32 rsvd[BFI_SGPG_RSVD_WD_LEN];
+};
+
+/*
+ * Large Message structure - 128 Bytes size Msgs
+ */
+#define BFI_LMSG_SZ 128
+#define BFI_LMSG_PL_WSZ \
+ ((BFI_LMSG_SZ - sizeof(struct bfi_mhdr_s)) / 4)
+
+struct bfi_msg_s {
+ struct bfi_mhdr_s mhdr;
+ u32 pl[BFI_LMSG_PL_WSZ];
+};
+
+/**
+ * Mailbox message structure
+ */
+#define BFI_MBMSG_SZ 7
+struct bfi_mbmsg_s {
+ struct bfi_mhdr_s mh;
+ u32 pl[BFI_MBMSG_SZ];
+};
+
+/**
+ * Message Classes
+ */
+enum bfi_mclass {
+ BFI_MC_IOC = 1, /* IO Controller (IOC) */
+ BFI_MC_DIAG = 2, /* Diagnostic Msgs */
+ BFI_MC_FLASH = 3, /* Flash message class */
+ BFI_MC_CEE = 4,
+ BFI_MC_FC_PORT = 5, /* FC port */
+ BFI_MC_IOCFC = 6, /* FC - IO Controller (IOC) */
+ BFI_MC_LL = 7, /* Link Layer */
+ BFI_MC_UF = 8, /* Unsolicited frame receive */
+ BFI_MC_FCXP = 9, /* FC Transport */
+ BFI_MC_LPS = 10, /* lport fc login services */
+ BFI_MC_RPORT = 11, /* Remote port */
+ BFI_MC_ITNIM = 12, /* I-T nexus (Initiator mode) */
+ BFI_MC_IOIM_READ = 13, /* read IO (Initiator mode) */
+ BFI_MC_IOIM_WRITE = 14, /* write IO (Initiator mode) */
+ BFI_MC_IOIM_IO = 15, /* IO (Initiator mode) */
+ BFI_MC_IOIM = 16, /* IO (Initiator mode) */
+ BFI_MC_IOIM_IOCOM = 17, /* good IO completion */
+ BFI_MC_TSKIM = 18, /* Initiator Task management */
+ BFI_MC_SBOOT = 19, /* SAN boot services */
+ BFI_MC_IPFC = 20, /* IP over FC Msgs */
+ BFI_MC_PORT = 21, /* Physical port */
+ BFI_MC_MAX = 32
+};
+
+#define BFI_IOC_MAX_CQS 4
+#define BFI_IOC_MAX_CQS_ASIC 8
+#define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */
+
+#pragma pack()
+
+#endif /* __BFI_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_boot.h b/drivers/scsi/bfa/include/bfi/bfi_boot.h
new file mode 100644
index 000000000000..5955afe7d108
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_boot.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+/*
+ * bfi_boot.h
+ */
+
+#ifndef __BFI_BOOT_H__
+#define __BFI_BOOT_H__
+
+#define BFI_BOOT_TYPE_OFF 8
+#define BFI_BOOT_PARAM_OFF 12
+
+#define BFI_BOOT_TYPE_NORMAL 0 /* param is device id */
+#define BFI_BOOT_TYPE_FLASH 1
+#define BFI_BOOT_TYPE_MEMTEST 2
+
+#define BFI_BOOT_MEMTEST_RES_ADDR 0x900
+#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3
+
+#endif
diff --git a/drivers/scsi/bfa/include/bfi/bfi_cbreg.h b/drivers/scsi/bfa/include/bfi/bfi_cbreg.h
new file mode 100644
index 000000000000..b3bb52b565b1
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_cbreg.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/*
+ * bfi_cbreg.h crossbow host block register definitions
+ *
+ * !!! Do not edit. Auto generated. !!!
+ */
+
+#ifndef __BFI_CBREG_H__
+#define __BFI_CBREG_H__
+
+
+#define HOSTFN0_INT_STATUS 0x00014000
+#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN0_INT_STATUS_LVL_SH 20
+#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH)
+#define __HOSTFN0_INT_STATUS_P 0x000fffff
+#define HOSTFN0_INT_MSK 0x00014004
+#define HOST_PAGE_NUM_FN0 0x00014008
+#define __HOST_PAGE_NUM_FN 0x000001ff
+#define HOSTFN1_INT_STATUS 0x00014100
+#define __HOSTFN1_INT_STAT_LVL_MK 0x00f00000
+#define __HOSTFN1_INT_STAT_LVL_SH 20
+#define __HOSTFN1_INT_STAT_LVL(_v) ((_v) << __HOSTFN1_INT_STAT_LVL_SH)
+#define __HOSTFN1_INT_STAT_P 0x000fffff
+#define HOSTFN1_INT_MSK 0x00014104
+#define HOST_PAGE_NUM_FN1 0x00014108
+#define APP_PLL_400_CTL_REG 0x00014204
+#define __P_400_PLL_LOCK 0x80000000
+#define __APP_PLL_400_SRAM_USE_100MHZ 0x00100000
+#define __APP_PLL_400_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_400_RESET_TIMER_SH 17
+#define __APP_PLL_400_RESET_TIMER(_v) ((_v) << __APP_PLL_400_RESET_TIMER_SH)
+#define __APP_PLL_400_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_400_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_400_CNTLMT0_1_SH 14
+#define __APP_PLL_400_CNTLMT0_1(_v) ((_v) << __APP_PLL_400_CNTLMT0_1_SH)
+#define __APP_PLL_400_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_400_JITLMT0_1_SH 12
+#define __APP_PLL_400_JITLMT0_1(_v) ((_v) << __APP_PLL_400_JITLMT0_1_SH)
+#define __APP_PLL_400_HREF 0x00000800
+#define __APP_PLL_400_HDIV 0x00000400
+#define __APP_PLL_400_P0_1_MK 0x00000300
+#define __APP_PLL_400_P0_1_SH 8
+#define __APP_PLL_400_P0_1(_v) ((_v) << __APP_PLL_400_P0_1_SH)
+#define __APP_PLL_400_Z0_2_MK 0x000000e0
+#define __APP_PLL_400_Z0_2_SH 5
+#define __APP_PLL_400_Z0_2(_v) ((_v) << __APP_PLL_400_Z0_2_SH)
+#define __APP_PLL_400_RSEL200500 0x00000010
+#define __APP_PLL_400_ENARST 0x00000008
+#define __APP_PLL_400_BYPASS 0x00000004
+#define __APP_PLL_400_LRESETN 0x00000002
+#define __APP_PLL_400_ENABLE 0x00000001
+#define APP_PLL_212_CTL_REG 0x00014208
+#define __P_212_PLL_LOCK 0x80000000
+#define __APP_PLL_212_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_212_RESET_TIMER_SH 17
+#define __APP_PLL_212_RESET_TIMER(_v) ((_v) << __APP_PLL_212_RESET_TIMER_SH)
+#define __APP_PLL_212_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_212_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_212_CNTLMT0_1_SH 14
+#define __APP_PLL_212_CNTLMT0_1(_v) ((_v) << __APP_PLL_212_CNTLMT0_1_SH)
+#define __APP_PLL_212_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_212_JITLMT0_1_SH 12
+#define __APP_PLL_212_JITLMT0_1(_v) ((_v) << __APP_PLL_212_JITLMT0_1_SH)
+#define __APP_PLL_212_HREF 0x00000800
+#define __APP_PLL_212_HDIV 0x00000400
+#define __APP_PLL_212_P0_1_MK 0x00000300
+#define __APP_PLL_212_P0_1_SH 8
+#define __APP_PLL_212_P0_1(_v) ((_v) << __APP_PLL_212_P0_1_SH)
+#define __APP_PLL_212_Z0_2_MK 0x000000e0
+#define __APP_PLL_212_Z0_2_SH 5
+#define __APP_PLL_212_Z0_2(_v) ((_v) << __APP_PLL_212_Z0_2_SH)
+#define __APP_PLL_212_RSEL200500 0x00000010
+#define __APP_PLL_212_ENARST 0x00000008
+#define __APP_PLL_212_BYPASS 0x00000004
+#define __APP_PLL_212_LRESETN 0x00000002
+#define __APP_PLL_212_ENABLE 0x00000001
+#define HOST_SEM0_REG 0x00014230
+#define __HOST_SEMAPHORE 0x00000001
+#define HOST_SEM1_REG 0x00014234
+#define HOST_SEM2_REG 0x00014238
+#define HOST_SEM3_REG 0x0001423c
+#define HOST_SEM0_INFO_REG 0x00014240
+#define HOST_SEM1_INFO_REG 0x00014244
+#define HOST_SEM2_INFO_REG 0x00014248
+#define HOST_SEM3_INFO_REG 0x0001424c
+#define HOSTFN0_LPU0_CMD_STAT 0x00019000
+#define __HOSTFN0_LPU0_MBOX_INFO_MK 0xfffffffe
+#define __HOSTFN0_LPU0_MBOX_INFO_SH 1
+#define __HOSTFN0_LPU0_MBOX_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX_INFO_SH)
+#define __HOSTFN0_LPU0_MBOX_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN0_CMD_STAT 0x00019008
+#define __LPU0_HOSTFN0_MBOX_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN0_MBOX_INFO_SH 1
+#define __LPU0_HOSTFN0_MBOX_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX_INFO_SH)
+#define __LPU0_HOSTFN0_MBOX_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU1_CMD_STAT 0x00019014
+#define __HOSTFN1_LPU1_MBOX_INFO_MK 0xfffffffe
+#define __HOSTFN1_LPU1_MBOX_INFO_SH 1
+#define __HOSTFN1_LPU1_MBOX_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX_INFO_SH)
+#define __HOSTFN1_LPU1_MBOX_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN1_CMD_STAT 0x0001901c
+#define __LPU1_HOSTFN1_MBOX_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN1_MBOX_INFO_SH 1
+#define __LPU1_HOSTFN1_MBOX_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX_INFO_SH)
+#define __LPU1_HOSTFN1_MBOX_CMD_STATUS 0x00000001
+#define CPE_Q0_DEPTH 0x00010014
+#define CPE_Q0_PI 0x0001001c
+#define CPE_Q0_CI 0x00010020
+#define CPE_Q1_DEPTH 0x00010034
+#define CPE_Q1_PI 0x0001003c
+#define CPE_Q1_CI 0x00010040
+#define CPE_Q2_DEPTH 0x00010054
+#define CPE_Q2_PI 0x0001005c
+#define CPE_Q2_CI 0x00010060
+#define CPE_Q3_DEPTH 0x00010074
+#define CPE_Q3_PI 0x0001007c
+#define CPE_Q3_CI 0x00010080
+#define CPE_Q4_DEPTH 0x00010094
+#define CPE_Q4_PI 0x0001009c
+#define CPE_Q4_CI 0x000100a0
+#define CPE_Q5_DEPTH 0x000100b4
+#define CPE_Q5_PI 0x000100bc
+#define CPE_Q5_CI 0x000100c0
+#define CPE_Q6_DEPTH 0x000100d4
+#define CPE_Q6_PI 0x000100dc
+#define CPE_Q6_CI 0x000100e0
+#define CPE_Q7_DEPTH 0x000100f4
+#define CPE_Q7_PI 0x000100fc
+#define CPE_Q7_CI 0x00010100
+#define RME_Q0_DEPTH 0x00011014
+#define RME_Q0_PI 0x0001101c
+#define RME_Q0_CI 0x00011020
+#define RME_Q1_DEPTH 0x00011034
+#define RME_Q1_PI 0x0001103c
+#define RME_Q1_CI 0x00011040
+#define RME_Q2_DEPTH 0x00011054
+#define RME_Q2_PI 0x0001105c
+#define RME_Q2_CI 0x00011060
+#define RME_Q3_DEPTH 0x00011074
+#define RME_Q3_PI 0x0001107c
+#define RME_Q3_CI 0x00011080
+#define RME_Q4_DEPTH 0x00011094
+#define RME_Q4_PI 0x0001109c
+#define RME_Q4_CI 0x000110a0
+#define RME_Q5_DEPTH 0x000110b4
+#define RME_Q5_PI 0x000110bc
+#define RME_Q5_CI 0x000110c0
+#define RME_Q6_DEPTH 0x000110d4
+#define RME_Q6_PI 0x000110dc
+#define RME_Q6_CI 0x000110e0
+#define RME_Q7_DEPTH 0x000110f4
+#define RME_Q7_PI 0x000110fc
+#define RME_Q7_CI 0x00011100
+#define PSS_CTL_REG 0x00018800
+#define __PSS_I2C_CLK_DIV_MK 0x00030000
+#define __PSS_I2C_CLK_DIV_SH 16
+#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH)
+#define __PSS_LMEM_INIT_DONE 0x00001000
+#define __PSS_LMEM_RESET 0x00000200
+#define __PSS_LMEM_INIT_EN 0x00000100
+#define __PSS_LPU1_RESET 0x00000002
+#define __PSS_LPU0_RESET 0x00000001
+
+
+/*
+ * These definitions are either in error/missing in spec. Its auto-generated
+ * from hard coded values in regparse.pl.
+ */
+#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c
+#define __EMPHPOST_AT_4G_SH_FIX 0x00000002
+#define __EMPHPRE_AT_4G_FIX 0x00000003
+#define __SFP_TXRATE_EN_FIX 0x00000100
+#define __SFP_RXRATE_EN_FIX 0x00000080
+
+
+/*
+ * These register definitions are auto-generated from hard coded values
+ * in regparse.pl.
+ */
+#define HOSTFN0_LPU_MBOX0_0 0x00019200
+#define HOSTFN1_LPU_MBOX0_8 0x00019260
+#define LPU_HOSTFN0_MBOX0_0 0x00019280
+#define LPU_HOSTFN1_MBOX0_8 0x000192e0
+
+
+/*
+ * These register mapping definitions are auto-generated from mapping tables
+ * in regparse.pl.
+ */
+#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG
+#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG
+#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
+#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
+#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+
+#define CPE_Q_DEPTH(__n) \
+ (CPE_Q0_DEPTH + (__n) * (CPE_Q1_DEPTH - CPE_Q0_DEPTH))
+#define CPE_Q_PI(__n) \
+ (CPE_Q0_PI + (__n) * (CPE_Q1_PI - CPE_Q0_PI))
+#define CPE_Q_CI(__n) \
+ (CPE_Q0_CI + (__n) * (CPE_Q1_CI - CPE_Q0_CI))
+#define RME_Q_DEPTH(__n) \
+ (RME_Q0_DEPTH + (__n) * (RME_Q1_DEPTH - RME_Q0_DEPTH))
+#define RME_Q_PI(__n) \
+ (RME_Q0_PI + (__n) * (RME_Q1_PI - RME_Q0_PI))
+#define RME_Q_CI(__n) \
+ (RME_Q0_CI + (__n) * (RME_Q1_CI - RME_Q0_CI))
+
+#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define CPE_Q_MASK(__q) ((__q) & 0x3)
+#define RME_Q_MASK(__q) ((__q) & 0x3)
+
+
+/*
+ * PCI MSI-X vector defines
+ */
+enum {
+ BFA_MSIX_CPE_Q0 = 0,
+ BFA_MSIX_CPE_Q1 = 1,
+ BFA_MSIX_CPE_Q2 = 2,
+ BFA_MSIX_CPE_Q3 = 3,
+ BFA_MSIX_CPE_Q4 = 4,
+ BFA_MSIX_CPE_Q5 = 5,
+ BFA_MSIX_CPE_Q6 = 6,
+ BFA_MSIX_CPE_Q7 = 7,
+ BFA_MSIX_RME_Q0 = 8,
+ BFA_MSIX_RME_Q1 = 9,
+ BFA_MSIX_RME_Q2 = 10,
+ BFA_MSIX_RME_Q3 = 11,
+ BFA_MSIX_RME_Q4 = 12,
+ BFA_MSIX_RME_Q5 = 13,
+ BFA_MSIX_RME_Q6 = 14,
+ BFA_MSIX_RME_Q7 = 15,
+ BFA_MSIX_ERR_EMC = 16,
+ BFA_MSIX_ERR_LPU0 = 17,
+ BFA_MSIX_ERR_LPU1 = 18,
+ BFA_MSIX_ERR_PSS = 19,
+ BFA_MSIX_MBOX_LPU0 = 20,
+ BFA_MSIX_MBOX_LPU1 = 21,
+ BFA_MSIX_CB_MAX = 22,
+};
+
+/*
+ * And corresponding host interrupt status bit field defines
+ */
+#define __HFN_INT_CPE_Q0 0x00000001U
+#define __HFN_INT_CPE_Q1 0x00000002U
+#define __HFN_INT_CPE_Q2 0x00000004U
+#define __HFN_INT_CPE_Q3 0x00000008U
+#define __HFN_INT_CPE_Q4 0x00000010U
+#define __HFN_INT_CPE_Q5 0x00000020U
+#define __HFN_INT_CPE_Q6 0x00000040U
+#define __HFN_INT_CPE_Q7 0x00000080U
+#define __HFN_INT_RME_Q0 0x00000100U
+#define __HFN_INT_RME_Q1 0x00000200U
+#define __HFN_INT_RME_Q2 0x00000400U
+#define __HFN_INT_RME_Q3 0x00000800U
+#define __HFN_INT_RME_Q4 0x00001000U
+#define __HFN_INT_RME_Q5 0x00002000U
+#define __HFN_INT_RME_Q6 0x00004000U
+#define __HFN_INT_RME_Q7 0x00008000U
+#define __HFN_INT_ERR_EMC 0x00010000U
+#define __HFN_INT_ERR_LPU0 0x00020000U
+#define __HFN_INT_ERR_LPU1 0x00040000U
+#define __HFN_INT_ERR_PSS 0x00080000U
+#define __HFN_INT_MBOX_LPU0 0x00100000U
+#define __HFN_INT_MBOX_LPU1 0x00200000U
+#define __HFN_INT_MBOX1_LPU0 0x00400000U
+#define __HFN_INT_MBOX1_LPU1 0x00800000U
+#define __HFN_INT_CPE_MASK 0x000000ffU
+#define __HFN_INT_RME_MASK 0x0000ff00U
+
+
+/*
+ * crossbow memory map.
+ */
+#define PSS_SMEM_PAGE_START 0x8000
+#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15))
+#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff)
+
+/*
+ * End of crossbow memory map
+ */
+
+
+#endif /* __BFI_CBREG_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_cee.h b/drivers/scsi/bfa/include/bfi/bfi_cee.h
new file mode 100644
index 000000000000..0970596583ea
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_cee.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+/**
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * bfi_dcbx.h BFI Interface (Mailbox commands and related structures)
+ * between host driver and DCBX/LLDP firmware module.
+ *
+**/
+
+#ifndef __BFI_CEE_H__
+#define __BFI_CEE_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+
+enum bfi_cee_h2i_msgs_e {
+ BFI_CEE_H2I_GET_CFG_REQ = 1,
+ BFI_CEE_H2I_RESET_STATS = 2,
+ BFI_CEE_H2I_GET_STATS_REQ = 3,
+};
+
+
+enum bfi_cee_i2h_msgs_e {
+ BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1),
+ BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2),
+ BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3),
+};
+
+
+/* Data structures */
+
+/*
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_lldp_reset_stats_s {
+ struct bfi_mhdr_s mh;
+};
+
+/*
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_cee_reset_stats_s {
+ struct bfi_mhdr_s mh;
+};
+
+/*
+ * BFI_CEE_H2I_GET_CFG_REQ
+ */
+struct bfi_cee_get_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u dma_addr;
+};
+
+
+/*
+ * BFI_CEE_I2H_GET_CFG_RSP
+ */
+struct bfi_cee_get_rsp_s {
+ struct bfi_mhdr_s mh;
+ u8 cmd_status;
+ u8 rsvd[3];
+};
+
+/*
+ * BFI_CEE_H2I_GET_STATS_REQ
+ */
+struct bfi_cee_stats_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u dma_addr;
+};
+
+
+/*
+ * BFI_CEE_I2H_GET_STATS_RSP
+ */
+struct bfi_cee_stats_rsp_s {
+ struct bfi_mhdr_s mh;
+ u8 cmd_status;
+ u8 rsvd[3];
+};
+
+
+
+union bfi_cee_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_cee_get_req_s get_req;
+ struct bfi_cee_stats_req_s stats_req;
+};
+
+
+union bfi_cee_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_cee_get_rsp_s get_rsp;
+ struct bfi_cee_stats_rsp_s stats_rsp;
+};
+
+#pragma pack()
+
+
+#endif /* __BFI_CEE_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
new file mode 100644
index 000000000000..d3caa58c0a0a
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/*
+ * bfi_ctreg.h catapult host block register definitions
+ *
+ * !!! Do not edit. Auto generated. !!!
+ */
+
+#ifndef __BFI_CTREG_H__
+#define __BFI_CTREG_H__
+
+
+#define HOSTFN0_LPU_MBOX0_0 0x00019200
+#define HOSTFN1_LPU_MBOX0_8 0x00019260
+#define LPU_HOSTFN0_MBOX0_0 0x00019280
+#define LPU_HOSTFN1_MBOX0_8 0x000192e0
+#define HOSTFN2_LPU_MBOX0_0 0x00019400
+#define HOSTFN3_LPU_MBOX0_8 0x00019460
+#define LPU_HOSTFN2_MBOX0_0 0x00019480
+#define LPU_HOSTFN3_MBOX0_8 0x000194e0
+#define HOSTFN0_INT_STATUS 0x00014000
+#define __HOSTFN0_HALT_OCCURRED 0x01000000
+#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN0_INT_STATUS_LVL_SH 20
+#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH)
+#define __HOSTFN0_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN0_INT_STATUS_P_SH 16
+#define __HOSTFN0_INT_STATUS_P(_v) ((_v) << __HOSTFN0_INT_STATUS_P_SH)
+#define __HOSTFN0_INT_STATUS_F 0x0000ffff
+#define HOSTFN0_INT_MSK 0x00014004
+#define HOST_PAGE_NUM_FN0 0x00014008
+#define __HOST_PAGE_NUM_FN 0x000001ff
+#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c
+#define __MSIX_ERR_INDEX_FN 0x000001ff
+#define HOSTFN1_INT_STATUS 0x00014100
+#define __HOSTFN1_HALT_OCCURRED 0x01000000
+#define __HOSTFN1_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN1_INT_STATUS_LVL_SH 20
+#define __HOSTFN1_INT_STATUS_LVL(_v) ((_v) << __HOSTFN1_INT_STATUS_LVL_SH)
+#define __HOSTFN1_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN1_INT_STATUS_P_SH 16
+#define __HOSTFN1_INT_STATUS_P(_v) ((_v) << __HOSTFN1_INT_STATUS_P_SH)
+#define __HOSTFN1_INT_STATUS_F 0x0000ffff
+#define HOSTFN1_INT_MSK 0x00014104
+#define HOST_PAGE_NUM_FN1 0x00014108
+#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c
+#define APP_PLL_425_CTL_REG 0x00014204
+#define __P_425_PLL_LOCK 0x80000000
+#define __APP_PLL_425_SRAM_USE_100MHZ 0x00100000
+#define __APP_PLL_425_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_425_RESET_TIMER_SH 17
+#define __APP_PLL_425_RESET_TIMER(_v) ((_v) << __APP_PLL_425_RESET_TIMER_SH)
+#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_425_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_425_CNTLMT0_1_SH 14
+#define __APP_PLL_425_CNTLMT0_1(_v) ((_v) << __APP_PLL_425_CNTLMT0_1_SH)
+#define __APP_PLL_425_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_425_JITLMT0_1_SH 12
+#define __APP_PLL_425_JITLMT0_1(_v) ((_v) << __APP_PLL_425_JITLMT0_1_SH)
+#define __APP_PLL_425_HREF 0x00000800
+#define __APP_PLL_425_HDIV 0x00000400
+#define __APP_PLL_425_P0_1_MK 0x00000300
+#define __APP_PLL_425_P0_1_SH 8
+#define __APP_PLL_425_P0_1(_v) ((_v) << __APP_PLL_425_P0_1_SH)
+#define __APP_PLL_425_Z0_2_MK 0x000000e0
+#define __APP_PLL_425_Z0_2_SH 5
+#define __APP_PLL_425_Z0_2(_v) ((_v) << __APP_PLL_425_Z0_2_SH)
+#define __APP_PLL_425_RSEL200500 0x00000010
+#define __APP_PLL_425_ENARST 0x00000008
+#define __APP_PLL_425_BYPASS 0x00000004
+#define __APP_PLL_425_LRESETN 0x00000002
+#define __APP_PLL_425_ENABLE 0x00000001
+#define APP_PLL_312_CTL_REG 0x00014208
+#define __P_312_PLL_LOCK 0x80000000
+#define __ENABLE_MAC_AHB_1 0x00800000
+#define __ENABLE_MAC_AHB_0 0x00400000
+#define __ENABLE_MAC_1 0x00200000
+#define __ENABLE_MAC_0 0x00100000
+#define __APP_PLL_312_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_312_RESET_TIMER_SH 17
+#define __APP_PLL_312_RESET_TIMER(_v) ((_v) << __APP_PLL_312_RESET_TIMER_SH)
+#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_312_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_312_CNTLMT0_1_SH 14
+#define __APP_PLL_312_CNTLMT0_1(_v) ((_v) << __APP_PLL_312_CNTLMT0_1_SH)
+#define __APP_PLL_312_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_312_JITLMT0_1_SH 12
+#define __APP_PLL_312_JITLMT0_1(_v) ((_v) << __APP_PLL_312_JITLMT0_1_SH)
+#define __APP_PLL_312_HREF 0x00000800
+#define __APP_PLL_312_HDIV 0x00000400
+#define __APP_PLL_312_P0_1_MK 0x00000300
+#define __APP_PLL_312_P0_1_SH 8
+#define __APP_PLL_312_P0_1(_v) ((_v) << __APP_PLL_312_P0_1_SH)
+#define __APP_PLL_312_Z0_2_MK 0x000000e0
+#define __APP_PLL_312_Z0_2_SH 5
+#define __APP_PLL_312_Z0_2(_v) ((_v) << __APP_PLL_312_Z0_2_SH)
+#define __APP_PLL_312_RSEL200500 0x00000010
+#define __APP_PLL_312_ENARST 0x00000008
+#define __APP_PLL_312_BYPASS 0x00000004
+#define __APP_PLL_312_LRESETN 0x00000002
+#define __APP_PLL_312_ENABLE 0x00000001
+#define MBIST_CTL_REG 0x00014220
+#define __EDRAM_BISTR_START 0x00000004
+#define __MBIST_RESET 0x00000002
+#define __MBIST_START 0x00000001
+#define MBIST_STAT_REG 0x00014224
+#define __EDRAM_BISTR_STATUS 0x00000008
+#define __EDRAM_BISTR_DONE 0x00000004
+#define __MEM_BIT_STATUS 0x00000002
+#define __MBIST_DONE 0x00000001
+#define HOST_SEM0_REG 0x00014230
+#define __HOST_SEMAPHORE 0x00000001
+#define HOST_SEM1_REG 0x00014234
+#define HOST_SEM2_REG 0x00014238
+#define HOST_SEM3_REG 0x0001423c
+#define HOST_SEM0_INFO_REG 0x00014240
+#define HOST_SEM1_INFO_REG 0x00014244
+#define HOST_SEM2_INFO_REG 0x00014248
+#define HOST_SEM3_INFO_REG 0x0001424c
+#define ETH_MAC_SER_REG 0x00014288
+#define __APP_EMS_CKBUFAMPIN 0x00000020
+#define __APP_EMS_REFCLKSEL 0x00000010
+#define __APP_EMS_CMLCKSEL 0x00000008
+#define __APP_EMS_REFCKBUFEN2 0x00000004
+#define __APP_EMS_REFCKBUFEN1 0x00000002
+#define __APP_EMS_CHANNEL_SEL 0x00000001
+#define HOSTFN2_INT_STATUS 0x00014300
+#define __HOSTFN2_HALT_OCCURRED 0x01000000
+#define __HOSTFN2_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN2_INT_STATUS_LVL_SH 20
+#define __HOSTFN2_INT_STATUS_LVL(_v) ((_v) << __HOSTFN2_INT_STATUS_LVL_SH)
+#define __HOSTFN2_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN2_INT_STATUS_P_SH 16
+#define __HOSTFN2_INT_STATUS_P(_v) ((_v) << __HOSTFN2_INT_STATUS_P_SH)
+#define __HOSTFN2_INT_STATUS_F 0x0000ffff
+#define HOSTFN2_INT_MSK 0x00014304
+#define HOST_PAGE_NUM_FN2 0x00014308
+#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c
+#define HOSTFN3_INT_STATUS 0x00014400
+#define __HALT_OCCURRED 0x01000000
+#define __HOSTFN3_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN3_INT_STATUS_LVL_SH 20
+#define __HOSTFN3_INT_STATUS_LVL(_v) ((_v) << __HOSTFN3_INT_STATUS_LVL_SH)
+#define __HOSTFN3_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN3_INT_STATUS_P_SH 16
+#define __HOSTFN3_INT_STATUS_P(_v) ((_v) << __HOSTFN3_INT_STATUS_P_SH)
+#define __HOSTFN3_INT_STATUS_F 0x0000ffff
+#define HOSTFN3_INT_MSK 0x00014404
+#define HOST_PAGE_NUM_FN3 0x00014408
+#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c
+#define FNC_ID_REG 0x00014600
+#define __FUNCTION_NUMBER 0x00000007
+#define FNC_PERS_REG 0x00014604
+#define __F3_FUNCTION_ACTIVE 0x80000000
+#define __F3_FUNCTION_MODE 0x40000000
+#define __F3_PORT_MAP_MK 0x30000000
+#define __F3_PORT_MAP_SH 28
+#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH)
+#define __F3_VM_MODE 0x08000000
+#define __F3_INTX_STATUS_MK 0x07000000
+#define __F3_INTX_STATUS_SH 24
+#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH)
+#define __F2_FUNCTION_ACTIVE 0x00800000
+#define __F2_FUNCTION_MODE 0x00400000
+#define __F2_PORT_MAP_MK 0x00300000
+#define __F2_PORT_MAP_SH 20
+#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH)
+#define __F2_VM_MODE 0x00080000
+#define __F2_INTX_STATUS_MK 0x00070000
+#define __F2_INTX_STATUS_SH 16
+#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH)
+#define __F1_FUNCTION_ACTIVE 0x00008000
+#define __F1_FUNCTION_MODE 0x00004000
+#define __F1_PORT_MAP_MK 0x00003000
+#define __F1_PORT_MAP_SH 12
+#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH)
+#define __F1_VM_MODE 0x00000800
+#define __F1_INTX_STATUS_MK 0x00000700
+#define __F1_INTX_STATUS_SH 8
+#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH)
+#define __F0_FUNCTION_ACTIVE 0x00000080
+#define __F0_FUNCTION_MODE 0x00000040
+#define __F0_PORT_MAP_MK 0x00000030
+#define __F0_PORT_MAP_SH 4
+#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH)
+#define __F0_VM_MODE 0x00000008
+#define __F0_INTX_STATUS 0x00000007
+enum {
+ __F0_INTX_STATUS_MSIX = 0x0,
+ __F0_INTX_STATUS_INTA = 0x1,
+ __F0_INTX_STATUS_INTB = 0x2,
+ __F0_INTX_STATUS_INTC = 0x3,
+ __F0_INTX_STATUS_INTD = 0x4,
+};
+#define OP_MODE 0x0001460c
+#define __APP_ETH_CLK_LOWSPEED 0x00000004
+#define __GLOBAL_CORECLK_HALFSPEED 0x00000002
+#define __GLOBAL_FCOE_MODE 0x00000001
+#define HOST_SEM4_REG 0x00014610
+#define HOST_SEM5_REG 0x00014614
+#define HOST_SEM6_REG 0x00014618
+#define HOST_SEM7_REG 0x0001461c
+#define HOST_SEM4_INFO_REG 0x00014620
+#define HOST_SEM5_INFO_REG 0x00014624
+#define HOST_SEM6_INFO_REG 0x00014628
+#define HOST_SEM7_INFO_REG 0x0001462c
+#define HOSTFN0_LPU0_MBOX0_CMD_STAT 0x00019000
+#define __HOSTFN0_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN0_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN0_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN0_LPU1_MBOX0_CMD_STAT 0x00019004
+#define __HOSTFN0_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN0_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN0_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN0_MBOX0_CMD_STAT 0x00019008
+#define __LPU0_HOSTFN0_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN0_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN0_MBOX0_CMD_STAT 0x0001900c
+#define __LPU1_HOSTFN0_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN0_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU0_MBOX0_CMD_STAT 0x00019010
+#define __HOSTFN1_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN1_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN1_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU1_MBOX0_CMD_STAT 0x00019014
+#define __HOSTFN1_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN1_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN1_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN1_MBOX0_CMD_STAT 0x00019018
+#define __LPU0_HOSTFN1_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN1_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN1_MBOX0_CMD_STAT 0x0001901c
+#define __LPU1_HOSTFN1_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN1_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN2_LPU0_MBOX0_CMD_STAT 0x00019150
+#define __HOSTFN2_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN2_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN2_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN2_LPU1_MBOX0_CMD_STAT 0x00019154
+#define __HOSTFN2_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN2_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN2_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN2_MBOX0_CMD_STAT 0x00019158
+#define __LPU0_HOSTFN2_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN2_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN2_MBOX0_CMD_STAT 0x0001915c
+#define __LPU1_HOSTFN2_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN2_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN3_LPU0_MBOX0_CMD_STAT 0x00019160
+#define __HOSTFN3_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN3_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN3_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN3_LPU1_MBOX0_CMD_STAT 0x00019164
+#define __HOSTFN3_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN3_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN3_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN3_MBOX0_CMD_STAT 0x00019168
+#define __LPU0_HOSTFN3_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN3_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN3_MBOX0_CMD_STAT 0x0001916c
+#define __LPU1_HOSTFN3_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN3_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS 0x00000001
+#define FW_INIT_HALT_P0 0x000191ac
+#define __FW_INIT_HALT_P 0x00000001
+#define FW_INIT_HALT_P1 0x000191bc
+#define CPE_PI_PTR_Q0 0x00038000
+#define __CPE_PI_UNUSED_MK 0xffff0000
+#define __CPE_PI_UNUSED_SH 16
+#define __CPE_PI_UNUSED(_v) ((_v) << __CPE_PI_UNUSED_SH)
+#define __CPE_PI_PTR 0x0000ffff
+#define CPE_PI_PTR_Q1 0x00038040
+#define CPE_CI_PTR_Q0 0x00038004
+#define __CPE_CI_UNUSED_MK 0xffff0000
+#define __CPE_CI_UNUSED_SH 16
+#define __CPE_CI_UNUSED(_v) ((_v) << __CPE_CI_UNUSED_SH)
+#define __CPE_CI_PTR 0x0000ffff
+#define CPE_CI_PTR_Q1 0x00038044
+#define CPE_DEPTH_Q0 0x00038008
+#define __CPE_DEPTH_UNUSED_MK 0xf8000000
+#define __CPE_DEPTH_UNUSED_SH 27
+#define __CPE_DEPTH_UNUSED(_v) ((_v) << __CPE_DEPTH_UNUSED_SH)
+#define __CPE_MSIX_VEC_INDEX_MK 0x07ff0000
+#define __CPE_MSIX_VEC_INDEX_SH 16
+#define __CPE_MSIX_VEC_INDEX(_v) ((_v) << __CPE_MSIX_VEC_INDEX_SH)
+#define __CPE_DEPTH 0x0000ffff
+#define CPE_DEPTH_Q1 0x00038048
+#define CPE_QCTRL_Q0 0x0003800c
+#define __CPE_CTRL_UNUSED30_MK 0xfc000000
+#define __CPE_CTRL_UNUSED30_SH 26
+#define __CPE_CTRL_UNUSED30(_v) ((_v) << __CPE_CTRL_UNUSED30_SH)
+#define __CPE_FUNC_INT_CTRL_MK 0x03000000
+#define __CPE_FUNC_INT_CTRL_SH 24
+#define __CPE_FUNC_INT_CTRL(_v) ((_v) << __CPE_FUNC_INT_CTRL_SH)
+enum {
+ __CPE_FUNC_INT_CTRL_DISABLE = 0x0,
+ __CPE_FUNC_INT_CTRL_F2NF = 0x1,
+ __CPE_FUNC_INT_CTRL_3QUART = 0x2,
+ __CPE_FUNC_INT_CTRL_HALF = 0x3,
+};
+#define __CPE_CTRL_UNUSED20_MK 0x00f00000
+#define __CPE_CTRL_UNUSED20_SH 20
+#define __CPE_CTRL_UNUSED20(_v) ((_v) << __CPE_CTRL_UNUSED20_SH)
+#define __CPE_SCI_TH_MK 0x000f0000
+#define __CPE_SCI_TH_SH 16
+#define __CPE_SCI_TH(_v) ((_v) << __CPE_SCI_TH_SH)
+#define __CPE_CTRL_UNUSED10_MK 0x0000c000
+#define __CPE_CTRL_UNUSED10_SH 14
+#define __CPE_CTRL_UNUSED10(_v) ((_v) << __CPE_CTRL_UNUSED10_SH)
+#define __CPE_ACK_PENDING 0x00002000
+#define __CPE_CTRL_UNUSED40_MK 0x00001c00
+#define __CPE_CTRL_UNUSED40_SH 10
+#define __CPE_CTRL_UNUSED40(_v) ((_v) << __CPE_CTRL_UNUSED40_SH)
+#define __CPE_PCIEID_MK 0x00000300
+#define __CPE_PCIEID_SH 8
+#define __CPE_PCIEID(_v) ((_v) << __CPE_PCIEID_SH)
+#define __CPE_CTRL_UNUSED00_MK 0x000000fe
+#define __CPE_CTRL_UNUSED00_SH 1
+#define __CPE_CTRL_UNUSED00(_v) ((_v) << __CPE_CTRL_UNUSED00_SH)
+#define __CPE_ESIZE 0x00000001
+#define CPE_QCTRL_Q1 0x0003804c
+#define __CPE_CTRL_UNUSED31_MK 0xfc000000
+#define __CPE_CTRL_UNUSED31_SH 26
+#define __CPE_CTRL_UNUSED31(_v) ((_v) << __CPE_CTRL_UNUSED31_SH)
+#define __CPE_CTRL_UNUSED21_MK 0x00f00000
+#define __CPE_CTRL_UNUSED21_SH 20
+#define __CPE_CTRL_UNUSED21(_v) ((_v) << __CPE_CTRL_UNUSED21_SH)
+#define __CPE_CTRL_UNUSED11_MK 0x0000c000
+#define __CPE_CTRL_UNUSED11_SH 14
+#define __CPE_CTRL_UNUSED11(_v) ((_v) << __CPE_CTRL_UNUSED11_SH)
+#define __CPE_CTRL_UNUSED41_MK 0x00001c00
+#define __CPE_CTRL_UNUSED41_SH 10
+#define __CPE_CTRL_UNUSED41(_v) ((_v) << __CPE_CTRL_UNUSED41_SH)
+#define __CPE_CTRL_UNUSED01_MK 0x000000fe
+#define __CPE_CTRL_UNUSED01_SH 1
+#define __CPE_CTRL_UNUSED01(_v) ((_v) << __CPE_CTRL_UNUSED01_SH)
+#define RME_PI_PTR_Q0 0x00038020
+#define __LATENCY_TIME_STAMP_MK 0xffff0000
+#define __LATENCY_TIME_STAMP_SH 16
+#define __LATENCY_TIME_STAMP(_v) ((_v) << __LATENCY_TIME_STAMP_SH)
+#define __RME_PI_PTR 0x0000ffff
+#define RME_PI_PTR_Q1 0x00038060
+#define RME_CI_PTR_Q0 0x00038024
+#define __DELAY_TIME_STAMP_MK 0xffff0000
+#define __DELAY_TIME_STAMP_SH 16
+#define __DELAY_TIME_STAMP(_v) ((_v) << __DELAY_TIME_STAMP_SH)
+#define __RME_CI_PTR 0x0000ffff
+#define RME_CI_PTR_Q1 0x00038064
+#define RME_DEPTH_Q0 0x00038028
+#define __RME_DEPTH_UNUSED_MK 0xf8000000
+#define __RME_DEPTH_UNUSED_SH 27
+#define __RME_DEPTH_UNUSED(_v) ((_v) << __RME_DEPTH_UNUSED_SH)
+#define __RME_MSIX_VEC_INDEX_MK 0x07ff0000
+#define __RME_MSIX_VEC_INDEX_SH 16
+#define __RME_MSIX_VEC_INDEX(_v) ((_v) << __RME_MSIX_VEC_INDEX_SH)
+#define __RME_DEPTH 0x0000ffff
+#define RME_DEPTH_Q1 0x00038068
+#define RME_QCTRL_Q0 0x0003802c
+#define __RME_INT_LATENCY_TIMER_MK 0xff000000
+#define __RME_INT_LATENCY_TIMER_SH 24
+#define __RME_INT_LATENCY_TIMER(_v) ((_v) << __RME_INT_LATENCY_TIMER_SH)
+#define __RME_INT_DELAY_TIMER_MK 0x00ff0000
+#define __RME_INT_DELAY_TIMER_SH 16
+#define __RME_INT_DELAY_TIMER(_v) ((_v) << __RME_INT_DELAY_TIMER_SH)
+#define __RME_INT_DELAY_DISABLE 0x00008000
+#define __RME_DLY_DELAY_DISABLE 0x00004000
+#define __RME_ACK_PENDING 0x00002000
+#define __RME_FULL_INTERRUPT_DISABLE 0x00001000
+#define __RME_CTRL_UNUSED10_MK 0x00000c00
+#define __RME_CTRL_UNUSED10_SH 10
+#define __RME_CTRL_UNUSED10(_v) ((_v) << __RME_CTRL_UNUSED10_SH)
+#define __RME_PCIEID_MK 0x00000300
+#define __RME_PCIEID_SH 8
+#define __RME_PCIEID(_v) ((_v) << __RME_PCIEID_SH)
+#define __RME_CTRL_UNUSED00_MK 0x000000fe
+#define __RME_CTRL_UNUSED00_SH 1
+#define __RME_CTRL_UNUSED00(_v) ((_v) << __RME_CTRL_UNUSED00_SH)
+#define __RME_ESIZE 0x00000001
+#define RME_QCTRL_Q1 0x0003806c
+#define __RME_CTRL_UNUSED11_MK 0x00000c00
+#define __RME_CTRL_UNUSED11_SH 10
+#define __RME_CTRL_UNUSED11(_v) ((_v) << __RME_CTRL_UNUSED11_SH)
+#define __RME_CTRL_UNUSED01_MK 0x000000fe
+#define __RME_CTRL_UNUSED01_SH 1
+#define __RME_CTRL_UNUSED01(_v) ((_v) << __RME_CTRL_UNUSED01_SH)
+#define PSS_CTL_REG 0x00018800
+#define __PSS_I2C_CLK_DIV_MK 0x007f0000
+#define __PSS_I2C_CLK_DIV_SH 16
+#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH)
+#define __PSS_LMEM_INIT_DONE 0x00001000
+#define __PSS_LMEM_RESET 0x00000200
+#define __PSS_LMEM_INIT_EN 0x00000100
+#define __PSS_LPU1_RESET 0x00000002
+#define __PSS_LPU0_RESET 0x00000001
+#define HQM_QSET0_RXQ_DRBL_P0 0x00038000
+#define __RXQ0_ADD_VECTORS_P 0x80000000
+#define __RXQ0_STOP_P 0x40000000
+#define __RXQ0_PRD_PTR_P 0x0000ffff
+#define HQM_QSET1_RXQ_DRBL_P0 0x00038080
+#define __RXQ1_ADD_VECTORS_P 0x80000000
+#define __RXQ1_STOP_P 0x40000000
+#define __RXQ1_PRD_PTR_P 0x0000ffff
+#define HQM_QSET0_RXQ_DRBL_P1 0x0003c000
+#define HQM_QSET1_RXQ_DRBL_P1 0x0003c080
+#define HQM_QSET0_TXQ_DRBL_P0 0x00038020
+#define __TXQ0_ADD_VECTORS_P 0x80000000
+#define __TXQ0_STOP_P 0x40000000
+#define __TXQ0_PRD_PTR_P 0x0000ffff
+#define HQM_QSET1_TXQ_DRBL_P0 0x000380a0
+#define __TXQ1_ADD_VECTORS_P 0x80000000
+#define __TXQ1_STOP_P 0x40000000
+#define __TXQ1_PRD_PTR_P 0x0000ffff
+#define HQM_QSET0_TXQ_DRBL_P1 0x0003c020
+#define HQM_QSET1_TXQ_DRBL_P1 0x0003c0a0
+#define HQM_QSET0_IB_DRBL_1_P0 0x00038040
+#define __IB1_0_ACK_P 0x80000000
+#define __IB1_0_DISABLE_P 0x40000000
+#define __IB1_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET1_IB_DRBL_1_P0 0x000380c0
+#define __IB1_1_ACK_P 0x80000000
+#define __IB1_1_DISABLE_P 0x40000000
+#define __IB1_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET0_IB_DRBL_1_P1 0x0003c040
+#define HQM_QSET1_IB_DRBL_1_P1 0x0003c0c0
+#define HQM_QSET0_IB_DRBL_2_P0 0x00038060
+#define __IB2_0_ACK_P 0x80000000
+#define __IB2_0_DISABLE_P 0x40000000
+#define __IB2_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET1_IB_DRBL_2_P0 0x000380e0
+#define __IB2_1_ACK_P 0x80000000
+#define __IB2_1_DISABLE_P 0x40000000
+#define __IB2_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET0_IB_DRBL_2_P1 0x0003c060
+#define HQM_QSET1_IB_DRBL_2_P1 0x0003c0e0
+
+
+/*
+ * These definitions are either in error/missing in spec. Its auto-generated
+ * from hard coded values in regparse.pl.
+ */
+#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c
+#define __EMPHPOST_AT_4G_SH_FIX 0x00000002
+#define __EMPHPRE_AT_4G_FIX 0x00000003
+#define __SFP_TXRATE_EN_FIX 0x00000100
+#define __SFP_RXRATE_EN_FIX 0x00000080
+
+
+/*
+ * These register definitions are auto-generated from hard coded values
+ * in regparse.pl.
+ */
+
+
+/*
+ * These register mapping definitions are auto-generated from mapping tables
+ * in regparse.pl.
+ */
+#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG
+#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG
+#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
+#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
+#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+
+#define CPE_DEPTH_Q(__n) \
+ (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
+#define CPE_QCTRL_Q(__n) \
+ (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0))
+#define CPE_PI_PTR_Q(__n) \
+ (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0))
+#define CPE_CI_PTR_Q(__n) \
+ (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0))
+#define RME_DEPTH_Q(__n) \
+ (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0))
+#define RME_QCTRL_Q(__n) \
+ (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0))
+#define RME_PI_PTR_Q(__n) \
+ (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
+#define RME_CI_PTR_Q(__n) \
+ (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
+#define HQM_QSET_RXQ_DRBL_P0(__n) \
+ (HQM_QSET0_RXQ_DRBL_P0 + (__n) * (HQM_QSET1_RXQ_DRBL_P0 - \
+ HQM_QSET0_RXQ_DRBL_P0))
+#define HQM_QSET_TXQ_DRBL_P0(__n) \
+ (HQM_QSET0_TXQ_DRBL_P0 + (__n) * (HQM_QSET1_TXQ_DRBL_P0 - \
+ HQM_QSET0_TXQ_DRBL_P0))
+#define HQM_QSET_IB_DRBL_1_P0(__n) \
+ (HQM_QSET0_IB_DRBL_1_P0 + (__n) * (HQM_QSET1_IB_DRBL_1_P0 - \
+ HQM_QSET0_IB_DRBL_1_P0))
+#define HQM_QSET_IB_DRBL_2_P0(__n) \
+ (HQM_QSET0_IB_DRBL_2_P0 + (__n) * (HQM_QSET1_IB_DRBL_2_P0 - \
+ HQM_QSET0_IB_DRBL_2_P0))
+#define HQM_QSET_RXQ_DRBL_P1(__n) \
+ (HQM_QSET0_RXQ_DRBL_P1 + (__n) * (HQM_QSET1_RXQ_DRBL_P1 - \
+ HQM_QSET0_RXQ_DRBL_P1))
+#define HQM_QSET_TXQ_DRBL_P1(__n) \
+ (HQM_QSET0_TXQ_DRBL_P1 + (__n) * (HQM_QSET1_TXQ_DRBL_P1 - \
+ HQM_QSET0_TXQ_DRBL_P1))
+#define HQM_QSET_IB_DRBL_1_P1(__n) \
+ (HQM_QSET0_IB_DRBL_1_P1 + (__n) * (HQM_QSET1_IB_DRBL_1_P1 - \
+ HQM_QSET0_IB_DRBL_1_P1))
+#define HQM_QSET_IB_DRBL_2_P1(__n) \
+ (HQM_QSET0_IB_DRBL_2_P1 + (__n) * (HQM_QSET1_IB_DRBL_2_P1 - \
+ HQM_QSET0_IB_DRBL_2_P1))
+
+#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define CPE_Q_MASK(__q) ((__q) & 0x3)
+#define RME_Q_MASK(__q) ((__q) & 0x3)
+
+
+/*
+ * PCI MSI-X vector defines
+ */
+enum {
+ BFA_MSIX_CPE_Q0 = 0,
+ BFA_MSIX_CPE_Q1 = 1,
+ BFA_MSIX_CPE_Q2 = 2,
+ BFA_MSIX_CPE_Q3 = 3,
+ BFA_MSIX_RME_Q0 = 4,
+ BFA_MSIX_RME_Q1 = 5,
+ BFA_MSIX_RME_Q2 = 6,
+ BFA_MSIX_RME_Q3 = 7,
+ BFA_MSIX_LPU_ERR = 8,
+ BFA_MSIX_CT_MAX = 9,
+};
+
+/*
+ * And corresponding host interrupt status bit field defines
+ */
+#define __HFN_INT_CPE_Q0 0x00000001U
+#define __HFN_INT_CPE_Q1 0x00000002U
+#define __HFN_INT_CPE_Q2 0x00000004U
+#define __HFN_INT_CPE_Q3 0x00000008U
+#define __HFN_INT_CPE_Q4 0x00000010U
+#define __HFN_INT_CPE_Q5 0x00000020U
+#define __HFN_INT_CPE_Q6 0x00000040U
+#define __HFN_INT_CPE_Q7 0x00000080U
+#define __HFN_INT_RME_Q0 0x00000100U
+#define __HFN_INT_RME_Q1 0x00000200U
+#define __HFN_INT_RME_Q2 0x00000400U
+#define __HFN_INT_RME_Q3 0x00000800U
+#define __HFN_INT_RME_Q4 0x00001000U
+#define __HFN_INT_RME_Q5 0x00002000U
+#define __HFN_INT_RME_Q6 0x00004000U
+#define __HFN_INT_RME_Q7 0x00008000U
+#define __HFN_INT_ERR_EMC 0x00010000U
+#define __HFN_INT_ERR_LPU0 0x00020000U
+#define __HFN_INT_ERR_LPU1 0x00040000U
+#define __HFN_INT_ERR_PSS 0x00080000U
+#define __HFN_INT_MBOX_LPU0 0x00100000U
+#define __HFN_INT_MBOX_LPU1 0x00200000U
+#define __HFN_INT_MBOX1_LPU0 0x00400000U
+#define __HFN_INT_MBOX1_LPU1 0x00800000U
+#define __HFN_INT_CPE_MASK 0x000000ffU
+#define __HFN_INT_RME_MASK 0x0000ff00U
+
+
+/*
+ * catapult memory map.
+ */
+#define LL_PGN_HQM0 0x0096
+#define LL_PGN_HQM1 0x0097
+#define PSS_SMEM_PAGE_START 0x8000
+#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15))
+#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff)
+
+/*
+ * End of catapult memory map
+ */
+
+
+#endif /* __BFI_CTREG_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_fabric.h b/drivers/scsi/bfa/include/bfi/bfi_fabric.h
new file mode 100644
index 000000000000..c0669ed41078
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_fabric.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_FABRIC_H__
+#define __BFI_FABRIC_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_fabric_h2i_msgs {
+ BFI_FABRIC_H2I_CREATE_REQ = 1,
+ BFI_FABRIC_H2I_DELETE_REQ = 2,
+ BFI_FABRIC_H2I_SETAUTH = 3,
+};
+
+enum bfi_fabric_i2h_msgs {
+ BFI_FABRIC_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_FABRIC_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_FABRIC_I2H_SETAUTH_RSP = BFA_I2HM(3),
+ BFI_FABRIC_I2H_ONLINE = BFA_I2HM(4),
+ BFI_FABRIC_I2H_OFFLINE = BFA_I2HM(5),
+};
+
+struct bfi_fabric_create_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u8 vf_en; /* virtual fabric enable */
+ u8 rsvd;
+ u16 vf_id; /* virtual fabric ID */
+ wwn_t pwwn; /* port name */
+ wwn_t nwwn; /* node name */
+};
+
+struct bfi_fabric_create_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 bfa_handle; /* host fabric handle */
+ u8 status; /* fabric create status */
+ u8 rsvd;
+};
+
+struct bfi_fabric_delete_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fw_handle; /* firmware fabric handle */
+ u16 rsvd;
+};
+
+struct bfi_fabric_delete_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 bfa_handle; /* host fabric handle */
+ u8 status; /* fabric deletion status */
+ u8 rsvd;
+};
+
+#define BFI_FABRIC_AUTHSECRET_LEN 64
+struct bfi_fabric_setauth_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fw_handle; /* f/w handle of fabric */
+ u8 algorithm;
+ u8 group;
+ u8 secret[BFI_FABRIC_AUTHSECRET_LEN];
+};
+
+union bfi_fabric_h2i_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_fabric_create_req_s *create_req;
+ struct bfi_fabric_delete_req_s *delete_req;
+};
+
+union bfi_fabric_i2h_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_fabric_create_rsp_s *create_rsp;
+ struct bfi_fabric_delete_rsp_s *delete_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_FABRIC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcpim.h b/drivers/scsi/bfa/include/bfi/bfi_fcpim.h
new file mode 100644
index 000000000000..52c059fb4c3a
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_fcpim.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_FCPIM_H__
+#define __BFI_FCPIM_H__
+
+#include "bfi.h"
+#include <protocol/fcp.h>
+
+#pragma pack(1)
+
+/*
+ * Initiator mode I-T nexus interface defines.
+ */
+
+enum bfi_itnim_h2i {
+ BFI_ITNIM_H2I_CREATE_REQ = 1, /* i-t nexus creation */
+ BFI_ITNIM_H2I_DELETE_REQ = 2, /* i-t nexus deletion */
+};
+
+enum bfi_itnim_i2h {
+ BFI_ITNIM_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_ITNIM_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_ITNIM_I2H_SLER_EVENT = BFA_I2HM(3),
+};
+
+struct bfi_itnim_create_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* f/w handle for itnim */
+ u8 class; /* FC class for IO */
+ u8 seq_rec; /* sequence recovery support */
+ u8 msg_no; /* seq id of the msg */
+};
+
+struct bfi_itnim_create_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* bfa handle for itnim */
+ u8 status; /* fcp request status */
+ u8 seq_id; /* seq id of the msg */
+};
+
+struct bfi_itnim_delete_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* f/w itnim handle */
+ u8 seq_id; /* seq id of the msg */
+ u8 rsvd;
+};
+
+struct bfi_itnim_delete_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* bfa handle for itnim */
+ u8 status; /* fcp request status */
+ u8 seq_id; /* seq id of the msg */
+};
+
+struct bfi_itnim_sler_event_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* bfa handle for itnim */
+ u16 rsvd;
+};
+
+union bfi_itnim_h2i_msg_u {
+ struct bfi_itnim_create_req_s *create_req;
+ struct bfi_itnim_delete_req_s *delete_req;
+ struct bfi_msg_s *msg;
+};
+
+union bfi_itnim_i2h_msg_u {
+ struct bfi_itnim_create_rsp_s *create_rsp;
+ struct bfi_itnim_delete_rsp_s *delete_rsp;
+ struct bfi_itnim_sler_event_s *sler_event;
+ struct bfi_msg_s *msg;
+};
+
+/*
+ * Initiator mode IO interface defines.
+ */
+
+enum bfi_ioim_h2i {
+ BFI_IOIM_H2I_IOABORT_REQ = 1, /* IO abort request */
+ BFI_IOIM_H2I_IOCLEANUP_REQ = 2, /* IO cleanup request */
+};
+
+enum bfi_ioim_i2h {
+ BFI_IOIM_I2H_IO_RSP = BFA_I2HM(1), /* non-fp IO response */
+ BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2),/* ABORT rsp */
+};
+
+/**
+ * IO command DIF info
+ */
+struct bfi_ioim_dif_s {
+ u32 dif_info[4];
+};
+
+/**
+ * FCP IO messages overview
+ *
+ * @note
+ * - Max CDB length supported is 64 bytes.
+ * - SCSI Linked commands and SCSI bi-directional Commands not
+ * supported.
+ *
+ */
+struct bfi_ioim_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 io_tag; /* I/O tag */
+ u16 rport_hdl; /* itnim/rport firmware handle */
+ struct fcp_cmnd_s cmnd; /* IO request info */
+
+ /**
+ * SG elements array within the IO request must be double word
+ * aligned. This aligment is required to optimize SGM setup for the IO.
+ */
+ struct bfi_sge_s sges[BFI_SGE_INLINE_MAX];
+ u8 io_timeout;
+ u8 dif_en;
+ u8 rsvd_a[2];
+ struct bfi_ioim_dif_s dif;
+};
+
+/**
+ * This table shows various IO status codes from firmware and their
+ * meaning. Host driver can use these status codes to further process
+ * IO completions.
+ *
+ * BFI_IOIM_STS_OK : IO completed with error free SCSI &
+ * transport status.
+ * - io-tag can be reused.
+ *
+ * BFA_IOIM_STS_SCSI_ERR : IO completed with scsi error.
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_HOST_ABORTED : IO was aborted successfully due to
+ * host request.
+ * - io-tag cannot be reused yet.
+ *
+ * BFI_IOIM_STS_ABORTED : IO was aborted successfully
+ * internally by f/w.
+ * - io-tag cannot be reused yet.
+ *
+ * BFI_IOIM_STS_TIMEDOUT : IO timedout and ABTS/RRQ is happening
+ * in the firmware and
+ * - io-tag cannot be reused yet.
+ *
+ * BFI_IOIM_STS_SQER_NEEDED : Firmware could not recover the IO
+ * with sequence level error
+ * logic and hence host needs to retry
+ * this IO with a different IO tag
+ * - io-tag cannot be used yet.
+ *
+ * BFI_IOIM_STS_NEXUS_ABORT : Second Level Error Recovery from host
+ * is required because 2 consecutive ABTS
+ * timedout and host needs logout and
+ * re-login with the target
+ * - io-tag cannot be used yet.
+ *
+ * BFI_IOIM_STS_UNDERRUN : IO completed with SCSI status good,
+ * but the data tranferred is less than
+ * the fcp data length in the command.
+ * ex. SCSI INQUIRY where transferred
+ * data length and residue count in FCP
+ * response accounts for total fcp-dl
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_OVERRUN : IO completed with SCSI status good,
+ * but the data transerred is more than
+ * fcp data length in the command. ex.
+ * TAPE IOs where blocks can of unequal
+ * lengths.
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_RES_FREE : Firmware has completed using io-tag
+ * during abort process
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_PROTO_ERR : Firmware detected a protocol error.
+ * ex target sent more data than
+ * requested, or there was data frame
+ * loss and other reasons
+ * - io-tag cannot be used yet.
+ *
+ * BFI_IOIM_STS_DIF_ERR : Firwmare detected DIF error. ex: DIF
+ * CRC err or Ref Tag err or App tag err.
+ * - io-tag can be reused.
+ *
+ * BFA_IOIM_STS_TSK_MGT_ABORT : IO was aborted because of Task
+ * Management command from the host
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_UTAG : Firmware does not know about this
+ * io_tag.
+ * - io-tag can be reused.
+ */
+enum bfi_ioim_status {
+ BFI_IOIM_STS_OK = 0,
+ BFI_IOIM_STS_HOST_ABORTED = 1,
+ BFI_IOIM_STS_ABORTED = 2,
+ BFI_IOIM_STS_TIMEDOUT = 3,
+ BFI_IOIM_STS_RES_FREE = 4,
+ BFI_IOIM_STS_SQER_NEEDED = 5,
+ BFI_IOIM_STS_PROTO_ERR = 6,
+ BFI_IOIM_STS_UTAG = 7,
+ BFI_IOIM_STS_PATHTOV = 8,
+};
+
+#define BFI_IOIM_SNSLEN (256)
+/**
+ * I/O response message
+ */
+struct bfi_ioim_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 io_tag; /* completed IO tag */
+ u16 bfa_rport_hndl; /* releated rport handle */
+ u8 io_status; /* IO completion status */
+ u8 reuse_io_tag; /* IO tag can be reused */
+ u16 abort_tag; /* host abort request tag */
+ u8 scsi_status; /* scsi status from target */
+ u8 sns_len; /* scsi sense length */
+ u8 resid_flags; /* IO residue flags */
+ u8 rsvd_a;
+ u32 residue; /* IO residual length in bytes */
+ u32 rsvd_b[3];
+};
+
+struct bfi_ioim_abort_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 io_tag; /* I/O tag */
+ u16 abort_tag; /* unique request tag */
+};
+
+/*
+ * Initiator mode task management command interface defines.
+ */
+
+enum bfi_tskim_h2i {
+ BFI_TSKIM_H2I_TM_REQ = 1, /* task-mgmt command */
+ BFI_TSKIM_H2I_ABORT_REQ = 2, /* task-mgmt command */
+};
+
+enum bfi_tskim_i2h {
+ BFI_TSKIM_I2H_TM_RSP = BFA_I2HM(1),
+};
+
+struct bfi_tskim_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 tsk_tag; /* task management tag */
+ u16 itn_fhdl; /* itn firmware handle */
+ lun_t lun; /* LU number */
+ u8 tm_flags; /* see fcp_tm_cmnd_t */
+ u8 t_secs; /* Timeout value in seconds */
+ u8 rsvd[2];
+};
+
+struct bfi_tskim_abortreq_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 tsk_tag; /* task management tag */
+ u16 rsvd;
+};
+
+enum bfi_tskim_status {
+ /*
+ * Following are FCP-4 spec defined status codes,
+ * **DO NOT CHANGE THEM **
+ */
+ BFI_TSKIM_STS_OK = 0,
+ BFI_TSKIM_STS_NOT_SUPP = 4,
+ BFI_TSKIM_STS_FAILED = 5,
+
+ /**
+ * Defined by BFA
+ */
+ BFI_TSKIM_STS_TIMEOUT = 10, /* TM request timedout */
+ BFI_TSKIM_STS_ABORTED = 11, /* Aborted on host request */
+};
+
+struct bfi_tskim_rsp_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 tsk_tag; /* task mgmt cmnd tag */
+ u8 tsk_status; /* @ref bfi_tskim_status */
+ u8 rsvd;
+};
+
+#pragma pack()
+
+#endif /* __BFI_FCPIM_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcxp.h b/drivers/scsi/bfa/include/bfi/bfi_fcxp.h
new file mode 100644
index 000000000000..e0e995a32828
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_fcxp.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_FCXP_H__
+#define __BFI_FCXP_H__
+
+#include "bfi.h"
+
+#pragma pack(1)
+
+enum bfi_fcxp_h2i {
+ BFI_FCXP_H2I_SEND_REQ = 1,
+};
+
+enum bfi_fcxp_i2h {
+ BFI_FCXP_I2H_SEND_RSP = BFA_I2HM(1),
+};
+
+#define BFA_FCXP_MAX_SGES 2
+
+/**
+ * FCXP send request structure
+ */
+struct bfi_fcxp_send_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 fcxp_tag; /* driver request tag */
+ u16 max_frmsz; /* max send frame size */
+ u16 vf_id; /* vsan tag if applicable */
+ u16 rport_fw_hndl; /* FW Handle for the remote port */
+ u8 class; /* FC class used for req/rsp */
+ u8 rsp_timeout; /* timeout in secs, 0-no response */
+ u8 cts; /* continue sequence */
+ u8 lp_tag; /* lport tag */
+ struct fchs_s fchs; /* request FC header structure */
+ u32 req_len; /* request payload length */
+ u32 rsp_maxlen; /* max response length expected */
+ struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */
+ struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */
+};
+
+/**
+ * FCXP send response structure
+ */
+struct bfi_fcxp_send_rsp_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 fcxp_tag; /* send request tag */
+ u8 req_status; /* request status */
+ u8 rsvd;
+ u32 rsp_len; /* actual response length */
+ u32 residue_len; /* residual response length */
+ struct fchs_s fchs; /* response FC header structure */
+};
+
+#pragma pack()
+
+#endif /* __BFI_FCXP_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
new file mode 100644
index 000000000000..026e9c06ae97
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_IOC_H__
+#define __BFI_IOC_H__
+
+#include "bfi.h"
+#include <defs/bfa_defs_ioc.h>
+
+#pragma pack(1)
+
+enum bfi_ioc_h2i_msgs {
+ BFI_IOC_H2I_ENABLE_REQ = 1,
+ BFI_IOC_H2I_DISABLE_REQ = 2,
+ BFI_IOC_H2I_GETATTR_REQ = 3,
+ BFI_IOC_H2I_DBG_SYNC = 4,
+ BFI_IOC_H2I_DBG_DUMP = 5,
+};
+
+enum bfi_ioc_i2h_msgs {
+ BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1),
+ BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2),
+ BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3),
+ BFI_IOC_I2H_READY_EVENT = BFA_I2HM(4),
+ BFI_IOC_I2H_HBEAT = BFA_I2HM(5),
+};
+
+/**
+ * BFI_IOC_H2I_GETATTR_REQ message
+ */
+struct bfi_ioc_getattr_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u attr_addr;
+};
+
+struct bfi_ioc_attr_s {
+ wwn_t mfg_wwn;
+ mac_t mfg_mac;
+ u16 rsvd_a;
+ char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+ u8 pcie_gen;
+ u8 pcie_lanes_orig;
+ u8 pcie_lanes;
+ u8 rx_bbcredit; /* receive buffer credits */
+ u32 adapter_prop; /* adapter properties */
+ u16 maxfrsize; /* max receive frame size */
+ char asic_rev;
+ u8 rsvd_b;
+ char fw_version[BFA_VERSION_LEN];
+ char optrom_version[BFA_VERSION_LEN];
+ struct bfa_mfg_vpd_s vpd;
+};
+
+/**
+ * BFI_IOC_I2H_GETATTR_REPLY message
+ */
+struct bfi_ioc_getattr_reply_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u8 status; /* cfg reply status */
+ u8 rsvd[3];
+};
+
+/**
+ * Firmware memory page offsets
+ */
+#define BFI_IOC_SMEM_PG0_CB (0x40)
+#define BFI_IOC_SMEM_PG0_CT (0x180)
+
+/**
+ * Firmware trace offset
+ */
+#define BFI_IOC_TRC_OFF (0x4b00)
+#define BFI_IOC_TRC_ENTS 256
+
+#define BFI_IOC_FW_SIGNATURE (0xbfadbfad)
+#define BFI_IOC_MD5SUM_SZ 4
+struct bfi_ioc_image_hdr_s {
+ u32 signature; /* constant signature */
+ u32 rsvd_a;
+ u32 exec; /* exec vector */
+ u32 param; /* parameters */
+ u32 rsvd_b[4];
+ u32 md5sum[BFI_IOC_MD5SUM_SZ];
+};
+
+/**
+ * BFI_IOC_I2H_READY_EVENT message
+ */
+struct bfi_ioc_rdy_event_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 init_status; /* init event status */
+ u8 rsvd[3];
+};
+
+struct bfi_ioc_hbeat_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u32 hb_count; /* current heart beat count */
+};
+
+/**
+ * IOC hardware/firmware state
+ */
+enum bfi_ioc_state {
+ BFI_IOC_UNINIT = 0, /* not initialized */
+ BFI_IOC_INITING = 1, /* h/w is being initialized */
+ BFI_IOC_HWINIT = 2, /* h/w is initialized */
+ BFI_IOC_CFG = 3, /* IOC configuration in progress */
+ BFI_IOC_OP = 4, /* IOC is operational */
+ BFI_IOC_DISABLING = 5, /* IOC is being disabled */
+ BFI_IOC_DISABLED = 6, /* IOC is disabled */
+ BFI_IOC_CFG_DISABLED = 7, /* IOC is being disabled;transient */
+ BFI_IOC_HBFAIL = 8, /* IOC heart-beat failure */
+ BFI_IOC_MEMTEST = 9, /* IOC is doing memtest */
+};
+
+#define BFI_IOC_ENDIAN_SIG 0x12345678
+
+enum {
+ BFI_ADAPTER_TYPE_FC = 0x01, /* FC adapters */
+ BFI_ADAPTER_TYPE_MK = 0x0f0000, /* adapter type mask */
+ BFI_ADAPTER_TYPE_SH = 16, /* adapter type shift */
+ BFI_ADAPTER_NPORTS_MK = 0xff00, /* number of ports mask */
+ BFI_ADAPTER_NPORTS_SH = 8, /* number of ports shift */
+ BFI_ADAPTER_SPEED_MK = 0xff, /* adapter speed mask */
+ BFI_ADAPTER_SPEED_SH = 0, /* adapter speed shift */
+ BFI_ADAPTER_PROTO = 0x100000, /* prototype adapaters */
+ BFI_ADAPTER_TTV = 0x200000, /* TTV debug capable */
+ BFI_ADAPTER_UNSUPP = 0x400000, /* unknown adapter type */
+};
+
+#define BFI_ADAPTER_GETP(__prop,__adap_prop) \
+ (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \
+ BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_SETP(__prop, __val) \
+ ((__val) << BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_IS_PROTO(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_PROTO)
+#define BFI_ADAPTER_IS_TTV(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_TTV)
+#define BFI_ADAPTER_IS_UNSUPP(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_UNSUPP)
+#define BFI_ADAPTER_IS_SPECIAL(__adap_type) \
+ ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \
+ BFI_ADAPTER_UNSUPP))
+
+/**
+ * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages
+ */
+struct bfi_ioc_ctrl_req_s {
+ struct bfi_mhdr_s mh;
+ u8 ioc_class;
+ u8 rsvd[3];
+};
+
+/**
+ * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
+ */
+struct bfi_ioc_ctrl_reply_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u8 status; /* enable/disable status */
+ u8 rsvd[3];
+};
+
+#define BFI_IOC_MSGSZ 8
+/**
+ * H2I Messages
+ */
+union bfi_ioc_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_ioc_ctrl_req_s enable_req;
+ struct bfi_ioc_ctrl_req_s disable_req;
+ struct bfi_ioc_getattr_req_s getattr_req;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * I2H Messages
+ */
+union bfi_ioc_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_ioc_rdy_event_s rdy_event;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+#pragma pack()
+
+#endif /* __BFI_IOC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
new file mode 100644
index 000000000000..c3760df72575
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_IOCFC_H__
+#define __BFI_IOCFC_H__
+
+#include "bfi.h"
+#include <defs/bfa_defs_ioc.h>
+#include <defs/bfa_defs_iocfc.h>
+#include <defs/bfa_defs_boot.h>
+
+#pragma pack(1)
+
+enum bfi_iocfc_h2i_msgs {
+ BFI_IOCFC_H2I_CFG_REQ = 1,
+ BFI_IOCFC_H2I_GET_STATS_REQ = 2,
+ BFI_IOCFC_H2I_CLEAR_STATS_REQ = 3,
+ BFI_IOCFC_H2I_SET_INTR_REQ = 4,
+ BFI_IOCFC_H2I_UPDATEQ_REQ = 5,
+};
+
+enum bfi_iocfc_i2h_msgs {
+ BFI_IOCFC_I2H_CFG_REPLY = BFA_I2HM(1),
+ BFI_IOCFC_I2H_GET_STATS_RSP = BFA_I2HM(2),
+ BFI_IOCFC_I2H_CLEAR_STATS_RSP = BFA_I2HM(3),
+ BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(5),
+};
+
+struct bfi_iocfc_cfg_s {
+ u8 num_cqs; /* Number of CQs to be used */
+ u8 sense_buf_len; /* SCSI sense length */
+ u8 trunk_enabled; /* port trunking enabled */
+ u8 trunk_ports; /* trunk ports bit map */
+ u32 endian_sig; /* endian signature of host */
+
+ /**
+ * Request and response circular queue base addresses, size and
+ * shadow index pointers.
+ */
+ union bfi_addr_u req_cq_ba[BFI_IOC_MAX_CQS];
+ union bfi_addr_u req_shadow_ci[BFI_IOC_MAX_CQS];
+ u16 req_cq_elems[BFI_IOC_MAX_CQS];
+ union bfi_addr_u rsp_cq_ba[BFI_IOC_MAX_CQS];
+ union bfi_addr_u rsp_shadow_pi[BFI_IOC_MAX_CQS];
+ u16 rsp_cq_elems[BFI_IOC_MAX_CQS];
+
+ union bfi_addr_u stats_addr; /* DMA-able address for stats */
+ union bfi_addr_u cfgrsp_addr; /* config response dma address */
+ union bfi_addr_u ioim_snsbase; /* IO sense buffer base address */
+ struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */
+};
+
+/**
+ * Boot target wwn information for this port. This contains either the stored
+ * or discovered boot target port wwns for the port.
+ */
+struct bfi_iocfc_bootwwns {
+ wwn_t wwn[BFA_BOOT_BOOTLUN_MAX];
+ u8 nwwns;
+ u8 rsvd[7];
+};
+
+struct bfi_iocfc_cfgrsp_s {
+ struct bfa_iocfc_fwcfg_s fwcfg;
+ struct bfa_iocfc_intr_attr_s intr_attr;
+ struct bfi_iocfc_bootwwns bootwwns;
+};
+
+/**
+ * BFI_IOCFC_H2I_CFG_REQ message
+ */
+struct bfi_iocfc_cfg_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u ioc_cfg_dma_addr;
+};
+
+/**
+ * BFI_IOCFC_I2H_CFG_REPLY message
+ */
+struct bfi_iocfc_cfg_reply_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u8 cfg_success; /* cfg reply status */
+ u8 lpu_bm; /* LPUs assigned for this IOC */
+ u8 rsvd[2];
+};
+
+/**
+ * BFI_IOCFC_H2I_GET_STATS_REQ & BFI_IOCFC_H2I_CLEAR_STATS_REQ messages
+ */
+struct bfi_iocfc_stats_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * BFI_IOCFC_I2H_GET_STATS_RSP & BFI_IOCFC_I2H_CLEAR_STATS_RSP messages
+ */
+struct bfi_iocfc_stats_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* reply status */
+ u8 rsvd[3];
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * BFI_IOCFC_H2I_SET_INTR_REQ message
+ */
+struct bfi_iocfc_set_intr_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 coalesce; /* enable intr coalescing*/
+ u8 rsvd[3];
+ u16 delay; /* delay timer 0..1125us */
+ u16 latency; /* latency timer 0..225us */
+};
+
+/**
+ * BFI_IOCFC_H2I_UPDATEQ_REQ message
+ */
+struct bfi_iocfc_updateq_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u32 reqq_ba; /* reqq base addr */
+ u32 rspq_ba; /* rspq base addr */
+ u32 reqq_sci; /* reqq shadow ci */
+ u32 rspq_spi; /* rspq shadow pi */
+};
+
+/**
+ * BFI_IOCFC_I2H_UPDATEQ_RSP message
+ */
+struct bfi_iocfc_updateq_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* updateq status */
+ u8 rsvd[3];
+};
+
+/**
+ * H2I Messages
+ */
+union bfi_iocfc_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_iocfc_cfg_req_s cfg_req;
+ struct bfi_iocfc_stats_req_s stats_get;
+ struct bfi_iocfc_stats_req_s stats_clr;
+ struct bfi_iocfc_updateq_req_s updateq_req;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * I2H Messages
+ */
+union bfi_iocfc_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_iocfc_cfg_reply_s cfg_reply;
+ struct bfi_iocfc_stats_rsp_s stats_get_rsp;
+ struct bfi_iocfc_stats_rsp_s stats_clr_rsp;
+ struct bfi_iocfc_updateq_rsp_s updateq_rsp;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+#pragma pack()
+
+#endif /* __BFI_IOCFC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_lport.h b/drivers/scsi/bfa/include/bfi/bfi_lport.h
new file mode 100644
index 000000000000..29010614bac9
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_lport.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_LPORT_H__
+#define __BFI_LPORT_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_lport_h2i_msgs {
+ BFI_LPORT_H2I_CREATE_REQ = 1,
+ BFI_LPORT_H2I_DELETE_REQ = 2,
+};
+
+enum bfi_lport_i2h_msgs {
+ BFI_LPORT_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_LPORT_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_LPORT_I2H_ONLINE = BFA_I2HM(3),
+ BFI_LPORT_I2H_OFFLINE = BFA_I2HM(4),
+};
+
+#define BFI_LPORT_MAX_SYNNAME 64
+
+enum bfi_lport_role_e {
+ BFI_LPORT_ROLE_FCPIM = 1,
+ BFI_LPORT_ROLE_FCPTM = 2,
+ BFI_LPORT_ROLE_IPFC = 4,
+};
+
+struct bfi_lport_create_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fabric_fwhdl; /* parent fabric instance */
+ u8 roles; /* lport FC-4 roles */
+ u8 rsvd;
+ wwn_t pwwn; /* port name */
+ wwn_t nwwn; /* node name */
+ u8 symname[BFI_LPORT_MAX_SYNNAME];
+};
+
+struct bfi_lport_create_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u8 status; /* lport creation status */
+ u8 rsvd[3];
+};
+
+struct bfi_lport_delete_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fw_handle; /* firmware lport handle */
+ u16 rsvd;
+};
+
+struct bfi_lport_delete_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 bfa_handle; /* host lport handle */
+ u8 status; /* lport deletion status */
+ u8 rsvd;
+};
+
+union bfi_lport_h2i_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_lport_create_req_s *create_req;
+ struct bfi_lport_delete_req_s *delete_req;
+};
+
+union bfi_lport_i2h_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_lport_create_rsp_s *create_rsp;
+ struct bfi_lport_delete_rsp_s *delete_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_LPORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_lps.h b/drivers/scsi/bfa/include/bfi/bfi_lps.h
new file mode 100644
index 000000000000..414b0e30f6ef
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_lps.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_LPS_H__
+#define __BFI_LPS_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_lps_h2i_msgs {
+ BFI_LPS_H2I_LOGIN_REQ = 1,
+ BFI_LPS_H2I_LOGOUT_REQ = 2,
+};
+
+enum bfi_lps_i2h_msgs {
+ BFI_LPS_H2I_LOGIN_RSP = BFA_I2HM(1),
+ BFI_LPS_H2I_LOGOUT_RSP = BFA_I2HM(2),
+};
+
+struct bfi_lps_login_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 alpa;
+ u16 pdu_size;
+ wwn_t pwwn;
+ wwn_t nwwn;
+ u8 fdisc;
+ u8 auth_en;
+ u8 rsvd[2];
+};
+
+struct bfi_lps_login_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 status;
+ u8 lsrjt_rsn;
+ u8 lsrjt_expl;
+ wwn_t port_name;
+ wwn_t node_name;
+ u16 bb_credit;
+ u8 f_port;
+ u8 npiv_en;
+ u32 lp_pid : 24;
+ u32 auth_req : 8;
+ mac_t lp_mac;
+ mac_t fcf_mac;
+ u8 ext_status;
+ u8 brcd_switch;/* attached peer is brcd switch */
+};
+
+struct bfi_lps_logout_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 rsvd[3];
+ wwn_t port_name;
+};
+
+struct bfi_lps_logout_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 status;
+ u8 rsvd[2];
+};
+
+union bfi_lps_h2i_msg_u {
+ struct bfi_mhdr_s *msg;
+ struct bfi_lps_login_req_s *login_req;
+ struct bfi_lps_logout_req_s *logout_req;
+};
+
+union bfi_lps_i2h_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_lps_login_rsp_s *login_rsp;
+ struct bfi_lps_logout_rsp_s *logout_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_LPS_H__ */
+
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_port.h b/drivers/scsi/bfa/include/bfi/bfi_port.h
new file mode 100644
index 000000000000..3ec3bea110ba
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_port.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFI_PORT_H__
+#define __BFI_PORT_H__
+
+#include <bfi/bfi.h>
+#include <defs/bfa_defs_pport.h>
+
+#pragma pack(1)
+
+enum bfi_port_h2i {
+ BFI_PORT_H2I_ENABLE_REQ = (1),
+ BFI_PORT_H2I_DISABLE_REQ = (2),
+ BFI_PORT_H2I_GET_STATS_REQ = (3),
+ BFI_PORT_H2I_CLEAR_STATS_REQ = (4),
+};
+
+enum bfi_port_i2h {
+ BFI_PORT_I2H_ENABLE_RSP = BFA_I2HM(1),
+ BFI_PORT_I2H_DISABLE_RSP = BFA_I2HM(2),
+ BFI_PORT_I2H_GET_STATS_RSP = BFA_I2HM(3),
+ BFI_PORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4),
+};
+
+/**
+ * Generic REQ type
+ */
+struct bfi_port_generic_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 msgtag; /* msgtag for reply */
+ u32 rsvd;
+};
+
+/**
+ * Generic RSP type
+ */
+struct bfi_port_generic_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* port enable status */
+ u8 rsvd[3];
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * @todo
+ * BFI_PORT_H2I_ENABLE_REQ
+ */
+
+/**
+ * @todo
+ * BFI_PORT_I2H_ENABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_DISABLE_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_DISABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_GET_STATS_REQ
+ */
+struct bfi_port_get_stats_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ union bfi_addr_u dma_addr;
+};
+
+/**
+ * BFI_PORT_I2H_GET_STATS_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_CLEAR_STATS_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_CLEAR_STATS_RSP
+ */
+
+union bfi_port_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_port_generic_req_s enable_req;
+ struct bfi_port_generic_req_s disable_req;
+ struct bfi_port_get_stats_req_s getstats_req;
+ struct bfi_port_generic_req_s clearstats_req;
+};
+
+union bfi_port_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_port_generic_rsp_s enable_rsp;
+ struct bfi_port_generic_rsp_s disable_rsp;
+ struct bfi_port_generic_rsp_s getstats_rsp;
+ struct bfi_port_generic_rsp_s clearstats_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_PORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_pport.h b/drivers/scsi/bfa/include/bfi/bfi_pport.h
new file mode 100644
index 000000000000..c96d246851af
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_pport.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFI_PPORT_H__
+#define __BFI_PPORT_H__
+
+#include <bfi/bfi.h>
+#include <defs/bfa_defs_pport.h>
+
+#pragma pack(1)
+
+enum bfi_pport_h2i {
+ BFI_PPORT_H2I_ENABLE_REQ = (1),
+ BFI_PPORT_H2I_DISABLE_REQ = (2),
+ BFI_PPORT_H2I_GET_STATS_REQ = (3),
+ BFI_PPORT_H2I_CLEAR_STATS_REQ = (4),
+ BFI_PPORT_H2I_SET_SVC_PARAMS_REQ = (5),
+ BFI_PPORT_H2I_ENABLE_RX_VF_TAG_REQ = (6),
+ BFI_PPORT_H2I_ENABLE_TX_VF_TAG_REQ = (7),
+ BFI_PPORT_H2I_GET_QOS_STATS_REQ = (8),
+ BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ = (9),
+};
+
+enum bfi_pport_i2h {
+ BFI_PPORT_I2H_ENABLE_RSP = BFA_I2HM(1),
+ BFI_PPORT_I2H_DISABLE_RSP = BFA_I2HM(2),
+ BFI_PPORT_I2H_GET_STATS_RSP = BFA_I2HM(3),
+ BFI_PPORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4),
+ BFI_PPORT_I2H_SET_SVC_PARAMS_RSP = BFA_I2HM(5),
+ BFI_PPORT_I2H_ENABLE_RX_VF_TAG_RSP = BFA_I2HM(6),
+ BFI_PPORT_I2H_ENABLE_TX_VF_TAG_RSP = BFA_I2HM(7),
+ BFI_PPORT_I2H_EVENT = BFA_I2HM(8),
+ BFI_PPORT_I2H_GET_QOS_STATS_RSP = BFA_I2HM(9),
+ BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP = BFA_I2HM(10),
+};
+
+/**
+ * Generic REQ type
+ */
+struct bfi_pport_generic_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * Generic RSP type
+ */
+struct bfi_pport_generic_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* port enable status */
+ u8 rsvd[3];
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * BFI_PPORT_H2I_ENABLE_REQ
+ */
+struct bfi_pport_enable_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 rsvd1;
+ wwn_t nwwn; /* node wwn of physical port */
+ wwn_t pwwn; /* port wwn of physical port */
+ struct bfa_pport_cfg_s port_cfg; /* port configuration */
+ union bfi_addr_u stats_dma_addr; /* DMA address for stats */
+ u32 msgtag; /* msgtag for reply */
+ u32 rsvd2;
+};
+
+/**
+ * BFI_PPORT_I2H_ENABLE_RSP
+ */
+#define bfi_pport_enable_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_DISABLE_REQ
+ */
+#define bfi_pport_disable_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_I2H_DISABLE_RSP
+ */
+#define bfi_pport_disable_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_GET_STATS_REQ
+ */
+#define bfi_pport_get_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_I2H_GET_STATS_RSP
+ */
+#define bfi_pport_get_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_CLEAR_STATS_REQ
+ */
+#define bfi_pport_clear_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_I2H_CLEAR_STATS_RSP
+ */
+#define bfi_pport_clear_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_GET_QOS_STATS_REQ
+ */
+#define bfi_pport_get_qos_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_H2I_GET_QOS_STATS_RSP
+ */
+#define bfi_pport_get_qos_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ
+ */
+#define bfi_pport_clear_qos_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_H2I_CLEAR_QOS_STATS_RSP
+ */
+#define bfi_pport_clear_qos_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_SET_SVC_PARAMS_REQ
+ */
+struct bfi_pport_set_svc_params_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u16 tx_bbcredit; /* Tx credits */
+ u16 rsvd;
+};
+
+/**
+ * BFI_PPORT_I2H_SET_SVC_PARAMS_RSP
+ */
+
+/**
+ * BFI_PPORT_I2H_EVENT
+ */
+struct bfi_pport_event_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ struct bfa_pport_link_s link_state;
+};
+
+union bfi_pport_h2i_msg_u {
+ struct bfi_mhdr_s *mhdr;
+ struct bfi_pport_enable_req_s *penable;
+ struct bfi_pport_generic_req_s *pdisable;
+ struct bfi_pport_generic_req_s *pgetstats;
+ struct bfi_pport_generic_req_s *pclearstats;
+ struct bfi_pport_set_svc_params_req_s *psetsvcparams;
+ struct bfi_pport_get_qos_stats_req_s *pgetqosstats;
+ struct bfi_pport_generic_req_s *pclearqosstats;
+};
+
+union bfi_pport_i2h_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_pport_generic_rsp_s *enable_rsp;
+ struct bfi_pport_disable_rsp_s *disable_rsp;
+ struct bfi_pport_generic_rsp_s *getstats_rsp;
+ struct bfi_pport_clear_stats_rsp_s *clearstats_rsp;
+ struct bfi_pport_set_svc_params_rsp_s *setsvcparasm_rsp;
+ struct bfi_pport_get_qos_stats_rsp_s *getqosstats_rsp;
+ struct bfi_pport_clear_qos_stats_rsp_s *clearqosstats_rsp;
+ struct bfi_pport_event_s *event;
+};
+
+#pragma pack()
+
+#endif /* __BFI_PPORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_rport.h b/drivers/scsi/bfa/include/bfi/bfi_rport.h
new file mode 100644
index 000000000000..3520f55f09d7
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_rport.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_RPORT_H__
+#define __BFI_RPORT_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_rport_h2i_msgs {
+ BFI_RPORT_H2I_CREATE_REQ = 1,
+ BFI_RPORT_H2I_DELETE_REQ = 2,
+ BFI_RPORT_H2I_SET_SPEED_REQ = 3,
+};
+
+enum bfi_rport_i2h_msgs {
+ BFI_RPORT_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_RPORT_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_RPORT_I2H_QOS_SCN = BFA_I2HM(3),
+};
+
+struct bfi_rport_create_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* host rport handle */
+ u16 max_frmsz; /* max rcv pdu size */
+ u32 pid : 24, /* remote port ID */
+ lp_tag : 8; /* local port tag */
+ u32 local_pid : 24, /* local port ID */
+ cisc : 8;
+ u8 fc_class; /* supported FC classes */
+ u8 vf_en; /* virtual fabric enable */
+ u16 vf_id; /* virtual fabric ID */
+};
+
+struct bfi_rport_create_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* rport creation status */
+ u8 rsvd[3];
+ u16 bfa_handle; /* host rport handle */
+ u16 fw_handle; /* firmware rport handle */
+ struct bfa_rport_qos_attr_s qos_attr; /* QoS Attributes */
+};
+
+struct bfa_rport_speed_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* firmware rport handle */
+ u8 speed; /*! rport's speed via RPSC */
+ u8 rsvd;
+};
+
+struct bfi_rport_delete_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* firmware rport handle */
+ u16 rsvd;
+};
+
+struct bfi_rport_delete_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* host rport handle */
+ u8 status; /* rport deletion status */
+ u8 rsvd;
+};
+
+struct bfi_rport_qos_scn_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* host rport handle */
+ u16 rsvd;
+ struct bfa_rport_qos_attr_s old_qos_attr; /* Old QoS Attributes */
+ struct bfa_rport_qos_attr_s new_qos_attr; /* New QoS Attributes */
+};
+
+union bfi_rport_h2i_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_rport_create_req_s *create_req;
+ struct bfi_rport_delete_req_s *delete_req;
+ struct bfi_rport_speed_req_s *speed_req;
+};
+
+union bfi_rport_i2h_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_rport_create_rsp_s *create_rsp;
+ struct bfi_rport_delete_rsp_s *delete_rsp;
+ struct bfi_rport_qos_scn_s *qos_scn_evt;
+};
+
+#pragma pack()
+
+#endif /* __BFI_RPORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_uf.h b/drivers/scsi/bfa/include/bfi/bfi_uf.h
new file mode 100644
index 000000000000..f328a9e7e622
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_uf.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFI_UF_H__
+#define __BFI_UF_H__
+
+#include "bfi.h"
+
+#pragma pack(1)
+
+enum bfi_uf_h2i {
+ BFI_UF_H2I_BUF_POST = 1,
+};
+
+enum bfi_uf_i2h {
+ BFI_UF_I2H_FRM_RCVD = BFA_I2HM(1),
+};
+
+#define BFA_UF_MAX_SGES 2
+
+struct bfi_uf_buf_post_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 buf_tag; /* buffer tag */
+ u16 buf_len; /* total buffer length */
+ struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */
+};
+
+struct bfi_uf_frm_rcvd_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 buf_tag; /* buffer tag */
+ u16 rsvd;
+ u16 frm_len; /* received frame length */
+ u16 xfr_len; /* tranferred length */
+};
+
+#pragma pack()
+
+#endif /* __BFI_UF_H__ */
diff --git a/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h b/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h
new file mode 100644
index 000000000000..43ba7064e81a
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_cna_trcmod.h CNA trace modules
+ */
+
+#ifndef __BFA_CNA_TRCMOD_H__
+#define __BFA_CNA_TRCMOD_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ BFA_TRC_CNA_CEE = 1,
+ BFA_TRC_CNA_PORT = 2,
+};
+
+#endif /* __BFA_CNA_TRCMOD_H__ */
diff --git a/drivers/scsi/bfa/include/cna/cee/bfa_cee.h b/drivers/scsi/bfa/include/cna/cee/bfa_cee.h
new file mode 100644
index 000000000000..77f297f68046
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/cee/bfa_cee.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_CEE_H__
+#define __BFA_CEE_H__
+
+#include <defs/bfa_defs_cee.h>
+#include <bfa_ioc.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+
+typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_hbfail_cbfn_t) (void *dev, bfa_status_t status);
+
+struct bfa_cee_cbfn_s {
+ bfa_cee_get_attr_cbfn_t get_attr_cbfn;
+ void *get_attr_cbarg;
+ bfa_cee_get_stats_cbfn_t get_stats_cbfn;
+ void *get_stats_cbarg;
+ bfa_cee_reset_stats_cbfn_t reset_stats_cbfn;
+ void *reset_stats_cbarg;
+};
+
+struct bfa_cee_s {
+ void *dev;
+ bfa_boolean_t get_attr_pending;
+ bfa_boolean_t get_stats_pending;
+ bfa_boolean_t reset_stats_pending;
+ bfa_status_t get_attr_status;
+ bfa_status_t get_stats_status;
+ bfa_status_t reset_stats_status;
+ struct bfa_cee_cbfn_s cbfn;
+ struct bfa_ioc_hbfail_notify_s hbfail;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_log_mod_s *logmod;
+ struct bfa_cee_attr_s *attr;
+ struct bfa_cee_stats_s *stats;
+ struct bfa_dma_s attr_dma;
+ struct bfa_dma_s stats_dma;
+ struct bfa_ioc_s *ioc;
+ struct bfa_mbox_cmd_s get_cfg_mb;
+ struct bfa_mbox_cmd_s get_stats_mb;
+ struct bfa_mbox_cmd_s reset_stats_mb;
+};
+
+u32 bfa_cee_meminfo(void);
+void bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva,
+ u64 dma_pa);
+void bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev,
+ struct bfa_trc_mod_s *trcmod,
+ struct bfa_log_mod_s *logmod);
+void bfa_cee_detach(struct bfa_cee_s *cee);
+bfa_status_t bfa_cee_get_attr(struct bfa_cee_s *cee,
+ struct bfa_cee_attr_s *attr,
+ bfa_cee_get_attr_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_cee_get_stats(struct bfa_cee_s *cee,
+ struct bfa_cee_stats_s *stats,
+ bfa_cee_get_stats_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_cee_reset_stats(struct bfa_cee_s *cee,
+ bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg);
+#endif /* __BFA_CEE_H__ */
diff --git a/drivers/scsi/bfa/include/cna/port/bfa_port.h b/drivers/scsi/bfa/include/cna/port/bfa_port.h
new file mode 100644
index 000000000000..7cbf17d3141b
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/port/bfa_port.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_PORT_H__
+#define __BFA_PORT_H__
+
+#include <defs/bfa_defs_port.h>
+#include <bfa_ioc.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+
+typedef void (*bfa_port_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_port_endis_cbfn_t) (void *dev, bfa_status_t status);
+
+struct bfa_port_s {
+ void *dev;
+ struct bfa_ioc_s *ioc;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_log_mod_s *logmod;
+ u32 msgtag;
+ bfa_boolean_t stats_busy;
+ struct bfa_mbox_cmd_s stats_mb;
+ bfa_port_stats_cbfn_t stats_cbfn;
+ void *stats_cbarg;
+ bfa_status_t stats_status;
+ union bfa_pport_stats_u *stats;
+ struct bfa_dma_s stats_dma;
+ bfa_boolean_t endis_pending;
+ struct bfa_mbox_cmd_s endis_mb;
+ bfa_port_endis_cbfn_t endis_cbfn;
+ void *endis_cbarg;
+ bfa_status_t endis_status;
+ struct bfa_ioc_hbfail_notify_s hbfail;
+};
+
+void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
+ void *dev, struct bfa_trc_mod_s *trcmod,
+ struct bfa_log_mod_s *logmod);
+void bfa_port_detach(struct bfa_port_s *port);
+void bfa_port_hbfail(void *arg);
+
+bfa_status_t bfa_port_get_stats(struct bfa_port_s *port,
+ union bfa_pport_stats_u *stats,
+ bfa_port_stats_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_port_clear_stats(struct bfa_port_s *port,
+ bfa_port_stats_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_port_enable(struct bfa_port_s *port,
+ bfa_port_endis_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_port_disable(struct bfa_port_s *port,
+ bfa_port_endis_cbfn_t cbfn, void *cbarg);
+u32 bfa_port_meminfo(void);
+void bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva,
+ u64 dma_pa);
+
+#endif /* __BFA_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h b/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h
new file mode 100644
index 000000000000..1563ee512218
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef __ETHPORT_DEFS_H__
+#define __ETHPORT_DEFS_H__
+
+struct bnad_drv_stats {
+ u64 netif_queue_stop;
+ u64 netif_queue_wakeup;
+ u64 tso4;
+ u64 tso6;
+ u64 tso_err;
+ u64 tcpcsum_offload;
+ u64 udpcsum_offload;
+ u64 csum_help;
+ u64 csum_help_err;
+
+ u64 hw_stats_updates;
+ u64 netif_rx_schedule;
+ u64 netif_rx_complete;
+ u64 netif_rx_dropped;
+};
+#endif
diff --git a/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h b/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h
new file mode 100644
index 000000000000..eb7548030d0f
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef __PHYPORT_DEFS_H__
+#define __PHYPORT_DEFS_H__
+
+#define BNA_TXF_ID_MAX 64
+#define BNA_RXF_ID_MAX 64
+
+/*
+ * Statistics
+ */
+
+/*
+ * TxF Frame Statistics
+ */
+struct bna_stats_txf {
+ u64 ucast_octets;
+ u64 ucast;
+ u64 ucast_vlan;
+
+ u64 mcast_octets;
+ u64 mcast;
+ u64 mcast_vlan;
+
+ u64 bcast_octets;
+ u64 bcast;
+ u64 bcast_vlan;
+
+ u64 errors;
+ u64 filter_vlan; /* frames filtered due to VLAN */
+ u64 filter_mac_sa; /* frames filtered due to SA check */
+};
+
+/*
+ * RxF Frame Statistics
+ */
+struct bna_stats_rxf {
+ u64 ucast_octets;
+ u64 ucast;
+ u64 ucast_vlan;
+
+ u64 mcast_octets;
+ u64 mcast;
+ u64 mcast_vlan;
+
+ u64 bcast_octets;
+ u64 bcast;
+ u64 bcast_vlan;
+ u64 frame_drops;
+};
+
+/*
+ * FC Tx Frame Statistics
+ */
+struct bna_stats_fc_tx {
+ u64 txf_ucast_octets;
+ u64 txf_ucast;
+ u64 txf_ucast_vlan;
+
+ u64 txf_mcast_octets;
+ u64 txf_mcast;
+ u64 txf_mcast_vlan;
+
+ u64 txf_bcast_octets;
+ u64 txf_bcast;
+ u64 txf_bcast_vlan;
+
+ u64 txf_parity_errors;
+ u64 txf_timeout;
+ u64 txf_fid_parity_errors;
+};
+
+/*
+ * FC Rx Frame Statistics
+ */
+struct bna_stats_fc_rx {
+ u64 rxf_ucast_octets;
+ u64 rxf_ucast;
+ u64 rxf_ucast_vlan;
+
+ u64 rxf_mcast_octets;
+ u64 rxf_mcast;
+ u64 rxf_mcast_vlan;
+
+ u64 rxf_bcast_octets;
+ u64 rxf_bcast;
+ u64 rxf_bcast_vlan;
+};
+
+/*
+ * RAD Frame Statistics
+ */
+struct cna_stats_rad {
+ u64 rx_frames;
+ u64 rx_octets;
+ u64 rx_vlan_frames;
+
+ u64 rx_ucast;
+ u64 rx_ucast_octets;
+ u64 rx_ucast_vlan;
+
+ u64 rx_mcast;
+ u64 rx_mcast_octets;
+ u64 rx_mcast_vlan;
+
+ u64 rx_bcast;
+ u64 rx_bcast_octets;
+ u64 rx_bcast_vlan;
+
+ u64 rx_drops;
+};
+
+/*
+ * BPC Tx Registers
+ */
+struct cna_stats_bpc_tx {
+ u64 tx_pause[8];
+ u64 tx_zero_pause[8]; /* Pause cancellation */
+ u64 tx_first_pause[8]; /* Pause initiation rather
+ *than retention */
+};
+
+/*
+ * BPC Rx Registers
+ */
+struct cna_stats_bpc_rx {
+ u64 rx_pause[8];
+ u64 rx_zero_pause[8]; /* Pause cancellation */
+ u64 rx_first_pause[8]; /* Pause initiation rather
+ *than retention */
+};
+
+/*
+ * MAC Rx Statistics
+ */
+struct cna_stats_mac_rx {
+ u64 frame_64; /* both rx and tx counter */
+ u64 frame_65_127; /* both rx and tx counter */
+ u64 frame_128_255; /* both rx and tx counter */
+ u64 frame_256_511; /* both rx and tx counter */
+ u64 frame_512_1023; /* both rx and tx counter */
+ u64 frame_1024_1518; /* both rx and tx counter */
+ u64 frame_1518_1522; /* both rx and tx counter */
+ u64 rx_bytes;
+ u64 rx_packets;
+ u64 rx_fcs_error;
+ u64 rx_multicast;
+ u64 rx_broadcast;
+ u64 rx_control_frames;
+ u64 rx_pause;
+ u64 rx_unknown_opcode;
+ u64 rx_alignment_error;
+ u64 rx_frame_length_error;
+ u64 rx_code_error;
+ u64 rx_carrier_sense_error;
+ u64 rx_undersize;
+ u64 rx_oversize;
+ u64 rx_fragments;
+ u64 rx_jabber;
+ u64 rx_drop;
+};
+
+/*
+ * MAC Tx Statistics
+ */
+struct cna_stats_mac_tx {
+ u64 tx_bytes;
+ u64 tx_packets;
+ u64 tx_multicast;
+ u64 tx_broadcast;
+ u64 tx_pause;
+ u64 tx_deferral;
+ u64 tx_excessive_deferral;
+ u64 tx_single_collision;
+ u64 tx_muliple_collision;
+ u64 tx_late_collision;
+ u64 tx_excessive_collision;
+ u64 tx_total_collision;
+ u64 tx_pause_honored;
+ u64 tx_drop;
+ u64 tx_jabber;
+ u64 tx_fcs_error;
+ u64 tx_control_frame;
+ u64 tx_oversize;
+ u64 tx_undersize;
+ u64 tx_fragments;
+};
+
+/*
+ * Complete statistics
+ */
+struct bna_stats {
+ struct cna_stats_mac_rx mac_rx_stats;
+ struct cna_stats_bpc_rx bpc_rx_stats;
+ struct cna_stats_rad rad_stats;
+ struct bna_stats_fc_rx fc_rx_stats;
+ struct cna_stats_mac_tx mac_tx_stats;
+ struct cna_stats_bpc_tx bpc_tx_stats;
+ struct bna_stats_fc_tx fc_tx_stats;
+ struct bna_stats_rxf rxf_stats[BNA_TXF_ID_MAX];
+ struct bna_stats_txf txf_stats[BNA_RXF_ID_MAX];
+};
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_checksum.h b/drivers/scsi/bfa/include/cs/bfa_checksum.h
new file mode 100644
index 000000000000..af8c1d533ba8
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_checksum.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_checksum.h BFA checksum utilities
+ */
+
+#ifndef __BFA_CHECKSUM_H__
+#define __BFA_CHECKSUM_H__
+
+static inline u32
+bfa_checksum_u32(u32 *buf, int sz)
+{
+ int i, m = sz >> 2;
+ u32 sum = 0;
+
+ for (i = 0; i < m; i++)
+ sum ^= buf[i];
+
+ return (sum);
+}
+
+static inline u16
+bfa_checksum_u16(u16 *buf, int sz)
+{
+ int i, m = sz >> 1;
+ u16 sum = 0;
+
+ for (i = 0; i < m; i++)
+ sum ^= buf[i];
+
+ return (sum);
+}
+
+static inline u8
+bfa_checksum_u8(u8 *buf, int sz)
+{
+ int i;
+ u8 sum = 0;
+
+ for (i = 0; i < sz; i++)
+ sum ^= buf[i];
+
+ return (sum);
+}
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_debug.h b/drivers/scsi/bfa/include/cs/bfa_debug.h
new file mode 100644
index 000000000000..441be86b1b0f
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_debug.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_debug.h BFA debug interfaces
+ */
+
+#ifndef __BFA_DEBUG_H__
+#define __BFA_DEBUG_H__
+
+#define bfa_assert(__cond) do { \
+ if (!(__cond)) \
+ bfa_panic(__LINE__, __FILE__, #__cond); \
+} while (0)
+
+#define bfa_sm_fault(__mod, __event) do { \
+ bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); \
+} while (0)
+
+#ifndef BFA_PERF_BUILD
+#define bfa_assert_fp(__cond) bfa_assert(__cond)
+#else
+#define bfa_assert_fp(__cond)
+#endif
+
+struct bfa_log_mod_s;
+void bfa_panic(int line, char *file, char *panicstr);
+void bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event);
+
+#endif /* __BFA_DEBUG_H__ */
diff --git a/drivers/scsi/bfa/include/cs/bfa_log.h b/drivers/scsi/bfa/include/cs/bfa_log.h
new file mode 100644
index 000000000000..761cbe22130a
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_log.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_log.h BFA log library data structure and function definition
+ */
+
+#ifndef __BFA_LOG_H__
+#define __BFA_LOG_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_aen.h>
+
+/*
+ * BFA log module definition
+ *
+ * To create a new module id:
+ * Add a #define at the end of the list below. Select a value for your
+ * definition so that it is one (1) greater than the previous
+ * definition. Modify the definition of BFA_LOG_MODULE_ID_MAX to become
+ * your new definition.
+ * Should have no gaps in between the values because this is used in arrays.
+ * IMPORTANT: AEN_IDs must be at the begining, otherwise update bfa_defs_aen.h
+ */
+
+enum bfa_log_module_id {
+ BFA_LOG_UNUSED_ID = 0,
+
+ /* AEN defs begin */
+ BFA_LOG_AEN_MIN = BFA_LOG_UNUSED_ID,
+
+ BFA_LOG_AEN_ID_ADAPTER = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ADAPTER,/* 1 */
+ BFA_LOG_AEN_ID_PORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_PORT, /* 2 */
+ BFA_LOG_AEN_ID_LPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_LPORT, /* 3 */
+ BFA_LOG_AEN_ID_RPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_RPORT, /* 4 */
+ BFA_LOG_AEN_ID_ITNIM = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ITNIM, /* 5 */
+ BFA_LOG_AEN_ID_TIN = BFA_LOG_AEN_MIN + BFA_AEN_CAT_TIN, /* 6 */
+ BFA_LOG_AEN_ID_IPFC = BFA_LOG_AEN_MIN + BFA_AEN_CAT_IPFC, /* 7 */
+ BFA_LOG_AEN_ID_AUDIT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_AUDIT, /* 8 */
+ BFA_LOG_AEN_ID_IOC = BFA_LOG_AEN_MIN + BFA_AEN_CAT_IOC, /* 9 */
+ BFA_LOG_AEN_ID_ETHPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ETHPORT,/* 10 */
+
+ BFA_LOG_AEN_MAX = BFA_LOG_AEN_ID_ETHPORT,
+ /* AEN defs end */
+
+ BFA_LOG_MODULE_ID_MIN = BFA_LOG_AEN_MAX,
+
+ BFA_LOG_FW_ID = BFA_LOG_MODULE_ID_MIN + 1,
+ BFA_LOG_HAL_ID = BFA_LOG_MODULE_ID_MIN + 2,
+ BFA_LOG_FCS_ID = BFA_LOG_MODULE_ID_MIN + 3,
+ BFA_LOG_WDRV_ID = BFA_LOG_MODULE_ID_MIN + 4,
+ BFA_LOG_LINUX_ID = BFA_LOG_MODULE_ID_MIN + 5,
+ BFA_LOG_SOLARIS_ID = BFA_LOG_MODULE_ID_MIN + 6,
+
+ BFA_LOG_MODULE_ID_MAX = BFA_LOG_SOLARIS_ID,
+
+ /* Not part of any arrays */
+ BFA_LOG_MODULE_ID_ALL = BFA_LOG_MODULE_ID_MAX + 1,
+ BFA_LOG_AEN_ALL = BFA_LOG_MODULE_ID_MAX + 2,
+ BFA_LOG_DRV_ALL = BFA_LOG_MODULE_ID_MAX + 3,
+};
+
+/*
+ * BFA log catalog name
+ */
+#define BFA_LOG_CAT_NAME "BFA"
+
+/*
+ * bfa log severity values
+ */
+enum bfa_log_severity {
+ BFA_LOG_INVALID = 0,
+ BFA_LOG_CRITICAL = 1,
+ BFA_LOG_ERROR = 2,
+ BFA_LOG_WARNING = 3,
+ BFA_LOG_INFO = 4,
+ BFA_LOG_NONE = 5,
+ BFA_LOG_LEVEL_MAX = BFA_LOG_NONE
+};
+
+#define BFA_LOG_MODID_OFFSET 16
+
+
+struct bfa_log_msgdef_s {
+ u32 msg_id; /* message id */
+ int attributes; /* attributes */
+ int severity; /* severity level */
+ char *msg_value;
+ /* msg string */
+ char *message;
+ /* msg format string */
+ int arg_type; /* argument type */
+ int arg_num; /* number of argument */
+};
+
+/*
+ * supported argument type
+ */
+enum bfa_log_arg_type {
+ BFA_LOG_S = 0, /* string */
+ BFA_LOG_D, /* decimal */
+ BFA_LOG_I, /* integer */
+ BFA_LOG_O, /* oct number */
+ BFA_LOG_U, /* unsigned integer */
+ BFA_LOG_X, /* hex number */
+ BFA_LOG_F, /* floating */
+ BFA_LOG_C, /* character */
+ BFA_LOG_L, /* double */
+ BFA_LOG_P /* pointer */
+};
+
+#define BFA_LOG_ARG_TYPE 2
+#define BFA_LOG_ARG0 (0 * BFA_LOG_ARG_TYPE)
+#define BFA_LOG_ARG1 (1 * BFA_LOG_ARG_TYPE)
+#define BFA_LOG_ARG2 (2 * BFA_LOG_ARG_TYPE)
+#define BFA_LOG_ARG3 (3 * BFA_LOG_ARG_TYPE)
+
+#define BFA_LOG_GET_MOD_ID(msgid) ((msgid >> BFA_LOG_MODID_OFFSET) & 0xff)
+#define BFA_LOG_GET_MSG_IDX(msgid) (msgid & 0xffff)
+#define BFA_LOG_GET_MSG_ID(msgdef) ((msgdef)->msg_id)
+#define BFA_LOG_GET_MSG_FMT_STRING(msgdef) ((msgdef)->message)
+#define BFA_LOG_GET_SEVERITY(msgdef) ((msgdef)->severity)
+
+/*
+ * Event attributes
+ */
+#define BFA_LOG_ATTR_NONE 0
+#define BFA_LOG_ATTR_AUDIT 1
+#define BFA_LOG_ATTR_LOG 2
+#define BFA_LOG_ATTR_FFDC 4
+
+#define BFA_LOG_CREATE_ID(msw, lsw) \
+ (((u32)msw << BFA_LOG_MODID_OFFSET) | lsw)
+
+struct bfa_log_mod_s;
+
+/**
+ * callback function
+ */
+typedef void (*bfa_log_cb_t)(struct bfa_log_mod_s *log_mod, u32 msg_id,
+ const char *format, ...);
+
+
+struct bfa_log_mod_s {
+ char instance_info[16]; /* instance info */
+ int log_level[BFA_LOG_MODULE_ID_MAX + 1];
+ /* log level for modules */
+ bfa_log_cb_t cbfn; /* callback function */
+};
+
+extern int bfa_log_init(struct bfa_log_mod_s *log_mod,
+ char *instance_name, bfa_log_cb_t cbfn);
+extern int bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...);
+extern bfa_status_t bfa_log_set_level(struct bfa_log_mod_s *log_mod,
+ int mod_id, enum bfa_log_severity log_level);
+extern bfa_status_t bfa_log_set_level_all(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level);
+extern bfa_status_t bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level);
+extern enum bfa_log_severity bfa_log_get_level(struct bfa_log_mod_s *log_mod,
+ int mod_id);
+extern enum bfa_log_severity bfa_log_get_msg_level(
+ struct bfa_log_mod_s *log_mod, u32 msg_id);
+/*
+ * array of messages generated from xml files
+ */
+extern struct bfa_log_msgdef_s bfa_log_msg_array[];
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_perf.h b/drivers/scsi/bfa/include/cs/bfa_perf.h
new file mode 100644
index 000000000000..45aa5f978ff5
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_perf.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFAD_PERF_H__
+#define __BFAD_PERF_H__
+
+#ifdef BFAD_PERF_BUILD
+
+#undef bfa_trc
+#undef bfa_trc32
+#undef bfa_assert
+#undef BFA_TRC_FILE
+
+#define bfa_trc(_trcp, _data)
+#define bfa_trc32(_trcp, _data)
+#define bfa_assert(__cond)
+#define BFA_TRC_FILE(__mod, __submod)
+
+#endif
+
+#endif /* __BFAD_PERF_H__ */
diff --git a/drivers/scsi/bfa/include/cs/bfa_plog.h b/drivers/scsi/bfa/include/cs/bfa_plog.h
new file mode 100644
index 000000000000..670f86e5fc6e
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_plog.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_PORTLOG_H__
+#define __BFA_PORTLOG_H__
+
+#include "protocol/fc.h"
+#include <defs/bfa_defs_types.h>
+
+#define BFA_PL_NLOG_ENTS 256
+#define BFA_PL_LOG_REC_INCR(_x) ((_x)++, (_x) %= BFA_PL_NLOG_ENTS)
+
+#define BFA_PL_STRING_LOG_SZ 32 /* number of chars in string log */
+#define BFA_PL_INT_LOG_SZ 8 /* number of integers in the integer log */
+
+enum bfa_plog_log_type {
+ BFA_PL_LOG_TYPE_INVALID = 0,
+ BFA_PL_LOG_TYPE_INT = 1,
+ BFA_PL_LOG_TYPE_STRING = 2,
+};
+
+/*
+ * the (fixed size) record format for each entry in the portlog
+ */
+struct bfa_plog_rec_s {
+ u32 tv; /* Filled by the portlog driver when the *
+ * entry is added to the circular log. */
+ u8 port; /* Source port that logged this entry. CM
+ * entities will use 0xFF */
+ u8 mid; /* Integer value to be used by all entities *
+ * while logging. The module id to string *
+ * conversion will be done by BFAL. See
+ * enum bfa_plog_mid */
+ u8 eid; /* indicates Rx, Tx, IOCTL, etc. See
+ * enum bfa_plog_eid */
+ u8 log_type; /* indicates string log or integer log.
+ * see bfa_plog_log_type_t */
+ u8 log_num_ints;
+ /*
+ * interpreted only if log_type is INT_LOG. indicates number of
+ * integers in the int_log[] (0-PL_INT_LOG_SZ).
+ */
+ u8 rsvd;
+ u16 misc; /* can be used to indicate fc frame length,
+ *etc.. */
+ union {
+ char string_log[BFA_PL_STRING_LOG_SZ];
+ u32 int_log[BFA_PL_INT_LOG_SZ];
+ } log_entry;
+
+};
+
+/*
+ * the following #defines will be used by the logging entities to indicate
+ * their module id. BFAL will convert the integer value to string format
+ *
+* process to be used while changing the following #defines:
+ * - Always add new entries at the end
+ * - define corresponding string in BFAL
+ * - Do not remove any entry or rearrange the order.
+ */
+enum bfa_plog_mid {
+ BFA_PL_MID_INVALID = 0,
+ BFA_PL_MID_DEBUG = 1,
+ BFA_PL_MID_DRVR = 2,
+ BFA_PL_MID_HAL = 3,
+ BFA_PL_MID_HAL_FCXP = 4,
+ BFA_PL_MID_HAL_UF = 5,
+ BFA_PL_MID_FCS = 6,
+ BFA_PL_MID_MAX = 7
+};
+
+#define BFA_PL_MID_STRLEN 8
+struct bfa_plog_mid_strings_s {
+ char m_str[BFA_PL_MID_STRLEN];
+};
+
+/*
+ * the following #defines will be used by the logging entities to indicate
+ * their event type. BFAL will convert the integer value to string format
+ *
+* process to be used while changing the following #defines:
+ * - Always add new entries at the end
+ * - define corresponding string in BFAL
+ * - Do not remove any entry or rearrange the order.
+ */
+enum bfa_plog_eid {
+ BFA_PL_EID_INVALID = 0,
+ BFA_PL_EID_IOC_DISABLE = 1,
+ BFA_PL_EID_IOC_ENABLE = 2,
+ BFA_PL_EID_PORT_DISABLE = 3,
+ BFA_PL_EID_PORT_ENABLE = 4,
+ BFA_PL_EID_PORT_ST_CHANGE = 5,
+ BFA_PL_EID_TX = 6,
+ BFA_PL_EID_TX_ACK1 = 7,
+ BFA_PL_EID_TX_RJT = 8,
+ BFA_PL_EID_TX_BSY = 9,
+ BFA_PL_EID_RX = 10,
+ BFA_PL_EID_RX_ACK1 = 11,
+ BFA_PL_EID_RX_RJT = 12,
+ BFA_PL_EID_RX_BSY = 13,
+ BFA_PL_EID_CT_IN = 14,
+ BFA_PL_EID_CT_OUT = 15,
+ BFA_PL_EID_DRIVER_START = 16,
+ BFA_PL_EID_RSCN = 17,
+ BFA_PL_EID_DEBUG = 18,
+ BFA_PL_EID_MISC = 19,
+ BFA_PL_EID_MAX = 20
+};
+
+#define BFA_PL_ENAME_STRLEN 8
+struct bfa_plog_eid_strings_s {
+ char e_str[BFA_PL_ENAME_STRLEN];
+};
+
+#define BFA_PL_SIG_LEN 8
+#define BFA_PL_SIG_STR "12pl123"
+
+/*
+ * per port circular log buffer
+ */
+struct bfa_plog_s {
+ char plog_sig[BFA_PL_SIG_LEN]; /* Start signature */
+ u8 plog_enabled;
+ u8 rsvd[7];
+ u32 ticks;
+ u16 head;
+ u16 tail;
+ struct bfa_plog_rec_s plog_recs[BFA_PL_NLOG_ENTS];
+};
+
+void bfa_plog_init(struct bfa_plog_s *plog);
+void bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc, char *log_str);
+void bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc,
+ u32 *intarr, u32 num_ints);
+void bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc,
+ struct fchs_s *fchdr);
+void bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc,
+ struct fchs_s *fchdr, u32 pld_w0);
+void bfa_plog_clear(struct bfa_plog_s *plog);
+void bfa_plog_enable(struct bfa_plog_s *plog);
+void bfa_plog_disable(struct bfa_plog_s *plog);
+bfa_boolean_t bfa_plog_get_setting(struct bfa_plog_s *plog);
+
+#endif /* __BFA_PORTLOG_H__ */
diff --git a/drivers/scsi/bfa/include/cs/bfa_q.h b/drivers/scsi/bfa/include/cs/bfa_q.h
new file mode 100644
index 000000000000..ea895facedbc
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_q.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_q.h Circular queue definitions.
+ */
+
+#ifndef __BFA_Q_H__
+#define __BFA_Q_H__
+
+#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
+#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next)
+#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev)
+
+/*
+ * bfa_q_qe_init - to initialize a queue element
+ */
+#define bfa_q_qe_init(_qe) { \
+ bfa_q_next(_qe) = (struct list_head *) NULL; \
+ bfa_q_prev(_qe) = (struct list_head *) NULL; \
+}
+
+/*
+ * bfa_q_deq - dequeue an element from head of the queue
+ */
+#define bfa_q_deq(_q, _qe) { \
+ if (!list_empty(_q)) { \
+ (*((struct list_head **) (_qe))) = bfa_q_next(_q); \
+ bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \
+ (struct list_head *) (_q); \
+ bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \
+ BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \
+ } else { \
+ *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+ } \
+}
+
+/*
+ * bfa_q_deq_tail - dequeue an element from tail of the queue
+ */
+#define bfa_q_deq_tail(_q, _qe) { \
+ if (!list_empty(_q)) { \
+ *((struct list_head **) (_qe)) = bfa_q_prev(_q); \
+ bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \
+ (struct list_head *) (_q); \
+ bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe); \
+ BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \
+ } else { \
+ *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+ } \
+}
+
+/*
+ * #ifdef BFA_DEBUG (Using bfa_assert to check for debug_build is not
+ * consistent across modules)
+ */
+#ifndef BFA_PERF_BUILD
+#define BFA_Q_DBG_INIT(_qe) bfa_q_qe_init(_qe)
+#else
+#define BFA_Q_DBG_INIT(_qe)
+#endif
+
+#define bfa_q_is_on_q(_q, _qe) \
+ bfa_q_is_on_q_func(_q, (struct list_head *)(_qe))
+extern int bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe);
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_sm.h b/drivers/scsi/bfa/include/cs/bfa_sm.h
new file mode 100644
index 000000000000..9877066680a6
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_sm.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfasm.h State machine defines
+ */
+
+#ifndef __BFA_SM_H__
+#define __BFA_SM_H__
+
+typedef void (*bfa_sm_t)(void *sm, int event);
+
+#define bfa_sm_set_state(_sm, _state) (_sm)->sm = (bfa_sm_t)(_state)
+#define bfa_sm_send_event(_sm, _event) (_sm)->sm((_sm), (_event))
+#define bfa_sm_get_state(_sm) ((_sm)->sm)
+#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state))
+
+/**
+ * For converting from state machine function to state encoding.
+ */
+struct bfa_sm_table_s {
+ bfa_sm_t sm; /* state machine function */
+ int state; /* state machine encoding */
+ char *name; /* state name for display */
+};
+#define BFA_SM(_sm) ((bfa_sm_t)(_sm))
+
+int bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm);
+
+/**
+ * State machine with entry actions.
+ */
+typedef void (*bfa_fsm_t)(void *fsm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc_s
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_fsm_state_decl(oc, st, otype, etype) \
+ static void oc ## _sm_ ## st(otype * fsm, etype event); \
+ static void oc ## _sm_ ## st ## _entry(otype * fsm)
+
+#define bfa_fsm_set_state(_fsm, _state) do { \
+ (_fsm)->fsm = (bfa_fsm_t)(_state); \
+ _state ## _entry(_fsm); \
+} while (0)
+
+#define bfa_fsm_send_event(_fsm, _event) \
+ (_fsm)->fsm((_fsm), (_event))
+#define bfa_fsm_cmp_state(_fsm, _state) \
+ ((_fsm)->fsm == (bfa_fsm_t)(_state))
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_trc.h b/drivers/scsi/bfa/include/cs/bfa_trc.h
new file mode 100644
index 000000000000..3e743928c74c
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_trc.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_TRC_H__
+#define __BFA_TRC_H__
+
+#include <bfa_os_inc.h>
+
+#ifndef BFA_TRC_MAX
+#define BFA_TRC_MAX (4 * 1024)
+#endif
+
+#ifndef BFA_TRC_TS
+#define BFA_TRC_TS(_trcm) ((_trcm)->ticks ++)
+#endif
+
+struct bfa_trc_s {
+#ifdef __BIGENDIAN
+ u16 fileno;
+ u16 line;
+#else
+ u16 line;
+ u16 fileno;
+#endif
+ u32 timestamp;
+ union {
+ struct {
+ u32 rsvd;
+ u32 u32;
+ } u32;
+ u64 u64;
+ } data;
+};
+
+
+struct bfa_trc_mod_s {
+ u32 head;
+ u32 tail;
+ u32 ntrc;
+ u32 stopped;
+ u32 ticks;
+ u32 rsvd[3];
+ struct bfa_trc_s trc[BFA_TRC_MAX];
+};
+
+
+enum {
+ BFA_TRC_FW = 1, /* firmware modules */
+ BFA_TRC_HAL = 2, /* BFA modules */
+ BFA_TRC_FCS = 3, /* BFA FCS modules */
+ BFA_TRC_LDRV = 4, /* Linux driver modules */
+ BFA_TRC_SDRV = 5, /* Solaris driver modules */
+ BFA_TRC_VDRV = 6, /* vmware driver modules */
+ BFA_TRC_WDRV = 7, /* windows driver modules */
+ BFA_TRC_AEN = 8, /* AEN module */
+ BFA_TRC_BIOS = 9, /* bios driver modules */
+ BFA_TRC_EFI = 10, /* EFI driver modules */
+ BNA_TRC_WDRV = 11, /* BNA windows driver modules */
+ BNA_TRC_VDRV = 12, /* BNA vmware driver modules */
+ BNA_TRC_SDRV = 13, /* BNA Solaris driver modules */
+ BNA_TRC_LDRV = 14, /* BNA Linux driver modules */
+ BNA_TRC_HAL = 15, /* BNA modules */
+ BFA_TRC_CNA = 16, /* Common modules */
+ BNA_TRC_IMDRV = 17 /* BNA windows intermediate driver modules */
+};
+#define BFA_TRC_MOD_SH 10
+#define BFA_TRC_MOD(__mod) ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH)
+
+/**
+ * Define a new tracing file (module). Module should match one defined above.
+ */
+#define BFA_TRC_FILE(__mod, __submod) \
+ static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \
+ BFA_TRC_MOD(__mod))
+
+
+#define bfa_trc32(_trcp, _data) \
+ __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data)
+
+
+#ifndef BFA_BOOT_BUILD
+#define bfa_trc(_trcp, _data) \
+ __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data)
+#else
+void bfa_boot_trc(struct bfa_trc_mod_s *trcmod, u16 fileno,
+ u16 line, u32 data);
+#define bfa_trc(_trcp, _data) \
+ bfa_boot_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data)
+#endif
+
+
+static inline void
+bfa_trc_init(struct bfa_trc_mod_s *trcm)
+{
+ trcm->head = trcm->tail = trcm->stopped = 0;
+ trcm->ntrc = BFA_TRC_MAX;
+}
+
+
+static inline void
+bfa_trc_stop(struct bfa_trc_mod_s *trcm)
+{
+ trcm->stopped = 1;
+}
+
+#ifdef FWTRC
+extern void dc_flush(void *data);
+#else
+#define dc_flush(data)
+#endif
+
+
+static inline void
+__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data)
+{
+ int tail = trcm->tail;
+ struct bfa_trc_s *trc = &trcm->trc[tail];
+
+ if (trcm->stopped)
+ return;
+
+ trc->fileno = (u16) fileno;
+ trc->line = (u16) line;
+ trc->data.u64 = data;
+ trc->timestamp = BFA_TRC_TS(trcm);
+ dc_flush(trc);
+
+ trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+ if (trcm->tail == trcm->head)
+ trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+ dc_flush(trcm);
+}
+
+
+static inline void
+__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data)
+{
+ int tail = trcm->tail;
+ struct bfa_trc_s *trc = &trcm->trc[tail];
+
+ if (trcm->stopped)
+ return;
+
+ trc->fileno = (u16) fileno;
+ trc->line = (u16) line;
+ trc->data.u32.u32 = data;
+ trc->timestamp = BFA_TRC_TS(trcm);
+ dc_flush(trc);
+
+ trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+ if (trcm->tail == trcm->head)
+ trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+ dc_flush(trcm);
+}
+
+#ifndef BFA_PERF_BUILD
+#define bfa_trc_fp(_trcp, _data) bfa_trc(_trcp, _data)
+#else
+#define bfa_trc_fp(_trcp, _data)
+#endif
+
+#endif /* __BFA_TRC_H__ */
+
diff --git a/drivers/scsi/bfa/include/cs/bfa_wc.h b/drivers/scsi/bfa/include/cs/bfa_wc.h
new file mode 100644
index 000000000000..0460bd4fc7c4
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_wc.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_wc.h Generic wait counter.
+ */
+
+#ifndef __BFA_WC_H__
+#define __BFA_WC_H__
+
+typedef void (*bfa_wc_resume_t) (void *cbarg);
+
+struct bfa_wc_s {
+ bfa_wc_resume_t wc_resume;
+ void *wc_cbarg;
+ int wc_count;
+};
+
+static inline void
+bfa_wc_up(struct bfa_wc_s *wc)
+{
+ wc->wc_count++;
+}
+
+static inline void
+bfa_wc_down(struct bfa_wc_s *wc)
+{
+ wc->wc_count--;
+ if (wc->wc_count == 0)
+ wc->wc_resume(wc->wc_cbarg);
+}
+
+/**
+ * Initialize a waiting counter.
+ */
+static inline void
+bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg)
+{
+ wc->wc_resume = wc_resume;
+ wc->wc_cbarg = wc_cbarg;
+ wc->wc_count = 0;
+ bfa_wc_up(wc);
+}
+
+/**
+ * Wait for counter to reach zero
+ */
+static inline void
+bfa_wc_wait(struct bfa_wc_s *wc)
+{
+ bfa_wc_down(wc);
+}
+
+#endif
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
new file mode 100644
index 000000000000..8c208fc8e329
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_ADAPTER_H__
+#define __BFA_DEFS_ADAPTER_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_version.h>
+#include <defs/bfa_defs_mfg.h>
+
+/**
+ * BFA adapter level attributes.
+ */
+enum {
+ BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE),
+ /*
+ *!< adapter serial num length
+ */
+ BFA_ADAPTER_MODEL_NAME_LEN = 16, /* model name length */
+ BFA_ADAPTER_MODEL_DESCR_LEN = 128, /* model description length */
+ BFA_ADAPTER_MFG_NAME_LEN = 8, /* manufacturer name length */
+ BFA_ADAPTER_SYM_NAME_LEN = 64, /* adapter symbolic name length */
+ BFA_ADAPTER_OS_TYPE_LEN = 64, /* adapter os type length */
+};
+
+struct bfa_adapter_attr_s {
+ char manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
+ char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+ u32 rsvd1;
+ char model[BFA_ADAPTER_MODEL_NAME_LEN];
+ char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
+ wwn_t pwwn;
+ char node_symname[FC_SYMNAME_MAX];
+ char hw_ver[BFA_VERSION_LEN];
+ char fw_ver[BFA_VERSION_LEN];
+ char optrom_ver[BFA_VERSION_LEN];
+ char os_type[BFA_ADAPTER_OS_TYPE_LEN];
+ struct bfa_mfg_vpd_s vpd;
+ struct mac_s mac;
+
+ u8 nports;
+ u8 max_speed;
+ u8 prototype;
+ char asic_rev;
+
+ u8 pcie_gen;
+ u8 pcie_lanes_orig;
+ u8 pcie_lanes;
+ u8 cna_capable;
+};
+
+/**
+ * BFA adapter level events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_PORT_AEN_ADD: [in]: None [out]: serial_num, pwwn, nports
+ * BFA_PORT_AEN_REMOVE: [in]: pwwn [out]: serial_num, pwwn, nports
+ */
+enum bfa_adapter_aen_event {
+ BFA_ADAPTER_AEN_ADD = 1, /* New Adapter found event */
+ BFA_ADAPTER_AEN_REMOVE = 2, /* Adapter removed event */
+};
+
+struct bfa_adapter_aen_data_s {
+ char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+ u32 nports; /* Number of NPorts */
+ wwn_t pwwn; /* WWN of one of its physical port */
+};
+
+#endif /* __BFA_DEFS_ADAPTER_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_aen.h b/drivers/scsi/bfa/include/defs/bfa_defs_aen.h
new file mode 100644
index 000000000000..4c81a613db3d
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_aen.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_AEN_H__
+#define __BFA_DEFS_AEN_H__
+
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_ioc.h>
+#include <defs/bfa_defs_adapter.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_lport.h>
+#include <defs/bfa_defs_rport.h>
+#include <defs/bfa_defs_itnim.h>
+#include <defs/bfa_defs_tin.h>
+#include <defs/bfa_defs_ipfc.h>
+#include <defs/bfa_defs_audit.h>
+#include <defs/bfa_defs_ethport.h>
+
+enum bfa_aen_category {
+ BFA_AEN_CAT_ADAPTER = 1,
+ BFA_AEN_CAT_PORT = 2,
+ BFA_AEN_CAT_LPORT = 3,
+ BFA_AEN_CAT_RPORT = 4,
+ BFA_AEN_CAT_ITNIM = 5,
+ BFA_AEN_CAT_TIN = 6,
+ BFA_AEN_CAT_IPFC = 7,
+ BFA_AEN_CAT_AUDIT = 8,
+ BFA_AEN_CAT_IOC = 9,
+ BFA_AEN_CAT_ETHPORT = 10,
+ BFA_AEN_MAX_CAT = 10
+};
+
+#pragma pack(1)
+union bfa_aen_data_u {
+ struct bfa_adapter_aen_data_s adapter;
+ struct bfa_port_aen_data_s port;
+ struct bfa_lport_aen_data_s lport;
+ struct bfa_rport_aen_data_s rport;
+ struct bfa_itnim_aen_data_s itnim;
+ struct bfa_audit_aen_data_s audit;
+ struct bfa_ioc_aen_data_s ioc;
+ struct bfa_ethport_aen_data_s ethport;
+};
+
+struct bfa_aen_entry_s {
+ enum bfa_aen_category aen_category;
+ int aen_type;
+ union bfa_aen_data_u aen_data;
+ struct bfa_timeval_s aen_tv;
+ s32 seq_num;
+ s32 bfad_num;
+ s32 rsvd[1];
+};
+
+#pragma pack()
+
+#define bfa_aen_event_t int
+
+#endif /* __BFA_DEFS_AEN_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_audit.h b/drivers/scsi/bfa/include/defs/bfa_defs_audit.h
new file mode 100644
index 000000000000..8e3a962bf20c
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_audit.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_AUDIT_H__
+#define __BFA_DEFS_AUDIT_H__
+
+#include <bfa_os_inc.h>
+
+/**
+ * BFA audit events
+ */
+enum bfa_audit_aen_event {
+ BFA_AUDIT_AEN_AUTH_ENABLE = 1,
+ BFA_AUDIT_AEN_AUTH_DISABLE = 2,
+};
+
+/**
+ * audit event data
+ */
+struct bfa_audit_aen_data_s {
+ wwn_t pwwn;
+};
+
+#endif /* __BFA_DEFS_AUDIT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
new file mode 100644
index 000000000000..dd19c83aba58
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_AUTH_H__
+#define __BFA_DEFS_AUTH_H__
+
+#include <defs/bfa_defs_types.h>
+
+#define PUBLIC_KEY 15409
+#define PRIVATE_KEY 19009
+#define KEY_LEN 32399
+#define BFA_AUTH_SECRET_STRING_LEN 256
+#define BFA_AUTH_FAIL_TIMEOUT 0xFF
+
+/**
+ * Authentication status
+ */
+enum bfa_auth_status {
+ BFA_AUTH_STATUS_NONE = 0, /* no authentication */
+ BFA_AUTH_UNINIT = 1, /* state - uninit */
+ BFA_AUTH_NEG_SEND = 2, /* state - negotiate send */
+ BFA_AUTH_CHAL_WAIT = 3, /* state - challenge wait */
+ BFA_AUTH_NEG_RETRY = 4, /* state - negotiate retry */
+ BFA_AUTH_REPLY_SEND = 5, /* state - reply send */
+ BFA_AUTH_STATUS_WAIT = 6, /* state - status wait */
+ BFA_AUTH_SUCCESS = 7, /* state - success */
+ BFA_AUTH_FAILED = 8, /* state - failed */
+ BFA_AUTH_STATUS_UNKNOWN = 9, /* authentication status unknown */
+};
+
+struct auth_proto_stats_s {
+ u32 auth_rjts;
+ u32 auth_negs;
+ u32 auth_dones;
+
+ u32 dhchap_challenges;
+ u32 dhchap_replies;
+ u32 dhchap_successes;
+};
+
+/**
+ * Authentication related statistics
+ */
+struct bfa_auth_stats_s {
+ u32 auth_failures; /* authentication failures */
+ u32 auth_successes; /* authentication successes*/
+ struct auth_proto_stats_s auth_rx_stats; /* Rx protocol stats */
+ struct auth_proto_stats_s auth_tx_stats; /* Tx protocol stats */
+};
+
+/**
+ * Authentication hash function algorithms
+ */
+enum bfa_auth_algo {
+ BFA_AUTH_ALGO_MD5 = 1, /* Message-Digest algorithm 5 */
+ BFA_AUTH_ALGO_SHA1 = 2, /* Secure Hash Algorithm 1 */
+ BFA_AUTH_ALGO_MS = 3, /* MD5, then SHA-1 */
+ BFA_AUTH_ALGO_SM = 4, /* SHA-1, then MD5 */
+};
+
+/**
+ * DH Groups
+ *
+ * Current value could be combination of one or more of the following values
+ */
+enum bfa_auth_group {
+ BFA_AUTH_GROUP_DHNULL = 0, /* DH NULL (value == 0) */
+ BFA_AUTH_GROUP_DH768 = 1, /* DH group 768 (value == 1) */
+ BFA_AUTH_GROUP_DH1024 = 2, /* DH group 1024 (value == 2) */
+ BFA_AUTH_GROUP_DH1280 = 4, /* DH group 1280 (value == 3) */
+ BFA_AUTH_GROUP_DH1536 = 8, /* DH group 1536 (value == 4) */
+
+ BFA_AUTH_GROUP_ALL = 256 /* Use default DH group order
+ * 0, 1, 2, 3, 4 */
+};
+
+/**
+ * Authentication secret sources
+ */
+enum bfa_auth_secretsource {
+ BFA_AUTH_SECSRC_LOCAL = 1, /* locally configured */
+ BFA_AUTH_SECSRC_RADIUS = 2, /* use radius server */
+ BFA_AUTH_SECSRC_TACACS = 3, /* TACACS server */
+};
+
+/**
+ * Authentication attributes
+ */
+struct bfa_auth_attr_s {
+ enum bfa_auth_status status;
+ enum bfa_auth_algo algo;
+ enum bfa_auth_group dh_grp;
+ u16 rjt_code;
+ u16 rjt_code_exp;
+ u8 secret_set;
+ u8 resv[7];
+};
+
+#endif /* __BFA_DEFS_AUTH_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
new file mode 100644
index 000000000000..6f4aa5283545
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_BOOT_H__
+#define __BFA_DEFS_BOOT_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_pport.h>
+
+enum {
+ BFA_BOOT_BOOTLUN_MAX = 4, /* maximum boot lun per IOC */
+};
+
+#define BOOT_CFG_REV1 1
+
+/**
+ * Boot options setting. Boot options setting determines from where
+ * to get the boot lun information
+ */
+enum bfa_boot_bootopt {
+ BFA_BOOT_AUTO_DISCOVER = 0, /* Boot from blun provided by fabric */
+ BFA_BOOT_STORED_BLUN = 1, /* Boot from bluns stored in flash */
+ BFA_BOOT_FIRST_LUN = 2, /* Boot from first discovered blun */
+};
+
+/**
+ * Boot lun information.
+ */
+struct bfa_boot_bootlun_s {
+ wwn_t pwwn; /* port wwn of target */
+ lun_t lun; /* 64-bit lun */
+};
+
+/**
+ * BOOT boot configuraton
+ */
+struct bfa_boot_cfg_s {
+ u8 version;
+ u8 rsvd1;
+ u16 chksum;
+
+ u8 enable; /* enable/disable SAN boot */
+ u8 speed; /* boot speed settings */
+ u8 topology; /* boot topology setting */
+ u8 bootopt; /* bfa_boot_bootopt_t */
+
+ u32 nbluns; /* number of boot luns */
+
+ u32 rsvd2;
+
+ struct bfa_boot_bootlun_s blun[BFA_BOOT_BOOTLUN_MAX];
+ struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX];
+};
+
+
+#endif /* __BFA_DEFS_BOOT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_cee.h b/drivers/scsi/bfa/include/defs/bfa_defs_cee.h
new file mode 100644
index 000000000000..520a22f52dd1
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_cee.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * bfa_defs_cee.h Interface declarations between host based
+ * BFAL and DCBX/LLDP module in Firmware
+ *
+ * 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.
+ */
+#ifndef __BFA_DEFS_CEE_H__
+#define __BFA_DEFS_CEE_H__
+
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_pport.h>
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+#define BFA_CEE_LLDP_MAX_STRING_LEN (128)
+
+
+/* FIXME: this is coming from the protocol spec. Can the host & apps share the
+ protocol .h files ?
+ */
+#define BFA_CEE_LLDP_SYS_CAP_OTHER 0x0001
+#define BFA_CEE_LLDP_SYS_CAP_REPEATER 0x0002
+#define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE 0x0004
+#define BFA_CEE_LLDP_SYS_CAP_WLAN_AP 0x0008
+#define BFA_CEE_LLDP_SYS_CAP_ROUTER 0x0010
+#define BFA_CEE_LLDP_SYS_CAP_TELEPHONE 0x0020
+#define BFA_CEE_LLDP_SYS_CAP_DOCSIS_CD 0x0040
+#define BFA_CEE_LLDP_SYS_CAP_STATION 0x0080
+#define BFA_CEE_LLDP_SYS_CAP_CVLAN 0x0100
+#define BFA_CEE_LLDP_SYS_CAP_SVLAN 0x0200
+#define BFA_CEE_LLDP_SYS_CAP_TPMR 0x0400
+
+
+/* LLDP string type */
+struct bfa_cee_lldp_str_s {
+ u8 sub_type;
+ u8 len;
+ u8 rsvd[2];
+ u8 value[BFA_CEE_LLDP_MAX_STRING_LEN];
+};
+
+
+/* LLDP paramters */
+struct bfa_cee_lldp_cfg_s {
+ struct bfa_cee_lldp_str_s chassis_id;
+ struct bfa_cee_lldp_str_s port_id;
+ struct bfa_cee_lldp_str_s port_desc;
+ struct bfa_cee_lldp_str_s sys_name;
+ struct bfa_cee_lldp_str_s sys_desc;
+ struct bfa_cee_lldp_str_s mgmt_addr;
+ u16 time_to_interval;
+ u16 enabled_system_cap;
+};
+
+enum bfa_cee_dcbx_version_e {
+ DCBX_PROTOCOL_PRECEE = 1,
+ DCBX_PROTOCOL_CEE = 2,
+};
+
+enum bfa_cee_lls_e {
+ CEE_LLS_DOWN_NO_TLV = 0, /* LLS is down because the TLV not sent by
+ * the peer */
+ CEE_LLS_DOWN = 1, /* LLS is down as advertised by the peer */
+ CEE_LLS_UP = 2,
+};
+
+/* CEE/DCBX parameters */
+struct bfa_cee_dcbx_cfg_s {
+ u8 pgid[8];
+ u8 pg_percentage[8];
+ u8 pfc_enabled; /* bitmap of priorties with PFC enabled */
+ u8 fcoe_user_priority; /* bitmap of priorities used for FcoE
+ * traffic */
+ u8 dcbx_version; /* operating version:CEE or preCEE */
+ u8 lls_fcoe; /* FCoE Logical Link Status */
+ u8 lls_lan; /* LAN Logical Link Status */
+ u8 rsvd[3];
+};
+
+/* CEE status */
+/* Making this to tri-state for the benefit of port list command */
+enum bfa_cee_status_e {
+ CEE_PHY_DOWN = 0,
+ CEE_PHY_UP = 1,
+ CEE_UP = 2,
+};
+
+/* CEE Query */
+struct bfa_cee_attr_s {
+ u8 cee_status;
+ u8 error_reason;
+ struct bfa_cee_lldp_cfg_s lldp_remote;
+ struct bfa_cee_dcbx_cfg_s dcbx_remote;
+ mac_t src_mac;
+ u8 link_speed;
+ u8 filler[3];
+};
+
+
+
+
+/* LLDP/DCBX/CEE Statistics */
+
+struct bfa_cee_lldp_stats_s {
+ u32 frames_transmitted;
+ u32 frames_aged_out;
+ u32 frames_discarded;
+ u32 frames_in_error;
+ u32 frames_rcvd;
+ u32 tlvs_discarded;
+ u32 tlvs_unrecognized;
+};
+
+struct bfa_cee_dcbx_stats_s {
+ u32 subtlvs_unrecognized;
+ u32 negotiation_failed;
+ u32 remote_cfg_changed;
+ u32 tlvs_received;
+ u32 tlvs_invalid;
+ u32 seqno;
+ u32 ackno;
+ u32 recvd_seqno;
+ u32 recvd_ackno;
+};
+
+struct bfa_cee_cfg_stats_s {
+ u32 cee_status_down;
+ u32 cee_status_up;
+ u32 cee_hw_cfg_changed;
+ u32 recvd_invalid_cfg;
+};
+
+
+struct bfa_cee_stats_s {
+ struct bfa_cee_lldp_stats_s lldp_stats;
+ struct bfa_cee_dcbx_stats_s dcbx_stats;
+ struct bfa_cee_cfg_stats_s cfg_stats;
+};
+
+#pragma pack()
+
+
+#endif /* __BFA_DEFS_CEE_H__ */
+
+
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
new file mode 100644
index 000000000000..57049805762b
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_DRIVER_H__
+#define __BFA_DEFS_DRIVER_H__
+
+/**
+ * Driver statistics
+ */
+ u16 tm_io_abort;
+ u16 tm_io_abort_comp;
+ u16 tm_lun_reset;
+ u16 tm_lun_reset_comp;
+ u16 tm_target_reset;
+ u16 tm_bus_reset;
+ u16 ioc_restart; /* IOC restart count */
+ u16 io_pending; /* outstanding io count per-IOC */
+ u64 control_req;
+ u64 input_req;
+ u64 output_req;
+ u64 input_words;
+ u64 output_words;
+} bfa_driver_stats_t;
+
+
+#endif /* __BFA_DEFS_DRIVER_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h b/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h
new file mode 100644
index 000000000000..79f9b3e146f7
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_ETHPORT_H__
+#define __BFA_DEFS_ETHPORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <protocol/types.h>
+#include <cna/pstats/phyport_defs.h>
+#include <cna/pstats/ethport_defs.h>
+
+struct bna_tx_info_s {
+ u32 miniport_state;
+ u32 adapter_state;
+ u64 tx_count;
+ u64 tx_wi;
+ u64 tx_sg;
+ u64 tx_tcp_chksum;
+ u64 tx_udp_chksum;
+ u64 tx_ip_chksum;
+ u64 tx_lsov1;
+ u64 tx_lsov2;
+ u64 tx_max_sg_len ;
+};
+
+struct bna_rx_queue_info_s {
+ u16 q_id ;
+ u16 buf_size ;
+ u16 buf_count ;
+ u16 rsvd ;
+ u64 rx_count ;
+ u64 rx_dropped ;
+ u64 rx_unsupported ;
+ u64 rx_internal_err ;
+ u64 rss_count ;
+ u64 vlan_count ;
+ u64 rx_tcp_chksum ;
+ u64 rx_udp_chksum ;
+ u64 rx_ip_chksum ;
+ u64 rx_hds ;
+};
+
+struct bna_rx_q_set_s {
+ u16 q_set_type;
+ u32 miniport_state;
+ u32 adapter_state;
+ struct bna_rx_queue_info_s rx_queue[2];
+};
+
+struct bna_port_stats_s {
+ struct bna_tx_info_s tx_stats;
+ u16 qset_count ;
+ struct bna_rx_q_set_s rx_qset[8];
+};
+
+struct bfa_ethport_stats_s {
+ struct bna_stats_txf txf_stats[1];
+ struct bna_stats_rxf rxf_stats[1];
+ struct bnad_drv_stats drv_stats;
+};
+
+/**
+ * Ethernet port events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_PORT_AEN_ETH_LINKUP: [in]: mac [out]: mac
+ * BFA_PORT_AEN_ETH_LINKDOWN: [in]: mac [out]: mac
+ * BFA_PORT_AEN_ETH_ENABLE: [in]: mac [out]: mac
+ * BFA_PORT_AEN_ETH_DISABLE: [in]: mac [out]: mac
+ *
+ */
+enum bfa_ethport_aen_event {
+ BFA_ETHPORT_AEN_LINKUP = 1, /* Base Port Ethernet link up event */
+ BFA_ETHPORT_AEN_LINKDOWN = 2, /* Base Port Ethernet link down event */
+ BFA_ETHPORT_AEN_ENABLE = 3, /* Base Port Ethernet link enable event */
+ BFA_ETHPORT_AEN_DISABLE = 4, /* Base Port Ethernet link disable
+ * event */
+};
+
+struct bfa_ethport_aen_data_s {
+ mac_t mac; /* MAC address of the physical port */
+};
+
+
+#endif /* __BFA_DEFS_ETHPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h
new file mode 100644
index 000000000000..c08f4f5026ac
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_FCPIM_H__
+#define __BFA_DEFS_FCPIM_H__
+
+struct bfa_fcpim_stats_s {
+ u32 total_ios; /* Total IO count */
+ u32 qresumes; /* IO waiting for CQ space */
+ u32 no_iotags; /* NO IO contexts */
+ u32 io_aborts; /* IO abort requests */
+ u32 no_tskims; /* NO task management contexts */
+ u32 iocomp_ok; /* IO completions with OK status */
+ u32 iocomp_underrun; /* IO underrun (good) */
+ u32 iocomp_overrun; /* IO overrun (good) */
+ u32 iocomp_aborted; /* Aborted IO requests */
+ u32 iocomp_timedout; /* IO timeouts */
+ u32 iocom_nexus_abort; /* IO selection timeouts */
+ u32 iocom_proto_err; /* IO protocol errors */
+ u32 iocom_dif_err; /* IO SBC-3 protection errors */
+ u32 iocom_tm_abort; /* IO aborted by TM requests */
+ u32 iocom_sqer_needed; /* IO retry for SQ error
+ *recovery */
+ u32 iocom_res_free; /* Delayed freeing of IO resources */
+ u32 iocomp_scsierr; /* IO with non-good SCSI status */
+ u32 iocom_hostabrts; /* Host IO abort requests */
+ u32 iocom_utags; /* IO comp with unknown tags */
+ u32 io_cleanups; /* IO implicitly aborted */
+ u32 io_tmaborts; /* IO aborted due to TM commands */
+ u32 rsvd;
+};
+#endif /*__BFA_DEFS_FCPIM_H__*/
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h
new file mode 100644
index 000000000000..9ccf53bef65a
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_IM_COMMON_H__
+#define __BFA_DEFS_IM_COMMON_H__
+
+#define BFA_ADAPTER_NAME_LEN 256
+#define BFA_ADAPTER_GUID_LEN 256
+#define RESERVED_VLAN_NAME L"PORT VLAN"
+#define PASSTHRU_VLAN_NAME L"PASSTHRU VLAN"
+
+ u64 tx_pkt_cnt;
+ u64 rx_pkt_cnt;
+ u32 duration;
+ u8 status;
+} bfa_im_stats_t, *pbfa_im_stats_t;
+
+#endif /* __BFA_DEFS_IM_COMMON_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h
new file mode 100644
index 000000000000..a486a7eb81d6
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_IM_TEAM_H__
+#define __BFA_DEFS_IM_TEAM_H__
+
+#include <protocol/types.h>
+
+#define BFA_TEAM_MAX_PORTS 8
+#define BFA_TEAM_NAME_LEN 256
+#define BFA_MAX_NUM_TEAMS 16
+#define BFA_TEAM_INVALID_DELAY -1
+
+ BFA_LACP_RATE_SLOW = 1,
+ BFA_LACP_RATE_FAST
+} bfa_im_lacp_rate_t;
+
+ BFA_TEAM_MODE_FAIL_OVER = 1,
+ BFA_TEAM_MODE_FAIL_BACK,
+ BFA_TEAM_MODE_LACP,
+ BFA_TEAM_MODE_NONE
+} bfa_im_team_mode_t;
+
+ BFA_XMIT_POLICY_L2 = 1,
+ BFA_XMIT_POLICY_L3_L4
+} bfa_im_xmit_policy_t;
+
+ bfa_im_team_mode_t team_mode;
+ bfa_im_lacp_rate_t lacp_rate;
+ bfa_im_xmit_policy_t xmit_policy;
+ int delay;
+ wchar_t primary[BFA_ADAPTER_NAME_LEN];
+ wchar_t preferred_primary[BFA_ADAPTER_NAME_LEN];
+ mac_t mac;
+ u16 num_ports;
+ u16 num_vlans;
+ u16 vlan_list[BFA_MAX_VLANS_PER_PORT];
+ wchar_t team_guid_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_GUID_LEN];
+ wchar_t ioc_name_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_NAME_LEN];
+} bfa_im_team_attr_t;
+
+ wchar_t team_name[BFA_TEAM_NAME_LEN];
+ bfa_im_xmit_policy_t xmit_policy;
+ int delay;
+ wchar_t primary[BFA_ADAPTER_NAME_LEN];
+ wchar_t preferred_primary[BFA_ADAPTER_NAME_LEN];
+} bfa_im_team_edit_t, *pbfa_im_team_edit_t;
+
+ wchar_t team_name[BFA_TEAM_NAME_LEN];
+ bfa_im_team_mode_t team_mode;
+ mac_t mac;
+} bfa_im_team_info_t;
+
+ bfa_im_team_info_t team_info[BFA_MAX_NUM_TEAMS];
+ u16 num_teams;
+} bfa_im_team_list_t, *pbfa_im_team_list_t;
+
+#endif /* __BFA_DEFS_IM_TEAM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
new file mode 100644
index 000000000000..b1d532da3a9d
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_IOC_H__
+#define __BFA_DEFS_IOC_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_version.h>
+#include <defs/bfa_defs_adapter.h>
+#include <defs/bfa_defs_pm.h>
+
+enum {
+ BFA_IOC_DRIVER_LEN = 16,
+ BFA_IOC_CHIP_REV_LEN = 8,
+};
+
+/**
+ * Driver and firmware versions.
+ */
+struct bfa_ioc_driver_attr_s {
+ char driver[BFA_IOC_DRIVER_LEN]; /* driver name */
+ char driver_ver[BFA_VERSION_LEN]; /* driver version */
+ char fw_ver[BFA_VERSION_LEN]; /* firmware version*/
+ char bios_ver[BFA_VERSION_LEN]; /* bios version */
+ char efi_ver[BFA_VERSION_LEN]; /* EFI version */
+ char ob_ver[BFA_VERSION_LEN]; /* openboot version*/
+};
+
+/**
+ * IOC PCI device attributes
+ */
+struct bfa_ioc_pci_attr_s {
+ u16 vendor_id; /* PCI vendor ID */
+ u16 device_id; /* PCI device ID */
+ u16 ssid; /* subsystem ID */
+ u16 ssvid; /* subsystem vendor ID */
+ u32 pcifn; /* PCI device function */
+ u32 rsvd; /* padding */
+ u8 chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */
+};
+
+/**
+ * IOC states
+ */
+enum bfa_ioc_state {
+ BFA_IOC_RESET = 1, /* IOC is in reset state */
+ BFA_IOC_SEMWAIT = 2, /* Waiting for IOC hardware semaphore */
+ BFA_IOC_HWINIT = 3, /* IOC hardware is being initialized */
+ BFA_IOC_GETATTR = 4, /* IOC is being configured */
+ BFA_IOC_OPERATIONAL = 5, /* IOC is operational */
+ BFA_IOC_INITFAIL = 6, /* IOC hardware failure */
+ BFA_IOC_HBFAIL = 7, /* IOC heart-beat failure */
+ BFA_IOC_DISABLING = 8, /* IOC is being disabled */
+ BFA_IOC_DISABLED = 9, /* IOC is disabled */
+ BFA_IOC_FWMISMATCH = 10, /* IOC firmware different from drivers */
+};
+
+/**
+ * IOC firmware stats
+ */
+struct bfa_fw_ioc_stats_s {
+ u32 hb_count;
+ u32 cfg_reqs;
+ u32 enable_reqs;
+ u32 disable_reqs;
+ u32 stats_reqs;
+ u32 clrstats_reqs;
+ u32 unknown_reqs;
+ u32 ic_reqs; /* interrupt coalesce reqs */
+};
+
+/**
+ * IOC driver stats
+ */
+struct bfa_ioc_drv_stats_s {
+ u32 ioc_isrs;
+ u32 ioc_enables;
+ u32 ioc_disables;
+ u32 ioc_hbfails;
+ u32 ioc_boots;
+ u32 stats_tmos;
+ u32 hb_count;
+ u32 disable_reqs;
+ u32 enable_reqs;
+ u32 disable_replies;
+ u32 enable_replies;
+};
+
+/**
+ * IOC statistics
+ */
+struct bfa_ioc_stats_s {
+ struct bfa_ioc_drv_stats_s drv_stats; /* driver IOC stats */
+ struct bfa_fw_ioc_stats_s fw_stats; /* firmware IOC stats */
+};
+
+
+enum bfa_ioc_type_e {
+ BFA_IOC_TYPE_FC = 1,
+ BFA_IOC_TYPE_FCoE = 2,
+ BFA_IOC_TYPE_LL = 3,
+};
+
+/**
+ * IOC attributes returned in queries
+ */
+struct bfa_ioc_attr_s {
+ enum bfa_ioc_type_e ioc_type;
+ enum bfa_ioc_state state; /* IOC state */
+ struct bfa_adapter_attr_s adapter_attr; /* HBA attributes */
+ struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */
+ struct bfa_ioc_pci_attr_s pci_attr;
+ u8 port_id; /* port number */
+};
+
+/**
+ * BFA IOC level events
+ */
+enum bfa_ioc_aen_event {
+ BFA_IOC_AEN_HBGOOD = 1, /* Heart Beat restore event */
+ BFA_IOC_AEN_HBFAIL = 2, /* Heart Beat failure event */
+ BFA_IOC_AEN_ENABLE = 3, /* IOC enabled event */
+ BFA_IOC_AEN_DISABLE = 4, /* IOC disabled event */
+ BFA_IOC_AEN_FWMISMATCH = 5, /* IOC firmware mismatch */
+};
+
+/**
+ * BFA IOC level event data, now just a place holder
+ */
+struct bfa_ioc_aen_data_s {
+ enum bfa_ioc_type_e ioc_type;
+ wwn_t pwwn;
+ mac_t mac;
+};
+
+#endif /* __BFA_DEFS_IOC_H__ */
+
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
new file mode 100644
index 000000000000..d76bcbd9820f
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_IOCFC_H__
+#define __BFA_DEFS_IOCFC_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_version.h>
+#include <defs/bfa_defs_adapter.h>
+#include <defs/bfa_defs_pm.h>
+
+#define BFA_IOCFC_INTR_DELAY 1125
+#define BFA_IOCFC_INTR_LATENCY 225
+
+/**
+ * Interrupt coalescing configuration.
+ */
+struct bfa_iocfc_intr_attr_s {
+ bfa_boolean_t coalesce; /* enable/disable coalescing */
+ u16 latency; /* latency in microseconds */
+ u16 delay; /* delay in microseconds */
+};
+
+/**
+ * IOC firmware configuraton
+ */
+struct bfa_iocfc_fwcfg_s {
+ u16 num_fabrics; /* number of fabrics */
+ u16 num_lports; /* number of local lports */
+ u16 num_rports; /* number of remote ports */
+ u16 num_ioim_reqs; /* number of IO reqs */
+ u16 num_tskim_reqs; /* task management requests */
+ u16 num_iotm_reqs; /* number of TM IO reqs */
+ u16 num_tsktm_reqs; /* TM task management requests*/
+ u16 num_fcxp_reqs; /* unassisted FC exchanges */
+ u16 num_uf_bufs; /* unsolicited recv buffers */
+ u8 num_cqs;
+ u8 rsvd;
+};
+
+struct bfa_iocfc_drvcfg_s {
+ u16 num_reqq_elems; /* number of req queue elements */
+ u16 num_rspq_elems; /* number of rsp queue elements */
+ u16 num_sgpgs; /* number of total SG pages */
+ u16 num_sboot_tgts; /* number of SAN boot targets */
+ u16 num_sboot_luns; /* number of SAN boot luns */
+ u16 ioc_recover; /* IOC recovery mode */
+ u16 min_cfg; /* minimum configuration */
+ u16 path_tov; /* device path timeout */
+ bfa_boolean_t delay_comp; /* delay completion of
+ failed inflight IOs */
+ u32 rsvd;
+};
+/**
+ * IOC configuration
+ */
+struct bfa_iocfc_cfg_s {
+ struct bfa_iocfc_fwcfg_s fwcfg; /* firmware side config */
+ struct bfa_iocfc_drvcfg_s drvcfg; /* driver side config */
+};
+
+/**
+ * IOC firmware IO stats
+ */
+struct bfa_fw_io_stats_s {
+ u32 host_abort; /* IO aborted by host driver*/
+ u32 host_cleanup; /* IO clean up by host driver */
+
+ u32 fw_io_timeout; /* IOs timedout */
+ u32 fw_frm_parse; /* frame parsed by f/w */
+ u32 fw_frm_data; /* fcp_data frame parsed by f/w */
+ u32 fw_frm_rsp; /* fcp_rsp frame parsed by f/w */
+ u32 fw_frm_xfer_rdy; /* xfer_rdy frame parsed by f/w */
+ u32 fw_frm_bls_acc; /* BLS ACC frame parsed by f/w */
+ u32 fw_frm_tgt_abort; /* target ABTS parsed by f/w */
+ u32 fw_frm_unknown; /* unknown parsed by f/w */
+ u32 fw_data_dma; /* f/w DMA'ed the data frame */
+ u32 fw_frm_drop; /* f/w drop the frame */
+
+ u32 rec_timeout; /* FW rec timed out */
+ u32 error_rec; /* FW sending rec on
+ * an error condition*/
+ u32 wait_for_si; /* FW wait for SI */
+ u32 rec_rsp_inval; /* REC rsp invalid */
+ u32 seqr_io_abort; /* target does not know cmd so abort */
+ u32 seqr_io_retry; /* SEQR failed so retry IO */
+
+ u32 itn_cisc_upd_rsp; /* ITN cisc updated on fcp_rsp */
+ u32 itn_cisc_upd_data; /* ITN cisc updated on fcp_data */
+ u32 itn_cisc_upd_xfer_rdy; /* ITN cisc updated on fcp_data */
+
+ u32 fcp_data_lost; /* fcp data lost */
+
+ u32 ro_set_in_xfer_rdy; /* Target set RO in Xfer_rdy frame */
+ u32 xfer_rdy_ooo_err; /* Out of order Xfer_rdy received */
+ u32 xfer_rdy_unknown_err; /* unknown error in xfer_rdy frame */
+
+ u32 io_abort_timeout; /* ABTS timedout */
+ u32 sler_initiated; /* SLER initiated */
+
+ u32 unexp_fcp_rsp; /* fcp response in wrong state */
+
+ u32 fcp_rsp_under_run; /* fcp rsp IO underrun */
+ u32 fcp_rsp_under_run_wr; /* fcp rsp IO underrun for write */
+ u32 fcp_rsp_under_run_err; /* fcp rsp IO underrun error */
+ u32 fcp_rsp_resid_inval; /* invalid residue */
+ u32 fcp_rsp_over_run; /* fcp rsp IO overrun */
+ u32 fcp_rsp_over_run_err; /* fcp rsp IO overrun error */
+ u32 fcp_rsp_proto_err; /* protocol error in fcp rsp */
+ u32 fcp_rsp_sense_err; /* error in sense info in fcp rsp */
+ u32 fcp_conf_req; /* FCP conf requested */
+
+ u32 tgt_aborted_io; /* target initiated abort */
+
+ u32 ioh_edtov_timeout_event;/* IOH edtov timer popped */
+ u32 ioh_fcp_rsp_excp_event; /* IOH FCP_RSP exception */
+ u32 ioh_fcp_conf_event; /* IOH FCP_CONF */
+ u32 ioh_mult_frm_rsp_event; /* IOH multi_frame FCP_RSP */
+ u32 ioh_hit_class2_event; /* IOH hit class2 */
+ u32 ioh_miss_other_event; /* IOH miss other */
+ u32 ioh_seq_cnt_err_event; /* IOH seq cnt error */
+ u32 ioh_len_err_event; /* IOH len error - fcp_dl !=
+ * bytes xfered */
+ u32 ioh_seq_len_err_event; /* IOH seq len error */
+ u32 ioh_data_oor_event; /* Data out of range */
+ u32 ioh_ro_ooo_event; /* Relative offset out of range */
+ u32 ioh_cpu_owned_event; /* IOH hit -iost owned by f/w */
+ u32 ioh_unexp_frame_event; /* unexpected frame recieved
+ * count */
+ u32 ioh_err_int; /* IOH error int during data-phase
+ * for scsi write
+ */
+};
+
+/**
+ * IOC port firmware stats
+ */
+
+struct bfa_fw_port_fpg_stats_s {
+ u32 intr_evt;
+ u32 intr;
+ u32 intr_excess;
+ u32 intr_cause0;
+ u32 intr_other;
+ u32 intr_other_ign;
+ u32 sig_lost;
+ u32 sig_regained;
+ u32 sync_lost;
+ u32 sync_to;
+ u32 sync_regained;
+ u32 div2_overflow;
+ u32 div2_underflow;
+ u32 efifo_overflow;
+ u32 efifo_underflow;
+ u32 idle_rx;
+ u32 lrr_rx;
+ u32 lr_rx;
+ u32 ols_rx;
+ u32 nos_rx;
+ u32 lip_rx;
+ u32 arbf0_rx;
+ u32 mrk_rx;
+ u32 const_mrk_rx;
+ u32 prim_unknown;
+ u32 rsvd;
+};
+
+
+struct bfa_fw_port_lksm_stats_s {
+ u32 hwsm_success; /* hwsm state machine success */
+ u32 hwsm_fails; /* hwsm fails */
+ u32 hwsm_wdtov; /* hwsm timed out */
+ u32 swsm_success; /* swsm success */
+ u32 swsm_fails; /* swsm fails */
+ u32 swsm_wdtov; /* swsm timed out */
+ u32 busybufs; /* link init failed due to busybuf */
+ u32 buf_waits; /* bufwait state entries */
+ u32 link_fails; /* link failures */
+ u32 psp_errors; /* primitive sequence protocol errors */
+ u32 lr_unexp; /* No. of times LR rx-ed unexpectedly */
+ u32 lrr_unexp; /* No. of times LRR rx-ed unexpectedly */
+ u32 lr_tx; /* No. of times LR tx started */
+ u32 lrr_tx; /* No. of times LRR tx started */
+ u32 ols_tx; /* No. of times OLS tx started */
+ u32 nos_tx; /* No. of times NOS tx started */
+};
+
+
+struct bfa_fw_port_snsm_stats_s {
+ u32 hwsm_success; /* Successful hwsm terminations */
+ u32 hwsm_fails; /* hwsm fail count */
+ u32 hwsm_wdtov; /* hwsm timed out */
+ u32 swsm_success; /* swsm success */
+ u32 swsm_wdtov; /* swsm timed out */
+ u32 error_resets; /* error resets initiated by upsm */
+ u32 sync_lost; /* Sync loss count */
+ u32 sig_lost; /* Signal loss count */
+};
+
+
+struct bfa_fw_port_physm_stats_s {
+ u32 module_inserts; /* Module insert count */
+ u32 module_xtracts; /* Module extracts count */
+ u32 module_invalids; /* Invalid module inserted count */
+ u32 module_read_ign; /* Module validation status ignored */
+ u32 laser_faults; /* Laser fault count */
+ u32 rsvd;
+};
+
+
+struct bfa_fw_fip_stats_s {
+ u32 disc_req; /* Discovery solicit requests */
+ u32 disc_rsp; /* Discovery solicit response */
+ u32 disc_err; /* Discovery advt. parse errors */
+ u32 disc_unsol; /* Discovery unsolicited */
+ u32 disc_timeouts; /* Discovery timeouts */
+ u32 linksvc_unsupp; /* Unsupported link service req */
+ u32 linksvc_err; /* Parse error in link service req */
+ u32 logo_req; /* Number of FIP logos received */
+ u32 clrvlink_req; /* Clear virtual link req */
+ u32 op_unsupp; /* Unsupported FIP operation */
+ u32 untagged; /* Untagged frames (ignored) */
+ u32 rsvd;
+};
+
+
+struct bfa_fw_lps_stats_s {
+ u32 mac_invalids; /* Invalid mac assigned */
+ u32 rsvd;
+};
+
+
+struct bfa_fw_fcoe_stats_s {
+ u32 cee_linkups; /* CEE link up count */
+ u32 cee_linkdns; /* CEE link down count */
+ u32 fip_linkups; /* FIP link up count */
+ u32 fip_linkdns; /* FIP link up count */
+ u32 fip_fails; /* FIP fail count */
+ u32 mac_invalids; /* Invalid mac assigned */
+};
+
+/**
+ * IOC firmware FCoE port stats
+ */
+struct bfa_fw_fcoe_port_stats_s {
+ struct bfa_fw_fcoe_stats_s fcoe_stats;
+ struct bfa_fw_fip_stats_s fip_stats;
+};
+
+/**
+ * IOC firmware FC port stats
+ */
+struct bfa_fw_fc_port_stats_s {
+ struct bfa_fw_port_fpg_stats_s fpg_stats;
+ struct bfa_fw_port_physm_stats_s physm_stats;
+ struct bfa_fw_port_snsm_stats_s snsm_stats;
+ struct bfa_fw_port_lksm_stats_s lksm_stats;
+};
+
+/**
+ * IOC firmware FC port stats
+ */
+union bfa_fw_port_stats_s {
+ struct bfa_fw_fc_port_stats_s fc_stats;
+ struct bfa_fw_fcoe_port_stats_s fcoe_stats;
+};
+
+/**
+ * IOC firmware stats
+ */
+struct bfa_fw_stats_s {
+ struct bfa_fw_ioc_stats_s ioc_stats;
+ struct bfa_fw_io_stats_s io_stats;
+ union bfa_fw_port_stats_s port_stats;
+};
+
+/**
+ * IOC statistics
+ */
+struct bfa_iocfc_stats_s {
+ struct bfa_fw_stats_s fw_stats; /* firmware IOC stats */
+};
+
+/**
+ * IOC attributes returned in queries
+ */
+struct bfa_iocfc_attr_s {
+ struct bfa_iocfc_cfg_s config; /* IOCFC config */
+ struct bfa_iocfc_intr_attr_s intr_attr; /* interrupt attr */
+};
+
+#define BFA_IOCFC_PATHTOV_MAX 60
+#define BFA_IOCFC_QDEPTH_MAX 2000
+
+#endif /* __BFA_DEFS_IOC_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h
new file mode 100644
index 000000000000..7cb63ea98f38
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_IPFC_H__
+#define __BFA_DEFS_IPFC_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+
+/**
+ * FCS ip remote port states
+ */
+enum bfa_iprp_state {
+ BFA_IPRP_UNINIT = 0, /* PORT is not yet initialized */
+ BFA_IPRP_ONLINE = 1, /* process login is complete */
+ BFA_IPRP_OFFLINE = 2, /* iprp is offline */
+};
+
+/**
+ * FCS remote port statistics
+ */
+struct bfa_iprp_stats_s {
+ u32 offlines;
+ u32 onlines;
+ u32 rscns;
+ u32 plogis;
+ u32 logos;
+ u32 plogi_timeouts;
+ u32 plogi_rejects;
+};
+
+/**
+ * FCS iprp attribute returned in queries
+ */
+struct bfa_iprp_attr_s {
+ enum bfa_iprp_state state;
+};
+
+struct bfa_ipfc_stats_s {
+ u32 arp_sent;
+ u32 arp_recv;
+ u32 arp_reply_sent;
+ u32 arp_reply_recv;
+ u32 farp_sent;
+ u32 farp_recv;
+ u32 farp_reply_sent;
+ u32 farp_reply_recv;
+ u32 farp_reject_sent;
+ u32 farp_reject_recv;
+};
+
+struct bfa_ipfc_attr_s {
+ bfa_boolean_t enabled;
+};
+
+#endif /* __BFA_DEFS_IPFC_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
new file mode 100644
index 000000000000..2ec769903d24
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_ITNIM_H__
+#define __BFA_DEFS_ITNIM_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+
+/**
+ * FCS itnim states
+ */
+enum bfa_itnim_state {
+ BFA_ITNIM_OFFLINE = 0, /* offline */
+ BFA_ITNIM_PRLI_SEND = 1, /* prli send */
+ BFA_ITNIM_PRLI_SENT = 2, /* prli sent */
+ BFA_ITNIM_PRLI_RETRY = 3, /* prli retry */
+ BFA_ITNIM_HCB_ONLINE = 4, /* online callback */
+ BFA_ITNIM_ONLINE = 5, /* online */
+ BFA_ITNIM_HCB_OFFLINE = 6, /* offline callback */
+ BFA_ITNIM_INITIATIOR = 7, /* initiator */
+};
+
+struct bfa_itnim_hal_stats_s {
+ u32 onlines; /* ITN nexus onlines (PRLI done) */
+ u32 offlines; /* ITN Nexus offlines */
+ u32 creates; /* ITN create requests */
+ u32 deletes; /* ITN delete requests */
+ u32 create_comps; /* ITN create completions */
+ u32 delete_comps; /* ITN delete completions */
+ u32 sler_events; /* SLER (sequence level error
+ * recovery) events */
+ u32 ioc_disabled; /* Num IOC disables */
+ u32 cleanup_comps; /* ITN cleanup completions */
+ u32 tm_cmnds; /* task management(TM) cmnds sent */
+ u32 tm_fw_rsps; /* TM cmds firmware responses */
+ u32 tm_success; /* TM successes */
+ u32 tm_failures; /* TM failures */
+ u32 tm_io_comps; /* TM IO completions */
+ u32 tm_qresumes; /* TM queue resumes (after waiting
+ * for resources)
+ */
+ u32 tm_iocdowns; /* TM cmnds affected by IOC down */
+ u32 tm_cleanups; /* TM cleanups */
+ u32 tm_cleanup_comps;
+ /* TM cleanup completions */
+ u32 ios; /* IO requests */
+ u32 io_comps; /* IO completions */
+ u64 input_reqs; /* INPUT requests */
+ u64 output_reqs; /* OUTPUT requests */
+};
+
+/**
+ * FCS remote port statistics
+ */
+struct bfa_itnim_stats_s {
+ u32 onlines; /* num rport online */
+ u32 offlines; /* num rport offline */
+ u32 prli_sent; /* num prli sent out */
+ u32 fcxp_alloc_wait;/* num fcxp alloc waits */
+ u32 prli_rsp_err; /* num prli rsp errors */
+ u32 prli_rsp_acc; /* num prli rsp accepts */
+ u32 initiator; /* rport is an initiator */
+ u32 prli_rsp_parse_err; /* prli rsp parsing errors */
+ u32 prli_rsp_rjt; /* num prli rsp rejects */
+ u32 timeout; /* num timeouts detected */
+ u32 sler; /* num sler notification from BFA */
+ u32 rsvd;
+ struct bfa_itnim_hal_stats_s hal_stats;
+};
+
+/**
+ * FCS itnim attributes returned in queries
+ */
+struct bfa_itnim_attr_s {
+ enum bfa_itnim_state state; /* FCS itnim state */
+ u8 retry; /* data retransmision support */
+ u8 task_retry_id; /* task retry ident support */
+ u8 rec_support; /* REC supported */
+ u8 conf_comp; /* confirmed completion supp */
+};
+
+/**
+ * BFA ITNIM events.
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_ITNIM_AEN_NEW: [in]: None [out]: vf_id, lpwwn
+ * BFA_ITNIM_AEN_DELETE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ * BFA_ITNIM_AEN_ONLINE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ * BFA_ITNIM_AEN_OFFLINE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ * BFA_ITNIM_AEN_DISCONNECT:[in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ */
+enum bfa_itnim_aen_event {
+ BFA_ITNIM_AEN_ONLINE = 1, /* Target online */
+ BFA_ITNIM_AEN_OFFLINE = 2, /* Target offline */
+ BFA_ITNIM_AEN_DISCONNECT = 3, /* Target disconnected */
+};
+
+/**
+ * BFA ITNIM event data structure.
+ */
+struct bfa_itnim_aen_data_s {
+ u16 vf_id; /* vf_id of the IT nexus */
+ u16 rsvd[3];
+ wwn_t ppwwn; /* WWN of its physical port */
+ wwn_t lpwwn; /* WWN of logical port */
+ wwn_t rpwwn; /* WWN of remote(target) port */
+};
+
+#endif /* __BFA_DEFS_ITNIM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_led.h b/drivers/scsi/bfa/include/defs/bfa_defs_led.h
new file mode 100644
index 000000000000..62039273264e
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_led.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_LED_H__
+#define __BFA_DEFS_LED_H__
+
+#define BFA_LED_MAX_NUM 3
+
+enum bfa_led_op {
+ BFA_LED_OFF = 0,
+ BFA_LED_ON = 1,
+ BFA_LED_FLICK = 2,
+ BFA_LED_BLINK = 3,
+};
+
+enum bfa_led_color {
+ BFA_LED_GREEN = 0,
+ BFA_LED_AMBER = 1,
+};
+
+#endif /* __BFA_DEFS_LED_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_lport.h b/drivers/scsi/bfa/include/defs/bfa_defs_lport.h
new file mode 100644
index 000000000000..7359f82aacfc
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_lport.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_LPORT_H__
+#define __BFA_DEFS_LPORT_H__
+
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_port.h>
+
+/**
+ * BFA AEN logical port events.
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_LPORT_AEN_NEW: [in]: None [out]: vf_id, ppwwn, lpwwn, roles
+ * BFA_LPORT_AEN_DELETE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_ONLINE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_OFFLINE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_DISCONNECT:[in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NEW_PROP: [in]: None [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_DELETE_PROP: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NEW_STANDARD: [in]: None [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_DELETE_STANDARD: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NPIV_DUP_WWN: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NPIV_FABRIC_MAX: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NPIV_UNKNOWN: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ */
+enum bfa_lport_aen_event {
+ BFA_LPORT_AEN_NEW = 1, /* LPort created event */
+ BFA_LPORT_AEN_DELETE = 2, /* LPort deleted event */
+ BFA_LPORT_AEN_ONLINE = 3, /* LPort online event */
+ BFA_LPORT_AEN_OFFLINE = 4, /* LPort offline event */
+ BFA_LPORT_AEN_DISCONNECT = 5, /* LPort disconnect event */
+ BFA_LPORT_AEN_NEW_PROP = 6, /* VPort created event */
+ BFA_LPORT_AEN_DELETE_PROP = 7, /* VPort deleted event */
+ BFA_LPORT_AEN_NEW_STANDARD = 8, /* VPort created event */
+ BFA_LPORT_AEN_DELETE_STANDARD = 9, /* VPort deleted event */
+ BFA_LPORT_AEN_NPIV_DUP_WWN = 10, /* VPort configured with
+ * duplicate WWN event
+ */
+ BFA_LPORT_AEN_NPIV_FABRIC_MAX = 11, /* Max NPIV in fabric/fport */
+ BFA_LPORT_AEN_NPIV_UNKNOWN = 12, /* Unknown NPIV Error code event */
+};
+
+/**
+ * BFA AEN event data structure
+ */
+struct bfa_lport_aen_data_s {
+ u16 vf_id; /* vf_id of this logical port */
+ u16 rsvd;
+ enum bfa_port_role roles; /* Logical port mode,IM/TM/IP etc */
+ wwn_t ppwwn; /* WWN of its physical port */
+ wwn_t lpwwn; /* WWN of this logical port */
+};
+
+#endif /* __BFA_DEFS_LPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
new file mode 100644
index 000000000000..13fd4ab6aae2
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_MFG_H__
+#define __BFA_DEFS_MFG_H__
+
+#include <bfa_os_inc.h>
+
+/**
+ * Manufacturing block version
+ */
+#define BFA_MFG_VERSION 1
+
+/**
+ * Manufacturing block format
+ */
+#define BFA_MFG_SERIALNUM_SIZE 11
+#define BFA_MFG_PARTNUM_SIZE 14
+#define BFA_MFG_SUPPLIER_ID_SIZE 10
+#define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20
+#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20
+#define BFA_MFG_SUPPLIER_REVISION_SIZE 4
+#define STRSZ(_n) (((_n) + 4) & ~3)
+
+/**
+ * VPD data length
+ */
+#define BFA_MFG_VPD_LEN 256
+
+/**
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_vpd_s {
+ u8 version; /* vpd data version */
+ u8 vpd_sig[3]; /* characters 'V', 'P', 'D' */
+ u8 chksum; /* u8 checksum */
+ u8 vendor; /* vendor */
+ u8 len; /* vpd data length excluding header */
+ u8 rsv;
+ u8 data[BFA_MFG_VPD_LEN]; /* vpd data */
+};
+
+#pragma pack(1)
+
+#endif /* __BFA_DEFS_MFG_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
new file mode 100644
index 000000000000..c9b83321694b
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_PCI_H__
+#define __BFA_DEFS_PCI_H__
+
+/**
+ * PCI device and vendor ID information
+ */
+enum {
+ BFA_PCI_VENDOR_ID_BROCADE = 0x1657,
+ BFA_PCI_DEVICE_ID_FC_8G2P = 0x13,
+ BFA_PCI_DEVICE_ID_FC_8G1P = 0x17,
+ BFA_PCI_DEVICE_ID_CT = 0x14,
+};
+
+/**
+ * PCI sub-system device and vendor ID information
+ */
+enum {
+ BFA_PCI_FCOE_SSDEVICE_ID = 0x14,
+};
+
+#define BFA_PCI_ACCESS_RANGES 1 /* Maximum number of device address ranges
+ * mapped through different BAR(s). */
+
+#endif /* __BFA_DEFS_PCI_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pm.h b/drivers/scsi/bfa/include/defs/bfa_defs_pm.h
new file mode 100644
index 000000000000..e8d6d959006e
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pm.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_PM_H__
+#define __BFA_DEFS_PM_H__
+
+#include <bfa_os_inc.h>
+
+/**
+ * BFA power management device states
+ */
+enum bfa_pm_ds {
+ BFA_PM_DS_D0 = 0, /* full power mode */
+ BFA_PM_DS_D1 = 1, /* power save state 1 */
+ BFA_PM_DS_D2 = 2, /* power save state 2 */
+ BFA_PM_DS_D3 = 3, /* power off state */
+};
+
+#endif /* __BFA_DEFS_PM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pom.h b/drivers/scsi/bfa/include/defs/bfa_defs_pom.h
new file mode 100644
index 000000000000..d9fa278472b7
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pom.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_POM_H__
+#define __BFA_DEFS_POM_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_types.h>
+
+/**
+ * POM health status levels for each attributes.
+ */
+enum bfa_pom_entry_health {
+ BFA_POM_HEALTH_NOINFO = 1, /* no information */
+ BFA_POM_HEALTH_NORMAL = 2, /* health is normal */
+ BFA_POM_HEALTH_WARNING = 3, /* warning level */
+ BFA_POM_HEALTH_ALARM = 4, /* alarming level */
+};
+
+/**
+ * Reading of temperature/voltage/current/power
+ */
+struct bfa_pom_entry_s {
+ enum bfa_pom_entry_health health; /* POM entry health */
+ u32 curr_value; /* current value */
+ u32 thr_warn_high; /* threshold warning high */
+ u32 thr_warn_low; /* threshold warning low */
+ u32 thr_alarm_low; /* threshold alaram low */
+ u32 thr_alarm_high; /* threshold alarm high */
+};
+
+/**
+ * POM attributes
+ */
+struct bfa_pom_attr_s {
+ struct bfa_pom_entry_s temperature; /* centigrade */
+ struct bfa_pom_entry_s voltage; /* volts */
+ struct bfa_pom_entry_s curr; /* milli amps */
+ struct bfa_pom_entry_s txpower; /* micro watts */
+ struct bfa_pom_entry_s rxpower; /* micro watts */
+};
+
+#endif /* __BFA_DEFS_POM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
new file mode 100644
index 000000000000..de0696c81bc4
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_PORT_H__
+#define __BFA_DEFS_PORT_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_ioc.h>
+
+#define BFA_FCS_FABRIC_IPADDR_SZ 16
+
+/**
+ * symbolic names for base port/virtual port
+ */
+#define BFA_SYMNAME_MAXLEN 128 /* vmware/windows uses 128 bytes */
+struct bfa_port_symname_s {
+ char symname[BFA_SYMNAME_MAXLEN];
+};
+
+/**
+* Roles of FCS port:
+ * - FCP IM and FCP TM roles cannot be enabled together for a FCS port
+ * - Create multiple ports if both IM and TM functions required.
+ * - Atleast one role must be specified.
+ */
+enum bfa_port_role {
+ BFA_PORT_ROLE_FCP_IM = 0x01, /* FCP initiator role */
+ BFA_PORT_ROLE_FCP_TM = 0x02, /* FCP target role */
+ BFA_PORT_ROLE_FCP_IPFC = 0x04, /* IP over FC role */
+ BFA_PORT_ROLE_FCP_MAX = BFA_PORT_ROLE_FCP_IPFC | BFA_PORT_ROLE_FCP_IM
+};
+
+/**
+ * FCS port configuration.
+ */
+struct bfa_port_cfg_s {
+ wwn_t pwwn; /* port wwn */
+ wwn_t nwwn; /* node wwn */
+ struct bfa_port_symname_s sym_name; /* vm port symbolic name */
+ enum bfa_port_role roles; /* FCS port roles */
+ u32 rsvd;
+ u8 tag[16]; /* opaque tag from application */
+};
+
+/**
+ * FCS port states
+ */
+enum bfa_port_state {
+ BFA_PORT_UNINIT = 0, /* PORT is not yet initialized */
+ BFA_PORT_FDISC = 1, /* FDISC is in progress */
+ BFA_PORT_ONLINE = 2, /* login to fabric is complete */
+ BFA_PORT_OFFLINE = 3, /* No login to fabric */
+};
+
+/**
+ * FCS port type. Required for VmWare.
+ */
+enum bfa_port_type {
+ BFA_PORT_TYPE_PHYSICAL = 0,
+ BFA_PORT_TYPE_VIRTUAL,
+};
+
+/**
+ * FCS port offline reason. Required for VmWare.
+ */
+enum bfa_port_offline_reason {
+ BFA_PORT_OFFLINE_UNKNOWN = 0,
+ BFA_PORT_OFFLINE_LINKDOWN,
+ BFA_PORT_OFFLINE_FAB_UNSUPPORTED, /* NPIV not supported by the
+ * fabric */
+ BFA_PORT_OFFLINE_FAB_NORESOURCES,
+ BFA_PORT_OFFLINE_FAB_LOGOUT,
+};
+
+/**
+ * FCS lport info. Required for VmWare.
+ */
+struct bfa_port_info_s {
+ u8 port_type; /* bfa_port_type_t : physical or
+ * virtual */
+ u8 port_state; /* one of bfa_port_state values */
+ u8 offline_reason; /* one of bfa_port_offline_reason_t
+ * values */
+ wwn_t port_wwn;
+ wwn_t node_wwn;
+
+ /*
+ * following 4 feilds are valid for Physical Ports only
+ */
+ u32 max_vports_supp; /* Max supported vports */
+ u32 num_vports_inuse; /* Num of in use vports */
+ u32 max_rports_supp; /* Max supported rports */
+ u32 num_rports_inuse; /* Num of doscovered rports */
+
+};
+
+/**
+ * FCS port statistics
+ */
+struct bfa_port_stats_s {
+ u32 ns_plogi_sent;
+ u32 ns_plogi_rsp_err;
+ u32 ns_plogi_acc_err;
+ u32 ns_plogi_accepts;
+ u32 ns_rejects; /* NS command rejects */
+ u32 ns_plogi_unknown_rsp;
+ u32 ns_plogi_alloc_wait;
+
+ u32 ns_retries; /* NS command retries */
+ u32 ns_timeouts; /* NS command timeouts */
+
+ u32 ns_rspnid_sent;
+ u32 ns_rspnid_accepts;
+ u32 ns_rspnid_rsp_err;
+ u32 ns_rspnid_rejects;
+ u32 ns_rspnid_alloc_wait;
+
+ u32 ns_rftid_sent;
+ u32 ns_rftid_accepts;
+ u32 ns_rftid_rsp_err;
+ u32 ns_rftid_rejects;
+ u32 ns_rftid_alloc_wait;
+
+ u32 ns_rffid_sent;
+ u32 ns_rffid_accepts;
+ u32 ns_rffid_rsp_err;
+ u32 ns_rffid_rejects;
+ u32 ns_rffid_alloc_wait;
+
+ u32 ns_gidft_sent;
+ u32 ns_gidft_accepts;
+ u32 ns_gidft_rsp_err;
+ u32 ns_gidft_rejects;
+ u32 ns_gidft_unknown_rsp;
+ u32 ns_gidft_alloc_wait;
+
+ /*
+ * Mgmt Server stats
+ */
+ u32 ms_retries; /* MS command retries */
+ u32 ms_timeouts; /* MS command timeouts */
+ u32 ms_plogi_sent;
+ u32 ms_plogi_rsp_err;
+ u32 ms_plogi_acc_err;
+ u32 ms_plogi_accepts;
+ u32 ms_rejects; /* NS command rejects */
+ u32 ms_plogi_unknown_rsp;
+ u32 ms_plogi_alloc_wait;
+
+ u32 num_rscn; /* Num of RSCN received */
+ u32 num_portid_rscn;/* Num portid format RSCN
+ * received */
+
+ u32 uf_recvs; /* unsolicited recv frames */
+ u32 uf_recv_drops; /* dropped received frames */
+
+ u32 rsvd; /* padding for 64 bit alignment */
+};
+
+/**
+ * BFA port attribute returned in queries
+ */
+struct bfa_port_attr_s {
+ enum bfa_port_state state; /* port state */
+ u32 pid; /* port ID */
+ struct bfa_port_cfg_s port_cfg; /* port configuration */
+ enum bfa_pport_type port_type; /* current topology */
+ u32 loopback; /* cable is externally looped back */
+ wwn_t fabric_name; /* attached switch's nwwn */
+ u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached
+ * fabric's ip addr */
+};
+
+/**
+ * BFA physical port Level events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_PORT_AEN_ONLINE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_OFFLINE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_RLIR: [in]: None [out]: pwwn, rlir_data, rlir_len
+ * BFA_PORT_AEN_SFP_INSERT: [in]: pwwn [out]: port_id, pwwn
+ * BFA_PORT_AEN_SFP_REMOVE: [in]: pwwn [out]: port_id, pwwn
+ * BFA_PORT_AEN_SFP_POM: [in]: pwwn [out]: level, port_id, pwwn
+ * BFA_PORT_AEN_ENABLE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_DISABLE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_AUTH_ON: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_AUTH_OFF: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_DISCONNECT: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_QOS_NEG: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_FABRIC_NAME_CHANGE: [in]: pwwn, [out]: pwwn, fwwn
+ *
+ */
+enum bfa_port_aen_event {
+ BFA_PORT_AEN_ONLINE = 1, /* Physical Port online event */
+ BFA_PORT_AEN_OFFLINE = 2, /* Physical Port offline event */
+ BFA_PORT_AEN_RLIR = 3, /* RLIR event, not supported */
+ BFA_PORT_AEN_SFP_INSERT = 4, /* SFP inserted event */
+ BFA_PORT_AEN_SFP_REMOVE = 5, /* SFP removed event */
+ BFA_PORT_AEN_SFP_POM = 6, /* SFP POM event */
+ BFA_PORT_AEN_ENABLE = 7, /* Physical Port enable event */
+ BFA_PORT_AEN_DISABLE = 8, /* Physical Port disable event */
+ BFA_PORT_AEN_AUTH_ON = 9, /* Physical Port auth success event */
+ BFA_PORT_AEN_AUTH_OFF = 10, /* Physical Port auth fail event */
+ BFA_PORT_AEN_DISCONNECT = 11, /* Physical Port disconnect event */
+ BFA_PORT_AEN_QOS_NEG = 12, /* Base Port QOS negotiation event */
+ BFA_PORT_AEN_FABRIC_NAME_CHANGE = 13, /* Fabric Name/WWN change
+ * event */
+ BFA_PORT_AEN_SFP_ACCESS_ERROR = 14, /* SFP read error event */
+ BFA_PORT_AEN_SFP_UNSUPPORT = 15, /* Unsupported SFP event */
+};
+
+enum bfa_port_aen_sfp_pom {
+ BFA_PORT_AEN_SFP_POM_GREEN = 1, /* Normal */
+ BFA_PORT_AEN_SFP_POM_AMBER = 2, /* Warning */
+ BFA_PORT_AEN_SFP_POM_RED = 3, /* Critical */
+ BFA_PORT_AEN_SFP_POM_MAX = BFA_PORT_AEN_SFP_POM_RED
+};
+
+struct bfa_port_aen_data_s {
+ enum bfa_ioc_type_e ioc_type;
+ wwn_t pwwn; /* WWN of the physical port */
+ wwn_t fwwn; /* WWN of the fabric port */
+ mac_t mac; /* MAC addres of the ethernet port,
+ * applicable to CNA port only */
+ int phy_port_num; /*! For SFP related events */
+ enum bfa_port_aen_sfp_pom level; /* Only transitions will
+ * be informed */
+};
+
+#endif /* __BFA_DEFS_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
new file mode 100644
index 000000000000..a000bc4e2d4a
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_PPORT_H__
+#define __BFA_DEFS_PPORT_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/fc.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_qos.h>
+#include <cna/pstats/phyport_defs.h>
+
+/* Modify char* port_stt[] in bfal_port.c if a new state was added */
+enum bfa_pport_states {
+ BFA_PPORT_ST_UNINIT = 1,
+ BFA_PPORT_ST_ENABLING_QWAIT = 2,
+ BFA_PPORT_ST_ENABLING = 3,
+ BFA_PPORT_ST_LINKDOWN = 4,
+ BFA_PPORT_ST_LINKUP = 5,
+ BFA_PPORT_ST_DISABLING_QWAIT = 6,
+ BFA_PPORT_ST_DISABLING = 7,
+ BFA_PPORT_ST_DISABLED = 8,
+ BFA_PPORT_ST_STOPPED = 9,
+ BFA_PPORT_ST_IOCDOWN = 10,
+ BFA_PPORT_ST_IOCDIS = 11,
+ BFA_PPORT_ST_FWMISMATCH = 12,
+ BFA_PPORT_ST_MAX_STATE,
+};
+
+/**
+ * Port speed settings. Each specific speed is a bit field. Use multiple
+ * bits to specify speeds to be selected for auto-negotiation.
+ */
+enum bfa_pport_speed {
+ BFA_PPORT_SPEED_UNKNOWN = 0,
+ BFA_PPORT_SPEED_1GBPS = 1,
+ BFA_PPORT_SPEED_2GBPS = 2,
+ BFA_PPORT_SPEED_4GBPS = 4,
+ BFA_PPORT_SPEED_8GBPS = 8,
+ BFA_PPORT_SPEED_10GBPS = 10,
+ BFA_PPORT_SPEED_AUTO =
+ (BFA_PPORT_SPEED_1GBPS | BFA_PPORT_SPEED_2GBPS |
+ BFA_PPORT_SPEED_4GBPS | BFA_PPORT_SPEED_8GBPS),
+};
+
+/**
+ * Port operational type (in sync with SNIA port type).
+ */
+enum bfa_pport_type {
+ BFA_PPORT_TYPE_UNKNOWN = 1, /* port type is unkown */
+ BFA_PPORT_TYPE_TRUNKED = 2, /* Trunked mode */
+ BFA_PPORT_TYPE_NPORT = 5, /* P2P with switched fabric */
+ BFA_PPORT_TYPE_NLPORT = 6, /* public loop */
+ BFA_PPORT_TYPE_LPORT = 20, /* private loop */
+ BFA_PPORT_TYPE_P2P = 21, /* P2P with no switched fabric */
+ BFA_PPORT_TYPE_VPORT = 22, /* NPIV - virtual port */
+};
+
+/**
+ * Port topology setting. A port's topology and fabric login status
+ * determine its operational type.
+ */
+enum bfa_pport_topology {
+ BFA_PPORT_TOPOLOGY_NONE = 0, /* No valid topology */
+ BFA_PPORT_TOPOLOGY_P2P = 1, /* P2P only */
+ BFA_PPORT_TOPOLOGY_LOOP = 2, /* LOOP topology */
+ BFA_PPORT_TOPOLOGY_AUTO = 3, /* auto topology selection */
+};
+
+/**
+ * Physical port loopback types.
+ */
+enum bfa_pport_opmode {
+ BFA_PPORT_OPMODE_NORMAL = 0x00, /* normal non-loopback mode */
+ BFA_PPORT_OPMODE_LB_INT = 0x01, /* internal loop back */
+ BFA_PPORT_OPMODE_LB_SLW = 0x02, /* serial link wrapback (serdes) */
+ BFA_PPORT_OPMODE_LB_EXT = 0x04, /* external loop back (serdes) */
+ BFA_PPORT_OPMODE_LB_CBL = 0x08, /* cabled loop back */
+ BFA_PPORT_OPMODE_LB_NLINT = 0x20, /* NL_Port internal loopback */
+};
+
+#define BFA_PPORT_OPMODE_LB_HARD(_mode) \
+ ((_mode == BFA_PPORT_OPMODE_LB_INT) || \
+ (_mode == BFA_PPORT_OPMODE_LB_SLW) || \
+ (_mode == BFA_PPORT_OPMODE_LB_EXT))
+
+/**
+ Port State (in sync with SNIA port state).
+ */
+enum bfa_pport_snia_state {
+ BFA_PPORT_STATE_UNKNOWN = 1, /* port is not initialized */
+ BFA_PPORT_STATE_ONLINE = 2, /* port is ONLINE */
+ BFA_PPORT_STATE_DISABLED = 3, /* port is disabled by user */
+ BFA_PPORT_STATE_BYPASSED = 4, /* port is bypassed (in LOOP) */
+ BFA_PPORT_STATE_DIAG = 5, /* port diagnostics is active */
+ BFA_PPORT_STATE_LINKDOWN = 6, /* link is down */
+ BFA_PPORT_STATE_LOOPBACK = 8, /* port is looped back */
+};
+
+/**
+ * Port link state
+ */
+enum bfa_pport_linkstate {
+ BFA_PPORT_LINKUP = 1, /* Physical port/Trunk link up */
+ BFA_PPORT_LINKDOWN = 2, /* Physical port/Trunk link down */
+ BFA_PPORT_TRUNK_LINKDOWN = 3, /* Trunk link down (new tmaster) */
+};
+
+/**
+ * Port link state event
+ */
+#define bfa_pport_event_t enum bfa_pport_linkstate
+
+/**
+ * Port link state reason code
+ */
+enum bfa_pport_linkstate_rsn {
+ BFA_PPORT_LINKSTATE_RSN_NONE = 0,
+ BFA_PPORT_LINKSTATE_RSN_DISABLED = 1,
+ BFA_PPORT_LINKSTATE_RSN_RX_NOS = 2,
+ BFA_PPORT_LINKSTATE_RSN_RX_OLS = 3,
+ BFA_PPORT_LINKSTATE_RSN_RX_LIP = 4,
+ BFA_PPORT_LINKSTATE_RSN_RX_LIPF7 = 5,
+ BFA_PPORT_LINKSTATE_RSN_SFP_REMOVED = 6,
+ BFA_PPORT_LINKSTATE_RSN_PORT_FAULT = 7,
+ BFA_PPORT_LINKSTATE_RSN_RX_LOS = 8,
+ BFA_PPORT_LINKSTATE_RSN_LOCAL_FAULT = 9,
+ BFA_PPORT_LINKSTATE_RSN_REMOTE_FAULT = 10,
+ BFA_PPORT_LINKSTATE_RSN_TIMEOUT = 11,
+
+
+
+ /* CEE related reason codes/errors */
+ CEE_LLDP_INFO_AGED_OUT = 20,
+ CEE_LLDP_SHUTDOWN_TLV_RCVD = 21,
+ CEE_PEER_NOT_ADVERTISE_DCBX = 22,
+ CEE_PEER_NOT_ADVERTISE_PG = 23,
+ CEE_PEER_NOT_ADVERTISE_PFC = 24,
+ CEE_PEER_NOT_ADVERTISE_FCOE = 25,
+ CEE_PG_NOT_COMPATIBLE = 26,
+ CEE_PFC_NOT_COMPATIBLE = 27,
+ CEE_FCOE_NOT_COMPATIBLE = 28,
+ CEE_BAD_PG_RCVD = 29,
+ CEE_BAD_BW_RCVD = 30,
+ CEE_BAD_PFC_RCVD = 31,
+ CEE_BAD_FCOE_PRI_RCVD = 32,
+ CEE_FCOE_PRI_PFC_OFF = 33,
+ CEE_DUP_CONTROL_TLV_RCVD = 34,
+ CEE_DUP_FEAT_TLV_RCVD = 35,
+ CEE_APPLY_NEW_CFG = 36, /* reason, not an error */
+ CEE_PROTOCOL_INIT = 37, /* reason, not an error */
+ CEE_PHY_LINK_DOWN = 38,
+ CEE_LLS_FCOE_ABSENT = 39,
+ CEE_LLS_FCOE_DOWN = 40
+};
+
+/**
+ * Default Target Rate Limiting Speed.
+ */
+#define BFA_PPORT_DEF_TRL_SPEED BFA_PPORT_SPEED_1GBPS
+
+/**
+ * Physical port configuration
+ */
+struct bfa_pport_cfg_s {
+ u8 topology; /* bfa_pport_topology */
+ u8 speed; /* enum bfa_pport_speed */
+ u8 trunked; /* trunked or not */
+ u8 qos_enabled; /* qos enabled or not */
+ u8 trunk_ports; /* bitmap of trunked ports */
+ u8 cfg_hardalpa; /* is hard alpa configured */
+ u16 maxfrsize; /* maximum frame size */
+ u8 hardalpa; /* configured hard alpa */
+ u8 rx_bbcredit; /* receive buffer credits */
+ u8 tx_bbcredit; /* transmit buffer credits */
+ u8 ratelimit; /* ratelimit enabled or not */
+ u8 trl_def_speed; /* ratelimit default speed */
+ u8 rsvd[3];
+ u16 path_tov; /* device path timeout */
+ u16 q_depth; /* SCSI Queue depth */
+};
+
+/**
+ * Port attribute values.
+ */
+struct bfa_pport_attr_s {
+ /*
+ * Static fields
+ */
+ wwn_t nwwn; /* node wwn */
+ wwn_t pwwn; /* port wwn */
+ enum fc_cos cos_supported; /* supported class of services */
+ u32 rsvd;
+ struct fc_symname_s port_symname; /* port symbolic name */
+ enum bfa_pport_speed speed_supported; /* supported speeds */
+ bfa_boolean_t pbind_enabled; /* Will be set if Persistent binding
+ * enabled. Relevant only in Windows
+ */
+
+ /*
+ * Configured values
+ */
+ struct bfa_pport_cfg_s pport_cfg; /* pport cfg */
+
+ /*
+ * Dynamic field - info from BFA
+ */
+ enum bfa_pport_states port_state; /* current port state */
+ enum bfa_pport_speed speed; /* current speed */
+ enum bfa_pport_topology topology; /* current topology */
+ bfa_boolean_t beacon; /* current beacon status */
+ bfa_boolean_t link_e2e_beacon;/* set if link beacon on */
+ bfa_boolean_t plog_enabled; /* set if portlog is enabled*/
+
+ /*
+ * Dynamic field - info from FCS
+ */
+ u32 pid; /* port ID */
+ enum bfa_pport_type port_type; /* current topology */
+ u32 loopback; /* external loopback */
+ u32 rsvd1;
+ u32 rsvd2; /* padding for 64 bit */
+};
+
+/**
+ * FC Port statistics.
+ */
+struct bfa_pport_fc_stats_s {
+ u64 secs_reset; /* seconds since stats is reset */
+ u64 tx_frames; /* transmitted frames */
+ u64 tx_words; /* transmitted words */
+ u64 rx_frames; /* received frames */
+ u64 rx_words; /* received words */
+ u64 lip_count; /* LIPs seen */
+ u64 nos_count; /* NOS count */
+ u64 error_frames; /* errored frames (sent?) */
+ u64 dropped_frames; /* dropped frames */
+ u64 link_failures; /* link failure count */
+ u64 loss_of_syncs; /* loss of sync count */
+ u64 loss_of_signals;/* loss of signal count */
+ u64 primseq_errs; /* primitive sequence protocol */
+ u64 bad_os_count; /* invalid ordered set */
+ u64 err_enc_out; /* Encoding error outside frame */
+ u64 invalid_crcs; /* frames received with invalid CRC*/
+ u64 undersized_frm; /* undersized frames */
+ u64 oversized_frm; /* oversized frames */
+ u64 bad_eof_frm; /* frames with bad EOF */
+ struct bfa_qos_stats_s qos_stats; /* QoS statistics */
+};
+
+/**
+ * Eth Port statistics.
+ */
+struct bfa_pport_eth_stats_s {
+ u64 secs_reset; /* seconds since stats is reset */
+ u64 frame_64; /* both rx and tx counter */
+ u64 frame_65_127; /* both rx and tx counter */
+ u64 frame_128_255; /* both rx and tx counter */
+ u64 frame_256_511; /* both rx and tx counter */
+ u64 frame_512_1023; /* both rx and tx counter */
+ u64 frame_1024_1518; /* both rx and tx counter */
+ u64 frame_1519_1522; /* both rx and tx counter */
+
+ u64 tx_bytes;
+ u64 tx_packets;
+ u64 tx_mcast_packets;
+ u64 tx_bcast_packets;
+ u64 tx_control_frame;
+ u64 tx_drop;
+ u64 tx_jabber;
+ u64 tx_fcs_error;
+ u64 tx_fragments;
+
+ u64 rx_bytes;
+ u64 rx_packets;
+ u64 rx_mcast_packets;
+ u64 rx_bcast_packets;
+ u64 rx_control_frames;
+ u64 rx_unknown_opcode;
+ u64 rx_drop;
+ u64 rx_jabber;
+ u64 rx_fcs_error;
+ u64 rx_alignment_error;
+ u64 rx_frame_length_error;
+ u64 rx_code_error;
+ u64 rx_fragments;
+
+ u64 rx_pause; /* BPC */
+ u64 rx_zero_pause; /* BPC Pause cancellation */
+ u64 tx_pause; /* BPC */
+ u64 tx_zero_pause; /* BPC Pause cancellation */
+ u64 rx_fcoe_pause; /* BPC */
+ u64 rx_fcoe_zero_pause; /* BPC Pause cancellation */
+ u64 tx_fcoe_pause; /* BPC */
+ u64 tx_fcoe_zero_pause; /* BPC Pause cancellation */
+};
+
+/**
+ * Port statistics.
+ */
+union bfa_pport_stats_u {
+ struct bfa_pport_fc_stats_s fc;
+ struct bfa_pport_eth_stats_s eth;
+};
+
+/**
+ * Port FCP mappings.
+ */
+struct bfa_pport_fcpmap_s {
+ char osdevname[256];
+ u32 bus;
+ u32 target;
+ u32 oslun;
+ u32 fcid;
+ wwn_t nwwn;
+ wwn_t pwwn;
+ u64 fcplun;
+ char luid[256];
+};
+
+/**
+ * Port RNID info.
+ */
+struct bfa_pport_rnid_s {
+ wwn_t wwn;
+ u32 unittype;
+ u32 portid;
+ u32 attached_nodes_num;
+ u16 ip_version;
+ u16 udp_port;
+ u8 ipaddr[16];
+ u16 rsvd;
+ u16 topologydiscoveryflags;
+};
+
+/**
+ * Link state information
+ */
+struct bfa_pport_link_s {
+ u8 linkstate; /* Link state bfa_pport_linkstate */
+ u8 linkstate_rsn; /* bfa_pport_linkstate_rsn_t */
+ u8 topology; /* P2P/LOOP bfa_pport_topology */
+ u8 speed; /* Link speed (1/2/4/8 G) */
+ u32 linkstate_opt; /* Linkstate optional data (debug) */
+ u8 trunked; /* Trunked or not (1 or 0) */
+ u8 resvd[3];
+ struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
+ struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
+ union {
+ struct {
+ u8 tmaster;/* Trunk Master or
+ * not (1 or 0) */
+ u8 tlinks; /* Trunk links bitmap
+ * (linkup) */
+ u8 resv1; /* Reserved */
+ } trunk_info;
+
+ struct {
+ u8 myalpa; /* alpa claimed */
+ u8 login_req; /* Login required or
+ * not (1 or 0) */
+ u8 alpabm_val;/* alpa bitmap valid
+ * or not (1 or 0) */
+ struct fc_alpabm_s alpabm; /* alpa bitmap */
+ } loop_info;
+ } tl;
+};
+
+#endif /* __BFA_DEFS_PPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_qos.h b/drivers/scsi/bfa/include/defs/bfa_defs_qos.h
new file mode 100644
index 000000000000..aadbacd1d2d7
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_qos.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_QOS_H__
+#define __BFA_DEFS_QOS_H__
+
+/**
+ * QoS states
+ */
+enum bfa_qos_state {
+ BFA_QOS_ONLINE = 1, /* QoS is online */
+ BFA_QOS_OFFLINE = 2, /* QoS is offline */
+};
+
+
+/**
+ * QoS Priority levels.
+ */
+enum bfa_qos_priority {
+ BFA_QOS_UNKNOWN = 0,
+ BFA_QOS_HIGH = 1, /* QoS Priority Level High */
+ BFA_QOS_MED = 2, /* QoS Priority Level Medium */
+ BFA_QOS_LOW = 3, /* QoS Priority Level Low */
+};
+
+
+/**
+ * QoS bandwidth allocation for each priority level
+ */
+enum bfa_qos_bw_alloc {
+ BFA_QOS_BW_HIGH = 60, /* bandwidth allocation for High */
+ BFA_QOS_BW_MED = 30, /* bandwidth allocation for Medium */
+ BFA_QOS_BW_LOW = 10, /* bandwidth allocation for Low */
+};
+
+/**
+ * QoS attribute returned in QoS Query
+ */
+struct bfa_qos_attr_s {
+ enum bfa_qos_state state; /* QoS current state */
+ u32 total_bb_cr; /* Total BB Credits */
+};
+
+/**
+ * These fields should be displayed only from the CLI.
+ * There will be a separate BFAL API (get_qos_vc_attr ?)
+ * to retrieve this.
+ *
+ */
+#define BFA_QOS_MAX_VC 16
+
+struct bfa_qos_vc_info_s {
+ u8 vc_credit;
+ u8 borrow_credit;
+ u8 priority;
+ u8 resvd;
+};
+
+struct bfa_qos_vc_attr_s {
+ u16 total_vc_count; /* Total VC Count */
+ u16 shared_credit;
+ u32 elp_opmode_flags;
+ struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC]; /* as many as
+ * total_vc_count */
+};
+
+/**
+ * QoS statistics
+ */
+struct bfa_qos_stats_s {
+ u32 flogi_sent; /* QoS Flogi sent */
+ u32 flogi_acc_recvd; /* QoS Flogi Acc received */
+ u32 flogi_rjt_recvd; /* QoS Flogi rejects received */
+ u32 flogi_retries; /* QoS Flogi retries */
+
+ u32 elp_recvd; /* QoS ELP received */
+ u32 elp_accepted; /* QoS ELP Accepted */
+ u32 elp_rejected; /* QoS ELP rejected */
+ u32 elp_dropped; /* QoS ELP dropped */
+
+ u32 qos_rscn_recvd; /* QoS RSCN received */
+ u32 rsvd; /* padding for 64 bit alignment */
+};
+
+#endif /* __BFA_DEFS_QOS_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_rport.h b/drivers/scsi/bfa/include/defs/bfa_defs_rport.h
new file mode 100644
index 000000000000..e0af59d6d2f6
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_rport.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_RPORT_H__
+#define __BFA_DEFS_RPORT_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_qos.h>
+
+/**
+ * FCS remote port states
+ */
+enum bfa_rport_state {
+ BFA_RPORT_UNINIT = 0, /* PORT is not yet initialized */
+ BFA_RPORT_OFFLINE = 1, /* rport is offline */
+ BFA_RPORT_PLOGI = 2, /* PLOGI to rport is in progress */
+ BFA_RPORT_ONLINE = 3, /* login to rport is complete */
+ BFA_RPORT_PLOGI_RETRY = 4, /* retrying login to rport */
+ BFA_RPORT_NSQUERY = 5, /* nameserver query */
+ BFA_RPORT_ADISC = 6, /* ADISC authentication */
+ BFA_RPORT_LOGO = 7, /* logging out with rport */
+ BFA_RPORT_LOGORCV = 8, /* handling LOGO from rport */
+ BFA_RPORT_NSDISC = 9, /* re-discover rport */
+};
+
+/**
+ * Rport Scsi Function : Initiator/Target.
+ */
+enum bfa_rport_function {
+ BFA_RPORT_INITIATOR = 0x01, /* SCSI Initiator */
+ BFA_RPORT_TARGET = 0x02, /* SCSI Target */
+};
+
+/**
+ * port/node symbolic names for rport
+ */
+#define BFA_RPORT_SYMNAME_MAXLEN 255
+struct bfa_rport_symname_s {
+ char symname[BFA_RPORT_SYMNAME_MAXLEN];
+};
+
+struct bfa_rport_hal_stats_s {
+ u32 sm_un_cr; /* uninit: create events */
+ u32 sm_un_unexp; /* uninit: exception events */
+ u32 sm_cr_on; /* created: online events */
+ u32 sm_cr_del; /* created: delete events */
+ u32 sm_cr_hwf; /* created: IOC down */
+ u32 sm_cr_unexp; /* created: exception events */
+ u32 sm_fwc_rsp; /* fw create: f/w responses */
+ u32 sm_fwc_del; /* fw create: delete events */
+ u32 sm_fwc_off; /* fw create: offline events */
+ u32 sm_fwc_hwf; /* fw create: IOC down */
+ u32 sm_fwc_unexp; /* fw create: exception events*/
+ u32 sm_on_off; /* online: offline events */
+ u32 sm_on_del; /* online: delete events */
+ u32 sm_on_hwf; /* online: IOC down events */
+ u32 sm_on_unexp; /* online: exception events */
+ u32 sm_fwd_rsp; /* fw delete: fw responses */
+ u32 sm_fwd_del; /* fw delete: delete events */
+ u32 sm_fwd_hwf; /* fw delete: IOC down events */
+ u32 sm_fwd_unexp; /* fw delete: exception events*/
+ u32 sm_off_del; /* offline: delete events */
+ u32 sm_off_on; /* offline: online events */
+ u32 sm_off_hwf; /* offline: IOC down events */
+ u32 sm_off_unexp; /* offline: exception events */
+ u32 sm_del_fwrsp; /* delete: fw responses */
+ u32 sm_del_hwf; /* delete: IOC down events */
+ u32 sm_del_unexp; /* delete: exception events */
+ u32 sm_delp_fwrsp; /* delete pend: fw responses */
+ u32 sm_delp_hwf; /* delete pend: IOC downs */
+ u32 sm_delp_unexp; /* delete pend: exceptions */
+ u32 sm_offp_fwrsp; /* off-pending: fw responses */
+ u32 sm_offp_del; /* off-pending: deletes */
+ u32 sm_offp_hwf; /* off-pending: IOC downs */
+ u32 sm_offp_unexp; /* off-pending: exceptions */
+ u32 sm_iocd_off; /* IOC down: offline events */
+ u32 sm_iocd_del; /* IOC down: delete events */
+ u32 sm_iocd_on; /* IOC down: online events */
+ u32 sm_iocd_unexp; /* IOC down: exceptions */
+ u32 rsvd;
+};
+
+/**
+ * FCS remote port statistics
+ */
+struct bfa_rport_stats_s {
+ u32 offlines; /* remote port offline count */
+ u32 onlines; /* remote port online count */
+ u32 rscns; /* RSCN affecting rport */
+ u32 plogis; /* plogis sent */
+ u32 plogi_accs; /* plogi accepts */
+ u32 plogi_timeouts; /* plogi timeouts */
+ u32 plogi_rejects; /* rcvd plogi rejects */
+ u32 plogi_failed; /* local failure */
+ u32 plogi_rcvd; /* plogis rcvd */
+ u32 prli_rcvd; /* inbound PRLIs */
+ u32 adisc_rcvd; /* ADISCs received */
+ u32 adisc_rejects; /* recvd ADISC rejects */
+ u32 adisc_sent; /* ADISC requests sent */
+ u32 adisc_accs; /* ADISC accepted by rport */
+ u32 adisc_failed; /* ADISC failed (no response) */
+ u32 adisc_rejected; /* ADISC rejected by us */
+ u32 logos; /* logos sent */
+ u32 logo_accs; /* LOGO accepts from rport */
+ u32 logo_failed; /* LOGO failures */
+ u32 logo_rejected; /* LOGO rejects from rport */
+ u32 logo_rcvd; /* LOGO from remote port */
+
+ u32 rpsc_rcvd; /* RPSC received */
+ u32 rpsc_rejects; /* recvd RPSC rejects */
+ u32 rpsc_sent; /* RPSC requests sent */
+ u32 rpsc_accs; /* RPSC accepted by rport */
+ u32 rpsc_failed; /* RPSC failed (no response) */
+ u32 rpsc_rejected; /* RPSC rejected by us */
+
+ u32 rsvd;
+ struct bfa_rport_hal_stats_s hal_stats; /* BFA rport stats */
+};
+
+/**
+ * Rport's QoS attributes
+ */
+struct bfa_rport_qos_attr_s {
+ enum bfa_qos_priority qos_priority; /* rport's QoS priority */
+ u32 qos_flow_id; /* QoS flow Id */
+};
+
+/**
+ * FCS remote port attributes returned in queries
+ */
+struct bfa_rport_attr_s {
+ wwn_t nwwn; /* node wwn */
+ wwn_t pwwn; /* port wwn */
+ enum fc_cos cos_supported; /* supported class of services */
+ u32 pid; /* port ID */
+ u32 df_sz; /* Max payload size */
+ enum bfa_rport_state state; /* Rport State machine state */
+ enum fc_cos fc_cos; /* FC classes of services */
+ bfa_boolean_t cisc; /* CISC capable device */
+ struct bfa_rport_symname_s symname; /* Symbolic Name */
+ enum bfa_rport_function scsi_function; /* Initiator/Target */
+ struct bfa_rport_qos_attr_s qos_attr; /* qos attributes */
+ enum bfa_pport_speed curr_speed; /* operating speed got from
+ * RPSC ELS. UNKNOWN, if RPSC
+ * is not supported */
+ bfa_boolean_t trl_enforced; /* TRL enforced ? TRUE/FALSE */
+ enum bfa_pport_speed assigned_speed; /* Speed assigned by the user.
+ * will be used if RPSC is not
+ * supported by the rport */
+};
+
+#define bfa_rport_aen_qos_data_t struct bfa_rport_qos_attr_s
+
+/**
+ * BFA remote port events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_RPORT_AEN_ONLINE: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn
+ * BFA_RPORT_AEN_OFFLINE: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn
+ * BFA_RPORT_AEN_DISCONNECT:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn
+ * BFA_RPORT_AEN_QOS_PRIO: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn, prio
+ * BFA_RPORT_AEN_QOS_FLOWID:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn, flow_id
+ */
+enum bfa_rport_aen_event {
+ BFA_RPORT_AEN_ONLINE = 1, /* RPort online event */
+ BFA_RPORT_AEN_OFFLINE = 2, /* RPort offline event */
+ BFA_RPORT_AEN_DISCONNECT = 3, /* RPort disconnect event */
+ BFA_RPORT_AEN_QOS_PRIO = 4, /* QOS priority change event */
+ BFA_RPORT_AEN_QOS_FLOWID = 5, /* QOS flow Id change event */
+};
+
+struct bfa_rport_aen_data_s {
+ u16 vf_id; /* vf_id of this logical port */
+ u16 rsvd[3];
+ wwn_t ppwwn; /* WWN of its physical port */
+ wwn_t lpwwn; /* WWN of this logical port */
+ wwn_t rpwwn; /* WWN of this remote port */
+ union {
+ bfa_rport_aen_qos_data_t qos;
+ } priv;
+};
+
+#endif /* __BFA_DEFS_RPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
new file mode 100644
index 000000000000..cdceaeb9f4b8
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_STATUS_H__
+#define __BFA_DEFS_STATUS_H__
+
+/**
+ * API status return values
+ *
+ * NOTE: The error msgs are auto generated from the comments. Only singe line
+ * comments are supported
+ */
+enum bfa_status {
+ BFA_STATUS_OK = 0, /* Success */
+ BFA_STATUS_FAILED = 1, /* Operation failed */
+ BFA_STATUS_EINVAL = 2, /* Invalid params Check input
+ * parameters */
+ BFA_STATUS_ENOMEM = 3, /* Out of resources */
+ BFA_STATUS_ENOSYS = 4, /* Function not implemented */
+ BFA_STATUS_ETIMER = 5, /* Timer expired - Retry, if
+ * persists, contact support */
+ BFA_STATUS_EPROTOCOL = 6, /* Protocol error */
+ BFA_STATUS_ENOFCPORTS = 7, /* No FC ports resources */
+ BFA_STATUS_NOFLASH = 8, /* Flash not present */
+ BFA_STATUS_BADFLASH = 9, /* Flash is corrupted or bad */
+ BFA_STATUS_SFP_UNSUPP = 10, /* Unsupported SFP - Replace SFP */
+ BFA_STATUS_UNKNOWN_VFID = 11, /* VF_ID not found */
+ BFA_STATUS_DATACORRUPTED = 12, /* Diag returned data corrupted
+ * contact support */
+ BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */
+ BFA_STATUS_ABORTED = 14, /* Operation aborted */
+ BFA_STATUS_NODEV = 15, /* Dev is not present */
+ BFA_STATUS_HDMA_FAILED = 16, /* Host dma failed contact support */
+ BFA_STATUS_FLASH_BAD_LEN = 17, /* Flash bad length */
+ BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */
+ BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */
+ BFA_STATUS_FCPT_LS_RJT = 20, /* Got LS_RJT for FC Pass
+ * through Req */
+ BFA_STATUS_VPORT_EXISTS = 21, /* VPORT already exists */
+ BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported
+ * limit */
+ BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed
+ * setting */
+ BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */
+ BFA_STATUS_CNFG_FAILED = 25, /* Setting can not be persisted */
+ BFA_STATUS_CMD_NOTSUPP = 26, /* Command/API not supported */
+ BFA_STATUS_NO_ADAPTER = 27, /* No Brocade Adapter Found */
+ BFA_STATUS_LINKDOWN = 28, /* Link is down - Check or replace
+ * SFP/cable */
+ BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */
+ BFA_STATUS_UNKNOWN_VWWN = 30, /* VPORT PWWN not found */
+ BFA_STATUS_NSLOGIN_FAILED = 31, /* Nameserver login failed */
+ BFA_STATUS_NO_RPORTS = 32, /* No remote ports found */
+ BFA_STATUS_NSQUERY_FAILED = 33, /* Nameserver query failed */
+ BFA_STATUS_PORT_OFFLINE = 34, /* Port is not online */
+ BFA_STATUS_RPORT_OFFLINE = 35, /* RPORT is not online */
+ BFA_STATUS_TGTOPEN_FAILED = 36, /* Remote SCSI target open failed */
+ BFA_STATUS_BAD_LUNS = 37, /* No valid LUNs found */
+ BFA_STATUS_IO_FAILURE = 38, /* SCSI target IO failure */
+ BFA_STATUS_NO_FABRIC = 39, /* No switched fabric present */
+ BFA_STATUS_EBADF = 40, /* Bad file descriptor */
+ BFA_STATUS_EINTR = 41, /* A signal was caught during ioctl */
+ BFA_STATUS_EIO = 42, /* I/O error */
+ BFA_STATUS_ENOTTY = 43, /* Inappropriate I/O control
+ * operation */
+ BFA_STATUS_ENXIO = 44, /* No such device or address */
+ BFA_STATUS_EFOPEN = 45, /* Failed to open file */
+ BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */
+ BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port
+ * first */
+ BFA_STATUS_BADFRMHDR = 48, /* Bad frame header */
+ BFA_STATUS_BADFRMSZ = 49, /* Bad frame size check and replace
+ * SFP/cable */
+ BFA_STATUS_MISSINGFRM = 50, /* Missing frame check and replace
+ * SFP/cable */
+ BFA_STATUS_LINKTIMEOUT = 51, /* Link timeout check and replace
+ * SFP/cable */
+ BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the
+ * rport */
+ BFA_STATUS_CHECKSUM_FAIL = 53, /* checksum failure */
+ BFA_STATUS_GZME_FAILED = 54, /* Get zone member query failed */
+ BFA_STATUS_SCSISTART_REQD = 55, /* SCSI disk require START command */
+ BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists
+ * contact support */
+ BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */
+ BFA_STATUS_MISMATCH = 58, /* Version mismatch */
+ BFA_STATUS_IOC_ENABLED = 59, /* IOC is already enabled */
+ BFA_STATUS_ADAPTER_ENABLED = 60, /* Adapter is not disabled disable
+ * adapter first */
+ BFA_STATUS_IOC_NON_OP = 61, /* IOC is not operational. Enable IOC
+ * and if it still fails,
+ * contact support */
+ BFA_STATUS_ADDR_MAP_FAILURE = 62, /* PCI base address not mapped
+ * in OS */
+ BFA_STATUS_SAME_NAME = 63, /* Name exists! use a different
+ * name */
+ BFA_STATUS_PENDING = 64, /* API completes asynchronously */
+ BFA_STATUS_8G_SPD = 65, /* Speed setting not valid for
+ * 8G HBA */
+ BFA_STATUS_4G_SPD = 66, /* Speed setting not valid for
+ * 4G HBA */
+ BFA_STATUS_AD_IS_ENABLE = 67, /* Adapter is already enabled */
+ BFA_STATUS_EINVAL_TOV = 68, /* Invalid path failover TOV */
+ BFA_STATUS_EINVAL_QDEPTH = 69, /* Invalid queue depth value */
+ BFA_STATUS_VERSION_FAIL = 70, /* Application/Driver version
+ * mismatch */
+ BFA_STATUS_DIAG_BUSY = 71, /* diag busy */
+ BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */
+ BFA_STATUS_BEACON_OFF = 73, /* Port Beacon already off */
+ BFA_STATUS_LBEACON_ON = 74, /* Link End-to-End Beacon already
+ * on */
+ BFA_STATUS_LBEACON_OFF = 75, /* Link End-to-End Beacon already
+ * off */
+ BFA_STATUS_PORT_NOT_INITED = 76, /* Port not initialized */
+ BFA_STATUS_RPSC_ENABLED = 77, /* Target has a valid speed */
+ BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */
+ BFA_STATUS_BAD_FILE = 79, /* Not a valid Brocade Boot Code
+ * file */
+ BFA_STATUS_RLIM_EN = 80, /* Target rate limiting is already
+ * enabled */
+ BFA_STATUS_RLIM_DIS = 81, /* Target rate limiting is already
+ * disabled */
+ BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */
+ BFA_STATUS_ADAPTER_DISABLED = 83, /* Adapter is already disabled */
+ BFA_STATUS_BIOS_DISABLED = 84, /* Bios is already disabled */
+ BFA_STATUS_AUTH_ENABLED = 85, /* Authentication is already
+ * enabled */
+ BFA_STATUS_AUTH_DISABLED = 86, /* Authentication is already
+ * disabled */
+ BFA_STATUS_ERROR_TRL_ENABLED = 87, /* Target rate limiting is
+ * enabled */
+ BFA_STATUS_ERROR_QOS_ENABLED = 88, /* QoS is enabled */
+ BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */
+ BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact
+ * support */
+ BFA_STATUS_INVALID_DEVID = 91, /* Invalid device id provided */
+ BFA_STATUS_QOS_ENABLED = 92, /* QOS is already enabled */
+ BFA_STATUS_QOS_DISABLED = 93, /* QOS is already disabled */
+ BFA_STATUS_INCORRECT_DRV_CONFIG = 94, /* Check configuration
+ * key/value pair */
+ BFA_STATUS_REG_FAIL = 95, /* Can't read windows registry */
+ BFA_STATUS_IM_INV_CODE = 96, /* Invalid IOCTL code */
+ BFA_STATUS_IM_INV_VLAN = 97, /* Invalid VLAN ID */
+ BFA_STATUS_IM_INV_ADAPT_NAME = 98, /* Invalid adapter name */
+ BFA_STATUS_IM_LOW_RESOURCES = 99, /* Memory allocation failure in
+ * driver */
+ BFA_STATUS_IM_VLANID_IS_PVID = 100, /* Given VLAN id same as PVID */
+ BFA_STATUS_IM_VLANID_EXISTS = 101, /* Given VLAN id already exists */
+ BFA_STATUS_IM_FW_UPDATE_FAIL = 102, /* Updating firmware with new
+ * VLAN ID failed */
+ BFA_STATUS_PORTLOG_ENABLED = 103, /* Port Log is already enabled */
+ BFA_STATUS_PORTLOG_DISABLED = 104, /* Port Log is already disabled */
+ BFA_STATUS_FILE_NOT_FOUND = 105, /* Specified file could not be
+ * found */
+ BFA_STATUS_QOS_FC_ONLY = 106, /* QOS can be enabled for FC mode
+ * only */
+ BFA_STATUS_RLIM_FC_ONLY = 107, /* RATELIM can be enabled for FC mode
+ * only */
+ BFA_STATUS_CT_SPD = 108, /* Invalid speed selection for Catapult. */
+ BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */
+ BFA_STATUS_CEE_NOT_DN = 110, /* eth port is not at down state, please
+ * bring down first */
+ BFA_STATUS_10G_SPD = 111, /* Speed setting not valid for 10G HBA */
+ BFA_STATUS_IM_INV_TEAM_NAME = 112, /* Invalid team name */
+ BFA_STATUS_IM_DUP_TEAM_NAME = 113, /* Given team name already
+ * exists */
+ BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114, /* Given adapter is part
+ * of another team */
+ BFA_STATUS_IM_ADAPT_HAS_VLANS = 115, /* Adapter has VLANs configured.
+ * Delete all VLANs before
+ * creating team */
+ BFA_STATUS_IM_PVID_MISMATCH = 116, /* Mismatching PVIDs configured
+ * for adapters */
+ BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117, /* Mismatching link speeds
+ * configured for adapters */
+ BFA_STATUS_IM_MTU_MISMATCH = 118, /* Mismatching MTUs configured for
+ * adapters */
+ BFA_STATUS_IM_RSS_MISMATCH = 119, /* Mismatching RSS parameters
+ * configured for adapters */
+ BFA_STATUS_IM_HDS_MISMATCH = 120, /* Mismatching HDS parameters
+ * configured for adapters */
+ BFA_STATUS_IM_OFFLOAD_MISMATCH = 121, /* Mismatching offload
+ * parameters configured for
+ * adapters */
+ BFA_STATUS_IM_PORT_PARAMS = 122, /* Error setting port parameters */
+ BFA_STATUS_IM_PORT_NOT_IN_TEAM = 123, /* Port is not part of team */
+ BFA_STATUS_IM_CANNOT_REM_PRI = 124, /* Primary adapter cannot be
+ * removed. Change primary before
+ * removing */
+ BFA_STATUS_IM_MAX_PORTS_REACHED = 125, /* Exceeding maximum ports
+ * per team */
+ BFA_STATUS_IM_LAST_PORT_DELETE = 126, /* Last port in team being
+ * deleted */
+ BFA_STATUS_IM_NO_DRIVER = 127, /* IM driver is not installed */
+ BFA_STATUS_IM_MAX_VLANS_REACHED = 128, /* Exceeding maximum VLANs
+ * per port */
+ BFA_STATUS_TOMCAT_SPD_NOT_ALLOWED = 129, /* Bios speed config not
+ * allowed for CNA */
+ BFA_STATUS_NO_MINPORT_DRIVER = 130, /* Miniport driver is not
+ * loaded */
+ BFA_STATUS_CARD_TYPE_MISMATCH = 131, /* Card type mismatch */
+ BFA_STATUS_BAD_ASICBLK = 132, /* Bad ASIC block */
+ BFA_STATUS_NO_DRIVER = 133, /* Storage/Ethernet driver not loaded */
+ BFA_STATUS_INVALID_MAC = 134, /* Invalid mac address */
+ BFA_STATUS_IM_NO_VLAN = 135, /* No VLANs configured on the adapter */
+ BFA_STATUS_IM_ETH_LB_FAILED = 136, /* Ethernet loopback test failed */
+ BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port vlan (PVID) */
+ BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port vlan (PVID) */
+ BFA_STATUS_CNA_NO_BOOT = 139, /* Boot upload not allowed for CNA */
+ BFA_STATUS_IM_PVID_NON_ZERO = 140, /* Port VLAN ID (PVID) is Set to
+ * Non-Zero Value */
+ BFA_STATUS_IM_INETCFG_LOCK_FAILED = 141, /* Acquiring Network
+ * Subsytem Lock Failed.Please
+ * try after some time */
+ BFA_STATUS_IM_GET_INETCFG_FAILED = 142, /* Acquiring Network Subsytem
+ * handle Failed. Please try
+ * after some time */
+ BFA_STATUS_IM_NOT_BOUND = 143, /* Brocade 10G Ethernet Service is not
+ * Enabled on this port */
+ BFA_STATUS_INSUFFICIENT_PERMS = 144, /* User doesn't have sufficient
+ * permissions to execute the BCU
+ * application */
+ BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved Vlan name
+ * string. The name is not allowed
+ * for the normal Vlans */
+ BFA_STATUS_CMD_NOTSUPP_CNA = 146, /* Command not supported for CNA */
+ BFA_STATUS_IM_PASSTHRU_EDIT = 147, /* Can not edit passthru vlan id */
+ BFA_STATUS_IM_BIND_FAILED = 148, /*! < IM Driver bind operation
+ * failed */
+ BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation
+ * failed */
+ BFA_STATUS_MAX_VAL /* Unknown error code */
+};
+#define bfa_status_t enum bfa_status
+
+enum bfa_eproto_status {
+ BFA_EPROTO_BAD_ACCEPT = 0,
+ BFA_EPROTO_UNKNOWN_RSP = 1
+};
+#define bfa_eproto_status_t enum bfa_eproto_status
+
+#endif /* __BFA_DEFS_STATUS_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tin.h b/drivers/scsi/bfa/include/defs/bfa_defs_tin.h
new file mode 100644
index 000000000000..e05a2db7abed
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_tin.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_TIN_H__
+#define __BFA_DEFS_TIN_H__
+
+#include <protocol/types.h>
+#include <protocol/fc.h>
+
+/**
+ * FCS tin states
+ */
+enum bfa_tin_state_e {
+ BFA_TIN_SM_OFFLINE = 0, /* tin is offline */
+ BFA_TIN_SM_WOS_LOGIN = 1, /* Waiting PRLI ACC/RJT from ULP */
+ BFA_TIN_SM_WFW_ONLINE = 2, /* Waiting ACK to PRLI ACC from FW */
+ BFA_TIN_SM_ONLINE = 3, /* tin login is complete */
+ BFA_TIN_SM_WIO_RELOGIN = 4, /* tin relogin is in progress */
+ BFA_TIN_SM_WIO_LOGOUT = 5, /* Processing of PRLO req from
+ * Initiator is in progress
+ */
+ BFA_TIN_SM_WOS_LOGOUT = 6, /* Processing of PRLO req from
+ * Initiator is in progress
+ */
+ BFA_TIN_SM_WIO_CLEAN = 7, /* Waiting for IO cleanup before tin
+ * is offline. This can be triggered
+ * by RPORT LOGO (rcvd/sent) or by
+ * PRLO (rcvd/sent)
+ */
+};
+
+struct bfa_prli_req_s {
+ struct fchs_s fchs;
+ struct fc_prli_s prli_payload;
+};
+
+struct bfa_prlo_req_s {
+ struct fchs_s fchs;
+ struct fc_prlo_s prlo_payload;
+};
+
+void bfa_tin_send_login_rsp(void *bfa_tin, u32 login_rsp,
+ struct fc_ls_rjt_s rjt_payload);
+void bfa_tin_send_logout_rsp(void *bfa_tin, u32 logout_rsp,
+ struct fc_ls_rjt_s rjt_payload);
+/**
+ * FCS target port statistics
+ */
+struct bfa_tin_stats_s {
+ u32 onlines; /* ITN nexus onlines (PRLI done) */
+ u32 offlines; /* ITN Nexus offlines */
+ u32 prli_req_parse_err; /* prli req parsing errors */
+ u32 prli_rsp_rjt; /* num prli rsp rejects sent */
+ u32 prli_rsp_acc; /* num prli rsp accepts sent */
+ u32 cleanup_comps; /* ITN cleanup completions */
+};
+
+/**
+ * FCS tin attributes returned in queries
+ */
+struct bfa_tin_attr_s {
+ enum bfa_tin_state_e state;
+ u8 seq_retry; /* Sequence retry supported */
+ u8 rsvd[3];
+};
+
+/**
+ * BFA TIN async event data structure for BFAL
+ */
+enum bfa_tin_aen_event {
+ BFA_TIN_AEN_ONLINE = 1, /* Target online */
+ BFA_TIN_AEN_OFFLINE = 2, /* Target offline */
+ BFA_TIN_AEN_DISCONNECT = 3, /* Target disconnected */
+};
+
+/**
+ * BFA TIN event data structure.
+ */
+struct bfa_tin_aen_data_s {
+ u16 vf_id; /* vf_id of the IT nexus */
+ u16 rsvd[3];
+ wwn_t lpwwn; /* WWN of logical port */
+ wwn_t rpwwn; /* WWN of remote(target) port */
+};
+
+/**
+ * Below APIs are needed from BFA driver
+ * Move these to BFA driver public header file?
+ */
+/* TIN rcvd new PRLI & gets bfad_tin_t ptr from driver this callback */
+void *bfad_tin_rcvd_login_req(void *bfad_tm_port, void *bfa_tin,
+ wwn_t rp_wwn, u32 rp_fcid,
+ struct bfa_prli_req_s prli_req);
+/* TIN rcvd new PRLO */
+void bfad_tin_rcvd_logout_req(void *bfad_tin, wwn_t rp_wwn, u32 rp_fcid,
+ struct bfa_prlo_req_s prlo_req);
+/* TIN is online and ready for IO */
+void bfad_tin_online(void *bfad_tin);
+/* TIN is offline and BFA driver can shutdown its upper stack */
+void bfad_tin_offline(void *bfad_tin);
+/* TIN does not need this BFA driver tin tag anymore, so can be freed */
+void bfad_tin_res_free(void *bfad_tin);
+
+#endif /* __BFA_DEFS_TIN_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h
new file mode 100644
index 000000000000..31881d218515
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_TSENSOR_H__
+#define __BFA_DEFS_TSENSOR_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_types.h>
+
+/**
+ * Temperature sensor status values
+ */
+enum bfa_tsensor_status {
+ BFA_TSENSOR_STATUS_UNKNOWN = 1, /* unkown status */
+ BFA_TSENSOR_STATUS_FAULTY = 2, /* sensor is faulty */
+ BFA_TSENSOR_STATUS_BELOW_MIN = 3, /* temperature below mininum */
+ BFA_TSENSOR_STATUS_NOMINAL = 4, /* normal temperature */
+ BFA_TSENSOR_STATUS_ABOVE_MAX = 5, /* temperature above maximum */
+};
+
+/**
+ * Temperature sensor attribute
+ */
+struct bfa_tsensor_attr_s {
+ enum bfa_tsensor_status status; /* temperature sensor status */
+ u32 value; /* current temperature in celsius */
+};
+
+#endif /* __BFA_DEFS_TSENSOR_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_types.h b/drivers/scsi/bfa/include/defs/bfa_defs_types.h
new file mode 100644
index 000000000000..4348332b107a
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_types.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_TYPES_H__
+#define __BFA_DEFS_TYPES_H__
+
+#include <bfa_os_inc.h>
+
+enum bfa_boolean {
+ BFA_FALSE = 0,
+ BFA_TRUE = 1
+};
+#define bfa_boolean_t enum bfa_boolean
+
+#define BFA_STRING_32 32
+
+#endif /* __BFA_DEFS_TYPES_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_version.h b/drivers/scsi/bfa/include/defs/bfa_defs_version.h
new file mode 100644
index 000000000000..f8902a2c9aad
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_version.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+#ifndef __BFA_DEFS_VERSION_H__
+#define __BFA_DEFS_VERSION_H__
+
+#define BFA_VERSION_LEN 64
+
+#endif
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vf.h b/drivers/scsi/bfa/include/defs/bfa_defs_vf.h
new file mode 100644
index 000000000000..3235be5e9423
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_vf.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_VF_H__
+#define __BFA_DEFS_VF_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_port.h>
+#include <protocol/types.h>
+
+/**
+ * VF states
+ */
+enum bfa_vf_state {
+ BFA_VF_UNINIT = 0, /* fabric is not yet initialized */
+ BFA_VF_LINK_DOWN = 1, /* link is down */
+ BFA_VF_FLOGI = 2, /* flogi is in progress */
+ BFA_VF_AUTH = 3, /* authentication in progress */
+ BFA_VF_NOFABRIC = 4, /* fabric is not present */
+ BFA_VF_ONLINE = 5, /* login to fabric is complete */
+ BFA_VF_EVFP = 6, /* EVFP is in progress */
+ BFA_VF_ISOLATED = 7, /* port isolated due to vf_id mismatch */
+};
+
+/**
+ * VF statistics
+ */
+struct bfa_vf_stats_s {
+ u32 flogi_sent; /* Num FLOGIs sent */
+ u32 flogi_rsp_err; /* FLOGI response errors */
+ u32 flogi_acc_err; /* FLOGI accept errors */
+ u32 flogi_accepts; /* FLOGI accepts received */
+ u32 flogi_rejects; /* FLOGI rejects received */
+ u32 flogi_unknown_rsp; /* Unknown responses for FLOGI */
+ u32 flogi_alloc_wait; /* Allocation waits prior to
+ * sending FLOGI
+ */
+ u32 flogi_rcvd; /* FLOGIs received */
+ u32 flogi_rejected; /* Incoming FLOGIs rejected */
+ u32 fabric_onlines; /* Internal fabric online
+ * notification sent to other
+ * modules
+ */
+ u32 fabric_offlines; /* Internal fabric offline
+ * notification sent to other
+ * modules
+ */
+ u32 resvd;
+};
+
+/**
+ * VF attributes returned in queries
+ */
+struct bfa_vf_attr_s {
+ enum bfa_vf_state state; /* VF state */
+ u32 rsvd;
+ wwn_t fabric_name; /* fabric name */
+};
+
+#endif /* __BFA_DEFS_VF_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vport.h b/drivers/scsi/bfa/include/defs/bfa_defs_vport.h
new file mode 100644
index 000000000000..9f021f43b3b4
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_vport.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_DEFS_VPORT_H__
+#define __BFA_DEFS_VPORT_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_port.h>
+#include <protocol/types.h>
+
+/**
+ * VPORT states
+ */
+enum bfa_vport_state {
+ BFA_FCS_VPORT_UNINIT = 0,
+ BFA_FCS_VPORT_CREATED = 1,
+ BFA_FCS_VPORT_OFFLINE = 1,
+ BFA_FCS_VPORT_FDISC_SEND = 2,
+ BFA_FCS_VPORT_FDISC = 3,
+ BFA_FCS_VPORT_FDISC_RETRY = 4,
+ BFA_FCS_VPORT_ONLINE = 5,
+ BFA_FCS_VPORT_DELETING = 6,
+ BFA_FCS_VPORT_CLEANUP = 6,
+ BFA_FCS_VPORT_LOGO_SEND = 7,
+ BFA_FCS_VPORT_LOGO = 8,
+ BFA_FCS_VPORT_ERROR = 9,
+ BFA_FCS_VPORT_MAX_STATE,
+};
+
+/**
+ * vport statistics
+ */
+struct bfa_vport_stats_s {
+ struct bfa_port_stats_s port_stats; /* base class (port) stats */
+ /*
+ * TODO - remove
+ */
+
+ u32 fdisc_sent; /* num fdisc sent */
+ u32 fdisc_accepts; /* fdisc accepts */
+ u32 fdisc_retries; /* fdisc retries */
+ u32 fdisc_timeouts; /* fdisc timeouts */
+ u32 fdisc_rsp_err; /* fdisc response error */
+ u32 fdisc_acc_bad; /* bad fdisc accepts */
+ u32 fdisc_rejects; /* fdisc rejects */
+ u32 fdisc_unknown_rsp;
+ /*
+ *!< fdisc rsp unknown error
+ */
+ u32 fdisc_alloc_wait;/* fdisc req (fcxp)alloc wait */
+
+ u32 logo_alloc_wait;/* logo req (fcxp) alloc wait */
+ u32 logo_sent; /* logo sent */
+ u32 logo_accepts; /* logo accepts */
+ u32 logo_rejects; /* logo rejects */
+ u32 logo_rsp_err; /* logo rsp errors */
+ u32 logo_unknown_rsp;
+ /* logo rsp unknown errors */
+
+ u32 fab_no_npiv; /* fabric does not support npiv */
+
+ u32 fab_offline; /* offline events from fab SM */
+ u32 fab_online; /* online events from fab SM */
+ u32 fab_cleanup; /* cleanup request from fab SM */
+ u32 rsvd;
+};
+
+/**
+ * BFA vport attribute returned in queries
+ */
+struct bfa_vport_attr_s {
+ struct bfa_port_attr_s port_attr; /* base class (port) attributes */
+ enum bfa_vport_state vport_state; /* vport state */
+ u32 rsvd;
+};
+
+#endif /* __BFA_DEFS_VPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb.h b/drivers/scsi/bfa/include/fcb/bfa_fcb.h
new file mode 100644
index 000000000000..2963b0bc30e7
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcb.h BFA FCS callback interfaces
+ */
+
+#ifndef __BFA_FCB_H__
+#define __BFA_FCB_H__
+
+/**
+ * fcb Main fcs callbacks
+ */
+
+void bfa_fcb_exit(struct bfad_s *bfad);
+
+
+
+#endif /* __BFA_FCB_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h
new file mode 100644
index 000000000000..a6c70aee0aa3
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+* : bfad_fcpim.h - BFA FCS initiator mode remote port callbacks
+ */
+
+#ifndef __BFAD_FCB_FCPIM_H__
+#define __BFAD_FCB_FCPIM_H__
+
+struct bfad_itnim_s;
+
+/*
+ * RPIM callbacks
+ */
+
+/**
+ * Memory allocation for remote port instance. Called before PRLI is
+ * initiated to the remote target port.
+ *
+ * @param[in] bfad - driver instance
+ * @param[out] itnim - FCS remote port (IM) instance
+ * @param[out] itnim_drv - driver remote port (IM) instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
+ struct bfad_itnim_s **itnim_drv);
+
+/**
+ * Free remote port (IM) instance.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] itnim_drv - driver remote port instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_free(struct bfad_s *bfad,
+ struct bfad_itnim_s *itnim_drv);
+
+/**
+ * Notification of when login with a remote target device is complete.
+ *
+ * @param[in] itnim_drv - driver remote port instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv);
+
+/**
+ * Notification when login with the remote device is severed.
+ *
+ * @param[in] itnim_drv - driver remote port instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv);
+
+void bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim_drv);
+void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim_drv);
+
+#endif /* __BFAD_FCB_FCPIM_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h
new file mode 100644
index 000000000000..5fd7f986fa32
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcb_port.h BFA FCS virtual port driver interfaces
+ */
+
+#ifndef __BFA_FCB_PORT_H__
+#define __BFA_FCB_PORT_H__
+
+#include <fcb/bfa_fcb_vport.h>
+/**
+ * fcs_port_fcb FCS port driver interfaces
+ */
+
+/*
+ * Forward declarations
+ */
+struct bfad_port_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Call from FCS to driver module when a port is instantiated. The port
+ * can be a base port or a virtual port with in the base fabric or
+ * a virtual fabric.
+ *
+ * On this callback, driver is supposed to create scsi_host, scsi_tgt or
+ * network interfaces bases on ports personality/roles.
+ *
+ * base port of base fabric: vf_drv == NULL && vp_drv == NULL
+ * vport of base fabric: vf_drv == NULL && vp_drv != NULL
+ * base port of VF: vf_drv != NULL && vp_drv == NULL
+ * vport of VF: vf_drv != NULL && vp_drv != NULL
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] port - FCS port instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+struct bfad_port_s *bfa_fcb_port_new(struct bfad_s *bfad,
+ struct bfa_fcs_port_s *port,
+ enum bfa_port_role roles, struct bfad_vf_s *vf_drv,
+ struct bfad_vport_s *vp_drv);
+
+/**
+ * Call from FCS to driver module when a port is deleted. The port
+ * can be a base port or a virtual port with in the base fabric or
+ * a virtual fabric.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+void bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
+
+/**
+ * Notification when port transitions to ONLINE state.
+ *
+ * Online notification is a logical link up for the local port. This
+ * notification is sent after a successfull FLOGI, or a successful
+ * link initialization in proviate-loop or N2N topologies.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+void bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
+
+/**
+ * Notification when port transitions to OFFLINE state.
+ *
+ * Offline notification is a logical link down for the local port.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+void bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
+
+
+#endif /* __BFA_FCB_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h
new file mode 100644
index 000000000000..e0261bb6d1c1
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcb_rport.h BFA FCS rport driver interfaces
+ */
+
+#ifndef __BFA_FCB_RPORT_H__
+#define __BFA_FCB_RPORT_H__
+
+/**
+ * fcs_rport_fcb Remote port driver interfaces
+ */
+
+
+struct bfad_rport_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Completion callback for bfa_fcs_rport_add().
+ *
+ * @param[in] rport_drv - driver instance of rport
+ *
+ * @return None
+ */
+void bfa_fcb_rport_add(struct bfad_rport_s *rport_drv);
+
+/**
+ * Completion callback for bfa_fcs_rport_remove().
+ *
+ * @param[in] rport_drv - driver instance of rport
+ *
+ * @return None
+ */
+void bfa_fcb_rport_remove(struct bfad_rport_s *rport_drv);
+
+/**
+ * Call to allocate a rport instance.
+ *
+ * @param[in] bfad - driver instance
+ * @param[out] rport - BFA FCS instance of rport
+ * @param[out] rport_drv - driver instance of rport
+ *
+ * @retval BFA_STATUS_OK - successfully allocated
+ * @retval BFA_STATUS_ENOMEM - cannot allocate
+ */
+bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad,
+ struct bfa_fcs_rport_s **rport,
+ struct bfad_rport_s **rport_drv);
+
+/**
+ * Call to free rport memory resources.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] rport_drv - driver instance of rport
+ *
+ * @return None
+ */
+void bfa_fcb_rport_free(struct bfad_s *bfad, struct bfad_rport_s **rport_drv);
+
+
+
+#endif /* __BFA_FCB_RPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h
new file mode 100644
index 000000000000..cfd3fac0a4e2
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcb_vf.h BFA FCS virtual fabric driver interfaces
+ */
+
+#ifndef __BFA_FCB_VF_H__
+#define __BFA_FCB_VF_H__
+
+/**
+ * fcs_vf_fcb Virtual fabric driver intrefaces
+ */
+
+
+struct bfad_vf_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Completion callback for bfa_fcs_vf_stop().
+ *
+ * @param[in] vf_drv - driver instance of vf
+ *
+ * @return None
+ */
+void bfa_fcb_vf_stop(struct bfad_vf_s *vf_drv);
+
+
+
+#endif /* __BFA_FCB_VF_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
new file mode 100644
index 000000000000..a39f474c2fcf
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcb_vport.h BFA FCS virtual port driver interfaces
+ */
+
+#ifndef __BFA_FCB_VPORT_H__
+#define __BFA_FCB_VPORT_H__
+
+/**
+ * fcs_vport_fcb Virtual port driver interfaces
+ */
+
+
+struct bfad_vport_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Completion callback for bfa_fcs_vport_delete().
+ *
+ * @param[in] vport_drv - driver instance of vport
+ *
+ * @return None
+ */
+void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv);
+
+
+
+#endif /* __BFA_FCB_VPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs.h b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
new file mode 100644
index 000000000000..627669c65546
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCS_H__
+#define __BFA_FCS_H__
+
+#include <cs/bfa_debug.h>
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_version.h>
+#include <bfa.h>
+#include <fcs/bfa_fcs_fabric.h>
+
+#define BFA_FCS_OS_STR_LEN 64
+
+struct bfa_fcs_stats_s {
+ struct {
+ u32 untagged; /* untagged receive frames */
+ u32 tagged; /* tagged receive frames */
+ u32 vfid_unknown; /* VF id is unknown */
+ } uf;
+};
+
+struct bfa_fcs_driver_info_s {
+ u8 version[BFA_VERSION_LEN]; /* Driver Version */
+ u8 host_machine_name[BFA_FCS_OS_STR_LEN];
+ u8 host_os_name[BFA_FCS_OS_STR_LEN]; /* OS name and version */
+ u8 host_os_patch[BFA_FCS_OS_STR_LEN];/* patch or service pack */
+ u8 os_device_name[BFA_FCS_OS_STR_LEN]; /* Driver Device Name */
+};
+
+struct bfa_fcs_s {
+ struct bfa_s *bfa; /* corresponding BFA bfa instance */
+ struct bfad_s *bfad; /* corresponding BDA driver instance */
+ struct bfa_log_mod_s *logm; /* driver logging module instance */
+ struct bfa_trc_mod_s *trcmod; /* tracing module */
+ struct bfa_aen_s *aen; /* aen component */
+ bfa_boolean_t vf_enabled; /* VF mode is enabled */
+ bfa_boolean_t min_cfg; /* min cfg enabled/disabled */
+ u16 port_vfid; /* port default VF ID */
+ struct bfa_fcs_driver_info_s driver_info;
+ struct bfa_fcs_fabric_s fabric; /* base fabric state machine */
+ struct bfa_fcs_stats_s stats; /* FCS statistics */
+ struct bfa_wc_s wc; /* waiting counter */
+};
+
+/*
+ * bfa fcs API functions
+ */
+void bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
+ bfa_boolean_t min_cfg);
+void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
+ struct bfa_fcs_driver_info_s *driver_info);
+void bfa_fcs_exit(struct bfa_fcs_s *fcs);
+void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod);
+void bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod);
+void bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen);
+void bfa_fcs_start(struct bfa_fcs_s *fcs);
+
+#endif /* __BFA_FCS_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h
new file mode 100644
index 000000000000..28c4c9ff08b3
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCS_AUTH_H__
+#define __BFA_FCS_AUTH_H__
+
+struct bfa_fcs_s;
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_auth.h>
+#include <defs/bfa_defs_vf.h>
+#include <cs/bfa_q.h>
+#include <cs/bfa_sm.h>
+#include <defs/bfa_defs_pport.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <protocol/fc_sp.h>
+
+struct bfa_fcs_fabric_s;
+
+
+
+struct bfa_fcs_auth_s {
+ bfa_sm_t sm; /* state machine */
+ bfa_boolean_t policy; /* authentication enabled/disabled */
+ enum bfa_auth_status status; /* authentication status */
+ enum auth_rjt_codes rjt_code; /* auth reject status */
+ enum auth_rjt_code_exps rjt_code_exp; /* auth reject reason */
+ enum bfa_auth_algo algo; /* Authentication algorithm */
+ struct bfa_auth_stats_s stats; /* Statistics */
+ enum auth_dh_gid group; /* DH(diffie-hellman) Group */
+ enum bfa_auth_secretsource source; /* Secret source */
+ char secret[BFA_AUTH_SECRET_STRING_LEN];
+ /* secret string */
+ u8 secret_len;
+ /* secret string length */
+ u8 nretries;
+ /* number of retries */
+ struct bfa_fcs_fabric_s *fabric;/* pointer to fabric */
+ u8 sentcode; /* pointer to response data */
+ u8 *response; /* pointer to response data */
+ struct bfa_timer_s delay_timer; /* delay timer */
+ struct bfa_fcxp_s *fcxp; /* pointer to fcxp */
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+};
+
+/**
+ * bfa fcs authentication public functions
+ */
+bfa_status_t bfa_fcs_auth_get_attr(struct bfa_fcs_s *port,
+ struct bfa_auth_attr_s *attr);
+bfa_status_t bfa_fcs_auth_set_policy(struct bfa_fcs_s *port,
+ bfa_boolean_t policy);
+enum bfa_auth_status bfa_fcs_auth_get_status(struct bfa_fcs_s *port);
+bfa_status_t bfa_fcs_auth_set_algo(struct bfa_fcs_s *port,
+ enum bfa_auth_algo algo);
+bfa_status_t bfa_fcs_auth_get_stats(struct bfa_fcs_s *port,
+ struct bfa_auth_stats_s *stats);
+bfa_status_t bfa_fcs_auth_set_dh_group(struct bfa_fcs_s *port, int group);
+bfa_status_t bfa_fcs_auth_set_secretstring(struct bfa_fcs_s *port,
+ char *secret);
+bfa_status_t bfa_fcs_auth_set_secretstring_encrypt(struct bfa_fcs_s *port,
+ u32 secret[], u32 len);
+bfa_status_t bfa_fcs_auth_set_secretsource(struct bfa_fcs_s *port,
+ enum bfa_auth_secretsource src);
+bfa_status_t bfa_fcs_auth_reset_stats(struct bfa_fcs_s *port);
+bfa_status_t bfa_fcs_auth_reinit(struct bfa_fcs_s *port);
+
+#endif /* __BFA_FCS_AUTH_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
new file mode 100644
index 000000000000..4ffd2242d3de
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCS_FABRIC_H__
+#define __BFA_FCS_FABRIC_H__
+
+struct bfa_fcs_s;
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_vf.h>
+#include <cs/bfa_q.h>
+#include <cs/bfa_sm.h>
+#include <defs/bfa_defs_pport.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <protocol/fc_sp.h>
+#include <fcs/bfa_fcs_auth.h>
+
+/*
+ * forward declaration
+ */
+struct bfad_vf_s;
+
+enum bfa_fcs_fabric_type {
+ BFA_FCS_FABRIC_UNKNOWN = 0,
+ BFA_FCS_FABRIC_SWITCHED = 1,
+ BFA_FCS_FABRIC_PLOOP = 2,
+ BFA_FCS_FABRIC_N2N = 3,
+};
+
+
+struct bfa_fcs_fabric_s {
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* state machine */
+ struct bfa_fcs_s *fcs; /* FCS instance */
+ struct bfa_fcs_port_s bport; /* base logical port */
+ enum bfa_fcs_fabric_type fab_type; /* fabric type */
+ enum bfa_pport_type oper_type; /* current link topology */
+ u8 is_vf; /* is virtual fabric? */
+ u8 is_npiv; /* is NPIV supported ? */
+ u8 is_auth; /* is Security/Auth supported ? */
+ u16 bb_credit; /* BB credit from fabric */
+ u16 vf_id; /* virtual fabric ID */
+ u16 num_vports; /* num vports */
+ u16 rsvd;
+ struct list_head vport_q; /* queue of virtual ports */
+ struct list_head vf_q; /* queue of virtual fabrics */
+ struct bfad_vf_s *vf_drv; /* driver vf structure */
+ struct bfa_timer_s link_timer; /* Link Failure timer. Vport */
+ wwn_t fabric_name; /* attached fabric name */
+ bfa_boolean_t auth_reqd; /* authentication required */
+ struct bfa_timer_s delay_timer; /* delay timer */
+ union {
+ u16 swp_vfid;/* switch port VF id */
+ } event_arg;
+ struct bfa_fcs_auth_s auth; /* authentication config */
+ struct bfa_wc_s wc; /* wait counter for delete */
+ struct bfa_vf_stats_s stats; /* fabric/vf stats */
+ struct bfa_lps_s *lps; /* lport login services */
+ u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached
+ * fabric's ip addr
+ */
+};
+
+#define bfa_fcs_fabric_npiv_capable(__f) (__f)->is_npiv
+#define bfa_fcs_fabric_is_switched(__f) \
+ ((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED)
+
+/**
+ * The design calls for a single implementation of base fabric and vf.
+ */
+#define bfa_fcs_vf_t struct bfa_fcs_fabric_s
+
+struct bfa_vf_event_s {
+ u32 undefined;
+};
+
+/**
+ * bfa fcs vf public functions
+ */
+bfa_status_t bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id);
+bfa_status_t bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs);
+bfa_status_t bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs,
+ u16 vf_id, struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vf_s *vf_drv);
+bfa_status_t bfa_fcs_vf_delete(bfa_fcs_vf_t *vf);
+void bfa_fcs_vf_start(bfa_fcs_vf_t *vf);
+bfa_status_t bfa_fcs_vf_stop(bfa_fcs_vf_t *vf);
+void bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
+void bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
+void bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr);
+void bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf,
+ struct bfa_vf_stats_s *vf_stats);
+void bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf);
+void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports);
+bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id);
+struct bfad_vf_s *bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf);
+
+#endif /* __BFA_FCS_FABRIC_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
new file mode 100644
index 000000000000..e719f2c3eb35
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_fcpim.h BFA FCS FCP Initiator Mode interfaces/defines.
+ */
+
+#ifndef __BFA_FCS_FCPIM_H__
+#define __BFA_FCS_FCPIM_H__
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_itnim.h>
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <bfa_fcpim.h>
+
+/*
+ * forward declarations
+ */
+struct bfad_itnim_s;
+
+struct bfa_fcs_itnim_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_fcs_rport_s *rport; /* parent remote rport */
+ struct bfad_itnim_s *itnim_drv; /* driver peer instance */
+ struct bfa_fcs_s *fcs; /* fcs instance */
+ struct bfa_timer_s timer; /* timer functions */
+ struct bfa_itnim_s *bfa_itnim; /* BFA itnim struct */
+ bfa_boolean_t seq_rec; /* seq recovery support */
+ bfa_boolean_t rec_support; /* REC supported */
+ bfa_boolean_t conf_comp; /* FCP_CONF support */
+ bfa_boolean_t task_retry_id; /* task retry id supp */
+ struct bfa_fcxp_wqe_s fcxp_wqe; /* wait qelem for fcxp */
+ struct bfa_fcxp_s *fcxp; /* FCXP in use */
+ struct bfa_itnim_stats_s stats; /* itn statistics */
+};
+
+
+static inline struct bfad_port_s *
+bfa_fcs_itnim_get_drvport(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->port->bfad_port;
+}
+
+
+static inline struct bfa_fcs_port_s *
+bfa_fcs_itnim_get_port(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->port;
+}
+
+
+static inline wwn_t
+bfa_fcs_itnim_get_nwwn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->nwwn;
+}
+
+
+static inline wwn_t
+bfa_fcs_itnim_get_pwwn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->pwwn;
+}
+
+
+static inline u32
+bfa_fcs_itnim_get_fcid(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->pid;
+}
+
+
+static inline u32
+bfa_fcs_itnim_get_maxfrsize(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->maxfrsize;
+}
+
+
+static inline enum fc_cos
+bfa_fcs_itnim_get_cos(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->fc_cos;
+}
+
+
+static inline struct bfad_itnim_s *
+bfa_fcs_itnim_get_drvitn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->itnim_drv;
+}
+
+
+static inline struct bfa_itnim_s *
+bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->bfa_itnim;
+}
+
+/**
+ * bfa fcs FCP Initiator mode API functions
+ */
+void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim,
+ struct bfa_itnim_attr_s *attr);
+void bfa_fcs_itnim_get_stats(struct bfa_fcs_itnim_s *itnim,
+ struct bfa_itnim_stats_s *stats);
+struct bfa_fcs_itnim_s *bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port,
+ wwn_t rpwwn);
+bfa_status_t bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_attr_s *attr);
+bfa_status_t bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_stats_s *stats);
+bfa_status_t bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port,
+ wwn_t rpwwn);
+#endif /* __BFA_FCS_FCPIM_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h
new file mode 100644
index 000000000000..4441fffc9c82
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_fdmi.h BFA fcs fdmi module public interface
+ */
+
+#ifndef __BFA_FCS_FDMI_H__
+#define __BFA_FCS_FDMI_H__
+#include <bfa_os_inc.h>
+#include <protocol/fdmi.h>
+
+#define BFA_FCS_FDMI_SUPORTED_SPEEDS (FDMI_TRANS_SPEED_1G | \
+ FDMI_TRANS_SPEED_2G | \
+ FDMI_TRANS_SPEED_4G | \
+ FDMI_TRANS_SPEED_8G)
+
+/*
+* HBA Attribute Block : BFA internal representation. Note : Some variable
+* sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based
+ * on this the size has been reduced to 16 bytes from the standard's 64 bytes.
+ */
+struct bfa_fcs_fdmi_hba_attr_s {
+ wwn_t node_name;
+ u8 manufacturer[64];
+ u8 serial_num[64];
+ u8 model[16];
+ u8 model_desc[256];
+ u8 hw_version[8];
+ u8 driver_version[8];
+ u8 option_rom_ver[BFA_VERSION_LEN];
+ u8 fw_version[8];
+ u8 os_name[256];
+ u32 max_ct_pyld;
+};
+
+/*
+ * Port Attribute Block
+ */
+struct bfa_fcs_fdmi_port_attr_s {
+ u8 supp_fc4_types[32]; /* supported FC4 types */
+ u32 supp_speed; /* supported speed */
+ u32 curr_speed; /* current Speed */
+ u32 max_frm_size; /* max frame size */
+ u8 os_device_name[256]; /* OS device Name */
+ u8 host_name[256]; /* host name */
+};
+
+#endif /* __BFA_FCS_FDMI_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
new file mode 100644
index 000000000000..b85cba884b96
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_port.h BFA fcs port module public interface
+ */
+
+#ifndef __BFA_FCS_PORT_H__
+#define __BFA_FCS_PORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_rport.h>
+#include <cs/bfa_q.h>
+#include <bfa_svc.h>
+#include <cs/bfa_wc.h>
+
+struct bfa_fcs_s;
+struct bfa_fcs_fabric_s;
+
+/*
+* @todo : need to move to a global config file.
+ * Maximum Vports supported per physical port or vf.
+ */
+#define BFA_FCS_MAX_VPORTS_SUPP_CB 255
+#define BFA_FCS_MAX_VPORTS_SUPP_CT 191
+
+/*
+* @todo : need to move to a global config file.
+ * Maximum Rports supported per port (physical/logical).
+ */
+#define BFA_FCS_MAX_RPORTS_SUPP 256 /* @todo : tentative value */
+
+
+struct bfa_fcs_port_ns_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_s *port; /* parent port */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+};
+
+
+struct bfa_fcs_port_scn_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_s *port; /* parent port */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+};
+
+
+struct bfa_fcs_port_fdmi_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_ms_s *ms; /* parent ms */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+ u8 retry_cnt; /* retry count */
+ u8 rsvd[3];
+};
+
+
+struct bfa_fcs_port_ms_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_s *port; /* parent port */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+ struct bfa_fcs_port_fdmi_s fdmi; /* FDMI component of MS */
+ u8 retry_cnt; /* retry count */
+ u8 rsvd[3];
+};
+
+
+struct bfa_fcs_port_fab_s {
+ struct bfa_fcs_port_ns_s ns; /* NS component of port */
+ struct bfa_fcs_port_scn_s scn; /* scn component of port */
+ struct bfa_fcs_port_ms_s ms; /* MS component of port */
+};
+
+
+
+#define MAX_ALPA_COUNT 127
+
+struct bfa_fcs_port_loop_s {
+ u8 num_alpa; /* Num of ALPA entries in the map */
+ u8 alpa_pos_map[MAX_ALPA_COUNT]; /* ALPA Positional
+ *Map */
+ struct bfa_fcs_port_s *port; /* parent port */
+};
+
+
+
+struct bfa_fcs_port_n2n_s {
+ u32 rsvd;
+ u16 reply_oxid; /* ox_id from the req flogi to be
+ *used in flogi acc */
+ wwn_t rem_port_wwn; /* Attached port's wwn */
+};
+
+
+union bfa_fcs_port_topo_u {
+ struct bfa_fcs_port_fab_s pfab;
+ struct bfa_fcs_port_loop_s ploop;
+ struct bfa_fcs_port_n2n_s pn2n;
+};
+
+
+struct bfa_fcs_port_s {
+ struct list_head qe; /* used by port/vport */
+ bfa_sm_t sm; /* state machine */
+ struct bfa_fcs_fabric_s *fabric; /* parent fabric */
+ struct bfa_port_cfg_s port_cfg; /* port configuration */
+ struct bfa_timer_s link_timer; /* timer for link offline */
+ u32 pid : 24; /* FC address */
+ u8 lp_tag; /* lport tag */
+ u16 num_rports; /* Num of r-ports */
+ struct list_head rport_q; /* queue of discovered r-ports */
+ struct bfa_fcs_s *fcs; /* FCS instance */
+ union bfa_fcs_port_topo_u port_topo; /* fabric/loop/n2n details */
+ struct bfad_port_s *bfad_port; /* driver peer instance */
+ struct bfa_fcs_vport_s *vport; /* NULL for base ports */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+ struct bfa_port_stats_s stats;
+ struct bfa_wc_s wc; /* waiting counter for events */
+};
+
+#define bfa_fcs_lport_t struct bfa_fcs_port_s
+
+/**
+ * Symbolic Name related defines
+ * Total bytes 255.
+ * Physical Port's symbolic name 128 bytes.
+ * For Vports, Vport's symbolic name is appended to the Physical port's
+ * Symbolic Name.
+ *
+ * Physical Port's symbolic name Format : (Total 128 bytes)
+ * Adapter Model number/name : 12 bytes
+ * Driver Version : 10 bytes
+ * Host Machine Name : 30 bytes
+ * Host OS Info : 48 bytes
+ * Host OS PATCH Info : 16 bytes
+ * ( remaining 12 bytes reserved to be used for separator)
+ */
+#define BFA_FCS_PORT_SYMBNAME_SEPARATOR " | "
+
+#define BFA_FCS_PORT_SYMBNAME_MODEL_SZ 12
+#define BFA_FCS_PORT_SYMBNAME_VERSION_SZ 10
+#define BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ 30
+#define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48
+#define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16
+
+/**
+ * Get FC port ID for a logical port.
+ */
+#define bfa_fcs_port_get_fcid(_lport) ((_lport)->pid)
+#define bfa_fcs_port_get_pwwn(_lport) ((_lport)->port_cfg.pwwn)
+#define bfa_fcs_port_get_nwwn(_lport) ((_lport)->port_cfg.nwwn)
+#define bfa_fcs_port_get_psym_name(_lport) ((_lport)->port_cfg.sym_name)
+#define bfa_fcs_port_is_initiator(_lport) \
+ ((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_IM)
+#define bfa_fcs_port_is_target(_lport) \
+ ((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_TM)
+#define bfa_fcs_port_get_nrports(_lport) \
+ ((_lport) ? (_lport)->num_rports : 0)
+
+static inline struct bfad_port_s *
+bfa_fcs_port_get_drvport(struct bfa_fcs_port_s *port)
+{
+ return port->bfad_port;
+}
+
+
+#define bfa_fcs_port_get_opertype(_lport) (_lport)->fabric->oper_type
+
+
+#define bfa_fcs_port_get_fabric_name(_lport) (_lport)->fabric->fabric_name
+
+
+#define bfa_fcs_port_get_fabric_ipaddr(_lport) (_lport)->fabric->fabric_ip_addr
+
+/**
+ * bfa fcs port public functions
+ */
+void bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs,
+ struct bfa_port_cfg_s *port_cfg);
+struct bfa_fcs_port_s *bfa_fcs_get_base_port(struct bfa_fcs_s *fcs);
+void bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port,
+ wwn_t rport_wwns[], int *nrports);
+
+wwn_t bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn,
+ int index, int nrports, bfa_boolean_t bwwn);
+
+struct bfa_fcs_port_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs,
+ u16 vf_id, wwn_t lpwwn);
+
+void bfa_fcs_port_get_info(struct bfa_fcs_port_s *port,
+ struct bfa_port_info_s *port_info);
+void bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
+ struct bfa_port_attr_s *port_attr);
+void bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port,
+ struct bfa_port_stats_s *port_stats);
+void bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port);
+enum bfa_pport_speed bfa_fcs_port_get_rport_max_speed(
+ struct bfa_fcs_port_s *port);
+void bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port);
+void bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port);
+
+#endif /* __BFA_FCS_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
new file mode 100644
index 000000000000..702b95b76c2d
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __BFA_FCS_RPORT_H__
+#define __BFA_FCS_RPORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <cs/bfa_q.h>
+#include <fcs/bfa_fcs.h>
+#include <defs/bfa_defs_rport.h>
+
+#define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */
+/*
+ * forward declarations
+ */
+struct bfad_rport_s;
+
+struct bfa_fcs_itnim_s;
+struct bfa_fcs_tin_s;
+struct bfa_fcs_iprp_s;
+
+/* Rport Features (RPF) */
+struct bfa_fcs_rpf_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_fcs_rport_s *rport; /* parent rport */
+ struct bfa_timer_s timer; /* general purpose timer */
+ struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */
+ struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */
+ int rpsc_retries; /* max RPSC retry attempts */
+ enum bfa_pport_speed rpsc_speed; /* Current Speed from RPSC.
+ * O if RPSC fails */
+ enum bfa_pport_speed assigned_speed; /* Speed assigned by the user.
+ * will be used if RPSC is not
+ * supported by the rport */
+};
+
+struct bfa_fcs_rport_s {
+ struct list_head qe; /* used by port/vport */
+ struct bfa_fcs_port_s *port; /* parent FCS port */
+ struct bfa_fcs_s *fcs; /* fcs instance */
+ struct bfad_rport_s *rp_drv; /* driver peer instance */
+ u32 pid; /* port ID of rport */
+ u16 maxfrsize; /* maximum frame size */
+ u16 reply_oxid; /* OX_ID of inbound requests */
+ enum fc_cos fc_cos; /* FC classes of service supp */
+ bfa_boolean_t cisc; /* CISC capable device */
+ wwn_t pwwn; /* port wwn of rport */
+ wwn_t nwwn; /* node wwn of rport */
+ struct bfa_rport_symname_s psym_name; /* port symbolic name */
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer; /* general purpose timer */
+ struct bfa_fcs_itnim_s *itnim; /* ITN initiator mode role */
+ struct bfa_fcs_tin_s *tin; /* ITN initiator mode role */
+ struct bfa_fcs_iprp_s *iprp; /* IP/FC role */
+ struct bfa_rport_s *bfa_rport; /* BFA Rport */
+ struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */
+ int plogi_retries; /* max plogi retry attempts */
+ int ns_retries; /* max NS query retry attempts */
+ struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */
+ struct bfa_rport_stats_s stats; /* rport stats */
+ enum bfa_rport_function scsi_function; /* Initiator/Target */
+ struct bfa_fcs_rpf_s rpf; /* Rport features module */
+};
+
+static inline struct bfa_rport_s *
+bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport)
+{
+ return rport->bfa_rport;
+}
+
+/**
+ * bfa fcs rport API functions
+ */
+bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn,
+ struct bfa_fcs_rport_s *rport,
+ struct bfad_rport_s *rport_drv);
+bfa_status_t bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_attr_s *attr);
+void bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_stats_s *stats);
+void bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport);
+struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port,
+ wwn_t rpwwn);
+struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn(
+ struct bfa_fcs_port_s *port, wwn_t rnwwn);
+void bfa_fcs_rport_set_del_timeout(u8 rport_tmo);
+void bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport,
+ enum bfa_pport_speed speed);
+#endif /* __BFA_FCS_RPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
new file mode 100644
index 000000000000..cd33f2cd5c34
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_vport.h BFA fcs vport module public interface
+ */
+
+#ifndef __BFA_FCS_VPORT_H__
+#define __BFA_FCS_VPORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_vport.h>
+#include <fcs/bfa_fcs.h>
+#include <fcb/bfa_fcb_vport.h>
+
+struct bfa_fcs_vport_s {
+ struct list_head qe; /* queue elem */
+ bfa_sm_t sm; /* state machine */
+ bfa_fcs_lport_t lport; /* logical port */
+ struct bfa_timer_s timer; /* general purpose timer */
+ struct bfad_vport_s *vport_drv; /* Driver private */
+ struct bfa_vport_stats_s vport_stats; /* vport statistics */
+ struct bfa_lps_s *lps; /* Lport login service */
+ int fdisc_retries;
+};
+
+#define bfa_fcs_vport_get_port(vport) \
+ ((struct bfa_fcs_port_s *)(&vport->port))
+
+/**
+ * bfa fcs vport public functions
+ */
+bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport,
+ struct bfa_fcs_s *fcs, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vport_s *vport_drv);
+bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport);
+bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport);
+bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
+ struct bfa_vport_attr_s *vport_attr);
+void bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
+ struct bfa_vport_stats_s *vport_stats);
+void bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport);
+struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs,
+ u16 vf_id, wwn_t vpwwn);
+
+#endif /* __BFA_FCS_VPORT_H__ */
diff --git a/drivers/scsi/bfa/include/log/bfa_log_fcs.h b/drivers/scsi/bfa/include/log/bfa_log_fcs.h
new file mode 100644
index 000000000000..b6f5df8827f8
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_fcs.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/*
+ * messages define for FCS Module
+ */
+#ifndef __BFA_LOG_FCS_H__
+#define __BFA_LOG_FCS_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_FCS_FABRIC_NOSWITCH \
+ (((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_FCS_FABRIC_ISOLATED \
+ (((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 2)
+#endif
diff --git a/drivers/scsi/bfa/include/log/bfa_log_hal.h b/drivers/scsi/bfa/include/log/bfa_log_hal.h
new file mode 100644
index 000000000000..0412aea2ec30
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_hal.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for HAL Module */
+#ifndef __BFA_LOG_HAL_H__
+#define __BFA_LOG_HAL_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_HAL_ASSERT \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_HAL_HEARTBEAT_FAILURE \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 2)
+#define BFA_LOG_HAL_FCPIM_PARM_INVALID \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 3)
+#define BFA_LOG_HAL_SM_ASSERT \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 4)
+#endif
diff --git a/drivers/scsi/bfa/include/log/bfa_log_linux.h b/drivers/scsi/bfa/include/log/bfa_log_linux.h
new file mode 100644
index 000000000000..317c0547ee16
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_linux.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/* messages define for LINUX Module */
+#ifndef __BFA_LOG_LINUX_H__
+#define __BFA_LOG_LINUX_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_LINUX_DEVICE_CLAIMED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_LINUX_HASH_INIT_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 2)
+#define BFA_LOG_LINUX_SYSFS_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 3)
+#define BFA_LOG_LINUX_MEM_ALLOC_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 4)
+#define BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 5)
+#define BFA_LOG_LINUX_ITNIM_FREE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 6)
+#define BFA_LOG_LINUX_ITNIM_ONLINE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 7)
+#define BFA_LOG_LINUX_ITNIM_OFFLINE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 8)
+#define BFA_LOG_LINUX_SCSI_HOST_FREE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 9)
+#define BFA_LOG_LINUX_SCSI_ABORT \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 10)
+#define BFA_LOG_LINUX_SCSI_ABORT_COMP \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 11)
+#endif
diff --git a/drivers/scsi/bfa/include/log/bfa_log_wdrv.h b/drivers/scsi/bfa/include/log/bfa_log_wdrv.h
new file mode 100644
index 000000000000..809a95f7afe2
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_wdrv.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/*
+ * messages define for WDRV Module
+ */
+#ifndef __BFA_LOG_WDRV_H__
+#define __BFA_LOG_WDRV_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_WDRV_IOC_INIT_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_WDRV_IOC_INTERNAL_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 2)
+#define BFA_LOG_WDRV_IOC_START_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 3)
+#define BFA_LOG_WDRV_IOC_STOP_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 4)
+#define BFA_LOG_WDRV_INSUFFICIENT_RESOURCES \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 5)
+#define BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 6)
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/ct.h b/drivers/scsi/bfa/include/protocol/ct.h
new file mode 100644
index 000000000000..c59d6630b070
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/ct.h
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __CT_H__
+#define __CT_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+struct ct_hdr_s{
+ u32 rev_id:8; /* Revision of the CT */
+ u32 in_id:24; /* Initiator Id */
+ u32 gs_type:8; /* Generic service Type */
+ u32 gs_sub_type:8; /* Generic service sub type */
+ u32 options:8; /* options */
+ u32 rsvrd:8; /* reserved */
+ u32 cmd_rsp_code:16;/* ct command/response code */
+ u32 max_res_size:16;/* maximum/residual size */
+ u32 frag_id:8; /* fragment ID */
+ u32 reason_code:8; /* reason code */
+ u32 exp_code:8; /* explanation code */
+ u32 vendor_unq:8; /* vendor unique */
+};
+
+/*
+ * defines for the Revision
+ */
+enum {
+ CT_GS3_REVISION = 0x01,
+};
+
+/*
+ * defines for gs_type
+ */
+enum {
+ CT_GSTYPE_KEYSERVICE = 0xF7,
+ CT_GSTYPE_ALIASSERVICE = 0xF8,
+ CT_GSTYPE_MGMTSERVICE = 0xFA,
+ CT_GSTYPE_TIMESERVICE = 0xFB,
+ CT_GSTYPE_DIRSERVICE = 0xFC,
+};
+
+/*
+ * defines for gs_sub_type for gs type directory service
+ */
+enum {
+ CT_GSSUBTYPE_NAMESERVER = 0x02,
+};
+
+/*
+ * defines for gs_sub_type for gs type management service
+ */
+enum {
+ CT_GSSUBTYPE_CFGSERVER = 0x01,
+ CT_GSSUBTYPE_UNZONED_NS = 0x02,
+ CT_GSSUBTYPE_ZONESERVER = 0x03,
+ CT_GSSUBTYPE_LOCKSERVER = 0x04,
+ CT_GSSUBTYPE_HBA_MGMTSERVER = 0x10, /* for FDMI */
+};
+
+/*
+ * defines for CT response code field
+ */
+enum {
+ CT_RSP_REJECT = 0x8001,
+ CT_RSP_ACCEPT = 0x8002,
+};
+
+/*
+ * defintions for CT reason code
+ */
+enum {
+ CT_RSN_INV_CMD = 0x01,
+ CT_RSN_INV_VER = 0x02,
+ CT_RSN_LOGIC_ERR = 0x03,
+ CT_RSN_INV_SIZE = 0x04,
+ CT_RSN_LOGICAL_BUSY = 0x05,
+ CT_RSN_PROTO_ERR = 0x07,
+ CT_RSN_UNABLE_TO_PERF = 0x09,
+ CT_RSN_NOT_SUPP = 0x0B,
+ CT_RSN_SERVER_NOT_AVBL = 0x0D,
+ CT_RSN_SESSION_COULD_NOT_BE_ESTBD = 0x0E,
+ CT_RSN_VENDOR_SPECIFIC = 0xFF,
+
+};
+
+/*
+ * definitions for explanations code for Name server
+ */
+enum {
+ CT_NS_EXP_NOADDITIONAL = 0x00,
+ CT_NS_EXP_ID_NOT_REG = 0x01,
+ CT_NS_EXP_PN_NOT_REG = 0x02,
+ CT_NS_EXP_NN_NOT_REG = 0x03,
+ CT_NS_EXP_CS_NOT_REG = 0x04,
+ CT_NS_EXP_IPN_NOT_REG = 0x05,
+ CT_NS_EXP_IPA_NOT_REG = 0x06,
+ CT_NS_EXP_FT_NOT_REG = 0x07,
+ CT_NS_EXP_SPN_NOT_REG = 0x08,
+ CT_NS_EXP_SNN_NOT_REG = 0x09,
+ CT_NS_EXP_PT_NOT_REG = 0x0A,
+ CT_NS_EXP_IPP_NOT_REG = 0x0B,
+ CT_NS_EXP_FPN_NOT_REG = 0x0C,
+ CT_NS_EXP_HA_NOT_REG = 0x0D,
+ CT_NS_EXP_FD_NOT_REG = 0x0E,
+ CT_NS_EXP_FF_NOT_REG = 0x0F,
+ CT_NS_EXP_ACCESSDENIED = 0x10,
+ CT_NS_EXP_UNACCEPTABLE_ID = 0x11,
+ CT_NS_EXP_DATABASEEMPTY = 0x12,
+ CT_NS_EXP_NOT_REG_IN_SCOPE = 0x13,
+ CT_NS_EXP_DOM_ID_NOT_PRESENT = 0x14,
+ CT_NS_EXP_PORT_NUM_NOT_PRESENT = 0x15,
+ CT_NS_EXP_NO_DEVICE_ATTACHED = 0x16
+};
+
+/*
+ * defintions for the explanation code for all servers
+ */
+enum {
+ CT_EXP_AUTH_EXCEPTION = 0xF1,
+ CT_EXP_DB_FULL = 0xF2,
+ CT_EXP_DB_EMPTY = 0xF3,
+ CT_EXP_PROCESSING_REQ = 0xF4,
+ CT_EXP_UNABLE_TO_VERIFY_CONN = 0xF5,
+ CT_EXP_DEVICES_NOT_IN_CMN_ZONE = 0xF6
+};
+
+/*
+ * Command codes for Name server
+ */
+enum {
+ GS_GID_PN = 0x0121, /* Get Id on port name */
+ GS_GPN_ID = 0x0112, /* Get port name on ID */
+ GS_GNN_ID = 0x0113, /* Get node name on ID */
+ GS_GID_FT = 0x0171, /* Get Id on FC4 type */
+ GS_GSPN_ID = 0x0118, /* Get symbolic PN on ID */
+ GS_RFT_ID = 0x0217, /* Register fc4type on ID */
+ GS_RSPN_ID = 0x0218, /* Register symbolic PN on ID */
+ GS_RPN_ID = 0x0212, /* Register port name */
+ GS_RNN_ID = 0x0213, /* Register node name */
+ GS_RCS_ID = 0x0214, /* Register class of service */
+ GS_RPT_ID = 0x021A, /* Register port type */
+ GS_GA_NXT = 0x0100, /* Get all next */
+ GS_RFF_ID = 0x021F, /* Register FC4 Feature */
+};
+
+struct fcgs_id_req_s{
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+};
+#define fcgs_gpnid_req_t struct fcgs_id_req_s
+#define fcgs_gnnid_req_t struct fcgs_id_req_s
+#define fcgs_gspnid_req_t struct fcgs_id_req_s
+
+struct fcgs_gidpn_req_s{
+ wwn_t port_name; /* port wwn */
+};
+
+struct fcgs_gidpn_resp_s{
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+};
+
+/**
+ * RFT_ID
+ */
+struct fcgs_rftid_req_s {
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+ u32 fc4_type[8]; /* fc4 types */
+};
+
+/**
+ * RFF_ID : Register FC4 features.
+ */
+
+#define FC_GS_FCP_FC4_FEATURE_INITIATOR 0x02
+#define FC_GS_FCP_FC4_FEATURE_TARGET 0x01
+
+struct fcgs_rffid_req_s{
+ u32 rsvd :8;
+ u32 dap :24; /* port identifier */
+ u32 rsvd1 :16;
+ u32 fc4ftr_bits :8; /* fc4 feature bits */
+ u32 fc4_type :8; /* corresponding FC4 Type */
+};
+
+/**
+ * GID_FT Request
+ */
+struct fcgs_gidft_req_s{
+ u8 reserved;
+ u8 domain_id; /* domain, 0 - all fabric */
+ u8 area_id; /* area, 0 - whole domain */
+ u8 fc4_type; /* FC_TYPE_FCP for SCSI devices */
+}; /* GID_FT Request */
+
+/**
+ * GID_FT Response
+ */
+struct fcgs_gidft_resp_s {
+ u8 last:1; /* last port identifier flag */
+ u8 reserved:7;
+ u32 pid:24; /* port identifier */
+}; /* GID_FT Response */
+
+/**
+ * RSPN_ID
+ */
+struct fcgs_rspnid_req_s{
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+ u8 spn_len; /* symbolic port name length */
+ u8 spn[256]; /* symbolic port name */
+};
+
+/**
+ * RPN_ID
+ */
+struct fcgs_rpnid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ wwn_t port_name;
+};
+
+/**
+ * RNN_ID
+ */
+struct fcgs_rnnid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ wwn_t node_name;
+};
+
+/**
+ * RCS_ID
+ */
+struct fcgs_rcsid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ u32 cos;
+};
+
+/**
+ * RPT_ID
+ */
+struct fcgs_rptid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ u32 port_type:8;
+ u32 rsvd1:24;
+};
+
+/**
+ * GA_NXT Request
+ */
+struct fcgs_ganxt_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+};
+
+/**
+ * GA_NXT Response
+ */
+struct fcgs_ganxt_rsp_s{
+ u32 port_type:8; /* Port Type */
+ u32 port_id:24; /* Port Identifier */
+ wwn_t port_name; /* Port Name */
+ u8 spn_len; /* Length of Symbolic Port Name */
+ char spn[255]; /* Symbolic Port Name */
+ wwn_t node_name; /* Node Name */
+ u8 snn_len; /* Length of Symbolic Node Name */
+ char snn[255]; /* Symbolic Node Name */
+ u8 ipa[8]; /* Initial Process Associator */
+ u8 ip[16]; /* IP Address */
+ u32 cos; /* Class of Service */
+ u32 fc4types[8]; /* FC-4 TYPEs */
+ wwn_t fabric_port_name;
+ /* Fabric Port Name */
+ u32 rsvd:8; /* Reserved */
+ u32 hard_addr:24; /* Hard Address */
+};
+
+/*
+ * Fabric Config Server
+ */
+
+/*
+ * Command codes for Fabric Configuration Server
+ */
+enum {
+ GS_FC_GFN_CMD = 0x0114, /* GS FC Get Fabric Name */
+ GS_FC_GMAL_CMD = 0x0116, /* GS FC GMAL */
+ GS_FC_TRACE_CMD = 0x0400, /* GS FC Trace Route */
+ GS_FC_PING_CMD = 0x0401, /* GS FC Ping */
+};
+
+/*
+ * Source or Destination Port Tags.
+ */
+enum {
+ GS_FTRACE_TAG_NPORT_ID = 1,
+ GS_FTRACE_TAG_NPORT_NAME = 2,
+};
+
+/*
+* Port Value : Could be a Port id or wwn
+ */
+union fcgs_port_val_u{
+ u32 nport_id;
+ wwn_t nport_wwn;
+};
+
+#define GS_FTRACE_MAX_HOP_COUNT 20
+#define GS_FTRACE_REVISION 1
+
+/*
+ * Ftrace Related Structures.
+ */
+
+/*
+ * STR (Switch Trace) Reject Reason Codes. From FC-SW.
+ */
+enum {
+ GS_FTRACE_STR_CMD_COMPLETED_SUCC = 0,
+ GS_FTRACE_STR_CMD_NOT_SUPP_IN_NEXT_SWITCH,
+ GS_FTRACE_STR_NO_RESP_FROM_NEXT_SWITCH,
+ GS_FTRACE_STR_MAX_HOP_CNT_REACHED,
+ GS_FTRACE_STR_SRC_PORT_NOT_FOUND,
+ GS_FTRACE_STR_DST_PORT_NOT_FOUND,
+ GS_FTRACE_STR_DEVICES_NOT_IN_COMMON_ZONE,
+ GS_FTRACE_STR_NO_ROUTE_BW_PORTS,
+ GS_FTRACE_STR_NO_ADDL_EXPLN,
+ GS_FTRACE_STR_FABRIC_BUSY,
+ GS_FTRACE_STR_FABRIC_BUILD_IN_PROGRESS,
+ GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_START = 0xf0,
+ GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_END = 0xff,
+};
+
+/*
+ * Ftrace Request
+ */
+struct fcgs_ftrace_req_s{
+ u32 revision;
+ u16 src_port_tag; /* Source Port tag */
+ u16 src_port_len; /* Source Port len */
+ union fcgs_port_val_u src_port_val; /* Source Port value */
+ u16 dst_port_tag; /* Destination Port tag */
+ u16 dst_port_len; /* Destination Port len */
+ union fcgs_port_val_u dst_port_val; /* Destination Port value */
+ u32 token;
+ u8 vendor_id[8]; /* T10 Vendor Identifier */
+ u8 vendor_info[8]; /* Vendor specific Info */
+ u32 max_hop_cnt; /* Max Hop Count */
+};
+
+/*
+ * Path info structure
+ */
+struct fcgs_ftrace_path_info_s{
+ wwn_t switch_name; /* Switch WWN */
+ u32 domain_id;
+ wwn_t ingress_port_name; /* Ingress ports wwn */
+ u32 ingress_phys_port_num; /* Ingress ports physical port
+ * number
+ */
+ wwn_t egress_port_name; /* Ingress ports wwn */
+ u32 egress_phys_port_num; /* Ingress ports physical port
+ * number
+ */
+};
+
+/*
+ * Ftrace Acc Response
+ */
+struct fcgs_ftrace_resp_s{
+ u32 revision;
+ u32 token;
+ u8 vendor_id[8]; /* T10 Vendor Identifier */
+ u8 vendor_info[8]; /* Vendor specific Info */
+ u32 str_rej_reason_code; /* STR Reject Reason Code */
+ u32 num_path_info_entries; /* No. of path info entries */
+ /*
+ * path info entry/entries.
+ */
+ struct fcgs_ftrace_path_info_s path_info[1];
+
+};
+
+/*
+* Fabric Config Server : FCPing
+ */
+
+/*
+ * FC Ping Request
+ */
+struct fcgs_fcping_req_s{
+ u32 revision;
+ u16 port_tag;
+ u16 port_len; /* Port len */
+ union fcgs_port_val_u port_val; /* Port value */
+ u32 token;
+};
+
+/*
+ * FC Ping Response
+ */
+struct fcgs_fcping_resp_s{
+ u32 token;
+};
+
+/*
+ * Command codes for zone server query.
+ */
+enum {
+ ZS_GZME = 0x0124, /* Get zone member extended */
+};
+
+/*
+ * ZS GZME request
+ */
+#define ZS_GZME_ZNAMELEN 32
+struct zs_gzme_req_s{
+ u8 znamelen;
+ u8 rsvd[3];
+ u8 zname[ZS_GZME_ZNAMELEN];
+};
+
+enum zs_mbr_type{
+ ZS_MBR_TYPE_PWWN = 1,
+ ZS_MBR_TYPE_DOMPORT = 2,
+ ZS_MBR_TYPE_PORTID = 3,
+ ZS_MBR_TYPE_NWWN = 4,
+};
+
+struct zs_mbr_wwn_s{
+ u8 mbr_type;
+ u8 rsvd[3];
+ wwn_t wwn;
+};
+
+struct zs_query_resp_s{
+ u32 nmbrs; /* number of zone members */
+ struct zs_mbr_wwn_s mbr[1];
+};
+
+/*
+ * GMAL Command ( Get ( interconnect Element) Management Address List)
+ * To retrieve the IP Address of a Switch.
+ */
+
+#define CT_GMAL_RESP_PREFIX_TELNET "telnet://"
+#define CT_GMAL_RESP_PREFIX_HTTP "http://"
+
+/* GMAL/GFN request */
+struct fcgs_req_s {
+ wwn_t wwn; /* PWWN/NWWN */
+};
+
+#define fcgs_gmal_req_t struct fcgs_req_s
+#define fcgs_gfn_req_t struct fcgs_req_s
+
+/* Accept Response to GMAL */
+struct fcgs_gmal_resp_s {
+ u32 ms_len; /* Num of entries */
+ u8 ms_ma[256];
+};
+
+struct fc_gmal_entry_s {
+ u8 len;
+ u8 prefix[7]; /* like "http://" */
+ u8 ip_addr[248];
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h
new file mode 100644
index 000000000000..3e39ba58cfb5
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fc.h
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __FC_H__
+#define __FC_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+/*
+ * Fibre Channel Header Structure (FCHS) definition
+ */
+struct fchs_s {
+#ifdef __BIGENDIAN
+ u32 routing:4; /* routing bits */
+ u32 cat_info:4; /* category info */
+#else
+ u32 cat_info:4; /* category info */
+ u32 routing:4; /* routing bits */
+#endif
+ u32 d_id:24; /* destination identifier */
+
+ u32 cs_ctl:8; /* class specific control */
+ u32 s_id:24; /* source identifier */
+
+ u32 type:8; /* data structure type */
+ u32 f_ctl:24; /* initial frame control */
+
+ u8 seq_id; /* sequence identifier */
+ u8 df_ctl; /* data field control */
+ u16 seq_cnt; /* sequence count */
+
+ u16 ox_id; /* originator exchange ID */
+ u16 rx_id; /* responder exchange ID */
+
+ u32 ro; /* relative offset */
+};
+/*
+ * Fibre Channel BB_E Header Structure
+ */
+struct fcbbehs_s {
+ u16 ver_rsvd;
+ u32 rsvd[2];
+ u32 rsvd__sof;
+};
+
+#define FC_SEQ_ID_MAX 256
+
+/*
+ * routing bit definitions
+ */
+enum {
+ FC_RTG_FC4_DEV_DATA = 0x0, /* FC-4 Device Data */
+ FC_RTG_EXT_LINK = 0x2, /* Extended Link Data */
+ FC_RTG_FC4_LINK_DATA = 0x3, /* FC-4 Link Data */
+ FC_RTG_VIDEO_DATA = 0x4, /* Video Data */
+ FC_RTG_EXT_HDR = 0x5, /* VFT, IFR or Encapsuled */
+ FC_RTG_BASIC_LINK = 0x8, /* Basic Link data */
+ FC_RTG_LINK_CTRL = 0xC, /* Link Control */
+};
+
+/*
+ * information category for extended link data and FC-4 Link Data
+ */
+enum {
+ FC_CAT_LD_REQUEST = 0x2, /* Request */
+ FC_CAT_LD_REPLY = 0x3, /* Reply */
+ FC_CAT_LD_DIAG = 0xF, /* for DIAG use only */
+};
+
+/*
+ * information category for extended headers (VFT, IFR or encapsulation)
+ */
+enum {
+ FC_CAT_VFT_HDR = 0x0, /* Virtual fabric tagging header */
+ FC_CAT_IFR_HDR = 0x1, /* Inter-Fabric routing header */
+ FC_CAT_ENC_HDR = 0x2, /* Encapsulation header */
+};
+
+/*
+ * information category for FC-4 device data
+ */
+enum {
+ FC_CAT_UNCATEG_INFO = 0x0, /* Uncategorized information */
+ FC_CAT_SOLICIT_DATA = 0x1, /* Solicited Data */
+ FC_CAT_UNSOLICIT_CTRL = 0x2, /* Unsolicited Control */
+ FC_CAT_SOLICIT_CTRL = 0x3, /* Solicited Control */
+ FC_CAT_UNSOLICIT_DATA = 0x4, /* Unsolicited Data */
+ FC_CAT_DATA_DESC = 0x5, /* Data Descriptor */
+ FC_CAT_UNSOLICIT_CMD = 0x6, /* Unsolicited Command */
+ FC_CAT_CMD_STATUS = 0x7, /* Command Status */
+};
+
+/*
+ * information category for Link Control
+ */
+enum {
+ FC_CAT_ACK_1 = 0x00,
+ FC_CAT_ACK_0_N = 0x01,
+ FC_CAT_P_RJT = 0x02,
+ FC_CAT_F_RJT = 0x03,
+ FC_CAT_P_BSY = 0x04,
+ FC_CAT_F_BSY_DATA = 0x05,
+ FC_CAT_F_BSY_LINK_CTL = 0x06,
+ FC_CAT_F_LCR = 0x07,
+ FC_CAT_NTY = 0x08,
+ FC_CAT_END = 0x09,
+};
+
+/*
+ * Type Field Definitions. FC-PH Section 18.5 pg. 165
+ */
+enum {
+ FC_TYPE_BLS = 0x0, /* Basic Link Service */
+ FC_TYPE_ELS = 0x1, /* Extended Link Service */
+ FC_TYPE_IP = 0x5, /* IP */
+ FC_TYPE_FCP = 0x8, /* SCSI-FCP */
+ FC_TYPE_GPP = 0x9, /* SCSI_GPP */
+ FC_TYPE_SERVICES = 0x20, /* Fibre Channel Services */
+ FC_TYPE_FC_FSS = 0x22, /* Fabric Switch Services */
+ FC_TYPE_FC_AL = 0x23, /* FC-AL */
+ FC_TYPE_FC_SNMP = 0x24, /* FC-SNMP */
+ FC_TYPE_MAX = 256, /* 256 FC-4 types */
+};
+
+struct fc_fc4types_s{
+ u8 bits[FC_TYPE_MAX / 8];
+};
+
+/*
+ * Frame Control Definitions. FC-PH Table-45. pg. 168
+ */
+enum {
+ FCTL_EC_ORIG = 0x000000, /* exchange originator */
+ FCTL_EC_RESP = 0x800000, /* exchange responder */
+ FCTL_SEQ_INI = 0x000000, /* sequence initiator */
+ FCTL_SEQ_REC = 0x400000, /* sequence recipient */
+ FCTL_FS_EXCH = 0x200000, /* first sequence of xchg */
+ FCTL_LS_EXCH = 0x100000, /* last sequence of xchg */
+ FCTL_END_SEQ = 0x080000, /* last frame of sequence */
+ FCTL_SI_XFER = 0x010000, /* seq initiative transfer */
+ FCTL_RO_PRESENT = 0x000008, /* relative offset present */
+ FCTL_FILLBYTE_MASK = 0x000003 /* , fill byte mask */
+};
+
+/*
+ * Fabric Well Known Addresses
+ */
+enum {
+ FC_MIN_WELL_KNOWN_ADDR = 0xFFFFF0,
+ FC_DOMAIN_CONTROLLER_MASK = 0xFFFC00,
+ FC_ALIAS_SERVER = 0xFFFFF8,
+ FC_MGMT_SERVER = 0xFFFFFA,
+ FC_TIME_SERVER = 0xFFFFFB,
+ FC_NAME_SERVER = 0xFFFFFC,
+ FC_FABRIC_CONTROLLER = 0xFFFFFD,
+ FC_FABRIC_PORT = 0xFFFFFE,
+ FC_BROADCAST_SERVER = 0xFFFFFF
+};
+
+/*
+ * domain/area/port defines
+ */
+#define FC_DOMAIN_MASK 0xFF0000
+#define FC_DOMAIN_SHIFT 16
+#define FC_AREA_MASK 0x00FF00
+#define FC_AREA_SHIFT 8
+#define FC_PORT_MASK 0x0000FF
+#define FC_PORT_SHIFT 0
+
+#define FC_GET_DOMAIN(p) (((p) & FC_DOMAIN_MASK) >> FC_DOMAIN_SHIFT)
+#define FC_GET_AREA(p) (((p) & FC_AREA_MASK) >> FC_AREA_SHIFT)
+#define FC_GET_PORT(p) (((p) & FC_PORT_MASK) >> FC_PORT_SHIFT)
+
+#define FC_DOMAIN_CTRLR(p) (FC_DOMAIN_CONTROLLER_MASK | (FC_GET_DOMAIN(p)))
+
+enum {
+ FC_RXID_ANY = 0xFFFFU,
+};
+
+/*
+ * generic ELS command
+ */
+struct fc_els_cmd_s{
+ u32 els_code:8; /* ELS Command Code */
+ u32 reserved:24;
+};
+
+/*
+ * ELS Command Codes. FC-PH Table-75. pg. 223
+ */
+enum {
+ FC_ELS_LS_RJT = 0x1, /* Link Service Reject. */
+ FC_ELS_ACC = 0x02, /* Accept */
+ FC_ELS_PLOGI = 0x03, /* N_Port Login. */
+ FC_ELS_FLOGI = 0x04, /* F_Port Login. */
+ FC_ELS_LOGO = 0x05, /* Logout. */
+ FC_ELS_ABTX = 0x06, /* Abort Exchange */
+ FC_ELS_RES = 0x08, /* Read Exchange status */
+ FC_ELS_RSS = 0x09, /* Read sequence status block */
+ FC_ELS_RSI = 0x0A, /* Request Sequence Initiative */
+ FC_ELS_ESTC = 0x0C, /* Estimate Credit. */
+ FC_ELS_RTV = 0x0E, /* Read Timeout Value. */
+ FC_ELS_RLS = 0x0F, /* Read Link Status. */
+ FC_ELS_ECHO = 0x10, /* Echo */
+ FC_ELS_TEST = 0x11, /* Test */
+ FC_ELS_RRQ = 0x12, /* Reinstate Recovery Qualifier. */
+ FC_ELS_REC = 0x13, /* Add this for TAPE support in FCR */
+ FC_ELS_PRLI = 0x20, /* Process Login */
+ FC_ELS_PRLO = 0x21, /* Process Logout. */
+ FC_ELS_SCN = 0x22, /* State Change Notification. */
+ FC_ELS_TPRLO = 0x24, /* Third Party Process Logout. */
+ FC_ELS_PDISC = 0x50, /* Discover N_Port Parameters. */
+ FC_ELS_FDISC = 0x51, /* Discover F_Port Parameters. */
+ FC_ELS_ADISC = 0x52, /* Discover Address. */
+ FC_ELS_FAN = 0x60, /* Fabric Address Notification */
+ FC_ELS_RSCN = 0x61, /* Reg State Change Notification */
+ FC_ELS_SCR = 0x62, /* State Change Registration. */
+ FC_ELS_RTIN = 0x77, /* Mangement server request */
+ FC_ELS_RNID = 0x78, /* Mangement server request */
+ FC_ELS_RLIR = 0x79, /* Registered Link Incident Record */
+
+ FC_ELS_RPSC = 0x7D, /* Report Port Speed Capabilities */
+ FC_ELS_QSA = 0x7E, /* Query Security Attributes. Ref FC-SP */
+ FC_ELS_E2E_LBEACON = 0x81,
+ /* End-to-End Link Beacon */
+ FC_ELS_AUTH = 0x90, /* Authentication. Ref FC-SP */
+ FC_ELS_RFCN = 0x97, /* Request Fabric Change Notification. Ref
+ *FC-SP */
+
+};
+
+/*
+ * Version numbers for FC-PH standards,
+ * used in login to indicate what port
+ * supports. See FC-PH-X table 158.
+ */
+enum {
+ FC_PH_VER_4_3 = 0x09,
+ FC_PH_VER_PH_3 = 0x20,
+};
+
+/*
+ * PDU size defines
+ */
+enum {
+ FC_MIN_PDUSZ = 512,
+ FC_MAX_PDUSZ = 2112,
+};
+
+/*
+ * N_Port PLOGI Common Service Parameters.
+ * FC-PH-x. Figure-76. pg. 308.
+ */
+struct fc_plogi_csp_s{
+ u8 verhi; /* FC-PH high version */
+ u8 verlo; /* FC-PH low version */
+ u16 bbcred; /* BB_Credit */
+
+#ifdef __BIGENDIAN
+ u8 ciro:1, /* continuously increasing RO */
+ rro:1, /* random relative offset */
+ npiv_supp:1, /* NPIV supported */
+ port_type:1, /* N_Port/F_port */
+ altbbcred:1, /* alternate BB_Credit */
+ resolution:1, /* ms/ns ED_TOV resolution */
+ vvl_info:1, /* VVL Info included */
+ reserved1:1;
+
+ u8 hg_supp:1,
+ query_dbc:1,
+ security:1,
+ sync_cap:1,
+ r_t_tov:1,
+ dh_dup_supp:1,
+ cisc:1, /* continuously increasing seq count */
+ payload:1;
+#else
+ u8 reserved2:2,
+ resolution:1, /* ms/ns ED_TOV resolution */
+ altbbcred:1, /* alternate BB_Credit */
+ port_type:1, /* N_Port/F_port */
+ npiv_supp:1, /* NPIV supported */
+ rro:1, /* random relative offset */
+ ciro:1; /* continuously increasing RO */
+
+ u8 payload:1,
+ cisc:1, /* continuously increasing seq count */
+ dh_dup_supp:1,
+ r_t_tov:1,
+ sync_cap:1,
+ security:1,
+ query_dbc:1,
+ hg_supp:1;
+#endif
+
+ u16 rxsz; /* recieve data_field size */
+
+ u16 conseq;
+ u16 ro_bitmap;
+
+ u32 e_d_tov;
+};
+
+/*
+ * N_Port PLOGI Class Specific Parameters.
+ * FC-PH-x. Figure 78. pg. 318.
+ */
+struct fc_plogi_clp_s{
+#ifdef __BIGENDIAN
+ u32 class_valid:1;
+ u32 intermix:1; /* class intermix supported if set =1.
+ * valid only for class1. Reserved for
+ * class2 & class3
+ */
+ u32 reserved1:2;
+ u32 sequential:1;
+ u32 reserved2:3;
+#else
+ u32 reserved2:3;
+ u32 sequential:1;
+ u32 reserved1:2;
+ u32 intermix:1; /* class intermix supported if set =1.
+ * valid only for class1. Reserved for
+ * class2 & class3
+ */
+ u32 class_valid:1;
+#endif
+
+ u32 reserved3:24;
+
+ u32 reserved4:16;
+ u32 rxsz:16; /* Receive data_field size */
+
+ u32 reserved5:8;
+ u32 conseq:8;
+ u32 e2e_credit:16; /* end to end credit */
+
+ u32 reserved7:8;
+ u32 ospx:8;
+ u32 reserved8:16;
+};
+
+#define FLOGI_VVL_BRCD 0x42524344 /* ASCII value for each character in
+ * string "BRCD" */
+
+/*
+ * PLOGI els command and reply payload
+ */
+struct fc_logi_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ struct fc_plogi_csp_s csp; /* common service params */
+ wwn_t port_name;
+ wwn_t node_name;
+ struct fc_plogi_clp_s class1; /* class 1 service parameters */
+ struct fc_plogi_clp_s class2; /* class 2 service parameters */
+ struct fc_plogi_clp_s class3; /* class 3 service parameters */
+ struct fc_plogi_clp_s class4; /* class 4 service parameters */
+ u8 vvl[16]; /* vendor version level */
+};
+
+/*
+ * LOGO els command payload
+ */
+struct fc_logo_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 nport_id:24; /* N_Port identifier of source */
+ wwn_t orig_port_name; /* Port name of the LOGO originator */
+};
+
+/*
+ * ADISC els command payload
+ */
+struct fc_adisc_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 orig_HA:24; /* originator hard address */
+ wwn_t orig_port_name; /* originator port name */
+ wwn_t orig_node_name; /* originator node name */
+ u32 res2:8;
+ u32 nport_id:24; /* originator NPortID */
+};
+
+/*
+ * Exchange status block
+ */
+struct fc_exch_status_blk_s{
+ u32 oxid:16;
+ u32 rxid:16;
+ u32 res1:8;
+ u32 orig_np:24; /* originator NPortID */
+ u32 res2:8;
+ u32 resp_np:24; /* responder NPortID */
+ u32 es_bits;
+ u32 res3;
+ /*
+ * un modified section of the fields
+ */
+};
+
+/*
+ * RES els command payload
+ */
+struct fc_res_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 nport_id:24; /* N_Port identifier of source */
+ u32 oxid:16;
+ u32 rxid:16;
+ u8 assoc_hdr[32];
+};
+
+/*
+ * RES els accept payload
+ */
+struct fc_res_acc_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ struct fc_exch_status_blk_s fc_exch_blk; /* Exchange status block */
+};
+
+/*
+ * REC els command payload
+ */
+struct fc_rec_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 nport_id:24; /* N_Port identifier of source */
+ u32 oxid:16;
+ u32 rxid:16;
+};
+
+#define FC_REC_ESB_OWN_RSP 0x80000000 /* responder owns */
+#define FC_REC_ESB_SI 0x40000000 /* SI is owned */
+#define FC_REC_ESB_COMP 0x20000000 /* exchange is complete */
+#define FC_REC_ESB_ENDCOND_ABN 0x10000000 /* abnormal ending */
+#define FC_REC_ESB_RQACT 0x04000000 /* recovery qual active */
+#define FC_REC_ESB_ERRP_MSK 0x03000000
+#define FC_REC_ESB_OXID_INV 0x00800000 /* invalid OXID */
+#define FC_REC_ESB_RXID_INV 0x00400000 /* invalid RXID */
+#define FC_REC_ESB_PRIO_INUSE 0x00200000
+
+/*
+ * REC els accept payload
+ */
+struct fc_rec_acc_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 oxid:16;
+ u32 rxid:16;
+ u32 res1:8;
+ u32 orig_id:24; /* N_Port id of exchange originator */
+ u32 res2:8;
+ u32 resp_id:24; /* N_Port id of exchange responder */
+ u32 count; /* data transfer count */
+ u32 e_stat; /* exchange status */
+};
+
+/*
+ * RSI els payload
+ */
+struct fc_rsi_s {
+ struct fc_els_cmd_s els_cmd;
+ u32 res1:8;
+ u32 orig_sid:24;
+ u32 oxid:16;
+ u32 rxid:16;
+};
+
+/*
+ * structure for PRLI paramater pages, both request & response
+ * see FC-PH-X table 113 & 115 for explanation also FCP table 8
+ */
+struct fc_prli_params_s{
+ u32 reserved: 16;
+#ifdef __BIGENDIAN
+ u32 reserved1: 5;
+ u32 rec_support : 1;
+ u32 task_retry_id : 1;
+ u32 retry : 1;
+
+ u32 confirm : 1;
+ u32 doverlay:1;
+ u32 initiator:1;
+ u32 target:1;
+ u32 cdmix:1;
+ u32 drmix:1;
+ u32 rxrdisab:1;
+ u32 wxrdisab:1;
+#else
+ u32 retry : 1;
+ u32 task_retry_id : 1;
+ u32 rec_support : 1;
+ u32 reserved1: 5;
+
+ u32 wxrdisab:1;
+ u32 rxrdisab:1;
+ u32 drmix:1;
+ u32 cdmix:1;
+ u32 target:1;
+ u32 initiator:1;
+ u32 doverlay:1;
+ u32 confirm : 1;
+#endif
+};
+
+/*
+ * valid values for rspcode in PRLI ACC payload
+ */
+enum {
+ FC_PRLI_ACC_XQTD = 0x1, /* request executed */
+ FC_PRLI_ACC_PREDEF_IMG = 0x5, /* predefined image - no prli needed */
+};
+
+struct fc_prli_params_page_s{
+ u32 type:8;
+ u32 codext:8;
+#ifdef __BIGENDIAN
+ u32 origprocasv:1;
+ u32 rsppav:1;
+ u32 imagepair:1;
+ u32 reserved1:1;
+ u32 rspcode:4;
+#else
+ u32 rspcode:4;
+ u32 reserved1:1;
+ u32 imagepair:1;
+ u32 rsppav:1;
+ u32 origprocasv:1;
+#endif
+ u32 reserved2:8;
+
+ u32 origprocas;
+ u32 rspprocas;
+ struct fc_prli_params_s servparams;
+};
+
+/*
+ * PRLI request and accept payload, FC-PH-X tables 112 & 114
+ */
+struct fc_prli_s{
+ u32 command:8;
+ u32 pglen:8;
+ u32 pagebytes:16;
+ struct fc_prli_params_page_s parampage;
+};
+
+/*
+ * PRLO logout params page
+ */
+struct fc_prlo_params_page_s{
+ u32 type:8;
+ u32 type_ext:8;
+#ifdef __BIGENDIAN
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 res1:14;
+#else
+ u32 res1:14;
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+#endif
+ u32 orig_process_assc;
+ u32 resp_process_assc;
+
+ u32 res2;
+};
+
+/*
+ * PRLO els command payload
+ */
+struct fc_prlo_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+ struct fc_prlo_params_page_s prlo_params[1];
+};
+
+/*
+ * PRLO Logout response parameter page
+ */
+struct fc_prlo_acc_params_page_s{
+ u32 type:8;
+ u32 type_ext:8;
+
+#ifdef __BIGENDIAN
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 res1:14;
+#else
+ u32 res1:14;
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+#endif
+ u32 orig_process_assc;
+ u32 resp_process_assc;
+
+ u32 fc4type_csp;
+};
+
+/*
+ * PRLO els command ACC payload
+ */
+struct fc_prlo_acc_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+ struct fc_prlo_acc_params_page_s prlo_acc_params[1];
+};
+
+/*
+ * SCR els command payload
+ */
+enum {
+ FC_SCR_REG_FUNC_FABRIC_DETECTED = 0x01,
+ FC_SCR_REG_FUNC_N_PORT_DETECTED = 0x02,
+ FC_SCR_REG_FUNC_FULL = 0x03,
+ FC_SCR_REG_FUNC_CLEAR_REG = 0xFF,
+};
+
+/* SCR VU registrations */
+enum {
+ FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE = 0x01
+};
+
+struct fc_scr_s{
+ u32 command:8;
+ u32 res:24;
+ u32 vu_reg_func:8; /* Vendor Unique Registrations */
+ u32 res1:16;
+ u32 reg_func:8;
+};
+
+/*
+ * Information category for Basic link data
+ */
+enum {
+ FC_CAT_NOP = 0x0,
+ FC_CAT_ABTS = 0x1,
+ FC_CAT_RMC = 0x2,
+ FC_CAT_BA_ACC = 0x4,
+ FC_CAT_BA_RJT = 0x5,
+ FC_CAT_PRMT = 0x6,
+};
+
+/*
+ * LS_RJT els reply payload
+ */
+struct fc_ls_rjt_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 reason_code:8; /* Reason code for reject */
+ u32 reason_code_expl:8; /* Reason code explanation */
+ u32 vendor_unique:8; /* Vendor specific */
+};
+
+/*
+ * LS_RJT reason codes
+ */
+enum {
+ FC_LS_RJT_RSN_INV_CMD_CODE = 0x01,
+ FC_LS_RJT_RSN_LOGICAL_ERROR = 0x03,
+ FC_LS_RJT_RSN_LOGICAL_BUSY = 0x05,
+ FC_LS_RJT_RSN_PROTOCOL_ERROR = 0x07,
+ FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD = 0x09,
+ FC_LS_RJT_RSN_CMD_NOT_SUPP = 0x0B,
+};
+
+/*
+ * LS_RJT reason code explanation
+ */
+enum {
+ FC_LS_RJT_EXP_NO_ADDL_INFO = 0x00,
+ FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS = 0x01,
+ FC_LS_RJT_EXP_SPARMS_ERR_INI_CTL = 0x03,
+ FC_LS_RJT_EXP_SPARMS_ERR_REC_CTL = 0x05,
+ FC_LS_RJT_EXP_SPARMS_ERR_RXSZ = 0x07,
+ FC_LS_RJT_EXP_SPARMS_ERR_CONSEQ = 0x09,
+ FC_LS_RJT_EXP_SPARMS_ERR_CREDIT = 0x0B,
+ FC_LS_RJT_EXP_INV_PORT_NAME = 0x0D,
+ FC_LS_RJT_EXP_INV_NODE_FABRIC_NAME = 0x0E,
+ FC_LS_RJT_EXP_INV_CSP = 0x0F,
+ FC_LS_RJT_EXP_INV_ASSOC_HDR = 0x11,
+ FC_LS_RJT_EXP_ASSOC_HDR_REQD = 0x13,
+ FC_LS_RJT_EXP_INV_ORIG_S_ID = 0x15,
+ FC_LS_RJT_EXP_INV_OXID_RXID_COMB = 0x17,
+ FC_LS_RJT_EXP_CMD_ALREADY_IN_PROG = 0x19,
+ FC_LS_RJT_EXP_LOGIN_REQUIRED = 0x1E,
+ FC_LS_RJT_EXP_INVALID_NPORT_ID = 0x1F,
+ FC_LS_RJT_EXP_INSUFF_RES = 0x29,
+ FC_LS_RJT_EXP_CMD_NOT_SUPP = 0x2C,
+ FC_LS_RJT_EXP_INV_PAYLOAD_LEN = 0x2D,
+};
+
+/*
+ * RRQ els command payload
+ */
+struct fc_rrq_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 s_id:24; /* exchange originator S_ID */
+
+ u32 ox_id:16; /* originator exchange ID */
+ u32 rx_id:16; /* responder exchange ID */
+
+ u32 res2[8]; /* optional association header */
+};
+
+/*
+ * ABTS BA_ACC reply payload
+ */
+struct fc_ba_acc_s{
+ u32 seq_id_valid:8; /* set to 0x00 for Abort Exchange */
+ u32 seq_id:8; /* invalid for Abort Exchange */
+ u32 res2:16;
+ u32 ox_id:16; /* OX_ID from ABTS frame */
+ u32 rx_id:16; /* RX_ID from ABTS frame */
+ u32 low_seq_cnt:16; /* set to 0x0000 for Abort Exchange */
+ u32 high_seq_cnt:16;/* set to 0xFFFF for Abort Exchange */
+};
+
+/*
+ * ABTS BA_RJT reject payload
+ */
+struct fc_ba_rjt_s{
+ u32 res1:8; /* Reserved */
+ u32 reason_code:8; /* reason code for reject */
+ u32 reason_expl:8; /* reason code explanation */
+ u32 vendor_unique:8;/* vendor unique reason code,set to 0 */
+};
+
+/*
+ * TPRLO logout parameter page
+ */
+struct fc_tprlo_params_page_s{
+ u32 type:8;
+ u32 type_ext:8;
+
+#ifdef __BIGENDIAN
+ u32 opa_valid:1;
+ u32 rpa_valid:1;
+ u32 tpo_nport_valid:1;
+ u32 global_process_logout:1;
+ u32 res1:12;
+#else
+ u32 res1:12;
+ u32 global_process_logout:1;
+ u32 tpo_nport_valid:1;
+ u32 rpa_valid:1;
+ u32 opa_valid:1;
+#endif
+
+ u32 orig_process_assc;
+ u32 resp_process_assc;
+
+ u32 res2:8;
+ u32 tpo_nport_id;
+};
+
+/*
+ * TPRLO ELS command payload
+ */
+struct fc_tprlo_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+
+ struct fc_tprlo_params_page_s tprlo_params[1];
+};
+
+enum fc_tprlo_type{
+ FC_GLOBAL_LOGO = 1,
+ FC_TPR_LOGO
+};
+
+/*
+ * TPRLO els command ACC payload
+ */
+struct fc_tprlo_acc_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+ struct fc_prlo_acc_params_page_s tprlo_acc_params[1];
+};
+
+/*
+ * RSCN els command req payload
+ */
+#define FC_RSCN_PGLEN 0x4
+
+enum fc_rscn_format{
+ FC_RSCN_FORMAT_PORTID = 0x0,
+ FC_RSCN_FORMAT_AREA = 0x1,
+ FC_RSCN_FORMAT_DOMAIN = 0x2,
+ FC_RSCN_FORMAT_FABRIC = 0x3,
+};
+
+struct fc_rscn_event_s{
+ u32 format:2;
+ u32 qualifier:4;
+ u32 resvd:2;
+ u32 portid:24;
+};
+
+struct fc_rscn_pl_s{
+ u8 command;
+ u8 pagelen;
+ u16 payldlen;
+ struct fc_rscn_event_s event[1];
+};
+
+/*
+ * ECHO els command req payload
+ */
+struct fc_echo_s {
+ struct fc_els_cmd_s els_cmd;
+};
+
+/*
+ * RNID els command
+ */
+
+#define RNID_NODEID_DATA_FORMAT_COMMON 0x00
+#define RNID_NODEID_DATA_FORMAT_FCP3 0x08
+#define RNID_NODEID_DATA_FORMAT_DISCOVERY 0xDF
+
+#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001
+#define RNID_ASSOCIATED_TYPE_OTHER 0x00000002
+#define RNID_ASSOCIATED_TYPE_HUB 0x00000003
+#define RNID_ASSOCIATED_TYPE_SWITCH 0x00000004
+#define RNID_ASSOCIATED_TYPE_GATEWAY 0x00000005
+#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE 0x00000009
+#define RNID_ASSOCIATED_TYPE_HOST 0x0000000A
+#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM 0x0000000B
+#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE 0x0000000E
+#define RNID_ASSOCIATED_TYPE_NAS_SERVER 0x00000011
+#define RNID_ASSOCIATED_TYPE_BRIDGE 0x00000002
+#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE 0x00000003
+#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE 0x000000FF
+
+/*
+ * RNID els command payload
+ */
+struct fc_rnid_cmd_s{
+ struct fc_els_cmd_s els_cmd;
+ u32 node_id_data_format:8;
+ u32 reserved:24;
+};
+
+/*
+ * RNID els response payload
+ */
+
+struct fc_rnid_common_id_data_s{
+ wwn_t port_name;
+ wwn_t node_name;
+};
+
+struct fc_rnid_general_topology_data_s{
+ u32 vendor_unique[4];
+ u32 asso_type;
+ u32 phy_port_num;
+ u32 num_attached_nodes;
+ u32 node_mgmt:8;
+ u32 ip_version:8;
+ u32 udp_tcp_port_num:16;
+ u32 ip_address[4];
+ u32 reserved:16;
+ u32 vendor_specific:16;
+};
+
+struct fc_rnid_acc_s{
+ struct fc_els_cmd_s els_cmd;
+ u32 node_id_data_format:8;
+ u32 common_id_data_length:8;
+ u32 reserved:8;
+ u32 specific_id_data_length:8;
+ struct fc_rnid_common_id_data_s common_id_data;
+ struct fc_rnid_general_topology_data_s gen_topology_data;
+};
+
+#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001
+#define RNID_ASSOCIATED_TYPE_OTHER 0x00000002
+#define RNID_ASSOCIATED_TYPE_HUB 0x00000003
+#define RNID_ASSOCIATED_TYPE_SWITCH 0x00000004
+#define RNID_ASSOCIATED_TYPE_GATEWAY 0x00000005
+#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE 0x00000009
+#define RNID_ASSOCIATED_TYPE_HOST 0x0000000A
+#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM 0x0000000B
+#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE 0x0000000E
+#define RNID_ASSOCIATED_TYPE_NAS_SERVER 0x00000011
+#define RNID_ASSOCIATED_TYPE_BRIDGE 0x00000002
+#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE 0x00000003
+#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE 0x000000FF
+
+enum fc_rpsc_speed_cap{
+ RPSC_SPEED_CAP_1G = 0x8000,
+ RPSC_SPEED_CAP_2G = 0x4000,
+ RPSC_SPEED_CAP_4G = 0x2000,
+ RPSC_SPEED_CAP_10G = 0x1000,
+ RPSC_SPEED_CAP_8G = 0x0800,
+ RPSC_SPEED_CAP_16G = 0x0400,
+
+ RPSC_SPEED_CAP_UNKNOWN = 0x0001,
+};
+
+enum fc_rpsc_op_speed_s{
+ RPSC_OP_SPEED_1G = 0x8000,
+ RPSC_OP_SPEED_2G = 0x4000,
+ RPSC_OP_SPEED_4G = 0x2000,
+ RPSC_OP_SPEED_10G = 0x1000,
+ RPSC_OP_SPEED_8G = 0x0800,
+ RPSC_OP_SPEED_16G = 0x0400,
+
+ RPSC_OP_SPEED_NOT_EST = 0x0001, /*! speed not established */
+};
+
+struct fc_rpsc_speed_info_s{
+ u16 port_speed_cap; /*! see fc_rpsc_speed_cap_t */
+ u16 port_op_speed; /*! see fc_rpsc_op_speed_t */
+};
+
+enum link_e2e_beacon_subcmd{
+ LINK_E2E_BEACON_ON = 1,
+ LINK_E2E_BEACON_OFF = 2
+};
+
+enum beacon_type{
+ BEACON_TYPE_NORMAL = 1, /*! Normal Beaconing. Green */
+ BEACON_TYPE_WARN = 2, /*! Warning Beaconing. Yellow/Amber */
+ BEACON_TYPE_CRITICAL = 3 /*! Critical Beaconing. Red */
+};
+
+struct link_e2e_beacon_param_s {
+ u8 beacon_type; /* Beacon Type. See beacon_type_t */
+ u8 beacon_frequency;
+ /* Beacon frequency. Number of blinks
+ * per 10 seconds
+ */
+ u16 beacon_duration;/* Beacon duration (in Seconds). The
+ * command operation should be
+ * terminated at the end of this
+ * timeout value.
+ *
+ * Ignored if diag_sub_cmd is
+ * LINK_E2E_BEACON_OFF.
+ *
+ * If 0, beaconing will continue till a
+ * BEACON OFF request is received
+ */
+};
+
+/*
+ * Link E2E beacon request/good response format. For LS_RJTs use fc_ls_rjt_t
+ */
+struct link_e2e_beacon_req_s{
+ u32 ls_code; /*! FC_ELS_E2E_LBEACON in requests *
+ *or FC_ELS_ACC in good replies */
+ u32 ls_sub_cmd; /*! See link_e2e_beacon_subcmd_t */
+ struct link_e2e_beacon_param_s beacon_parm;
+};
+
+/**
+ * If RPSC request is sent to the Domain Controller, the request is for
+ * all the ports within that domain (TODO - I don't think FOS implements
+ * this...).
+ */
+struct fc_rpsc_cmd_s{
+ struct fc_els_cmd_s els_cmd;
+};
+
+/*
+ * RPSC Acc
+ */
+struct fc_rpsc_acc_s{
+ u32 command:8;
+ u32 rsvd:8;
+ u32 num_entries:16;
+
+ struct fc_rpsc_speed_info_s speed_info[1];
+};
+
+/**
+ * If RPSC2 request is sent to the Domain Controller,
+ */
+#define FC_BRCD_TOKEN 0x42524344
+
+struct fc_rpsc2_cmd_s{
+ struct fc_els_cmd_s els_cmd;
+ u32 token;
+ u16 resvd;
+ u16 num_pids; /* Number of pids in the request */
+ struct {
+ u32 rsvd1:8;
+ u32 pid:24; /* port identifier */
+ } pid_list[1];
+};
+
+enum fc_rpsc2_port_type{
+ RPSC2_PORT_TYPE_UNKNOWN = 0,
+ RPSC2_PORT_TYPE_NPORT = 1,
+ RPSC2_PORT_TYPE_NLPORT = 2,
+ RPSC2_PORT_TYPE_NPIV_PORT = 0x5f,
+ RPSC2_PORT_TYPE_NPORT_TRUNK = 0x6f,
+};
+
+/*
+ * RPSC2 portInfo entry structure
+ */
+struct fc_rpsc2_port_info_s{
+ u32 pid; /* PID */
+ u16 resvd1;
+ u16 index; /* port number / index */
+ u8 resvd2;
+ u8 type; /* port type N/NL/... */
+ u16 speed; /* port Operating Speed */
+};
+
+/*
+ * RPSC2 Accept payload
+ */
+struct fc_rpsc2_acc_s{
+ u8 els_cmd;
+ u8 resvd;
+ u16 num_pids; /* Number of pids in the request */
+ struct fc_rpsc2_port_info_s port_info[1]; /* port information */
+};
+
+/**
+ * bit fields so that multiple classes can be specified
+ */
+enum fc_cos{
+ FC_CLASS_2 = 0x04,
+ FC_CLASS_3 = 0x08,
+ FC_CLASS_2_3 = 0x0C,
+};
+
+/*
+ * symbolic name
+ */
+struct fc_symname_s{
+ u8 symname[FC_SYMNAME_MAX];
+};
+
+struct fc_alpabm_s{
+ u8 alpa_bm[FC_ALPA_MAX / 8];
+};
+
+/*
+ * protocol default timeout values
+ */
+#define FC_ED_TOV 2
+#define FC_REC_TOV (FC_ED_TOV + 1)
+#define FC_RA_TOV 10
+#define FC_ELS_TOV (2 * FC_RA_TOV)
+
+/*
+ * virtual fabric related defines
+ */
+#define FC_VF_ID_NULL 0 /* must not be used as VF_ID */
+#define FC_VF_ID_MIN 1
+#define FC_VF_ID_MAX 0xEFF
+#define FC_VF_ID_CTL 0xFEF /* control VF_ID */
+
+/**
+ * Virtual Fabric Tagging header format
+ * @caution This is defined only in BIG ENDIAN format.
+ */
+struct fc_vft_s{
+ u32 r_ctl:8;
+ u32 ver:2;
+ u32 type:4;
+ u32 res_a:2;
+ u32 priority:3;
+ u32 vf_id:12;
+ u32 res_b:1;
+ u32 hopct:8;
+ u32 res_c:24;
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/fc_sp.h b/drivers/scsi/bfa/include/protocol/fc_sp.h
new file mode 100644
index 000000000000..55bb0b31d04b
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fc_sp.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __FC_SP_H__
+#define __FC_SP_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+enum auth_els_flags{
+ FC_AUTH_ELS_MORE_FRAGS_FLAG = 0x80, /*! bit-7. More Fragments
+ * Follow
+ */
+ FC_AUTH_ELS_CONCAT_FLAG = 0x40, /*! bit-6. Concatenation Flag */
+ FC_AUTH_ELS_SEQ_NUM_FLAG = 0x01 /*! bit-0. Sequence Number */
+};
+
+enum auth_msg_codes{
+ FC_AUTH_MC_AUTH_RJT = 0x0A, /*! Auth Reject */
+ FC_AUTH_MC_AUTH_NEG = 0x0B, /*! Auth Negotiate */
+ FC_AUTH_MC_AUTH_DONE = 0x0C, /*! Auth Done */
+
+ FC_AUTH_MC_DHCHAP_CHAL = 0x10, /*! DHCHAP Challenge */
+ FC_AUTH_MC_DHCHAP_REPLY = 0x11, /*! DHCHAP Reply */
+ FC_AUTH_MC_DHCHAP_SUCC = 0x12, /*! DHCHAP Success */
+
+ FC_AUTH_MC_FCAP_REQ = 0x13, /*! FCAP Request */
+ FC_AUTH_MC_FCAP_ACK = 0x14, /*! FCAP Acknowledge */
+ FC_AUTH_MC_FCAP_CONF = 0x15, /*! FCAP Confirm */
+
+ FC_AUTH_MC_FCPAP_INIT = 0x16, /*! FCPAP Init */
+ FC_AUTH_MC_FCPAP_ACC = 0x17, /*! FCPAP Accept */
+ FC_AUTH_MC_FCPAP_COMP = 0x18, /*! FCPAP Complete */
+
+ FC_AUTH_MC_IKE_SA_INIT = 0x22, /*! IKE SA INIT */
+ FC_AUTH_MC_IKE_SA_AUTH = 0x23, /*! IKE SA Auth */
+ FC_AUTH_MC_IKE_CREATE_CHILD_SA = 0x24, /*! IKE Create Child SA */
+ FC_AUTH_MC_IKE_INFO = 0x25, /*! IKE informational */
+};
+
+enum auth_proto_version{
+ FC_AUTH_PROTO_VER_1 = 1, /*! Protocol Version 1 */
+};
+
+enum {
+ FC_AUTH_ELS_COMMAND_CODE = 0x90,/*! Authentication ELS Command code */
+ FC_AUTH_PROTO_PARAM_LEN_SZ = 4, /*! Size of Proto Parameter Len Field */
+ FC_AUTH_PROTO_PARAM_VAL_SZ = 4, /*! Size of Proto Parameter Val Field */
+ FC_MAX_AUTH_SECRET_LEN = 256,
+ /*! Maximum secret string length */
+ FC_AUTH_NUM_USABLE_PROTO_LEN_SZ = 4,
+ /*! Size of usable protocols field */
+ FC_AUTH_RESP_VALUE_LEN_SZ = 4,
+ /*! Size of response value length */
+ FC_MAX_CHAP_KEY_LEN = 256, /*! Maximum md5 digest length */
+ FC_MAX_AUTH_RETRIES = 3, /*! Maximum number of retries */
+ FC_MD5_DIGEST_LEN = 16, /*! MD5 digest length */
+ FC_SHA1_DIGEST_LEN = 20, /*! SHA1 digest length */
+ FC_MAX_DHG_SUPPORTED = 1, /*! Maximum DH Groups supported */
+ FC_MAX_ALG_SUPPORTED = 1, /*! Maximum algorithms supported */
+ FC_MAX_PROTO_SUPPORTED = 1, /*! Maximum protocols supported */
+ FC_START_TXN_ID = 2, /*! Starting transaction ID */
+};
+
+enum auth_proto_id{
+ FC_AUTH_PROTO_DHCHAP = 0x00000001,
+ FC_AUTH_PROTO_FCAP = 0x00000002,
+ FC_AUTH_PROTO_FCPAP = 0x00000003,
+ FC_AUTH_PROTO_IKEv2 = 0x00000004,
+ FC_AUTH_PROTO_IKEv2_AUTH = 0x00000005,
+};
+
+struct auth_name_s{
+ u16 name_tag; /*! Name Tag = 1 for Authentication */
+ u16 name_len; /*! Name Length = 8 for Authentication
+ */
+ wwn_t name; /*! Name. TODO - is this PWWN */
+};
+
+
+enum auth_hash_func{
+ FC_AUTH_HASH_FUNC_MD5 = 0x00000005,
+ FC_AUTH_HASH_FUNC_SHA_1 = 0x00000006,
+};
+
+enum auth_dh_gid{
+ FC_AUTH_DH_GID_0_DHG_NULL = 0x00000000,
+ FC_AUTH_DH_GID_1_DHG_1024 = 0x00000001,
+ FC_AUTH_DH_GID_2_DHG_1280 = 0x00000002,
+ FC_AUTH_DH_GID_3_DHG_1536 = 0x00000003,
+ FC_AUTH_DH_GID_4_DHG_2048 = 0x00000004,
+ FC_AUTH_DH_GID_6_DHG_3072 = 0x00000006,
+ FC_AUTH_DH_GID_7_DHG_4096 = 0x00000007,
+ FC_AUTH_DH_GID_8_DHG_6144 = 0x00000008,
+ FC_AUTH_DH_GID_9_DHG_8192 = 0x00000009,
+};
+
+struct auth_els_msg_s {
+ u8 auth_els_code; /* Authentication ELS Code (0x90) */
+ u8 auth_els_flag; /* Authentication ELS Flags */
+ u8 auth_msg_code; /* Authentication Message Code */
+ u8 proto_version; /* Protocol Version */
+ u32 msg_len; /* Message Length */
+ u32 trans_id; /* Transaction Identifier (T_ID) */
+
+ /* Msg payload follows... */
+};
+
+
+enum auth_neg_param_tags {
+ FC_AUTH_NEG_DHCHAP_HASHLIST = 0x0001,
+ FC_AUTH_NEG_DHCHAP_DHG_ID_LIST = 0x0002,
+};
+
+
+struct dhchap_param_format_s {
+ u16 tag; /*! Parameter Tag. See
+ * auth_neg_param_tags_t
+ */
+ u16 word_cnt;
+
+ /* followed by variable length parameter value... */
+};
+
+struct auth_proto_params_s {
+ u32 proto_param_len;
+ u32 proto_id;
+
+ /*
+ * Followed by variable length Protocol specific parameters. DH-CHAP
+ * uses dhchap_param_format_t
+ */
+};
+
+struct auth_neg_msg_s {
+ struct auth_name_s auth_ini_name;
+ u32 usable_auth_protos;
+ struct auth_proto_params_s proto_params[1]; /*! (1..usable_auth_proto)
+ * protocol params
+ */
+};
+
+struct auth_dh_val_s {
+ u32 dh_val_len;
+ u32 dh_val[1];
+};
+
+struct auth_dhchap_chal_msg_s {
+ struct auth_els_msg_s hdr;
+ struct auth_name_s auth_responder_name; /* TODO VRK - is auth_name_t
+ * type OK?
+ */
+ u32 hash_id;
+ u32 dh_grp_id;
+ u32 chal_val_len;
+ char chal_val[1];
+
+ /* ...followed by variable Challenge length/value and DH length/value */
+};
+
+
+enum auth_rjt_codes {
+ FC_AUTH_RJT_CODE_AUTH_FAILURE = 0x01,
+ FC_AUTH_RJT_CODE_LOGICAL_ERR = 0x02,
+};
+
+enum auth_rjt_code_exps {
+ FC_AUTH_CEXP_AUTH_MECH_NOT_USABLE = 0x01,
+ FC_AUTH_CEXP_DH_GROUP_NOT_USABLE = 0x02,
+ FC_AUTH_CEXP_HASH_FUNC_NOT_USABLE = 0x03,
+ FC_AUTH_CEXP_AUTH_XACT_STARTED = 0x04,
+ FC_AUTH_CEXP_AUTH_FAILED = 0x05,
+ FC_AUTH_CEXP_INCORRECT_PLD = 0x06,
+ FC_AUTH_CEXP_INCORRECT_PROTO_MSG = 0x07,
+ FC_AUTH_CEXP_RESTART_AUTH_PROTO = 0x08,
+ FC_AUTH_CEXP_AUTH_CONCAT_NOT_SUPP = 0x09,
+ FC_AUTH_CEXP_PROTO_VER_NOT_SUPP = 0x0A,
+};
+
+enum auth_status {
+ FC_AUTH_STATE_INPROGRESS = 0, /*! authentication in progress */
+ FC_AUTH_STATE_FAILED = 1, /*! authentication failed */
+ FC_AUTH_STATE_SUCCESS = 2 /*! authentication successful */
+};
+
+struct auth_rjt_msg_s {
+ struct auth_els_msg_s hdr;
+ u8 reason_code;
+ u8 reason_code_exp;
+ u8 rsvd[2];
+};
+
+
+struct auth_dhchap_neg_msg_s {
+ struct auth_els_msg_s hdr;
+ struct auth_neg_msg_s nego;
+};
+
+struct auth_dhchap_reply_msg_s {
+ struct auth_els_msg_s hdr;
+
+ /*
+ * followed by response value length & Value + DH Value Length & Value
+ */
+};
+
+#pragma pack()
+
+#endif /* __FC_SP_H__ */
diff --git a/drivers/scsi/bfa/include/protocol/fcp.h b/drivers/scsi/bfa/include/protocol/fcp.h
new file mode 100644
index 000000000000..9ade68ad2853
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fcp.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __FCPPROTO_H__
+#define __FCPPROTO_H__
+
+#include <protocol/scsi.h>
+
+#pragma pack(1)
+
+enum {
+ FCP_RJT = 0x01000000, /* SRR reject */
+ FCP_SRR_ACCEPT = 0x02000000, /* SRR accept */
+ FCP_SRR = 0x14000000, /* Sequence Retransmission Request */
+};
+
+/*
+ * SRR FC-4 LS payload
+ */
+struct fc_srr_s{
+ u32 ls_cmd;
+ u32 ox_id:16; /* ox-id */
+ u32 rx_id:16; /* rx-id */
+ u32 ro; /* relative offset */
+ u32 r_ctl:8; /* R_CTL for I.U. */
+ u32 res:24;
+};
+
+
+/*
+ * FCP_CMND definitions
+ */
+#define FCP_CMND_CDB_LEN 16
+#define FCP_CMND_LUN_LEN 8
+
+struct fcp_cmnd_s{
+ lun_t lun; /* 64-bit LU number */
+ u8 crn; /* command reference number */
+#ifdef __BIGENDIAN
+ u8 resvd:1,
+ priority:4, /* FCP-3: SAM-3 priority */
+ taskattr:3; /* scsi task attribute */
+#else
+ u8 taskattr:3, /* scsi task attribute */
+ priority:4, /* FCP-3: SAM-3 priority */
+ resvd:1;
+#endif
+ u8 tm_flags; /* task management flags */
+#ifdef __BIGENDIAN
+ u8 addl_cdb_len:6, /* additional CDB length words */
+ iodir:2; /* read/write FCP_DATA IUs */
+#else
+ u8 iodir:2, /* read/write FCP_DATA IUs */
+ addl_cdb_len:6; /* additional CDB length */
+#endif
+ struct scsi_cdb_s cdb;
+
+ /*
+ * !!! additional cdb bytes follows here!!!
+ */
+ u32 fcp_dl; /* bytes to be transferred */
+};
+
+#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN)
+#define fcp_cmnd_fcpdl(_cmnd) ((&(_cmnd)->fcp_dl)[(_cmnd)->addl_cdb_len])
+
+/*
+ * fcp_cmnd_t.iodir field values
+ */
+enum fcp_iodir{
+ FCP_IODIR_NONE = 0,
+ FCP_IODIR_WRITE = 1,
+ FCP_IODIR_READ = 2,
+ FCP_IODIR_RW = 3,
+};
+
+/*
+ * Task attribute field
+ */
+enum {
+ FCP_TASK_ATTR_SIMPLE = 0,
+ FCP_TASK_ATTR_HOQ = 1,
+ FCP_TASK_ATTR_ORDERED = 2,
+ FCP_TASK_ATTR_ACA = 4,
+ FCP_TASK_ATTR_UNTAGGED = 5, /* obsolete in FCP-3 */
+};
+
+/*
+ * Task management flags field - only one bit shall be set
+ */
+#ifndef BIT
+#define BIT(_x) (1 << (_x))
+#endif
+enum fcp_tm_cmnd{
+ FCP_TM_ABORT_TASK_SET = BIT(1),
+ FCP_TM_CLEAR_TASK_SET = BIT(2),
+ FCP_TM_LUN_RESET = BIT(4),
+ FCP_TM_TARGET_RESET = BIT(5), /* obsolete in FCP-3 */
+ FCP_TM_CLEAR_ACA = BIT(6),
+};
+
+/*
+ * FCP_XFER_RDY IU defines
+ */
+struct fcp_xfer_rdy_s{
+ u32 data_ro;
+ u32 burst_len;
+ u32 reserved;
+};
+
+/*
+ * FCP_RSP residue flags
+ */
+enum fcp_residue{
+ FCP_NO_RESIDUE = 0, /* no residue */
+ FCP_RESID_OVER = 1, /* more data left that was not sent */
+ FCP_RESID_UNDER = 2, /* less data than requested */
+};
+
+enum {
+ FCP_RSPINFO_GOOD = 0,
+ FCP_RSPINFO_DATALEN_MISMATCH = 1,
+ FCP_RSPINFO_CMND_INVALID = 2,
+ FCP_RSPINFO_ROLEN_MISMATCH = 3,
+ FCP_RSPINFO_TM_NOT_SUPP = 4,
+ FCP_RSPINFO_TM_FAILED = 5,
+};
+
+struct fcp_rspinfo_s{
+ u32 res0:24;
+ u32 rsp_code:8; /* response code (as above) */
+ u32 res1;
+};
+
+struct fcp_resp_s{
+ u32 reserved[2]; /* 2 words reserved */
+ u16 reserved2;
+#ifdef __BIGENDIAN
+ u8 reserved3:3;
+ u8 fcp_conf_req:1; /* FCP_CONF is requested */
+ u8 resid_flags:2; /* underflow/overflow */
+ u8 sns_len_valid:1;/* sense len is valid */
+ u8 rsp_len_valid:1;/* response len is valid */
+#else
+ u8 rsp_len_valid:1;/* response len is valid */
+ u8 sns_len_valid:1;/* sense len is valid */
+ u8 resid_flags:2; /* underflow/overflow */
+ u8 fcp_conf_req:1; /* FCP_CONF is requested */
+ u8 reserved3:3;
+#endif
+ u8 scsi_status; /* one byte SCSI status */
+ u32 residue; /* residual data bytes */
+ u32 sns_len; /* length od sense info */
+ u32 rsp_len; /* length of response info */
+};
+
+#define fcp_snslen(__fcprsp) ((__fcprsp)->sns_len_valid ? \
+ (__fcprsp)->sns_len : 0)
+#define fcp_rsplen(__fcprsp) ((__fcprsp)->rsp_len_valid ? \
+ (__fcprsp)->rsp_len : 0)
+#define fcp_rspinfo(__fcprsp) ((struct fcp_rspinfo_s *)((__fcprsp) + 1))
+#define fcp_snsinfo(__fcprsp) (((u8 *)fcp_rspinfo(__fcprsp)) + \
+ fcp_rsplen(__fcprsp))
+
+struct fcp_cmnd_fr_s{
+ struct fchs_s fchs;
+ struct fcp_cmnd_s fcp;
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/fdmi.h b/drivers/scsi/bfa/include/protocol/fdmi.h
new file mode 100644
index 000000000000..6c05c268c71b
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fdmi.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __FDMI_H__
+#define __FDMI_H__
+
+#include <protocol/types.h>
+#include <protocol/fc.h>
+#include <protocol/ct.h>
+
+#pragma pack(1)
+
+/*
+ * FDMI Command Codes
+ */
+#define FDMI_GRHL 0x0100
+#define FDMI_GHAT 0x0101
+#define FDMI_GRPL 0x0102
+#define FDMI_GPAT 0x0110
+#define FDMI_RHBA 0x0200
+#define FDMI_RHAT 0x0201
+#define FDMI_RPRT 0x0210
+#define FDMI_RPA 0x0211
+#define FDMI_DHBA 0x0300
+#define FDMI_DPRT 0x0310
+
+/*
+ * FDMI reason codes
+ */
+#define FDMI_NO_ADDITIONAL_EXP 0x00
+#define FDMI_HBA_ALREADY_REG 0x10
+#define FDMI_HBA_ATTRIB_NOT_REG 0x11
+#define FDMI_HBA_ATTRIB_MULTIPLE 0x12
+#define FDMI_HBA_ATTRIB_LENGTH_INVALID 0x13
+#define FDMI_HBA_ATTRIB_NOT_PRESENT 0x14
+#define FDMI_PORT_ORIG_NOT_IN_LIST 0x15
+#define FDMI_PORT_HBA_NOT_IN_LIST 0x16
+#define FDMI_PORT_ATTRIB_NOT_REG 0x20
+#define FDMI_PORT_NOT_REG 0x21
+#define FDMI_PORT_ATTRIB_MULTIPLE 0x22
+#define FDMI_PORT_ATTRIB_LENGTH_INVALID 0x23
+#define FDMI_PORT_ALREADY_REGISTEREED 0x24
+
+/*
+ * FDMI Transmission Speed Mask values
+ */
+#define FDMI_TRANS_SPEED_1G 0x00000001
+#define FDMI_TRANS_SPEED_2G 0x00000002
+#define FDMI_TRANS_SPEED_10G 0x00000004
+#define FDMI_TRANS_SPEED_4G 0x00000008
+#define FDMI_TRANS_SPEED_8G 0x00000010
+#define FDMI_TRANS_SPEED_16G 0x00000020
+#define FDMI_TRANS_SPEED_UNKNOWN 0x00008000
+
+/*
+ * FDMI HBA attribute types
+ */
+enum fdmi_hba_attribute_type {
+ FDMI_HBA_ATTRIB_NODENAME = 1, /* 0x0001 */
+ FDMI_HBA_ATTRIB_MANUFACTURER, /* 0x0002 */
+ FDMI_HBA_ATTRIB_SERIALNUM, /* 0x0003 */
+ FDMI_HBA_ATTRIB_MODEL, /* 0x0004 */
+ FDMI_HBA_ATTRIB_MODEL_DESC, /* 0x0005 */
+ FDMI_HBA_ATTRIB_HW_VERSION, /* 0x0006 */
+ FDMI_HBA_ATTRIB_DRIVER_VERSION, /* 0x0007 */
+ FDMI_HBA_ATTRIB_ROM_VERSION, /* 0x0008 */
+ FDMI_HBA_ATTRIB_FW_VERSION, /* 0x0009 */
+ FDMI_HBA_ATTRIB_OS_NAME, /* 0x000A */
+ FDMI_HBA_ATTRIB_MAX_CT, /* 0x000B */
+
+ FDMI_HBA_ATTRIB_MAX_TYPE
+};
+
+/*
+ * FDMI Port attribute types
+ */
+enum fdmi_port_attribute_type {
+ FDMI_PORT_ATTRIB_FC4_TYPES = 1, /* 0x0001 */
+ FDMI_PORT_ATTRIB_SUPP_SPEED, /* 0x0002 */
+ FDMI_PORT_ATTRIB_PORT_SPEED, /* 0x0003 */
+ FDMI_PORT_ATTRIB_FRAME_SIZE, /* 0x0004 */
+ FDMI_PORT_ATTRIB_DEV_NAME, /* 0x0005 */
+ FDMI_PORT_ATTRIB_HOST_NAME, /* 0x0006 */
+
+ FDMI_PORT_ATTR_MAX_TYPE
+};
+
+/*
+ * FDMI attribute
+ */
+struct fdmi_attr_s {
+ u16 type;
+ u16 len;
+ u8 value[1];
+};
+
+/*
+ * HBA Attribute Block
+ */
+struct fdmi_hba_attr_s {
+ u32 attr_count; /* # of attributes */
+ struct fdmi_attr_s hba_attr; /* n attributes */
+};
+
+/*
+ * Registered Port List
+ */
+struct fdmi_port_list_s {
+ u32 num_ports; /* number Of Port Entries */
+ wwn_t port_entry; /* one or more */
+};
+
+/*
+ * Port Attribute Block
+ */
+struct fdmi_port_attr_s {
+ u32 attr_count; /* # of attributes */
+ struct fdmi_attr_s port_attr; /* n attributes */
+};
+
+/*
+ * FDMI Register HBA Attributes
+ */
+struct fdmi_rhba_s {
+ wwn_t hba_id; /* HBA Identifier */
+ struct fdmi_port_list_s port_list; /* Registered Port List */
+ struct fdmi_hba_attr_s hba_attr_blk; /* HBA attribute block */
+};
+
+/*
+ * FDMI Register Port
+ */
+struct fdmi_rprt_s {
+ wwn_t hba_id; /* HBA Identifier */
+ wwn_t port_name; /* Port wwn */
+ struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */
+};
+
+/*
+ * FDMI Register Port Attributes
+ */
+struct fdmi_rpa_s {
+ wwn_t port_name; /* port wwn */
+ struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/pcifw.h b/drivers/scsi/bfa/include/protocol/pcifw.h
new file mode 100644
index 000000000000..6830dc3ee58a
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/pcifw.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * pcifw.h PCI FW related headers
+ */
+
+#ifndef __PCIFW_H__
+#define __PCIFW_H__
+
+#pragma pack(1)
+
+struct pnp_hdr_s{
+ u32 signature; /* "$PnP" */
+ u8 rev; /* Struct revision */
+ u8 len; /* Header structure len in multiples
+ * of 16 bytes */
+ u16 off; /* Offset to next header 00 if none */
+ u8 rsvd; /* Reserved byte */
+ u8 cksum; /* 8-bit checksum for this header */
+ u32 pnp_dev_id; /* PnP Device Id */
+ u16 mfstr; /* Pointer to manufacturer string */
+ u16 prstr; /* Pointer to product string */
+ u8 devtype[3]; /* Device Type Code */
+ u8 devind; /* Device Indicator */
+ u16 bcventr; /* Bootstrap entry vector */
+ u16 rsvd2; /* Reserved */
+ u16 sriv; /* Static resource information vector */
+};
+
+struct pci_3_0_ds_s{
+ u32 sig; /* Signature "PCIR" */
+ u16 vendid; /* Vendor ID */
+ u16 devid; /* Device ID */
+ u16 devlistoff; /* Device List Offset */
+ u16 len; /* PCI Data Structure Length */
+ u8 rev; /* PCI Data Structure Revision */
+ u8 clcode[3]; /* Class Code */
+ u16 imglen; /* Code image length in multiples of
+ * 512 bytes */
+ u16 coderev; /* Revision level of code/data */
+ u8 codetype; /* Code type 0x00 - BIOS */
+ u8 indr; /* Last image indicator */
+ u16 mrtimglen; /* Max Run Time Image Length */
+ u16 cuoff; /* Config Utility Code Header Offset */
+ u16 dmtfclp; /* DMTF CLP entry point offset */
+};
+
+struct pci_optrom_hdr_s{
+ u16 sig; /* Signature 0x55AA */
+ u8 len; /* Option ROM length in units of 512 bytes */
+ u8 inivec[3]; /* Initialization vector */
+ u8 rsvd[16]; /* Reserved field */
+ u16 verptr; /* Pointer to version string - private */
+ u16 pcids; /* Pointer to PCI data structure */
+ u16 pnphdr; /* Pointer to PnP expansion header */
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/scsi.h b/drivers/scsi/bfa/include/protocol/scsi.h
new file mode 100644
index 000000000000..b220e6b4f6e1
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/scsi.h
@@ -0,0 +1,1648 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __SCSI_H__
+#define __SCSI_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+/*
+ * generic SCSI cdb definition
+ */
+#define SCSI_MAX_CDBLEN 16
+struct scsi_cdb_s{
+ u8 scsi_cdb[SCSI_MAX_CDBLEN];
+};
+
+/*
+ * scsi lun serial number definition
+ */
+#define SCSI_LUN_SN_LEN 32
+struct scsi_lun_sn_s{
+ u8 lun_sn[SCSI_LUN_SN_LEN];
+};
+
+/*
+ * SCSI Direct Access Commands
+ */
+enum {
+ SCSI_OP_TEST_UNIT_READY = 0x00,
+ SCSI_OP_REQUEST_SENSE = 0x03,
+ SCSI_OP_FORMAT_UNIT = 0x04,
+ SCSI_OP_READ6 = 0x08,
+ SCSI_OP_WRITE6 = 0x0A,
+ SCSI_OP_WRITE_FILEMARKS = 0x10,
+ SCSI_OP_INQUIRY = 0x12,
+ SCSI_OP_MODE_SELECT6 = 0x15,
+ SCSI_OP_RESERVE6 = 0x16,
+ SCSI_OP_RELEASE6 = 0x17,
+ SCSI_OP_MODE_SENSE6 = 0x1A,
+ SCSI_OP_START_STOP_UNIT = 0x1B,
+ SCSI_OP_SEND_DIAGNOSTIC = 0x1D,
+ SCSI_OP_READ_CAPACITY = 0x25,
+ SCSI_OP_READ10 = 0x28,
+ SCSI_OP_WRITE10 = 0x2A,
+ SCSI_OP_VERIFY10 = 0x2F,
+ SCSI_OP_READ_DEFECT_DATA = 0x37,
+ SCSI_OP_LOG_SELECT = 0x4C,
+ SCSI_OP_LOG_SENSE = 0x4D,
+ SCSI_OP_MODE_SELECT10 = 0x55,
+ SCSI_OP_RESERVE10 = 0x56,
+ SCSI_OP_RELEASE10 = 0x57,
+ SCSI_OP_MODE_SENSE10 = 0x5A,
+ SCSI_OP_PER_RESERVE_IN = 0x5E,
+ SCSI_OP_PER_RESERVE_OUR = 0x5E,
+ SCSI_OP_READ16 = 0x88,
+ SCSI_OP_WRITE16 = 0x8A,
+ SCSI_OP_VERIFY16 = 0x8F,
+ SCSI_OP_READ_CAPACITY16 = 0x9E,
+ SCSI_OP_REPORT_LUNS = 0xA0,
+ SCSI_OP_READ12 = 0xA8,
+ SCSI_OP_WRITE12 = 0xAA,
+ SCSI_OP_UNDEF = 0xFF,
+};
+
+/*
+ * SCSI START_STOP_UNIT command
+ */
+struct scsi_start_stop_unit_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved1:4;
+ u8 immed:1;
+#else
+ u8 immed:1;
+ u8 reserved1:4;
+ u8 lun:3;
+#endif
+ u8 reserved2;
+ u8 reserved3;
+#ifdef __BIGENDIAN
+ u8 power_conditions:4;
+ u8 reserved4:2;
+ u8 loEj:1;
+ u8 start:1;
+#else
+ u8 start:1;
+ u8 loEj:1;
+ u8 reserved4:2;
+ u8 power_conditions:4;
+#endif
+ u8 control;
+};
+
+/*
+ * SCSI SEND_DIAGNOSTIC command
+ */
+struct scsi_send_diagnostic_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 self_test_code:3;
+ u8 pf:1;
+ u8 reserved1:1;
+ u8 self_test:1;
+ u8 dev_offl:1;
+ u8 unit_offl:1;
+#else
+ u8 unit_offl:1;
+ u8 dev_offl:1;
+ u8 self_test:1;
+ u8 reserved1:1;
+ u8 pf:1;
+ u8 self_test_code:3;
+#endif
+ u8 reserved2;
+
+ u8 param_list_length[2]; /* MSB first */
+ u8 control;
+
+};
+
+/*
+ * SCSI READ10/WRITE10 commands
+ */
+struct scsi_rw10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 dpo:1; /* Disable Page Out */
+ u8 fua:1; /* Force Unit Access */
+ u8 reserved1:2;
+ u8 rel_adr:1; /* relative address */
+#else
+ u8 rel_adr:1;
+ u8 reserved1:2;
+ u8 fua:1;
+ u8 dpo:1;
+ u8 lun:3;
+#endif
+ u8 lba0; /* logical block address - MSB */
+ u8 lba1;
+ u8 lba2;
+ u8 lba3; /* LSB */
+ u8 reserved3;
+ u8 xfer_length0; /* transfer length in blocks - MSB */
+ u8 xfer_length1; /* LSB */
+ u8 control;
+};
+
+#define SCSI_CDB10_GET_LBA(cdb) \
+ (((cdb)->lba0 << 24) | ((cdb)->lba1 << 16) | \
+ ((cdb)->lba2 << 8) | (cdb)->lba3)
+
+#define SCSI_CDB10_SET_LBA(cdb, lba) { \
+ (cdb)->lba0 = lba >> 24; \
+ (cdb)->lba1 = (lba >> 16) & 0xFF; \
+ (cdb)->lba2 = (lba >> 8) & 0xFF; \
+ (cdb)->lba3 = lba & 0xFF; \
+}
+
+#define SCSI_CDB10_GET_TL(cdb) \
+ ((cdb)->xfer_length0 << 8 | (cdb)->xfer_length1)
+#define SCSI_CDB10_SET_TL(cdb, tl) { \
+ (cdb)->xfer_length0 = tl >> 8; \
+ (cdb)->xfer_length1 = tl & 0xFF; \
+}
+
+/*
+ * SCSI READ6/WRITE6 commands
+ */
+struct scsi_rw6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 lba0:5; /* MSb */
+#else
+ u8 lba0:5; /* MSb */
+ u8 lun:3;
+#endif
+ u8 lba1;
+ u8 lba2; /* LSB */
+ u8 xfer_length;
+ u8 control;
+};
+
+#define SCSI_TAPE_CDB6_GET_TL(cdb) \
+ (((cdb)->tl0 << 16) | ((cdb)->tl1 << 8) | (cdb)->tl2)
+
+#define SCSI_TAPE_CDB6_SET_TL(cdb, tl) { \
+ (cdb)->tl0 = tl >> 16; \
+ (cdb)->tl1 = (tl >> 8) & 0xFF; \
+ (cdb)->tl2 = tl & 0xFF; \
+}
+
+/*
+ * SCSI sequential (TAPE) wrtie command
+ */
+struct scsi_tape_wr_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 rsvd:7;
+ u8 fixed:1; /* MSb */
+#else
+ u8 fixed:1; /* MSb */
+ u8 rsvd:7;
+#endif
+ u8 tl0; /* Msb */
+ u8 tl1;
+ u8 tl2; /* Lsb */
+
+ u8 control;
+};
+
+#define SCSI_CDB6_GET_LBA(cdb) \
+ (((cdb)->lba0 << 16) | ((cdb)->lba1 << 8) | (cdb)->lba2)
+
+#define SCSI_CDB6_SET_LBA(cdb, lba) { \
+ (cdb)->lba0 = lba >> 16; \
+ (cdb)->lba1 = (lba >> 8) & 0xFF; \
+ (cdb)->lba2 = lba & 0xFF; \
+}
+
+#define SCSI_CDB6_GET_TL(cdb) ((cdb)->xfer_length)
+#define SCSI_CDB6_SET_TL(cdb, tl) { \
+ (cdb)->xfer_length = tl; \
+}
+
+/*
+ * SCSI sense data format
+ */
+struct scsi_sense_s{
+#ifdef __BIGENDIAN
+ u8 valid:1;
+ u8 rsp_code:7;
+#else
+ u8 rsp_code:7;
+ u8 valid:1;
+#endif
+ u8 seg_num;
+#ifdef __BIGENDIAN
+ u8 file_mark:1;
+ u8 eom:1; /* end of media */
+ u8 ili:1; /* incorrect length indicator */
+ u8 reserved:1;
+ u8 sense_key:4;
+#else
+ u8 sense_key:4;
+ u8 reserved:1;
+ u8 ili:1; /* incorrect length indicator */
+ u8 eom:1; /* end of media */
+ u8 file_mark:1;
+#endif
+ u8 information[4]; /* device-type or command specific info
+ */
+ u8 add_sense_length;
+ /* additional sense length */
+ u8 command_info[4];/* command specific information
+ */
+ u8 asc; /* additional sense code */
+ u8 ascq; /* additional sense code qualifier */
+ u8 fru_code; /* field replaceable unit code */
+#ifdef __BIGENDIAN
+ u8 sksv:1; /* sense key specific valid */
+ u8 c_d:1; /* command/data bit */
+ u8 res1:2;
+ u8 bpv:1; /* bit pointer valid */
+ u8 bpointer:3; /* bit pointer */
+#else
+ u8 bpointer:3; /* bit pointer */
+ u8 bpv:1; /* bit pointer valid */
+ u8 res1:2;
+ u8 c_d:1; /* command/data bit */
+ u8 sksv:1; /* sense key specific valid */
+#endif
+ u8 fpointer[2]; /* field pointer */
+};
+
+#define SCSI_SENSE_CUR_ERR 0x70
+#define SCSI_SENSE_DEF_ERR 0x71
+
+/*
+ * SCSI sense key values
+ */
+#define SCSI_SK_NO_SENSE 0x0
+#define SCSI_SK_REC_ERR 0x1 /* recovered error */
+#define SCSI_SK_NOT_READY 0x2
+#define SCSI_SK_MED_ERR 0x3 /* medium error */
+#define SCSI_SK_HW_ERR 0x4 /* hardware error */
+#define SCSI_SK_ILLEGAL_REQ 0x5
+#define SCSI_SK_UNIT_ATT 0x6 /* unit attention */
+#define SCSI_SK_DATA_PROTECT 0x7
+#define SCSI_SK_BLANK_CHECK 0x8
+#define SCSI_SK_VENDOR_SPEC 0x9
+#define SCSI_SK_COPY_ABORTED 0xA
+#define SCSI_SK_ABORTED_CMND 0xB
+#define SCSI_SK_VOL_OVERFLOW 0xD
+#define SCSI_SK_MISCOMPARE 0xE
+
+/*
+ * SCSI additional sense codes
+ */
+#define SCSI_ASC_NO_ADD_SENSE 0x00
+#define SCSI_ASC_LUN_NOT_READY 0x04
+#define SCSI_ASC_LUN_COMMUNICATION 0x08
+#define SCSI_ASC_WRITE_ERROR 0x0C
+#define SCSI_ASC_INVALID_CMND_CODE 0x20
+#define SCSI_ASC_BAD_LBA 0x21
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_LUN_NOT_SUPPORTED 0x25
+#define SCSI_ASC_LUN_WRITE_PROTECT 0x27
+#define SCSI_ASC_POWERON_BDR 0x29 /* power on reset, bus reset,
+ * bus device reset
+ */
+#define SCSI_ASC_PARAMS_CHANGED 0x2A
+#define SCSI_ASC_CMND_CLEARED_BY_A_I 0x2F
+#define SCSI_ASC_SAVING_PARAM_NOTSUPP 0x39
+#define SCSI_ASC_TOCC 0x3F /* target operating condtions
+ * changed
+ */
+#define SCSI_ASC_PARITY_ERROR 0x47
+#define SCSI_ASC_CMND_PHASE_ERROR 0x4A
+#define SCSI_ASC_DATA_PHASE_ERROR 0x4B
+#define SCSI_ASC_VENDOR_SPEC 0x7F
+
+/*
+ * SCSI additional sense code qualifiers
+ */
+#define SCSI_ASCQ_CAUSE_NOT_REPORT 0x00
+#define SCSI_ASCQ_BECOMING_READY 0x01
+#define SCSI_ASCQ_INIT_CMD_REQ 0x02
+#define SCSI_ASCQ_FORMAT_IN_PROGRESS 0x04
+#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07
+#define SCSI_ASCQ_SELF_TEST_IN_PROGRESS 0x09
+#define SCSI_ASCQ_WR_UNEXP_UNSOL_DATA 0x0C
+#define SCSI_ASCQ_WR_NOTENG_UNSOL_DATA 0x0D
+
+#define SCSI_ASCQ_LBA_OUT_OF_RANGE 0x00
+#define SCSI_ASCQ_INVALID_ELEMENT_ADDR 0x01
+
+#define SCSI_ASCQ_LUN_WRITE_PROTECTED 0x00
+#define SCSI_ASCQ_LUN_HW_WRITE_PROTECTED 0x01
+#define SCSI_ASCQ_LUN_SW_WRITE_PROTECTED 0x02
+
+#define SCSI_ASCQ_POR 0x01 /* power on reset */
+#define SCSI_ASCQ_SBR 0x02 /* scsi bus reset */
+#define SCSI_ASCQ_BDR 0x03 /* bus device reset */
+#define SCSI_ASCQ_DIR 0x04 /* device internal reset */
+
+#define SCSI_ASCQ_MODE_PARAMS_CHANGED 0x01
+#define SCSI_ASCQ_LOG_PARAMS_CHANGED 0x02
+#define SCSI_ASCQ_RESERVATIONS_PREEMPTED 0x03
+#define SCSI_ASCQ_RESERVATIONS_RELEASED 0x04
+#define SCSI_ASCQ_REGISTRATIONS_PREEMPTED 0x05
+
+#define SCSI_ASCQ_MICROCODE_CHANGED 0x01
+#define SCSI_ASCQ_CHANGED_OPER_COND 0x02
+#define SCSI_ASCQ_INQ_CHANGED 0x03 /* inquiry data changed */
+#define SCSI_ASCQ_DI_CHANGED 0x05 /* device id changed */
+#define SCSI_ASCQ_RL_DATA_CHANGED 0x0E /* report luns data changed */
+
+#define SCSI_ASCQ_DP_CRC_ERR 0x01 /* data phase crc error */
+#define SCSI_ASCQ_DP_SCSI_PARITY_ERR 0x02 /* data phase scsi parity error
+ */
+#define SCSI_ASCQ_IU_CRC_ERR 0x03 /* information unit crc error */
+#define SCSI_ASCQ_PROTO_SERV_CRC_ERR 0x05
+
+#define SCSI_ASCQ_LUN_TIME_OUT 0x01
+
+/* ------------------------------------------------------------
+ * SCSI INQUIRY
+ * ------------------------------------------------------------*/
+
+struct scsi_inquiry_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved1:3;
+ u8 cmd_dt:1;
+ u8 evpd:1;
+#else
+ u8 evpd:1;
+ u8 cmd_dt:1;
+ u8 reserved1:3;
+ u8 lun:3;
+#endif
+ u8 page_code;
+ u8 reserved2;
+ u8 alloc_length;
+ u8 control;
+};
+
+struct scsi_inquiry_vendor_s{
+ u8 vendor_id[8];
+};
+
+struct scsi_inquiry_prodid_s{
+ u8 product_id[16];
+};
+
+struct scsi_inquiry_prodrev_s{
+ u8 product_rev[4];
+};
+
+struct scsi_inquiry_data_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3; /* peripheral qualifier */
+ u8 device_type:5; /* peripheral device type */
+
+ u8 rmb:1; /* removable medium bit */
+ u8 device_type_mod:7; /* device type modifier */
+
+ u8 version;
+
+ u8 aenc:1; /* async event notification capability
+ */
+ u8 trm_iop:1; /* terminate I/O process */
+ u8 norm_aca:1; /* normal ACA supported */
+ u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */
+ u8 rsp_data_format:4;
+
+ u8 additional_len;
+ u8 sccs:1;
+ u8 reserved1:7;
+
+ u8 reserved2:1;
+ u8 enc_serv:1; /* enclosure service component */
+ u8 reserved3:1;
+ u8 multi_port:1; /* multi-port device */
+ u8 m_chngr:1; /* device in medium transport element */
+ u8 ack_req_q:1; /* SIP specific bit */
+ u8 addr32:1; /* SIP specific bit */
+ u8 addr16:1; /* SIP specific bit */
+
+ u8 rel_adr:1; /* relative address */
+ u8 w_bus32:1;
+ u8 w_bus16:1;
+ u8 synchronous:1;
+ u8 linked_commands:1;
+ u8 trans_dis:1;
+ u8 cmd_queue:1; /* command queueing supported */
+ u8 soft_reset:1; /* soft reset alternative (VS) */
+#else
+ u8 device_type:5; /* peripheral device type */
+ u8 peripheral_qual:3;
+ /* peripheral qualifier */
+
+ u8 device_type_mod:7;
+ /* device type modifier */
+ u8 rmb:1; /* removable medium bit */
+
+ u8 version;
+
+ u8 rsp_data_format:4;
+ u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */
+ u8 norm_aca:1; /* normal ACA supported */
+ u8 terminate_iop:1;/* terminate I/O process */
+ u8 aenc:1; /* async event notification capability
+ */
+
+ u8 additional_len;
+ u8 reserved1:7;
+ u8 sccs:1;
+
+ u8 addr16:1; /* SIP specific bit */
+ u8 addr32:1; /* SIP specific bit */
+ u8 ack_req_q:1; /* SIP specific bit */
+ u8 m_chngr:1; /* device in medium transport element */
+ u8 multi_port:1; /* multi-port device */
+ u8 reserved3:1; /* TBD - Vendor Specific */
+ u8 enc_serv:1; /* enclosure service component */
+ u8 reserved2:1;
+
+ u8 soft_seset:1; /* soft reset alternative (VS) */
+ u8 cmd_queue:1; /* command queueing supported */
+ u8 trans_dis:1;
+ u8 linked_commands:1;
+ u8 synchronous:1;
+ u8 w_bus16:1;
+ u8 w_bus32:1;
+ u8 rel_adr:1; /* relative address */
+#endif
+ struct scsi_inquiry_vendor_s vendor_id;
+ struct scsi_inquiry_prodid_s product_id;
+ struct scsi_inquiry_prodrev_s product_rev;
+ u8 vendor_specific[20];
+ u8 reserved4[40];
+};
+
+/*
+ * inquiry.peripheral_qual field values
+ */
+#define SCSI_DEVQUAL_DEFAULT 0
+#define SCSI_DEVQUAL_NOT_CONNECTED 1
+#define SCSI_DEVQUAL_NOT_SUPPORTED 3
+
+/*
+ * inquiry.device_type field values
+ */
+#define SCSI_DEVICE_DIRECT_ACCESS 0x00
+#define SCSI_DEVICE_SEQ_ACCESS 0x01
+#define SCSI_DEVICE_ARRAY_CONTROLLER 0x0C
+#define SCSI_DEVICE_UNKNOWN 0x1F
+
+/*
+ * inquiry.version
+ */
+#define SCSI_VERSION_ANSI_X3131 2 /* ANSI X3.131 SCSI-2 */
+#define SCSI_VERSION_SPC 3 /* SPC (SCSI-3), ANSI X3.301:1997 */
+#define SCSI_VERSION_SPC_2 4 /* SPC-2 */
+
+/*
+ * response data format
+ */
+#define SCSI_RSP_DATA_FORMAT 2 /* SCSI-2 & SPC */
+
+/*
+ * SCSI inquiry page codes
+ */
+#define SCSI_INQ_PAGE_VPD_PAGES 0x00 /* supported vpd pages */
+#define SCSI_INQ_PAGE_USN_PAGE 0x80 /* unit serial number page */
+#define SCSI_INQ_PAGE_DEV_IDENT 0x83 /* device indentification page
+ */
+#define SCSI_INQ_PAGES_MAX 3
+
+/*
+ * supported vital product data pages
+ */
+struct scsi_inq_page_vpd_pages_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3;
+ u8 device_type:5;
+#else
+ u8 device_type:5;
+ u8 peripheral_qual:3;
+#endif
+ u8 page_code;
+ u8 reserved;
+ u8 page_length;
+ u8 pages[SCSI_INQ_PAGES_MAX];
+};
+
+/*
+ * Unit serial number page
+ */
+#define SCSI_INQ_USN_LEN 32
+
+struct scsi_inq_usn_s{
+ char usn[SCSI_INQ_USN_LEN];
+};
+
+struct scsi_inq_page_usn_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3;
+ u8 device_type:5;
+#else
+ u8 device_type:5;
+ u8 peripheral_qual:3;
+#endif
+ u8 page_code;
+ u8 reserved1;
+ u8 page_length;
+ struct scsi_inq_usn_s usn;
+};
+
+enum {
+ SCSI_INQ_DIP_CODE_BINARY = 1, /* identifier has binary value */
+ SCSI_INQ_DIP_CODE_ASCII = 2, /* identifier has ascii value */
+};
+
+enum {
+ SCSI_INQ_DIP_ASSOC_LUN = 0, /* id is associated with device */
+ SCSI_INQ_DIP_ASSOC_PORT = 1, /* id is associated with port that
+ * received the request
+ */
+};
+
+enum {
+ SCSI_INQ_ID_TYPE_VENDOR = 1,
+ SCSI_INQ_ID_TYPE_IEEE = 2,
+ SCSI_INQ_ID_TYPE_FC_FS = 3,
+ SCSI_INQ_ID_TYPE_OTHER = 4,
+};
+
+struct scsi_inq_dip_desc_s{
+#ifdef __BIGENDIAN
+ u8 res0:4;
+ u8 code_set:4;
+ u8 res1:2;
+ u8 association:2;
+ u8 id_type:4;
+#else
+ u8 code_set:4;
+ u8 res0:4;
+ u8 id_type:4;
+ u8 association:2;
+ u8 res1:2;
+#endif
+ u8 res2;
+ u8 id_len;
+ struct scsi_lun_sn_s id;
+};
+
+/*
+ * Device indentification page
+ */
+struct scsi_inq_page_dev_ident_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3;
+ u8 device_type:5;
+#else
+ u8 device_type:5;
+ u8 peripheral_qual:3;
+#endif
+ u8 page_code;
+ u8 reserved1;
+ u8 page_length;
+ struct scsi_inq_dip_desc_s desc;
+};
+
+/* ------------------------------------------------------------
+ * READ CAPACITY
+ * ------------------------------------------------------------
+ */
+
+struct scsi_read_capacity_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved1:4;
+ u8 rel_adr:1;
+#else
+ u8 rel_adr:1;
+ u8 reserved1:4;
+ u8 lun:3;
+#endif
+ u8 lba0; /* MSB */
+ u8 lba1;
+ u8 lba2;
+ u8 lba3; /* LSB */
+ u8 reserved2;
+ u8 reserved3;
+#ifdef __BIGENDIAN
+ u8 reserved4:7;
+ u8 pmi:1; /* partial medium indicator */
+#else
+ u8 pmi:1; /* partial medium indicator */
+ u8 reserved4:7;
+#endif
+ u8 control;
+};
+
+struct scsi_read_capacity_data_s{
+ u32 max_lba; /* maximum LBA available */
+ u32 block_length; /* in bytes */
+};
+
+struct scsi_read_capacity16_data_s{
+ u64 lba; /* maximum LBA available */
+ u32 block_length; /* in bytes */
+#ifdef __BIGENDIAN
+ u8 reserved1:4,
+ p_type:3,
+ prot_en:1;
+ u8 reserved2:4,
+ lb_pbe:4; /* logical blocks per physical block
+ * exponent */
+ u16 reserved3:2,
+ lba_align:14; /* lowest aligned logical block
+ * address */
+#else
+ u16 lba_align:14, /* lowest aligned logical block
+ * address */
+ reserved3:2;
+ u8 lb_pbe:4, /* logical blocks per physical block
+ * exponent */
+ reserved2:4;
+ u8 prot_en:1,
+ p_type:3,
+ reserved1:4;
+#endif
+ u64 reserved4;
+ u64 reserved5;
+};
+
+/* ------------------------------------------------------------
+ * REPORT LUNS command
+ * ------------------------------------------------------------
+ */
+
+struct scsi_report_luns_s{
+ u8 opcode; /* A0h - REPORT LUNS opCode */
+ u8 reserved1[5];
+ u8 alloc_length[4];/* allocation length MSB first */
+ u8 reserved2;
+ u8 control;
+};
+
+#define SCSI_REPORT_LUN_ALLOC_LENGTH(rl) \
+ ((rl->alloc_length[0] << 24) | (rl->alloc_length[1] << 16) | \
+ (rl->alloc_length[2] << 8) | (rl->alloc_length[3]))
+
+#define SCSI_REPORT_LUNS_SET_ALLOCLEN(rl, alloc_len) { \
+ (rl)->alloc_length[0] = (alloc_len) >> 24; \
+ (rl)->alloc_length[1] = ((alloc_len) >> 16) & 0xFF; \
+ (rl)->alloc_length[2] = ((alloc_len) >> 8) & 0xFF; \
+ (rl)->alloc_length[3] = (alloc_len) & 0xFF; \
+}
+
+struct scsi_report_luns_data_s{
+ u32 lun_list_length; /* length of LUN list length */
+ u32 reserved;
+ lun_t lun[1]; /* first LUN in lun list */
+};
+
+/* -------------------------------------------------------------
+ * SCSI mode parameters
+ * -----------------------------------------------------------
+ */
+enum {
+ SCSI_DA_MEDIUM_DEF = 0, /* direct access default medium type */
+ SCSI_DA_MEDIUM_SS = 1, /* direct access single sided */
+ SCSI_DA_MEDIUM_DS = 2, /* direct access double sided */
+};
+
+/*
+ * SCSI Mode Select(6) cdb
+ */
+struct scsi_mode_select6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 pf:1; /* page format */
+ u8 reserved2:3;
+ u8 sp:1; /* save pages if set to 1 */
+#else
+ u8 sp:1; /* save pages if set to 1 */
+ u8 reserved2:3;
+ u8 pf:1; /* page format */
+ u8 reserved1:3;
+#endif
+ u8 reserved3[2];
+ u8 alloc_len;
+ u8 control;
+};
+
+/*
+ * SCSI Mode Select(10) cdb
+ */
+struct scsi_mode_select10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 pf:1; /* page format */
+ u8 reserved2:3;
+ u8 sp:1; /* save pages if set to 1 */
+#else
+ u8 sp:1; /* save pages if set to 1 */
+ u8 reserved2:3;
+ u8 pf:1; /* page format */
+ u8 reserved1:3;
+#endif
+ u8 reserved3[5];
+ u8 alloc_len_msb;
+ u8 alloc_len_lsb;
+ u8 control;
+};
+
+/*
+ * SCSI Mode Sense(6) cdb
+ */
+struct scsi_mode_sense6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:4;
+ u8 dbd:1; /* disable block discriptors if set to 1 */
+ u8 reserved2:3;
+
+ u8 pc:2; /* page control */
+ u8 page_code:6;
+#else
+ u8 reserved2:3;
+ u8 dbd:1; /* disable block descriptors if set to 1 */
+ u8 reserved1:4;
+
+ u8 page_code:6;
+ u8 pc:2; /* page control */
+#endif
+ u8 reserved3;
+ u8 alloc_len;
+ u8 control;
+};
+
+/*
+ * SCSI Mode Sense(10) cdb
+ */
+struct scsi_mode_sense10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 LLBAA:1; /* long LBA accepted if set to 1 */
+ u8 dbd:1; /* disable block descriptors if set
+ * to 1
+ */
+ u8 reserved2:3;
+
+ u8 pc:2; /* page control */
+ u8 page_code:6;
+#else
+ u8 reserved2:3;
+ u8 dbd:1; /* disable block descriptors if set to
+ * 1
+ */
+ u8 LLBAA:1; /* long LBA accepted if set to 1 */
+ u8 reserved1:3;
+
+ u8 page_code:6;
+ u8 pc:2; /* page control */
+#endif
+ u8 reserved3[4];
+ u8 alloc_len_msb;
+ u8 alloc_len_lsb;
+ u8 control;
+};
+
+#define SCSI_CDB10_GET_AL(cdb) \
+ ((cdb)->alloc_len_msb << 8 | (cdb)->alloc_len_lsb)
+
+#define SCSI_CDB10_SET_AL(cdb, al) { \
+ (cdb)->alloc_len_msb = al >> 8; \
+ (cdb)->alloc_len_lsb = al & 0xFF; \
+}
+
+#define SCSI_CDB6_GET_AL(cdb) ((cdb)->alloc_len)
+
+#define SCSI_CDB6_SET_AL(cdb, al) { \
+ (cdb)->alloc_len = al; \
+}
+
+/*
+ * page control field values
+ */
+#define SCSI_PC_CURRENT_VALUES 0x0
+#define SCSI_PC_CHANGEABLE_VALUES 0x1
+#define SCSI_PC_DEFAULT_VALUES 0x2
+#define SCSI_PC_SAVED_VALUES 0x3
+
+/*
+ * SCSI mode page codes
+ */
+#define SCSI_MP_VENDOR_SPEC 0x00
+#define SCSI_MP_DISC_RECN 0x02 /* disconnect-reconnect page */
+#define SCSI_MP_FORMAT_DEVICE 0x03
+#define SCSI_MP_RDG 0x04 /* rigid disk geometry page */
+#define SCSI_MP_FDP 0x05 /* flexible disk page */
+#define SCSI_MP_CACHING 0x08 /* caching page */
+#define SCSI_MP_CONTROL 0x0A /* control mode page */
+#define SCSI_MP_MED_TYPES_SUP 0x0B /* medium types supported page */
+#define SCSI_MP_INFO_EXCP_CNTL 0x1C /* informational exception control */
+#define SCSI_MP_ALL 0x3F /* return all pages - mode sense only */
+
+/*
+ * mode parameter header
+ */
+struct scsi_mode_param_header6_s{
+ u8 mode_datalen;
+ u8 medium_type;
+
+ /*
+ * device specific parameters expanded for direct access devices
+ */
+#ifdef __BIGENDIAN
+ u32 wp:1; /* write protected */
+ u32 reserved1:2;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved2:4;
+#else
+ u32 reserved2:4;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved1:2;
+ u32 wp:1; /* write protected */
+#endif
+
+ u8 block_desclen;
+};
+
+struct scsi_mode_param_header10_s{
+ u32 mode_datalen:16;
+ u32 medium_type:8;
+
+ /*
+ * device specific parameters expanded for direct access devices
+ */
+#ifdef __BIGENDIAN
+ u32 wp:1; /* write protected */
+ u32 reserved1:2;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved2:4;
+#else
+ u32 reserved2:4;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved1:2;
+ u32 wp:1; /* write protected */
+#endif
+
+#ifdef __BIGENDIAN
+ u32 reserved3:7;
+ u32 longlba:1;
+#else
+ u32 longlba:1;
+ u32 reserved3:7;
+#endif
+ u32 reserved4:8;
+ u32 block_desclen:16;
+};
+
+/*
+ * mode parameter block descriptor
+ */
+struct scsi_mode_param_desc_s{
+ u32 nblks;
+ u32 density_code:8;
+ u32 block_length:24;
+};
+
+/*
+ * Disconnect-reconnect mode page format
+ */
+struct scsi_mp_disc_recn_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+ u8 buf_full_ratio;
+ u8 buf_empty_ratio;
+
+ u8 bil_msb; /* bus inactivity limit -MSB */
+ u8 bil_lsb; /* bus inactivity limit -LSB */
+
+ u8 dtl_msb; /* disconnect time limit - MSB */
+ u8 dtl_lsb; /* disconnect time limit - LSB */
+
+ u8 ctl_msb; /* connect time limit - MSB */
+ u8 ctl_lsb; /* connect time limit - LSB */
+
+ u8 max_burst_len_msb;
+ u8 max_burst_len_lsb;
+#ifdef __BIGENDIAN
+ u8 emdp:1; /* enable modify data pointers */
+ u8 fa:3; /* fair arbitration */
+ u8 dimm:1; /* disconnect immediate */
+ u8 dtdc:3; /* data transfer disconnect control */
+#else
+ u8 dtdc:3; /* data transfer disconnect control */
+ u8 dimm:1; /* disconnect immediate */
+ u8 fa:3; /* fair arbitration */
+ u8 emdp:1; /* enable modify data pointers */
+#endif
+
+ u8 reserved3;
+
+ u8 first_burst_len_msb;
+ u8 first_burst_len_lsb;
+};
+
+/*
+ * SCSI format device mode page
+ */
+struct scsi_mp_format_device_s{
+#ifdef __BIGENDIAN
+ u32 ps:1;
+ u32 reserved1:1;
+ u32 page_code:6;
+#else
+ u32 page_code:6;
+ u32 reserved1:1;
+ u32 ps:1;
+#endif
+ u32 page_len:8;
+ u32 tracks_per_zone:16;
+
+ u32 a_sec_per_zone:16;
+ u32 a_tracks_per_zone:16;
+
+ u32 a_tracks_per_lun:16; /* alternate tracks/lun-MSB */
+ u32 sec_per_track:16; /* sectors/track-MSB */
+
+ u32 bytes_per_sector:16;
+ u32 interleave:16;
+
+ u32 tsf:16; /* track skew factor-MSB */
+ u32 csf:16; /* cylinder skew factor-MSB */
+
+#ifdef __BIGENDIAN
+ u32 ssec:1; /* soft sector formatting */
+ u32 hsec:1; /* hard sector formatting */
+ u32 rmb:1; /* removable media */
+ u32 surf:1; /* surface */
+ u32 reserved2:4;
+#else
+ u32 reserved2:4;
+ u32 surf:1; /* surface */
+ u32 rmb:1; /* removable media */
+ u32 hsec:1; /* hard sector formatting */
+ u32 ssec:1; /* soft sector formatting */
+#endif
+ u32 reserved3:24;
+};
+
+/*
+ * SCSI rigid disk device geometry page
+ */
+struct scsi_mp_rigid_device_geometry_s{
+#ifdef __BIGENDIAN
+ u32 ps:1;
+ u32 reserved1:1;
+ u32 page_code:6;
+#else
+ u32 page_code:6;
+ u32 reserved1:1;
+ u32 ps:1;
+#endif
+ u32 page_len:8;
+ u32 num_cylinders0:8;
+ u32 num_cylinders1:8;
+
+ u32 num_cylinders2:8;
+ u32 num_heads:8;
+ u32 scwp0:8;
+ u32 scwp1:8;
+
+ u32 scwp2:8;
+ u32 scrwc0:8;
+ u32 scrwc1:8;
+ u32 scrwc2:8;
+
+ u32 dsr:16;
+ u32 lscyl0:8;
+ u32 lscyl1:8;
+
+ u32 lscyl2:8;
+#ifdef __BIGENDIAN
+ u32 reserved2:6;
+ u32 rpl:2; /* rotational position locking */
+#else
+ u32 rpl:2; /* rotational position locking */
+ u32 reserved2:6;
+#endif
+ u32 rot_off:8;
+ u32 reserved3:8;
+
+ u32 med_rot_rate:16;
+ u32 reserved4:16;
+};
+
+/*
+ * SCSI caching mode page
+ */
+struct scsi_mp_caching_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 res1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 res1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+#ifdef __BIGENDIAN
+ u8 ic:1; /* initiator control */
+ u8 abpf:1; /* abort pre-fetch */
+ u8 cap:1; /* caching analysis permitted */
+ u8 disc:1; /* discontinuity */
+ u8 size:1; /* size enable */
+ u8 wce:1; /* write cache enable */
+ u8 mf:1; /* multiplication factor */
+ u8 rcd:1; /* read cache disable */
+
+ u8 drrp:4; /* demand read retention priority */
+ u8 wrp:4; /* write retention priority */
+#else
+ u8 rcd:1; /* read cache disable */
+ u8 mf:1; /* multiplication factor */
+ u8 wce:1; /* write cache enable */
+ u8 size:1; /* size enable */
+ u8 disc:1; /* discontinuity */
+ u8 cap:1; /* caching analysis permitted */
+ u8 abpf:1; /* abort pre-fetch */
+ u8 ic:1; /* initiator control */
+
+ u8 wrp:4; /* write retention priority */
+ u8 drrp:4; /* demand read retention priority */
+#endif
+ u8 dptl[2];/* disable pre-fetch transfer length */
+ u8 min_prefetch[2];
+ u8 max_prefetch[2];
+ u8 max_prefetch_limit[2];
+#ifdef __BIGENDIAN
+ u8 fsw:1; /* force sequential write */
+ u8 lbcss:1;/* logical block cache segment size */
+ u8 dra:1; /* disable read ahead */
+ u8 vs:2; /* vendor specific */
+ u8 res2:3;
+#else
+ u8 res2:3;
+ u8 vs:2; /* vendor specific */
+ u8 dra:1; /* disable read ahead */
+ u8 lbcss:1;/* logical block cache segment size */
+ u8 fsw:1; /* force sequential write */
+#endif
+ u8 num_cache_segs;
+
+ u8 cache_seg_size[2];
+ u8 res3;
+ u8 non_cache_seg_size[3];
+};
+
+/*
+ * SCSI control mode page
+ */
+struct scsi_mp_control_page_s{
+#ifdef __BIGENDIAN
+u8 ps:1;
+u8 reserved1:1;
+u8 page_code:6;
+#else
+u8 page_code:6;
+u8 reserved1:1;
+u8 ps:1;
+#endif
+ u8 page_len;
+#ifdef __BIGENDIAN
+ u8 tst:3; /* task set type */
+ u8 reserved3:3;
+ u8 gltsd:1; /* global logging target save disable */
+ u8 rlec:1; /* report log exception condition */
+
+ u8 qalgo_mod:4; /* queue alogorithm modifier */
+ u8 reserved4:1;
+ u8 qerr:2; /* queue error management */
+ u8 dque:1; /* disable queuing */
+
+ u8 reserved5:1;
+ u8 rac:1; /* report a check */
+ u8 reserved6:2;
+ u8 swp:1; /* software write protect */
+ u8 raerp:1; /* ready AER permission */
+ u8 uaaerp:1; /* unit attenstion AER permission */
+ u8 eaerp:1; /* error AER permission */
+
+ u8 reserved7:5;
+ u8 autoload_mod:3;
+#else
+ u8 rlec:1; /* report log exception condition */
+ u8 gltsd:1; /* global logging target save disable */
+ u8 reserved3:3;
+ u8 tst:3; /* task set type */
+
+ u8 dque:1; /* disable queuing */
+ u8 qerr:2; /* queue error management */
+ u8 reserved4:1;
+ u8 qalgo_mod:4; /* queue alogorithm modifier */
+
+ u8 eaerp:1; /* error AER permission */
+ u8 uaaerp:1; /* unit attenstion AER permission */
+ u8 raerp:1; /* ready AER permission */
+ u8 swp:1; /* software write protect */
+ u8 reserved6:2;
+ u8 rac:1; /* report a check */
+ u8 reserved5:1;
+
+ u8 autoload_mod:3;
+ u8 reserved7:5;
+#endif
+ u8 rahp_msb; /* ready AER holdoff period - MSB */
+ u8 rahp_lsb; /* ready AER holdoff period - LSB */
+
+ u8 busy_timeout_period_msb;
+ u8 busy_timeout_period_lsb;
+
+ u8 ext_selftest_compl_time_msb;
+ u8 ext_selftest_compl_time_lsb;
+};
+
+/*
+ * SCSI medium types supported mode page
+ */
+struct scsi_mp_medium_types_sup_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+
+ u8 reserved3[2];
+ u8 med_type1_sup; /* medium type one supported */
+ u8 med_type2_sup; /* medium type two supported */
+ u8 med_type3_sup; /* medium type three supported */
+ u8 med_type4_sup; /* medium type four supported */
+};
+
+/*
+ * SCSI informational exception control mode page
+ */
+struct scsi_mp_info_excpt_cntl_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+#ifdef __BIGENDIAN
+ u8 perf:1; /* performance */
+ u8 reserved3:1;
+ u8 ebf:1; /* enable background fucntion */
+ u8 ewasc:1; /* enable warning */
+ u8 dexcpt:1; /* disable exception control */
+ u8 test:1; /* enable test device failure
+ * notification
+ */
+ u8 reserved4:1;
+ u8 log_error:1;
+
+ u8 reserved5:4;
+ u8 mrie:4; /* method of reporting info
+ * exceptions
+ */
+#else
+ u8 log_error:1;
+ u8 reserved4:1;
+ u8 test:1; /* enable test device failure
+ * notification
+ */
+ u8 dexcpt:1; /* disable exception control */
+ u8 ewasc:1; /* enable warning */
+ u8 ebf:1; /* enable background fucntion */
+ u8 reserved3:1;
+ u8 perf:1; /* performance */
+
+ u8 mrie:4; /* method of reporting info
+ * exceptions
+ */
+ u8 reserved5:4;
+#endif
+ u8 interval_timer_msb;
+ u8 interval_timer_lsb;
+
+ u8 report_count_msb;
+ u8 report_count_lsb;
+};
+
+/*
+ * Methods of reporting informational exceptions
+ */
+#define SCSI_MP_IEC_NO_REPORT 0x0 /* no reporting of exceptions */
+#define SCSI_MP_IEC_AER 0x1 /* async event reporting */
+#define SCSI_MP_IEC_UNIT_ATTN 0x2 /* generate unit attenstion */
+#define SCSI_MO_IEC_COND_REC_ERR 0x3 /* conditionally generate recovered
+ * error
+ */
+#define SCSI_MP_IEC_UNCOND_REC_ERR 0x4 /* unconditionally generate recovered
+ * error
+ */
+#define SCSI_MP_IEC_NO_SENSE 0x5 /* generate no sense */
+#define SCSI_MP_IEC_ON_REQUEST 0x6 /* only report exceptions on request */
+
+/*
+ * SCSI flexible disk page
+ */
+struct scsi_mp_flexible_disk_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+
+ u8 transfer_rate_msb;
+ u8 transfer_rate_lsb;
+
+ u8 num_heads;
+ u8 num_sectors;
+
+ u8 bytes_per_sector_msb;
+ u8 bytes_per_sector_lsb;
+
+ u8 num_cylinders_msb;
+ u8 num_cylinders_lsb;
+
+ u8 sc_wpc_msb; /* starting cylinder-write
+ * precompensation msb
+ */
+ u8 sc_wpc_lsb; /* starting cylinder-write
+ * precompensation lsb
+ */
+ u8 sc_rwc_msb; /* starting cylinder-reduced write
+ * current msb
+ */
+ u8 sc_rwc_lsb; /* starting cylinder-reduced write
+ * current lsb
+ */
+
+ u8 dev_step_rate_msb;
+ u8 dev_step_rate_lsb;
+
+ u8 dev_step_pulse_width;
+
+ u8 head_sd_msb; /* head settle delay msb */
+ u8 head_sd_lsb; /* head settle delay lsb */
+
+ u8 motor_on_delay;
+ u8 motor_off_delay;
+#ifdef __BIGENDIAN
+ u8 trdy:1; /* true ready bit */
+ u8 ssn:1; /* start sector number bit */
+ u8 mo:1; /* motor on bit */
+ u8 reserved3:5;
+
+ u8 reserved4:4;
+ u8 spc:4; /* step pulse per cylinder */
+#else
+ u8 reserved3:5;
+ u8 mo:1; /* motor on bit */
+ u8 ssn:1; /* start sector number bit */
+ u8 trdy:1; /* true ready bit */
+
+ u8 spc:4; /* step pulse per cylinder */
+ u8 reserved4:4;
+#endif
+ u8 write_comp;
+ u8 head_load_delay;
+ u8 head_unload_delay;
+#ifdef __BIGENDIAN
+ u8 pin34:4; /* pin34 usage */
+ u8 pin2:4; /* pin2 usage */
+
+ u8 pin4:4; /* pin4 usage */
+ u8 pin1:4; /* pin1 usage */
+#else
+ u8 pin2:4; /* pin2 usage */
+ u8 pin34:4; /* pin34 usage */
+
+ u8 pin1:4; /* pin1 usage */
+ u8 pin4:4; /* pin4 usage */
+#endif
+ u8 med_rot_rate_msb;
+ u8 med_rot_rate_lsb;
+
+ u8 reserved5[2];
+};
+
+struct scsi_mode_page_format_data6_s{
+ struct scsi_mode_param_header6_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_format_device_s format; /* format device data */
+};
+
+struct scsi_mode_page_format_data10_s{
+ struct scsi_mode_param_header10_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_format_device_s format; /* format device data */
+};
+
+struct scsi_mode_page_rdg_data6_s{
+ struct scsi_mode_param_header6_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_rigid_device_geometry_s rdg;
+ /* rigid geometry data */
+};
+
+struct scsi_mode_page_rdg_data10_s{
+ struct scsi_mode_param_header10_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_rigid_device_geometry_s rdg;
+ /* rigid geometry data */
+};
+
+struct scsi_mode_page_cache6_s{
+ struct scsi_mode_param_header6_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_caching_s cache; /* cache page data */
+};
+
+struct scsi_mode_page_cache10_s{
+ struct scsi_mode_param_header10_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_caching_s cache; /* cache page data */
+};
+
+/* --------------------------------------------------------------
+ * Format Unit command
+ * ------------------------------------------------------------
+ */
+
+/*
+ * Format Unit CDB
+ */
+struct scsi_format_unit_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 res1:3;
+ u8 fmtdata:1; /* if set, data out phase has format
+ * data
+ */
+ u8 cmplst:1; /* if set, defect list is complete */
+ u8 def_list:3; /* format of defect descriptor is
+ * fmtdata =1
+ */
+#else
+ u8 def_list:3; /* format of defect descriptor is
+ * fmtdata = 1
+ */
+ u8 cmplst:1; /* if set, defect list is complete */
+ u8 fmtdata:1; /* if set, data out phase has format
+ * data
+ */
+ u8 res1:3;
+#endif
+ u8 interleave_msb;
+ u8 interleave_lsb;
+ u8 vendor_spec;
+ u8 control;
+};
+
+/*
+ * h
+ */
+struct scsi_reserve6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved:3;
+ u8 obsolete:4;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 obsolete:4;
+ u8 reserved:3;
+#endif
+ u8 reservation_id;
+ u16 param_list_len;
+ u8 control;
+};
+
+/*
+ * h
+ */
+struct scsi_release6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 obsolete:4;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 obsolete:4;
+ u8 reserved1:3;
+#endif
+ u8 reservation_id;
+ u16 reserved2;
+ u8 control;
+};
+
+/*
+ * h
+ */
+struct scsi_reserve10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 third_party:1;
+ u8 reserved2:2;
+ u8 long_id:1;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 long_id:1;
+ u8 reserved2:2;
+ u8 third_party:1;
+ u8 reserved1:3;
+#endif
+ u8 reservation_id;
+ u8 third_pty_dev_id;
+ u8 reserved3;
+ u8 reserved4;
+ u8 reserved5;
+ u16 param_list_len;
+ u8 control;
+};
+
+struct scsi_release10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 third_party:1;
+ u8 reserved2:2;
+ u8 long_id:1;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 long_id:1;
+ u8 reserved2:2;
+ u8 third_party:1;
+ u8 reserved1:3;
+#endif
+ u8 reservation_id;
+ u8 third_pty_dev_id;
+ u8 reserved3;
+ u8 reserved4;
+ u8 reserved5;
+ u16 param_list_len;
+ u8 control;
+};
+
+struct scsi_verify10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 dpo:1;
+ u8 reserved:2;
+ u8 bytchk:1;
+ u8 reladdr:1;
+#else
+ u8 reladdr:1;
+ u8 bytchk:1;
+ u8 reserved:2;
+ u8 dpo:1;
+ u8 lun:3;
+#endif
+ u8 lba0;
+ u8 lba1;
+ u8 lba2;
+ u8 lba3;
+ u8 reserved1;
+ u8 verification_len0;
+ u8 verification_len1;
+ u8 control_byte;
+};
+
+struct scsi_request_sense_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved:5;
+#else
+ u8 reserved:5;
+ u8 lun:3;
+#endif
+ u8 reserved0;
+ u8 reserved1;
+ u8 alloc_len;
+ u8 control_byte;
+};
+
+/* ------------------------------------------------------------
+ * SCSI status byte values
+ * ------------------------------------------------------------
+ */
+#define SCSI_STATUS_GOOD 0x00
+#define SCSI_STATUS_CHECK_CONDITION 0x02
+#define SCSI_STATUS_CONDITION_MET 0x04
+#define SCSI_STATUS_BUSY 0x08
+#define SCSI_STATUS_INTERMEDIATE 0x10
+#define SCSI_STATUS_ICM 0x14 /* intermediate condition met */
+#define SCSI_STATUS_RESERVATION_CONFLICT 0x18
+#define SCSI_STATUS_COMMAND_TERMINATED 0x22
+#define SCSI_STATUS_QUEUE_FULL 0x28
+#define SCSI_STATUS_ACA_ACTIVE 0x30
+
+#define SCSI_MAX_ALLOC_LEN 0xFF /* maximum allocarion length
+ * in CDBs
+ */
+
+#define SCSI_OP_WRITE_VERIFY10 0x2E
+#define SCSI_OP_WRITE_VERIFY12 0xAE
+#define SCSI_OP_UNDEF 0xFF
+
+/*
+ * SCSI WRITE-VERIFY(10) command
+ */
+struct scsi_write_verify10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 dpo:1; /* Disable Page Out */
+ u8 reserved2:1;
+ u8 ebp:1; /* erse by-pass */
+ u8 bytchk:1; /* byte check */
+ u8 rel_adr:1; /* relative address */
+#else
+ u8 rel_adr:1; /* relative address */
+ u8 bytchk:1; /* byte check */
+ u8 ebp:1; /* erse by-pass */
+ u8 reserved2:1;
+ u8 dpo:1; /* Disable Page Out */
+ u8 reserved1:3;
+#endif
+ u8 lba0; /* logical block address - MSB */
+ u8 lba1;
+ u8 lba2;
+ u8 lba3; /* LSB */
+ u8 reserved3;
+ u8 xfer_length0; /* transfer length in blocks - MSB */
+ u8 xfer_length1; /* LSB */
+ u8 control;
+};
+
+#pragma pack()
+
+#endif /* __SCSI_H__ */
diff --git a/drivers/scsi/bfa/include/protocol/types.h b/drivers/scsi/bfa/include/protocol/types.h
new file mode 100644
index 000000000000..2875a6cced3b
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/types.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * types.h Protocol defined base types
+ */
+
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#include <bfa_os_inc.h>
+
+#define wwn_t u64
+#define lun_t u64
+
+#define WWN_NULL (0)
+#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */
+#define FC_ALPA_MAX 128
+
+#pragma pack(1)
+
+#define MAC_ADDRLEN (6)
+struct mac_s { u8 mac[MAC_ADDRLEN]; };
+#define mac_t struct mac_s
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/loop.c b/drivers/scsi/bfa/loop.c
new file mode 100644
index 000000000000..a418dedebe9e
--- /dev/null
+++ b/drivers/scsi/bfa/loop.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * port_loop.c vport private loop implementation.
+ */
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, LOOP);
+
+/**
+ * ALPA to LIXA bitmap mapping
+ *
+ * ALPA 0x00 (Word 0, Bit 30) is invalid for N_Ports. Also Word 0 Bit 31
+ * is for L_bit (login required) and is filled as ALPA 0x00 here.
+ */
+static const u8 port_loop_alpa_map[] = {
+ 0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, /* Word 3 Bits 0..7 */
+ 0xD9, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, /* Word 3 Bits 8..15 */
+ 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC7, 0xC6, 0xC5, /* Word 3 Bits 16..23 */
+ 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, 0xB4, 0xB3, /* Word 3 Bits 24..31 */
+
+ 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, /* Word 2 Bits 0..7 */
+ 0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, /* Word 2 Bits 8..15 */
+ 0x98, 0x97, 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, /* Word 2 Bits 16..23 */
+ 0x80, 0x7C, 0x7A, 0x79, 0x76, 0x75, 0x74, 0x73, /* Word 2 Bits 24..31 */
+
+ 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, /* Word 1 Bits 0..7 */
+ 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56, /* Word 1 Bits 8..15 */
+ 0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, /* Word 1 Bits 16..23 */
+ 0x4B, 0x4A, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, /* Word 1 Bits 24..31 */
+
+ 0x3A, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, /* Word 0 Bits 0..7 */
+ 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x27, 0x26, /* Word 0 Bits 8..15 */
+ 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17, /* Word 0 Bits 16..23 */
+ 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, /* Word 0 Bits 24..31 */
+};
+
+/*
+ * Local Functions
+ */
+bfa_status_t bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port,
+ u8 alpa);
+
+void bfa_fcs_port_loop_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);
+
+bfa_status_t bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port,
+ u8 alpa);
+
+void bfa_fcs_port_loop_adisc_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);
+
+bfa_status_t bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port,
+ u8 alpa);
+
+void bfa_fcs_port_loop_plogi_acc_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);
+
+bfa_status_t bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port,
+ u8 alpa);
+
+void bfa_fcs_port_loop_adisc_acc_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);
+/**
+ * Called by port to initializar in provate LOOP topology.
+ */
+void
+bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Called by port to notify transition to online state.
+ */
+void
+bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port)
+{
+
+ u8 num_alpa = port->port_topo.ploop.num_alpa;
+ u8 *alpa_pos_map = port->port_topo.ploop.alpa_pos_map;
+ struct bfa_fcs_rport_s *r_port;
+ int ii = 0;
+
+ /*
+ * If the port role is Initiator Mode, create Rports.
+ */
+ if (port->port_cfg.roles == BFA_PORT_ROLE_FCP_IM) {
+ /*
+ * Check if the ALPA positional bitmap is available.
+ * if not, we send PLOGI to all possible ALPAs.
+ */
+ if (num_alpa > 0) {
+ for (ii = 0; ii < num_alpa; ii++) {
+ /*
+ * ignore ALPA of bfa port
+ */
+ if (alpa_pos_map[ii] != port->pid) {
+ r_port = bfa_fcs_rport_create(port,
+ alpa_pos_map[ii]);
+ }
+ }
+ } else {
+ for (ii = 0; ii < MAX_ALPA_COUNT; ii++) {
+ /*
+ * ignore ALPA of bfa port
+ */
+ if ((port_loop_alpa_map[ii] > 0)
+ && (port_loop_alpa_map[ii] != port->pid))
+ bfa_fcs_port_loop_send_plogi(port,
+ port_loop_alpa_map[ii]);
+ /**TBD */
+ }
+ }
+ } else {
+ /*
+ * TBD Target Mode ??
+ */
+ }
+
+}
+
+/**
+ * Called by port to notify transition to offline state.
+ */
+void
+bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port)
+{
+
+}
+
+/**
+ * Called by port to notify a LIP on the loop.
+ */
+void
+bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Local Functions.
+ */
+bfa_status_t
+bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp = NULL;
+ int len;
+
+ bfa_trc(port->fcs, alpa);
+
+ fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
+ NULL);
+ bfa_assert(fcxp);
+
+ len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn,
+ bfa_pport_get_maxfrsize(port->fcs->bfa));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs,
+ bfa_fcs_port_loop_plogi_response, (void *)port,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Called by fcxp to notify the Plogi response
+ */
+void
+bfa_fcs_port_loop_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_port_s *port = (struct bfa_fcs_port_s *) cbarg;
+ struct fc_logi_s *plogi_resp;
+ struct fc_els_cmd_s *els_cmd;
+
+ bfa_trc(port->fcs, req_status);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ /*
+ * @todo
+ * This could mean that the device with this APLA does not
+ * exist on the loop.
+ */
+
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+ plogi_resp = (struct fc_logi_s *) els_cmd;
+
+ if (els_cmd->els_code == FC_ELS_ACC) {
+ bfa_fcs_rport_start(port, rsp_fchs, plogi_resp);
+ } else {
+ bfa_trc(port->fcs, plogi_resp->els_cmd.els_code);
+ bfa_assert(0);
+ }
+}
+
+bfa_status_t
+bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port, u8 alpa)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(port->fcs, alpa);
+
+ fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
+ NULL);
+ bfa_assert(fcxp);
+
+ len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn,
+ bfa_pport_get_maxfrsize(port->fcs->bfa));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs,
+ bfa_fcs_port_loop_plogi_acc_response,
+ (void *)port, FC_MAX_PDUSZ, 0); /* No response
+ * expected
+ */
+
+ return BFA_STATUS_OK;
+}
+
+/*
+ * Plogi Acc Response
+ * We donot do any processing here.
+ */
+void
+bfa_fcs_port_loop_plogi_acc_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_port_s *port = (struct bfa_fcs_port_s *) cbarg;
+
+ bfa_trc(port->fcs, port->pid);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ return;
+ }
+}
+
+bfa_status_t
+bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port, u8 alpa)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(port->fcs, alpa);
+
+ fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
+ NULL);
+ bfa_assert(fcxp);
+
+ len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs,
+ bfa_fcs_port_loop_adisc_response, (void *)port,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Called by fcxp to notify the ADISC response
+ */
+void
+bfa_fcs_port_loop_adisc_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_port_s *port = (struct bfa_fcs_port_s *) cbarg;
+ struct bfa_fcs_rport_s *rport;
+ struct fc_adisc_s *adisc_resp;
+ struct fc_els_cmd_s *els_cmd;
+ u32 pid = rsp_fchs->s_id;
+
+ bfa_trc(port->fcs, req_status);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ /*
+ * TBD : we may need to retry certain requests
+ */
+ bfa_fcxp_free(fcxp);
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+ adisc_resp = (struct fc_adisc_s *) els_cmd;
+
+ if (els_cmd->els_code == FC_ELS_ACC) {
+ } else {
+ bfa_trc(port->fcs, adisc_resp->els_cmd.els_code);
+
+ /*
+ * TBD: we may need to check for reject codes and retry
+ */
+ rport = bfa_fcs_port_get_rport_by_pid(port, pid);
+ if (rport) {
+ list_del(&rport->qe);
+ bfa_fcs_rport_delete(rport);
+ }
+
+ }
+ return;
+}
+
+bfa_status_t
+bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port, u8 alpa)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(port->fcs, alpa);
+
+ fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
+ NULL);
+ bfa_assert(fcxp);
+
+ len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs,
+ bfa_fcs_port_loop_adisc_acc_response,
+ (void *)port, FC_MAX_PDUSZ, 0); /* no reponse
+ * expected
+ */
+
+ return BFA_STATUS_OK;
+}
+
+/*
+ * Adisc Acc Response
+ * We donot do any processing here.
+ */
+void
+bfa_fcs_port_loop_adisc_acc_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_port_s *port = (struct bfa_fcs_port_s *) cbarg;
+
+ bfa_trc(port->fcs, port->pid);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ return;
+ }
+}
diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c
new file mode 100644
index 000000000000..8f51a83f1834
--- /dev/null
+++ b/drivers/scsi/bfa/lport_api.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * port_api.c BFA FCS port
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include "fcs_rport.h"
+#include "fcs_fabric.h"
+#include "fcs_trcmod.h"
+#include "fcs_vport.h"
+
+BFA_TRC_FILE(FCS, PORT_API);
+
+
+
+/**
+ * fcs_port_api BFA FCS port API
+ */
+
+void
+bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg)
+{
+}
+
+struct bfa_fcs_port_s *
+bfa_fcs_get_base_port(struct bfa_fcs_s *fcs)
+{
+ return (&fcs->fabric.bport);
+}
+
+wwn_t
+bfa_fcs_port_get_rport(struct bfa_fcs_port_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_os_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_port_get_rports(struct bfa_fcs_port_s *port, wwn_t rport_wwns[],
+ int *nrports)
+{
+ struct list_head *qh, *qe;
+ struct bfa_fcs_rport_s *rport = NULL;
+ int i;
+ struct bfa_fcs_s *fcs;
+
+ if (port == NULL || rport_wwns == 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_os_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;
+ }
+
+ rport_wwns[i] = rport->pwwn;
+
+ i++;
+ qe = bfa_q_next(qe);
+ }
+
+ bfa_trc(fcs, i);
+ *nrports = i;
+ return;
+}
+
+/*
+ * Iterate's through all the rport's in the given port to
+ * determine the maximum operating speed.
+ */
+enum bfa_pport_speed
+bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port)
+{
+ struct list_head *qh, *qe;
+ struct bfa_fcs_rport_s *rport = NULL;
+ struct bfa_fcs_s *fcs;
+ enum bfa_pport_speed max_speed = 0;
+ struct bfa_pport_attr_s pport_attr;
+ enum bfa_pport_speed pport_speed;
+
+ if (port == NULL)
+ return 0;
+
+ fcs = port->fcs;
+
+ /*
+ * Get Physical port's current speed
+ */
+ bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+ pport_speed = pport_attr.speed;
+ bfa_trc(fcs, pport_speed);
+
+ qh = &port->rport_q;
+ qe = bfa_q_first(qh);
+
+ while (qe != qh) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000)
+ || (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE)) {
+ qe = bfa_q_next(qe);
+ continue;
+ }
+
+ if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_8GBPS)
+ || (rport->rpf.rpsc_speed > pport_speed)) {
+ max_speed = rport->rpf.rpsc_speed;
+ break;
+ } else if (rport->rpf.rpsc_speed > max_speed) {
+ max_speed = rport->rpf.rpsc_speed;
+ }
+
+ qe = bfa_q_next(qe);
+ }
+
+ bfa_trc(fcs, max_speed);
+ return max_speed;
+}
+
+struct bfa_fcs_port_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;
+
+ bfa_assert(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 VmWare's NPIV_VPORT_GETINFO.
+ */
+void
+bfa_fcs_port_get_info(struct bfa_fcs_port_s *port,
+ struct bfa_port_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_PORT_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_port_get_pwwn(port);
+ port_info->node_wwn = bfa_fcs_port_get_nwwn(port);
+
+ port_info->max_vports_supp = bfa_fcs_vport_get_max(port->fcs);
+ port_info->num_vports_inuse =
+ bfa_fcs_fabric_vport_count(port->fabric);
+ 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_PORT_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_port_get_pwwn(port);
+ port_info->node_wwn = bfa_fcs_port_get_nwwn(port);
+ }
+}
+
+void
+bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port,
+ struct bfa_port_stats_s *port_stats)
+{
+ bfa_os_memcpy(port_stats, &fcs_port->stats,
+ sizeof(struct bfa_port_stats_s));
+ return;
+}
+
+void
+bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port)
+{
+ bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_port_stats_s));
+ return;
+}
+
+void
+bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port)
+{
+ fcs_port->port_cfg.roles |= BFA_PORT_ROLE_FCP_IPFC;
+ return;
+}
+
+void
+bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port)
+{
+ fcs_port->port_cfg.roles &= ~BFA_PORT_ROLE_FCP_IPFC;
+ return;
+}
+
+
diff --git a/drivers/scsi/bfa/lport_priv.h b/drivers/scsi/bfa/lport_priv.h
new file mode 100644
index 000000000000..dbae370a599a
--- /dev/null
+++ b/drivers/scsi/bfa/lport_priv.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+#ifndef __VP_PRIV_H__
+#define __VP_PRIV_H__
+
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_vport.h>
+
+/*
+ * Functions exported by vps
+ */
+void bfa_fcs_vport_init(struct bfa_fcs_vport_s *vport);
+
+/*
+ * Functions exported by vps
+ */
+void bfa_fcs_vps_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_vps_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_vps_lip(struct bfa_fcs_port_s *port);
+
+/*
+ * Functions exported by port_fab
+ */
+void bfa_fcs_port_fab_init(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_fab_online(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_fab_rx_frame(struct bfa_fcs_port_s *port,
+ u8 *rx_frame, u32 len);
+
+/*
+ * Functions exported by VP-NS.
+ */
+void bfa_fcs_port_ns_init(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_ns_online(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port);
+
+/*
+ * Functions exported by VP-SCN
+ */
+void bfa_fcs_port_scn_init(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_scn_online(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_frame, u32 len);
+
+/*
+ * Functions exported by VP-N2N
+ */
+
+void bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_n2n_rx_frame(struct bfa_fcs_port_s *port,
+ u8 *rx_frame, u32 len);
+
+/*
+ * Functions exported by VP-LOOP
+ */
+void bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_rx_frame(struct bfa_fcs_port_s *port,
+ u8 *rx_frame, u32 len);
+
+#endif /* __VP_PRIV_H__ */
diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c
new file mode 100644
index 000000000000..c96b3ca007ae
--- /dev/null
+++ b/drivers/scsi/bfa/ms.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, MS);
+
+#define BFA_FCS_MS_CMD_MAX_RETRIES 2
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_ms_send_plogi(void *ms_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ms_timeout(void *arg);
+static void bfa_fcs_port_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_port_ms_send_gmal(void *ms_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_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_port_ms_send_gfn(void *ms_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_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_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+/**
+ * Start in offline state - awaiting NS to send start.
+ */
+static void
+bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_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_port_ms_sm_plogi_sending);
+ bfa_fcs_port_ms_send_plogi(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_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_port_ms_sm_plogi);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_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_port_ms_sm_plogi_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer,
+ bfa_fcs_port_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_port_fdmi_online(ms);
+
+ /**
+ * if this is a Vport, go to online state.
+ */
+ if (ms->port->vport) {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
+ break;
+ }
+
+ /*
+ * For a base port we need to get the
+ * switch's IP address.
+ */
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending);
+ bfa_fcs_port_ms_send_gmal(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_discard(ms->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_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_port_ms_sm_plogi_sending);
+ bfa_fcs_port_ms_send_plogi(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_timer_stop(&ms->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_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_port_ms_sm_offline);
+ /*
+ * now invoke MS related sub-modules
+ */
+ bfa_fcs_port_fdmi_offline(ms);
+ break;
+
+ case MSSM_EVENT_PORT_FABRIC_RSCN:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
+ ms->retry_cnt = 0;
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_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_port_ms_sm_gmal);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_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_port_ms_sm_gmal_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->timer, bfa_fcs_port_ms_timeout, ms,
+ BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ ms->retry_cnt = 0;
+ }
+ break;
+
+ case MSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_discard(ms->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_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_port_ms_sm_gmal_sending);
+ bfa_fcs_port_ms_send_gmal(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_timer_stop(&ms->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * ms_pvt MS local functions
+ */
+
+static void
+bfa_fcs_port_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ms_s *ms = ms_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
+ bfa_fcs_port_ms_send_gmal, ms);
+ return;
+ }
+ ms->fcxp = fcxp;
+
+ len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port),
+ bfa_lps_get_peer_nwwn(port->fabric->lps));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response,
+ (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
+ struct bfa_fcs_port_s *port = ms->port;
+ struct ct_hdr_s *cthdr = NULL;
+ struct fcgs_gmal_resp_s *gmal_resp;
+ struct fc_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 = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1);
+ num_entries = bfa_os_ntohl(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 fc_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_port_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_port_ms_sm_gfn_sending(struct bfa_fcs_port_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_port_ms_sm_gfn);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_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_port_ms_sm_gfn_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->timer, bfa_fcs_port_ms_timeout, ms,
+ BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
+ ms->retry_cnt = 0;
+ }
+ break;
+
+ case MSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_discard(ms->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_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_port_ms_sm_gfn_sending);
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_timer_stop(&ms->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * ms_pvt MS local functions
+ */
+
+static void
+bfa_fcs_port_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ms_s *ms = ms_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
+ bfa_fcs_port_ms_send_gfn, ms);
+ return;
+ }
+ ms->fcxp = fcxp;
+
+ len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port),
+ bfa_lps_get_peer_nwwn(port->fabric->lps));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response,
+ (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
+ struct bfa_fcs_port_s *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 = bfa_os_ntohs(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_port_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_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ms_s *ms = ms_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ port->stats.ms_plogi_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
+ bfa_fcs_port_ms_send_plogi, ms);
+ return;
+ }
+ ms->fcxp = fcxp;
+
+ len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_os_hton3b(FC_MGMT_SERVER),
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn,
+ bfa_pport_get_maxfrsize(port->fcs->bfa));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response,
+ (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ms_plogi_sent++;
+ bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
+
+ struct bfa_fcs_port_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_port_ms_timeout(void *arg)
+{
+ struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)arg;
+
+ ms->port->stats.ms_timeouts++;
+ bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT);
+}
+
+
+void
+bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
+
+ ms->port = port;
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+
+ /*
+ * Invoke init routines of sub modules.
+ */
+ bfa_fcs_port_fdmi_init(ms);
+}
+
+void
+bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
+
+ ms->port = port;
+ bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE);
+}
+
+void
+bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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_port_ms_fabric_rscn(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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_port_ms_sm_online))
+ bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN);
+}
diff --git a/drivers/scsi/bfa/n2n.c b/drivers/scsi/bfa/n2n.c
new file mode 100644
index 000000000000..735456824346
--- /dev/null
+++ b/drivers/scsi/bfa/n2n.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * n2n.c n2n implementation.
+ */
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, N2N);
+
+/**
+ * Called by fcs/port to initialize N2N topology.
+ */
+void
+bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Called by fcs/port to notify transition to online state.
+ */
+void
+bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_n2n_s *n2n_port = &port->port_topo.pn2n;
+ struct bfa_port_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;
+ /**
+ * First, check if we know the device by pwwn.
+ */
+ rport = bfa_fcs_port_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_fcs_rport_online(rport);
+ 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_port_get_rport_by_pid(port, 0);
+ bfa_assert(rport != NULL);
+ if (rport) {
+ bfa_trc(port->fcs, rport->pwwn);
+ bfa_fcs_rport_delete(rport);
+ }
+ }
+ bfa_fcs_rport_create(port, N2N_REMOTE_PID);
+ }
+}
+
+/**
+ * Called by fcs/port to notify transition to offline state.
+ */
+void
+bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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;
+}
+
+
diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c
new file mode 100644
index 000000000000..59fea99d67a4
--- /dev/null
+++ b/drivers/scsi/bfa/ns.c
@@ -0,0 +1,1243 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * @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
+ */
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfa_iocfc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, NS);
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_ns_send_plogi(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_rft_id(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_rff_id(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_timeout(void *arg);
+static void bfa_fcs_port_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_port_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_port_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_port_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_port_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_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port,
+ u32 *pid_buf,
+ u32 n_pids);
+
+static void bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *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_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+/**
+ * Start in offline state - awaiting linkup
+ */
+static void
+bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_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_port_ns_sm_plogi_sending);
+ bfa_fcs_port_ns_send_plogi(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_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_port_ns_sm_plogi);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_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_port_ns_sm_plogi_retry);
+ ns->port->stats.ns_retries++;
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer,
+ bfa_fcs_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id);
+ bfa_fcs_port_ns_send_rspn_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_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_port_ns_sm_plogi_sending);
+ bfa_fcs_port_ns_send_plogi(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_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_port_ns_sm_rspn_id);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_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_port_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_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id);
+ bfa_fcs_port_ns_send_rft_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_fcxp_discard(ns->fcxp);
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_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_port_ns_sm_sending_rspn_id);
+ bfa_fcs_port_ns_send_rspn_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_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_port_ns_sm_rft_id);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_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_port_ns_sm_sending_rff_id);
+ bfa_fcs_port_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_port_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_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_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_port_ns_sm_sending_rft_id);
+ bfa_fcs_port_ns_send_rft_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_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_port_ns_sm_rff_id);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_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_port_ns_boot_target_disc(ns->port);
+ bfa_sm_set_state(ns, bfa_fcs_port_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_port_ns_sm_sending_gid_ft);
+ bfa_fcs_port_ns_send_gid_ft(ns, NULL);
+ } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) {
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online);
+ }
+ /*
+ * kick off mgmt srvr state machine
+ */
+ bfa_fcs_port_ms_online(ns->port);
+ break;
+
+ case NSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_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_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_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_port_ns_sm_sending_rff_id);
+ bfa_fcs_port_ns_send_rff_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+static void
+bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_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_port_ns_sm_gid_ft);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_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_port_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_port_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_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_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_port_ns_sm_sending_gid_ft);
+ bfa_fcs_port_ns_send_gid_ft(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_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_port_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_port_ns_sm_sending_gid_ft);
+ bfa_fcs_port_ns_send_gid_ft(ns, NULL);
+ };
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * ns_pvt Nameserver local functions
+ */
+
+static void
+bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ port->stats.ns_plogi_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_plogi, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_os_hton3b(FC_NAME_SERVER),
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn,
+ bfa_pport_get_maxfrsize(port->fcs->bfa));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+ port->stats.ns_plogi_sent++;
+
+ bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_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_port_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+ u8 symbl[256];
+ u8 *psymbl = &symbl[0];
+
+ bfa_os_memset(symbl, 0, sizeof(symbl));
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ port->stats.ns_rspnid_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_rspn_id, ns);
+ 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_port_get_psym_name
+ (bfa_fcs_get_base_port(port->fcs))),
+ strlen((char *)
+ &bfa_fcs_port_get_psym_name(bfa_fcs_get_base_port
+ (port->fcs))));
+
+ /*
+ * Ensure we have a null terminating string.
+ */
+ ((char *)
+ psymbl)[strlen((char *)
+ &bfa_fcs_port_get_psym_name
+ (bfa_fcs_get_base_port(port->fcs)))] = 0;
+
+ strncat((char *)psymbl,
+ (char *)&(bfa_fcs_port_get_psym_name(port)),
+ strlen((char *)&bfa_fcs_port_get_psym_name(port)));
+ } else {
+ psymbl = (u8 *) &(bfa_fcs_port_get_psym_name(port));
+ }
+
+ len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_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_port_ns_rspn_id_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ns_rspnid_sent++;
+
+ bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_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 = bfa_os_ntohs(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
+ * TBD, Need to retrieve this from the OS driver, in case IPFC is enabled ?
+ */
+static void
+bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ port->stats.ns_rftid_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_rft_id, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_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_port_ns_rft_id_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ns_rftid_sent++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_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 = bfa_os_ntohs(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_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ port->stats.ns_rffid_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_rff_id, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) {
+ fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR;
+ } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) {
+ fc4_ftrs = FC_GS_FCP_FC4_FEATURE_TARGET;
+ }
+
+ len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_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_port_ns_rff_id_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ns_rffid_sent++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_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 = bfa_os_ntohs(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_port_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ port->stats.ns_gidft_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_gid_ft, ns);
+ 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_port_ns_gid_ft_response,
+ (void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa),
+ FC_RA_TOV);
+
+ port->stats.ns_gidft_sent++;
+
+ bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_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 = bfa_os_ntohs(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_port_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_port_t.
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+static void
+bfa_fcs_port_ns_timeout(void *arg)
+{
+ struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_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_port_ns_process_gidft_pids(struct bfa_fcs_port_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_port_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_port_ns_init(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);
+
+ ns->port = port;
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+}
+
+void
+bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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_port_ns_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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_port_ns_query(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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_port_ns_boot_target_disc(struct bfa_fcs_port_s *port)
+{
+
+ struct bfa_fcs_rport_s *rport;
+ u8 nwwns;
+ wwn_t *wwns;
+ 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]);
+ bfa_assert(rport);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/plog.c b/drivers/scsi/bfa/plog.c
new file mode 100644
index 000000000000..86af818d17bb
--- /dev/null
+++ b/drivers/scsi/bfa/plog.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa_os_inc.h>
+#include <cs/bfa_plog.h>
+#include <cs/bfa_debug.h>
+
+static int
+plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec)
+{
+ if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT)
+ && (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING))
+ return 1;
+
+ if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT)
+ && (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ))
+ return 1;
+
+ return 0;
+}
+
+static void
+bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
+{
+ u16 tail;
+ struct bfa_plog_rec_s *pl_recp;
+
+ if (plog->plog_enabled == 0)
+ return;
+
+ if (plkd_validate_logrec(pl_rec)) {
+ bfa_assert(0);
+ return;
+ }
+
+ tail = plog->tail;
+
+ pl_recp = &(plog->plog_recs[tail]);
+
+ bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
+
+ pl_recp->tv = BFA_TRC_TS(plog);
+ BFA_PL_LOG_REC_INCR(plog->tail);
+
+ if (plog->head == plog->tail)
+ BFA_PL_LOG_REC_INCR(plog->head);
+}
+
+void
+bfa_plog_init(struct bfa_plog_s *plog)
+{
+ bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s));
+
+ bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
+ plog->head = plog->tail = 0;
+ plog->plog_enabled = 1;
+}
+
+void
+bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event,
+ u16 misc, char *log_str)
+{
+ struct bfa_plog_rec_s lp;
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ lp.mid = mid;
+ lp.eid = event;
+ lp.log_type = BFA_PL_LOG_TYPE_STRING;
+ lp.misc = misc;
+ strncpy(lp.log_entry.string_log, log_str,
+ BFA_PL_STRING_LOG_SZ - 1);
+ lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
+ bfa_plog_add(plog, &lp);
+ }
+}
+
+void
+bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event,
+ u16 misc, u32 *intarr, u32 num_ints)
+{
+ struct bfa_plog_rec_s lp;
+ u32 i;
+
+ if (num_ints > BFA_PL_INT_LOG_SZ)
+ num_ints = BFA_PL_INT_LOG_SZ;
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ lp.mid = mid;
+ lp.eid = event;
+ lp.log_type = BFA_PL_LOG_TYPE_INT;
+ lp.misc = misc;
+
+ for (i = 0; i < num_ints; i++)
+ bfa_os_assign(lp.log_entry.int_log[i],
+ intarr[i]);
+
+ lp.log_num_ints = (u8) num_ints;
+
+ bfa_plog_add(plog, &lp);
+ }
+}
+
+void
+bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event,
+ u16 misc, struct fchs_s *fchdr)
+{
+ struct bfa_plog_rec_s lp;
+ u32 *tmp_int = (u32 *) fchdr;
+ u32 ints[BFA_PL_INT_LOG_SZ];
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+
+ ints[0] = tmp_int[0];
+ ints[1] = tmp_int[1];
+ ints[2] = tmp_int[4];
+
+ bfa_plog_intarr(plog, mid, event, misc, ints, 3);
+ }
+}
+
+void
+bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr,
+ u32 pld_w0)
+{
+ struct bfa_plog_rec_s lp;
+ u32 *tmp_int = (u32 *) fchdr;
+ u32 ints[BFA_PL_INT_LOG_SZ];
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+
+ ints[0] = tmp_int[0];
+ ints[1] = tmp_int[1];
+ ints[2] = tmp_int[4];
+ ints[3] = pld_w0;
+
+ bfa_plog_intarr(plog, mid, event, misc, ints, 4);
+ }
+}
+
+void
+bfa_plog_clear(struct bfa_plog_s *plog)
+{
+ plog->head = plog->tail = 0;
+}
+
+void
+bfa_plog_enable(struct bfa_plog_s *plog)
+{
+ plog->plog_enabled = 1;
+}
+
+void
+bfa_plog_disable(struct bfa_plog_s *plog)
+{
+ plog->plog_enabled = 0;
+}
+
+bfa_boolean_t
+bfa_plog_get_setting(struct bfa_plog_s *plog)
+{
+ return((bfa_boolean_t)plog->plog_enabled);
+}
diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c
new file mode 100644
index 000000000000..9cf58bb138dc
--- /dev/null
+++ b/drivers/scsi/bfa/rport.c
@@ -0,0 +1,2618 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * rport.c Remote port implementation.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcbuild.h"
+#include "fcs_vport.h"
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_fcpim.h"
+#include "fcs_fcptm.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include <fcb/bfa_fcb_rport.h>
+#include <aen/bfa_aen_rport.h>
+
+BFA_TRC_FILE(FCS, RPORT);
+
+#define BFA_FCS_RPORT_MAX_RETRIES (5)
+
+/* In millisecs */
+static u32 bfa_fcs_rport_del_timeout =
+ BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000;
+
+/*
+ * forward declarations
+ */
+static struct bfa_fcs_rport_s *bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port,
+ wwn_t pwwn, u32 rpid);
+static void bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport,
+ struct fc_logi_s *plogi);
+static void bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_timeout(void *arg);
+static void bfa_fcs_rport_send_plogi(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_send_plogiacc(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_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_rport_send_adisc(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_adisc_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_rport_send_gidpn(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_gidpn_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_rport_send_logo(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_send_logo_acc(void *rport_cbarg);
+static void bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len);
+static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u8 reason_code,
+ u8 reason_code_expl);
+static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len);
+/**
+ * fcs_rport_sm FCS rport state machine events
+ */
+
+enum rport_event {
+ RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */
+ RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */
+ RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */
+ RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */
+ RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */
+ RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */
+ RPSM_EVENT_DELETE = 7, /* RPORT delete request */
+ RPSM_EVENT_SCN = 8, /* state change notification */
+ RPSM_EVENT_ACCEPTED = 9,/* Good response from remote device */
+ RPSM_EVENT_FAILED = 10, /* Request to rport failed. */
+ RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */
+ RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */
+ RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */
+ RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */
+ RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */
+ RPSM_EVENT_ADDRESS_DISC = 16 /* Need to Discover rport's PID */
+};
+
+static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+
+static struct bfa_sm_table_s rport_sm_table[] = {
+ {BFA_SM(bfa_fcs_rport_sm_uninit), BFA_RPORT_UNINIT},
+ {BFA_SM(bfa_fcs_rport_sm_plogi_sending), BFA_RPORT_PLOGI},
+ {BFA_SM(bfa_fcs_rport_sm_plogiacc_sending), BFA_RPORT_ONLINE},
+ {BFA_SM(bfa_fcs_rport_sm_plogi_retry), BFA_RPORT_PLOGI_RETRY},
+ {BFA_SM(bfa_fcs_rport_sm_plogi), BFA_RPORT_PLOGI},
+ {BFA_SM(bfa_fcs_rport_sm_hal_online), BFA_RPORT_ONLINE},
+ {BFA_SM(bfa_fcs_rport_sm_online), BFA_RPORT_ONLINE},
+ {BFA_SM(bfa_fcs_rport_sm_nsquery_sending), BFA_RPORT_NSQUERY},
+ {BFA_SM(bfa_fcs_rport_sm_nsquery), BFA_RPORT_NSQUERY},
+ {BFA_SM(bfa_fcs_rport_sm_adisc_sending), BFA_RPORT_ADISC},
+ {BFA_SM(bfa_fcs_rport_sm_adisc), BFA_RPORT_ADISC},
+ {BFA_SM(bfa_fcs_rport_sm_fc4_logorcv), BFA_RPORT_LOGORCV},
+ {BFA_SM(bfa_fcs_rport_sm_fc4_logosend), BFA_RPORT_LOGO},
+ {BFA_SM(bfa_fcs_rport_sm_fc4_offline), BFA_RPORT_OFFLINE},
+ {BFA_SM(bfa_fcs_rport_sm_hcb_offline), BFA_RPORT_OFFLINE},
+ {BFA_SM(bfa_fcs_rport_sm_hcb_logorcv), BFA_RPORT_LOGORCV},
+ {BFA_SM(bfa_fcs_rport_sm_hcb_logosend), BFA_RPORT_LOGO},
+ {BFA_SM(bfa_fcs_rport_sm_logo_sending), BFA_RPORT_LOGO},
+ {BFA_SM(bfa_fcs_rport_sm_offline), BFA_RPORT_OFFLINE},
+ {BFA_SM(bfa_fcs_rport_sm_nsdisc_sending), BFA_RPORT_NSDISC},
+ {BFA_SM(bfa_fcs_rport_sm_nsdisc_retry), BFA_RPORT_NSDISC},
+ {BFA_SM(bfa_fcs_rport_sm_nsdisc_sent), BFA_RPORT_NSDISC},
+};
+
+/**
+ * Beginning state.
+ */
+static void
+bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_PLOGI_SEND:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ rport->plogi_retries = 0;
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ case RPSM_EVENT_ADDRESS_DISC:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is being sent.
+ */
+static void
+bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_SCN:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is being sent.
+ */
+static void
+bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * Ignore, SCN is possibly online notification.
+ */
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_HCB_OFFLINE:
+ /**
+ * Ignore BFA callback, on a PLOGI receive we call bfa offline.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is sent.
+ */
+static void
+bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_SCN:
+ bfa_timer_stop(&rport->timer);
+ /*
+ * !! fall through !!
+ */
+
+ case RPSM_EVENT_TIMEOUT:
+ rport->plogi_retries++;
+ if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ } else {
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_timer_stop(&rport->timer);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_stop(&rport->timer);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is sent.
+ */
+static void
+bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ rport->plogi_retries = 0;
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_fcs_rport_send_logo_acc(rport);
+ bfa_fcxp_discard(rport->fcxp);
+ /*
+ * !! fall through !!
+ */
+ case RPSM_EVENT_FAILED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * Ignore SCN - wait for PLOGI response.
+ */
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is complete. Awaiting BFA rport online callback. FC-4s
+ * are offline.
+ */
+static void
+bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_ONLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_online);
+ bfa_fcs_rport_online_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_rport_offline(rport->bfa_rport);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * @todo
+ * Ignore SCN - PLOGI just completed, FC-4 login should detect
+ * device failures.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is ONLINE. FC-4s active.
+ */
+static void
+bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_SCN:
+ /**
+ * Pause FC-4 activity till rport is authenticated.
+ * In switched fabrics, check presence of device in nameserver
+ * first.
+ */
+ bfa_fcs_rport_fc4_pause(rport);
+
+ if (bfa_fcs_fabric_is_switched(rport->port->fabric)) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsquery_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending);
+ bfa_fcs_rport_send_adisc(rport, NULL);
+ }
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. NS query is being sent
+ * prior to ADISC authentication with rport. FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsquery);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * ignore SCN, wait for response to query itself
+ */
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. NS query is sent to rport.
+ * FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending);
+ bfa_fcs_rport_send_adisc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_FAILED:
+ rport->ns_retries++;
+ if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsquery_sending);
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcs_rport_offline_action(rport);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ case RPSM_EVENT_PLOGI_RCVD:
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. ADISC is being sent for
+ * authenticating with rport. FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. ADISC is to rport.
+ * FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_online);
+ bfa_fcs_rport_fc4_resume(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ /**
+ * Too complex to cleanup FC-4 & rport and then acc to PLOGI.
+ * At least go offline when a PLOGI is received.
+ */
+ bfa_fcxp_discard(rport->fcxp);
+ /*
+ * !!! fall through !!!
+ */
+
+ case RPSM_EVENT_FAILED:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * already processing RSCN
+ */
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport has sent LOGO. Awaiting FC-4 offline completion callback.
+ */
+static void
+bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FC4_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * LOGO needs to be sent to rport. Awaiting FC-4 offline completion
+ * callback.
+ */
+static void
+bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FC4_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is going offline. Awaiting FC-4 offline completion callback.
+ */
+static void
+bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FC4_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ /**
+ * rport is already going offline.
+ * SCN - ignore and wait till transitioning to offline state
+ */
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is offline. FC-4s are offline. Awaiting BFA rport offline
+ * callback.
+ */
+static void
+bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_OFFLINE:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ if (bfa_fcs_port_is_online(rport->port)) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_LOGO_RCVD:
+ /**
+ * Ignore, already offline.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is offline. FC-4s are offline. Awaiting BFA rport offline
+ * callback to send LOGO accept.
+ */
+static void
+bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_OFFLINE:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ if (rport->pid)
+ bfa_fcs_rport_send_logo_acc(rport);
+ /*
+ * If the lport is online and if the rport is not a well known
+ * address port, we try to re-discover the r-port.
+ */
+ if (bfa_fcs_port_is_online(rport->port)
+ && (!BFA_FCS_PID_IS_WKA(rport->pid))) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ /*
+ * if it is not a well known address, reset the pid to
+ *
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ /**
+ * Ignore - already processing a LOGO.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is being deleted. FC-4s are offline. Awaiting BFA rport offline
+ * callback to send LOGO.
+ */
+static void
+bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_logo_sending);
+ bfa_fcs_rport_send_logo(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is being deleted. FC-4s are offline. LOGO is being sent.
+ */
+static void
+bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ /*
+ * Once LOGO is sent, we donot wait for the response
+ */
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is offline. FC-4s are offline. BFA rport is offline.
+ * Timer active to delete stale rport.
+ */
+static void
+bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_timer_stop(&rport->timer);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_LOGO_IMP:
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_SEND:
+ bfa_timer_stop(&rport->timer);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ rport->plogi_retries = 0;
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport address has changed. Nameserver discovery request is being sent.
+ */
+static void
+bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sent);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PLOGI_SEND:
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ rport->ns_retries = 0; /* reset the retry count */
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Nameserver discovery failed. Waiting for timeout to retry.
+ */
+static void
+bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_timer_stop(&rport->timer);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_stop(&rport->timer);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_fcs_rport_send_logo_acc(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport address has changed. Nameserver discovery request is sent.
+ */
+static void
+bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ if (rport->pid) {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ } else {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ }
+ break;
+
+ case RPSM_EVENT_FAILED:
+ rport->ns_retries++;
+ if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ };
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * ignore, wait for NS query response
+ */
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ /**
+ * Not logged-in yet. Accept LOGO.
+ */
+ bfa_fcs_rport_send_logo_acc(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_rport_private FCS RPORT provate functions
+ */
+
+static void
+bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_plogi, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn,
+ bfa_pport_get_maxfrsize(port->fcs->bfa));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response,
+ (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ rport->stats.plogis++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_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_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct fc_logi_s *plogi_rsp;
+ struct fc_ls_rjt_s *ls_rjt;
+ struct bfa_fcs_rport_s *twin;
+ struct list_head *qe;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(rport->fcs, req_status);
+ rport->stats.plogi_failed++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ return;
+ }
+
+ plogi_rsp = (struct fc_logi_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ /**
+ * Check for failure first.
+ */
+ if (plogi_rsp->els_cmd.els_code != FC_ELS_ACC) {
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ bfa_trc(rport->fcs, ls_rjt->reason_code);
+ bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
+
+ rport->stats.plogi_rejects++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ return;
+ }
+
+ /**
+ * PLOGI is complete. Make sure this device is not one of the known
+ * device with a new FC port address.
+ */
+ list_for_each(qe, &rport->port->rport_q) {
+ twin = (struct bfa_fcs_rport_s *)qe;
+ if (twin == rport)
+ continue;
+ if (!rport->pwwn && (plogi_rsp->port_name == twin->pwwn)) {
+ bfa_trc(rport->fcs, twin->pid);
+ bfa_trc(rport->fcs, rport->pid);
+
+ /*
+ * Update plogi stats in twin
+ */
+ twin->stats.plogis += rport->stats.plogis;
+ twin->stats.plogi_rejects += rport->stats.plogi_rejects;
+ twin->stats.plogi_timeouts +=
+ rport->stats.plogi_timeouts;
+ twin->stats.plogi_failed += rport->stats.plogi_failed;
+ twin->stats.plogi_rcvd += rport->stats.plogi_rcvd;
+ twin->stats.plogi_accs++;
+
+ bfa_fcs_rport_delete(rport);
+
+ bfa_fcs_rport_update(twin, plogi_rsp);
+ twin->pid = rsp_fchs->s_id;
+ bfa_sm_send_event(twin, RPSM_EVENT_PLOGI_COMP);
+ return;
+ }
+ }
+
+ /**
+ * Normal login path -- no evil twins.
+ */
+ rport->stats.plogi_accs++;
+ bfa_fcs_rport_update(rport, plogi_rsp);
+ bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
+}
+
+static void
+bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_plogiacc, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), rport->reply_oxid,
+ port->port_cfg.pwwn, port->port_cfg.nwwn,
+ bfa_pport_get_maxfrsize(port->fcs->bfa));
+
+ 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);
+
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_adisc, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.pwwn, port->port_cfg.nwwn);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response,
+ rport, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ rport->stats.adisc_sent++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_adisc_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_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ void *pld = bfa_fcxp_get_rspbuf(fcxp);
+ struct fc_ls_rjt_s *ls_rjt;
+
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(rport->fcs, req_status);
+ rport->stats.adisc_failed++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ return;
+ }
+
+ if (fc_adisc_rsp_parse((struct fc_adisc_s *)pld, rsp_len, rport->pwwn,
+ rport->nwwn) == FC_PARSE_OK) {
+ rport->stats.adisc_accs++;
+ bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
+ return;
+ }
+
+ rport->stats.adisc_rejects++;
+ ls_rjt = pld;
+ bfa_trc(rport->fcs, ls_rjt->els_cmd.els_code);
+ bfa_trc(rport->fcs, ls_rjt->reason_code);
+ bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+}
+
+static void
+bfa_fcs_rport_send_gidpn(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(rport->fcs, rport->pid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_gidpn, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_gidpn_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port), 0, rport->pwwn);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_rport_gidpn_response,
+ (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_gidpn_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_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct bfa_fcs_rport_s *twin;
+ struct list_head *qe;
+ struct ct_hdr_s *cthdr;
+ struct fcgs_gidpn_resp_s *gidpn_rsp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ /*
+ * Check if the pid is the same as before.
+ */
+ gidpn_rsp = (struct fcgs_gidpn_resp_s *) (cthdr + 1);
+
+ if (gidpn_rsp->dap == rport->pid) {
+ /*
+ * Device is online
+ */
+ bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
+ } else {
+ /*
+ * Device's PID has changed. We need to cleanup and
+ * re-login. If there is another device with the the
+ * newly discovered pid, send an scn notice so that its
+ * new pid can be discovered.
+ */
+ list_for_each(qe, &rport->port->rport_q) {
+ twin = (struct bfa_fcs_rport_s *)qe;
+ if (twin == rport)
+ continue;
+ if (gidpn_rsp->dap == twin->pid) {
+ bfa_trc(rport->fcs, twin->pid);
+ bfa_trc(rport->fcs, rport->pid);
+
+ twin->pid = 0;
+ bfa_sm_send_event(twin,
+ RPSM_EVENT_ADDRESS_CHANGE);
+ }
+ }
+ rport->pid = gidpn_rsp->dap;
+ bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_CHANGE);
+ }
+ return;
+ }
+
+ /*
+ * Reject Response
+ */
+ switch (cthdr->reason_code) {
+ case CT_RSN_LOGICAL_BUSY:
+ /*
+ * Need to retry
+ */
+ bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT);
+ break;
+
+ case CT_RSN_UNABLE_TO_PERF:
+ /*
+ * device doesn't exist : Start timer to cleanup this later.
+ */
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ break;
+
+ default:
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ break;
+ }
+}
+
+/**
+ * Called to send a logout to the rport.
+ */
+static void
+bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ u16 len;
+
+ bfa_trc(rport->fcs, rport->pid);
+
+ port = rport->port;
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_logo, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_logo_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), 0,
+ bfa_fcs_port_get_pwwn(port));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, NULL, rport, FC_MAX_PDUSZ,
+ FC_ED_TOV);
+
+ rport->stats.logos++;
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+/**
+ * Send ACC for a LOGO received.
+ */
+static void
+bfa_fcs_rport_send_logo_acc(void *rport_cbarg)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ u16 len;
+
+ bfa_trc(rport->fcs, rport->pid);
+
+ port = rport->port;
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ rport->stats.logo_rcvd++;
+ len = fc_logo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), rport->reply_oxid);
+
+ 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);
+}
+
+/**
+ * This routine will be called by bfa_timer on timer timeouts.
+ *
+ * param[in] rport - pointer to bfa_fcs_port_ns_t.
+ * param[out] rport_status - pointer to return vport status in
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+static void
+bfa_fcs_rport_timeout(void *arg)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)arg;
+
+ rport->stats.plogi_timeouts++;
+ bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT);
+}
+
+static void
+bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len)
+{
+ struct bfa_fcxp_s *fcxp;
+ struct fchs_s fchs;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_prli_s *prli;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+
+ rport->stats.prli_rcvd++;
+
+ if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) {
+ /*
+ * Target Mode : Let the fcptm handle it
+ */
+ bfa_fcs_tin_rx_prli(rport->tin, rx_fchs, len);
+ return;
+ }
+
+ /*
+ * We are either in Initiator or ipfc Mode
+ */
+ prli = (struct fc_prli_s *) (rx_fchs + 1);
+
+ if (prli->parampage.servparams.initiator) {
+ bfa_trc(rport->fcs, prli->parampage.type);
+ rport->scsi_function = BFA_RPORT_INITIATOR;
+ bfa_fcs_itnim_is_initiator(rport->itnim);
+ } else {
+ /*
+ * @todo: PRLI from a target ?
+ */
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ rport->scsi_function = BFA_RPORT_TARGET;
+ }
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_prli_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ port->port_cfg.roles);
+
+ 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_rport_process_rpsc(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len)
+{
+ struct bfa_fcxp_s *fcxp;
+ struct fchs_s fchs;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_rpsc_speed_info_s speeds;
+ struct bfa_pport_attr_s pport_attr;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+
+ rport->stats.rpsc_rcvd++;
+ speeds.port_speed_cap =
+ RPSC_SPEED_CAP_1G | RPSC_SPEED_CAP_2G | RPSC_SPEED_CAP_4G |
+ RPSC_SPEED_CAP_8G;
+
+ /*
+ * get curent speed from pport attributes from BFA
+ */
+ bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+
+ speeds.port_op_speed = fc_bfa_speed_to_rpsc_operspeed(pport_attr.speed);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_rpsc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ &speeds);
+
+ 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_rport_process_adisc(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len)
+{
+ struct bfa_fcxp_s *fcxp;
+ struct fchs_s fchs;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_adisc_s *adisc;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+
+ rport->stats.adisc_rcvd++;
+
+ if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) {
+ /*
+ * @todo : Target Mode handling
+ */
+ bfa_trc(port->fcs, rx_fchs->d_id);
+ bfa_assert(0);
+ return;
+ }
+
+ adisc = (struct fc_adisc_s *) (rx_fchs + 1);
+
+ /*
+ * Accept if the itnim for this rport is online. Else reject the ADISC
+ */
+ if (bfa_fcs_itnim_get_online_state(rport->itnim) == BFA_STATUS_OK) {
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port),
+ rx_fchs->ox_id, port->port_cfg.pwwn,
+ port->port_cfg.nwwn);
+
+ 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);
+ } else {
+ rport->stats.adisc_rejected++;
+ bfa_fcs_rport_send_ls_rjt(rport, rx_fchs,
+ FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD,
+ FC_LS_RJT_EXP_LOGIN_REQUIRED);
+ }
+
+}
+
+static void
+bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct bfa_rport_info_s rport_info;
+
+ rport_info.pid = rport->pid;
+ rport_info.local_pid = port->pid;
+ rport_info.lp_tag = port->lp_tag;
+ rport_info.vf_id = port->fabric->vf_id;
+ rport_info.vf_en = port->fabric->is_vf;
+ rport_info.fc_class = rport->fc_cos;
+ rport_info.cisc = rport->cisc;
+ rport_info.max_frmsz = rport->maxfrsize;
+ bfa_rport_online(rport->bfa_rport, &rport_info);
+}
+
+static void
+bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport)
+{
+ if (bfa_fcs_port_is_initiator(rport->port))
+ bfa_fcs_itnim_pause(rport->itnim);
+
+ if (bfa_fcs_port_is_target(rport->port))
+ bfa_fcs_tin_pause(rport->tin);
+}
+
+static void
+bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport)
+{
+ if (bfa_fcs_port_is_initiator(rport->port))
+ bfa_fcs_itnim_resume(rport->itnim);
+
+ if (bfa_fcs_port_is_target(rport->port))
+ bfa_fcs_tin_resume(rport->tin);
+}
+
+static struct bfa_fcs_rport_s *
+bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, wwn_t pwwn, u32 rpid)
+{
+ struct bfa_fcs_s *fcs = port->fcs;
+ struct bfa_fcs_rport_s *rport;
+ struct bfad_rport_s *rport_drv;
+
+ /**
+ * allocate rport
+ */
+ if (bfa_fcb_rport_alloc(fcs->bfad, &rport, &rport_drv)
+ != BFA_STATUS_OK) {
+ bfa_trc(fcs, rpid);
+ return NULL;
+ }
+
+ /*
+ * Initialize r-port
+ */
+ rport->port = port;
+ rport->fcs = fcs;
+ rport->rp_drv = rport_drv;
+ rport->pid = rpid;
+ rport->pwwn = pwwn;
+
+ /**
+ * allocate BFA rport
+ */
+ rport->bfa_rport = bfa_rport_create(port->fcs->bfa, rport);
+ if (!rport->bfa_rport) {
+ bfa_trc(fcs, rpid);
+ kfree(rport_drv);
+ return NULL;
+ }
+
+ /**
+ * allocate FC-4s
+ */
+ bfa_assert(bfa_fcs_port_is_initiator(port) ^
+ bfa_fcs_port_is_target(port));
+
+ if (bfa_fcs_port_is_initiator(port)) {
+ rport->itnim = bfa_fcs_itnim_create(rport);
+ if (!rport->itnim) {
+ bfa_trc(fcs, rpid);
+ bfa_rport_delete(rport->bfa_rport);
+ kfree(rport_drv);
+ return NULL;
+ }
+ }
+
+ if (bfa_fcs_port_is_target(port)) {
+ rport->tin = bfa_fcs_tin_create(rport);
+ if (!rport->tin) {
+ bfa_trc(fcs, rpid);
+ bfa_rport_delete(rport->bfa_rport);
+ kfree(rport_drv);
+ return NULL;
+ }
+ }
+
+ bfa_fcs_port_add_rport(port, rport);
+
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+
+ /*
+ * Initialize the Rport Features(RPF) Sub Module
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rpf_init(rport);
+
+ return rport;
+}
+
+
+static void
+bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ /**
+ * - delete FC-4s
+ * - delete BFA rport
+ * - remove from queue of rports
+ */
+ if (bfa_fcs_port_is_initiator(port))
+ bfa_fcs_itnim_delete(rport->itnim);
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_tin_delete(rport->tin);
+
+ bfa_rport_delete(rport->bfa_rport);
+ bfa_fcs_port_del_rport(port, rport);
+ kfree(rport->rp_drv);
+}
+
+static void
+bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport,
+ enum bfa_rport_aen_event event,
+ struct bfa_rport_aen_data_s *data)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = rport->fcs->logm;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(rport->port);
+ wwn_t rpwwn = rport->pwwn;
+ char lpwwn_ptr[BFA_STRING_32];
+ char rpwwn_ptr[BFA_STRING_32];
+ char *prio_str[] = { "unknown", "high", "medium", "low" };
+
+ wwn2str(lpwwn_ptr, lpwwn);
+ wwn2str(rpwwn_ptr, rpwwn);
+
+ switch (event) {
+ case BFA_RPORT_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_RPORT_ONLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_RPORT_OFFLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_RPORT_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_QOS_PRIO:
+ aen_data.rport.priv.qos = data->priv.qos;
+ bfa_log(logmod, BFA_AEN_RPORT_QOS_PRIO,
+ prio_str[aen_data.rport.priv.qos.qos_priority],
+ rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_QOS_FLOWID:
+ aen_data.rport.priv.qos = data->priv.qos;
+ bfa_log(logmod, BFA_AEN_RPORT_QOS_FLOWID,
+ aen_data.rport.priv.qos.qos_flow_id, rpwwn_ptr,
+ lpwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.rport.vf_id = rport->port->fabric->vf_id;
+ aen_data.rport.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(rport->fcs));
+ aen_data.rport.lpwwn = lpwwn;
+ aen_data.rport.rpwwn = rpwwn;
+}
+
+static void
+bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ rport->stats.onlines++;
+
+ if (bfa_fcs_port_is_initiator(port)) {
+ bfa_fcs_itnim_rport_online(rport->itnim);
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rpf_rport_online(rport);
+ };
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_tin_rport_online(rport->tin);
+
+ /*
+ * Don't post events for well known addresses
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_ONLINE, NULL);
+}
+
+static void
+bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ rport->stats.offlines++;
+
+ /*
+ * Don't post events for well known addresses
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
+ if (bfa_fcs_port_is_online(rport->port) == BFA_TRUE) {
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_DISCONNECT,
+ NULL);
+ } else {
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_OFFLINE,
+ NULL);
+ }
+ }
+
+ if (bfa_fcs_port_is_initiator(port)) {
+ bfa_fcs_itnim_rport_offline(rport->itnim);
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rpf_rport_offline(rport);
+ }
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_tin_rport_offline(rport->tin);
+}
+
+/**
+ * Update rport parameters from PLOGI or PLOGI accept.
+ */
+static void
+bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ /**
+ * - port name
+ * - node name
+ */
+ rport->pwwn = plogi->port_name;
+ rport->nwwn = plogi->node_name;
+
+ /**
+ * - class of service
+ */
+ rport->fc_cos = 0;
+ if (plogi->class3.class_valid)
+ rport->fc_cos = FC_CLASS_3;
+
+ if (plogi->class2.class_valid)
+ rport->fc_cos |= FC_CLASS_2;
+
+ /**
+ * - CISC
+ * - MAX receive frame size
+ */
+ rport->cisc = plogi->csp.cisc;
+ rport->maxfrsize = bfa_os_ntohs(plogi->class3.rxsz);
+
+ bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+ bfa_trc(port->fcs, port->fabric->bb_credit);
+ /**
+ * Direct Attach P2P mode :
+ * This is to handle a bug (233476) in IBM targets in Direct Attach
+ * Mode. Basically, in FLOGI Accept the target would have erroneously
+ * set the BB Credit to the value used in the FLOGI sent by the HBA.
+ * It uses the correct value (its own BB credit) in PLOGI.
+ */
+ if ((!bfa_fcs_fabric_is_switched(port->fabric))
+ && (bfa_os_ntohs(plogi->csp.bbcred) < port->fabric->bb_credit)) {
+
+ bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+ bfa_trc(port->fcs, port->fabric->bb_credit);
+
+ port->fabric->bb_credit = bfa_os_ntohs(plogi->csp.bbcred);
+ bfa_pport_set_tx_bbcredit(port->fcs->bfa,
+ port->fabric->bb_credit);
+ }
+
+}
+
+/**
+ * Called to handle LOGO received from an existing remote port.
+ */
+static void
+bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs)
+{
+ rport->reply_oxid = fchs->ox_id;
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ rport->stats.logo_rcvd++;
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_RCVD);
+}
+
+
+
+/**
+ * fcs_rport_public FCS rport public interfaces
+ */
+
+/**
+ * Called by bport/vport to create a remote port instance for a discovered
+ * remote device.
+ *
+ * @param[in] port - base port or vport
+ * @param[in] rpid - remote port ID
+ *
+ * @return None
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_create(struct bfa_fcs_port_s *port, u32 rpid)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, rpid);
+ rport = bfa_fcs_rport_alloc(port, WWN_NULL, rpid);
+ if (!rport)
+ return NULL;
+
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
+ return rport;
+}
+
+/**
+ * Called to create a rport for which only the wwn is known.
+ *
+ * @param[in] port - base port
+ * @param[in] rpwwn - remote port wwn
+ *
+ * @return None
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, rpwwn);
+ rport = bfa_fcs_rport_alloc(port, rpwwn, 0);
+ if (!rport)
+ return NULL;
+
+ bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC);
+ return rport;
+}
+
+/**
+ * Called by bport in private loop topology to indicate that a
+ * rport has been discovered and plogi has been completed.
+ *
+ * @param[in] port - base port or vport
+ * @param[in] rpid - remote port ID
+ */
+void
+bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *fchs,
+ struct fc_logi_s *plogi)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_rport_alloc(port, WWN_NULL, fchs->s_id);
+ if (!rport)
+ return;
+
+ bfa_fcs_rport_update(rport, plogi);
+
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_COMP);
+}
+
+/**
+ * Called by bport/vport to handle PLOGI received from a new remote port.
+ * If an existing rport does a plogi, it will be handled separately.
+ */
+void
+bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, struct fchs_s *fchs,
+ struct fc_logi_s *plogi)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_rport_alloc(port, plogi->port_name, fchs->s_id);
+ if (!rport)
+ return;
+
+ bfa_fcs_rport_update(rport, plogi);
+
+ rport->reply_oxid = fchs->ox_id;
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ rport->stats.plogi_rcvd++;
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD);
+}
+
+static int
+wwn_compare(wwn_t wwn1, wwn_t wwn2)
+{
+ u8 *b1 = (u8 *) &wwn1;
+ u8 *b2 = (u8 *) &wwn2;
+ int i;
+
+ for (i = 0; i < sizeof(wwn_t); i++) {
+ if (b1[i] < b2[i])
+ return -1;
+ if (b1[i] > b2[i])
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Called by bport/vport to handle PLOGI received from an existing
+ * remote port.
+ */
+void
+bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi)
+{
+ /**
+ * @todo Handle P2P and initiator-initiator.
+ */
+
+ bfa_fcs_rport_update(rport, plogi);
+
+ rport->reply_oxid = rx_fchs->ox_id;
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ /**
+ * In Switched fabric topology,
+ * PLOGI to each other. If our pwwn is smaller, ignore it,
+ * if it is not a well known address.
+ * If the link topology is N2N,
+ * this Plogi should be accepted.
+ */
+ if ((wwn_compare(rport->port->port_cfg.pwwn, rport->pwwn) == -1)
+ && (bfa_fcs_fabric_is_switched(rport->port->fabric))
+ && (!BFA_FCS_PID_IS_WKA(rport->pid))) {
+ bfa_trc(rport->fcs, rport->pid);
+ return;
+ }
+
+ rport->stats.plogi_rcvd++;
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD);
+}
+
+/**
+ * Called by bport/vport to delete a remote port instance.
+ *
+* Rport delete is called under the following conditions:
+ * - vport is deleted
+ * - vf is deleted
+ * - explicit request from OS to delete rport (vmware)
+ */
+void
+bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
+}
+
+/**
+ * Called by bport/vport to when a target goes offline.
+ *
+ */
+void
+bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
+}
+
+/**
+ * Called by bport in n2n when a target (attached port) becomes online.
+ *
+ */
+void
+bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
+}
+
+/**
+ * Called by bport/vport to notify SCN for the remote port
+ */
+void
+bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport)
+{
+
+ rport->stats.rscns++;
+ bfa_sm_send_event(rport, RPSM_EVENT_SCN);
+}
+
+/**
+ * Called by fcpim to notify that the ITN cleanup is done.
+ */
+void
+bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
+}
+
+/**
+ * Called by fcptm to notify that the ITN cleanup is done.
+ */
+void
+bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
+}
+
+/**
+ * This routine BFA callback for bfa_rport_online() call.
+ *
+ * param[in] cb_arg - rport struct.
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+void
+bfa_cb_rport_online(void *cbarg)
+{
+
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_sm_send_event(rport, RPSM_EVENT_HCB_ONLINE);
+}
+
+/**
+ * This routine BFA callback for bfa_rport_offline() call.
+ *
+ * param[in] rport -
+ *
+ * return
+ * void
+ *
+ * Special Considerations:
+ *
+ * note
+ */
+void
+bfa_cb_rport_offline(void *cbarg)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_sm_send_event(rport, RPSM_EVENT_HCB_OFFLINE);
+}
+
+/**
+ * This routine is a static BFA callback when there is a QoS flow_id
+ * change notification
+ *
+ * @param[in] rport -
+ *
+ * @return void
+ *
+ * Special Considerations:
+ *
+ * @note
+ */
+void
+bfa_cb_rport_qos_scn_flowid(void *cbarg,
+ struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct bfa_rport_aen_data_s aen_data;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ aen_data.priv.qos = new_qos_attr;
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data);
+}
+
+/**
+ * This routine is a static BFA callback when there is a QoS priority
+ * change notification
+ *
+ * @param[in] rport -
+ *
+ * @return void
+ *
+ * Special Considerations:
+ *
+ * @note
+ */
+void
+bfa_cb_rport_qos_scn_prio(void *cbarg, struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct bfa_rport_aen_data_s aen_data;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ aen_data.priv.qos = new_qos_attr;
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_PRIO, &aen_data);
+}
+
+/**
+ * Called to process any unsolicted frames from this remote port
+ */
+void
+bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
+}
+
+/**
+ * Called to process any unsolicted frames from this remote port
+ */
+void
+bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
+ u16 len)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_els_cmd_s *els_cmd;
+
+ bfa_trc(rport->fcs, fchs->s_id);
+ bfa_trc(rport->fcs, fchs->d_id);
+ bfa_trc(rport->fcs, fchs->type);
+
+ if (fchs->type != FC_TYPE_ELS)
+ return;
+
+ els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ bfa_trc(rport->fcs, els_cmd->els_code);
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_LOGO:
+ bfa_fcs_rport_process_logo(rport, fchs);
+ break;
+
+ case FC_ELS_ADISC:
+ bfa_fcs_rport_process_adisc(rport, fchs, len);
+ break;
+
+ case FC_ELS_PRLO:
+ if (bfa_fcs_port_is_initiator(port))
+ bfa_fcs_fcpim_uf_recv(rport->itnim, fchs, len);
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_fcptm_uf_recv(rport->tin, fchs, len);
+ break;
+
+ case FC_ELS_PRLI:
+ bfa_fcs_rport_process_prli(rport, fchs, len);
+ break;
+
+ case FC_ELS_RPSC:
+ bfa_fcs_rport_process_rpsc(rport, fchs, len);
+ break;
+
+ default:
+ bfa_fcs_rport_send_ls_rjt(rport, fchs,
+ FC_LS_RJT_RSN_CMD_NOT_SUPP,
+ FC_LS_RJT_EXP_NO_ADDL_INFO);
+ break;
+ }
+}
+
+/*
+ * Send a LS reject
+ */
+static void
+bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
+ u8 reason_code, u8 reason_code_expl)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(rport->fcs, rx_fchs->s_id);
+
+ fcxp = bfa_fcs_fcxp_alloc(rport->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ reason_code, reason_code_expl);
+
+ 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);
+}
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs)
+{
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+/**
+ * Return state of rport.
+ */
+int
+bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport)
+{
+ return bfa_sm_to_state(rport_sm_table, rport->sm);
+}
+
+/**
+ * Called by the Driver to set rport delete/ageout timeout
+ *
+ * param[in] rport timeout value in seconds.
+ *
+ * return None
+ */
+void
+bfa_fcs_rport_set_del_timeout(u8 rport_tmo)
+{
+ /*
+ * convert to Millisecs
+ */
+ if (rport_tmo > 0)
+ bfa_fcs_rport_del_timeout = rport_tmo * 1000;
+}
diff --git a/drivers/scsi/bfa/rport_api.c b/drivers/scsi/bfa/rport_api.c
new file mode 100644
index 000000000000..3dae1774181e
--- /dev/null
+++ b/drivers/scsi/bfa/rport_api.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_vport.h"
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+
+BFA_TRC_FILE(FCS, RPORT_API);
+
+/**
+ * rport_api.c Remote port implementation.
+ */
+
+/**
+ * fcs_rport_api FCS rport API.
+ */
+
+/**
+ * Direct API to add a target by port wwn. This interface is used, for
+ * example, by bios when target pwwn is known from boot lun configuration.
+ */
+bfa_status_t
+bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn,
+ struct bfa_fcs_rport_s *rport,
+ struct bfad_rport_s *rport_drv)
+{
+ bfa_trc(port->fcs, *pwwn);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Direct API to remove a target and its associated resources. This
+ * interface is used, for example, by vmware driver to remove target
+ * ports from the target list for a VM.
+ */
+bfa_status_t
+bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in)
+{
+
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(rport_in->fcs, rport_in->pwwn);
+
+ rport = bfa_fcs_port_get_rport_by_pwwn(rport_in->port, rport_in->pwwn);
+ if (rport == NULL) {
+ /*
+ * TBD Error handling
+ */
+ bfa_trc(rport_in->fcs, rport_in->pid);
+ return BFA_STATUS_UNKNOWN_RWWN;
+ }
+
+ /*
+ * TBD if this remote port is online, send a logo
+ */
+ return BFA_STATUS_OK;
+
+}
+
+/**
+ * Remote device status for display/debug.
+ */
+void
+bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_attr_s *rport_attr)
+{
+ struct bfa_rport_qos_attr_s qos_attr;
+ struct bfa_fcs_port_s *port = rport->port;
+
+ bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
+
+ rport_attr->pid = rport->pid;
+ rport_attr->pwwn = rport->pwwn;
+ rport_attr->nwwn = rport->nwwn;
+ rport_attr->cos_supported = rport->fc_cos;
+ rport_attr->df_sz = rport->maxfrsize;
+ rport_attr->state = bfa_fcs_rport_get_state(rport);
+ rport_attr->fc_cos = rport->fc_cos;
+ rport_attr->cisc = rport->cisc;
+ rport_attr->scsi_function = rport->scsi_function;
+ rport_attr->curr_speed = rport->rpf.rpsc_speed;
+ rport_attr->assigned_speed = rport->rpf.assigned_speed;
+
+ bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr);
+ rport_attr->qos_attr = qos_attr;
+
+ rport_attr->trl_enforced = BFA_FALSE;
+ if (bfa_pport_is_ratelim(port->fcs->bfa)) {
+ if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) ||
+ (rport->rpf.rpsc_speed <
+ bfa_fcs_port_get_rport_max_speed(port)))
+ rport_attr->trl_enforced = BFA_TRUE;
+ }
+
+ /*
+ * TODO
+ * rport->symname
+ */
+}
+
+/**
+ * Per remote device statistics.
+ */
+void
+bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_stats_s *stats)
+{
+ *stats = rport->stats;
+}
+
+void
+bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport)
+{
+ bfa_os_memset((char *)&rport->stats, 0,
+ sizeof(struct bfa_rport_stats_s));
+}
+
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_port_get_rport_by_pwwn(port, rpwwn);
+ if (rport == NULL) {
+ /*
+ * TBD Error handling
+ */
+ }
+
+ return rport;
+}
+
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_port_s *port, wwn_t rnwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_port_get_rport_by_nwwn(port, rnwwn);
+ if (rport == NULL) {
+ /*
+ * TBD Error handling
+ */
+ }
+
+ return rport;
+}
+
+/*
+ * This API is to set the Rport's speed. Should be used when RPSC is not
+ * supported by the rport.
+ */
+void
+bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport,
+ enum bfa_pport_speed speed)
+{
+ rport->rpf.assigned_speed = speed;
+
+ /* Set this speed in f/w only if the RPSC speed is not available */
+ if (rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN)
+ bfa_rport_speed(rport->bfa_rport, speed);
+}
+
+
diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c
new file mode 100644
index 000000000000..8a1f59d596c1
--- /dev/null
+++ b/drivers/scsi/bfa/rport_ftrs.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * rport_ftrs.c Remote port features (RPF) implementation.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcbuild.h"
+#include "fcs_rport.h"
+#include "fcs_lport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+
+BFA_TRC_FILE(FCS, RPORT_FTRS);
+
+#define BFA_FCS_RPF_RETRIES (3)
+#define BFA_FCS_RPF_RETRY_TIMEOUT (1000) /* 1 sec (In millisecs) */
+
+static void bfa_fcs_rpf_send_rpsc2(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rpf_rpsc2_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_rpf_timeout(void *arg);
+
+/**
+ * fcs_rport_ftrs_sm FCS rport state machine events
+ */
+
+enum rpf_event {
+ RPFSM_EVENT_RPORT_OFFLINE = 1, /* Rport offline */
+ RPFSM_EVENT_RPORT_ONLINE = 2, /* Rport online */
+ RPFSM_EVENT_FCXP_SENT = 3, /* Frame from has been sent */
+ RPFSM_EVENT_TIMEOUT = 4, /* Rport SM timeout event */
+ RPFSM_EVENT_RPSC_COMP = 5,
+ RPFSM_EVENT_RPSC_FAIL = 6,
+ RPFSM_EVENT_RPSC_ERROR = 7,
+};
+
+static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+
+static void
+bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_RPORT_ONLINE :
+ if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
+ rpf->rpsc_retries = 0;
+ bfa_fcs_rpf_send_rpsc2(rpf, NULL);
+ break;
+ };
+
+ case RPFSM_EVENT_RPORT_OFFLINE :
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc);
+ break;
+
+ case RPFSM_EVENT_RPORT_OFFLINE :
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe);
+ rpf->rpsc_retries = 0;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_RPSC_COMP:
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
+ /* Update speed info in f/w via BFA */
+ if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN) {
+ bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed);
+ } else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN) {
+ bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed);
+ }
+ break;
+
+ case RPFSM_EVENT_RPSC_FAIL:
+ /* RPSC not supported by rport */
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
+ break;
+
+ case RPFSM_EVENT_RPSC_ERROR:
+ /* need to retry...delayed a bit. */
+ if (rpf->rpsc_retries++ < BFA_FCS_RPF_RETRIES) {
+ bfa_timer_start(rport->fcs->bfa, &rpf->timer,
+ bfa_fcs_rpf_timeout, rpf,
+ BFA_FCS_RPF_RETRY_TIMEOUT);
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_retry);
+ } else {
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
+ }
+ break;
+
+ case RPFSM_EVENT_RPORT_OFFLINE :
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
+ bfa_fcxp_discard(rpf->fcxp);
+ rpf->rpsc_retries = 0;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_TIMEOUT :
+ /* re-send the RPSC */
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
+ bfa_fcs_rpf_send_rpsc2(rpf, NULL);
+ break;
+
+ case RPFSM_EVENT_RPORT_OFFLINE :
+ bfa_timer_stop(&rpf->timer);
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
+ rpf->rpsc_retries = 0;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_RPORT_OFFLINE :
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
+ rpf->rpsc_retries = 0;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_RPORT_ONLINE :
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
+ bfa_fcs_rpf_send_rpsc2(rpf, NULL);
+ break;
+
+ case RPFSM_EVENT_RPORT_OFFLINE :
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+/**
+ * Called when Rport is created.
+ */
+void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_rpf_s *rpf = &rport->rpf;
+
+ bfa_trc(rport->fcs, rport->pid);
+ rpf->rport = rport;
+
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit);
+}
+
+/**
+ * Called when Rport becomes online
+ */
+void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport)
+{
+ bfa_trc(rport->fcs, rport->pid);
+
+ if (__fcs_min_cfg(rport->port->fcs))
+ return;
+
+ if (bfa_fcs_fabric_is_switched(rport->port->fabric))
+ bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE);
+}
+
+/**
+ * Called when Rport becomes offline
+ */
+void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport)
+{
+ bfa_trc(rport->fcs, rport->pid);
+
+ if (__fcs_min_cfg(rport->port->fcs))
+ return;
+
+ bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE);
+}
+
+static void
+bfa_fcs_rpf_timeout(void *arg)
+{
+ struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) arg;
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_sm_send_event(rpf, RPFSM_EVENT_TIMEOUT);
+}
+
+static void
+bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *)rpf_cbarg;
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rpf->fcxp_wqe,
+ bfa_fcs_rpf_send_rpsc2, rpf);
+ return;
+ }
+ rpf->fcxp = fcxp;
+
+ len = fc_rpsc2_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), &rport->pid, 1);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response,
+ rpf, FC_MAX_PDUSZ, FC_RA_TOV);
+ rport->stats.rpsc_sent++;
+ bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT);
+
+}
+
+static void
+bfa_fcs_rpf_rpsc2_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_rpf_s *rpf = (struct bfa_fcs_rpf_s *) cbarg;
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+ struct fc_ls_rjt_s *ls_rjt;
+ struct fc_rpsc2_acc_s *rpsc2_acc;
+ u16 num_ents;
+
+ bfa_trc(rport->fcs, req_status);
+
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(rport->fcs, req_status);
+ if (req_status == BFA_STATUS_ETIMER)
+ rport->stats.rpsc_failed++;
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
+ return;
+ }
+
+ rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp);
+ if (rpsc2_acc->els_cmd == FC_ELS_ACC) {
+ rport->stats.rpsc_accs++;
+ num_ents = bfa_os_ntohs(rpsc2_acc->num_pids);
+ bfa_trc(rport->fcs, num_ents);
+ if (num_ents > 0) {
+ bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid);
+ bfa_trc(rport->fcs,
+ bfa_os_ntohs(rpsc2_acc->port_info[0].pid));
+ bfa_trc(rport->fcs,
+ bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+ bfa_trc(rport->fcs,
+ bfa_os_ntohs(rpsc2_acc->port_info[0].index));
+ bfa_trc(rport->fcs,
+ rpsc2_acc->port_info[0].type);
+
+ if (rpsc2_acc->port_info[0].speed == 0) {
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
+ return;
+ }
+
+ rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed(
+ bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP);
+ }
+ } else {
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+ bfa_trc(rport->fcs, ls_rjt->reason_code);
+ bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
+ rport->stats.rpsc_rejects++;
+ if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) {
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL);
+ } else {
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
+ }
+ }
+}
diff --git a/drivers/scsi/bfa/scn.c b/drivers/scsi/bfa/scn.c
new file mode 100644
index 000000000000..bd4771ff62c8
--- /dev/null
+++ b/drivers/scsi/bfa/scn.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2005-2009 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 <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_ms.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, SCN);
+
+#define FC_QOS_RSCN_EVENT 0x0c
+#define FC_FABRIC_NAME_RSCN_EVENT 0x0d
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_scn_send_scr(void *scn_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_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_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs);
+static void bfa_fcs_port_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_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+
+/**
+ * Starting state - awaiting link up.
+ */
+static void
+bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_PORT_ONLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
+ bfa_fcs_port_scn_send_scr(scn, NULL);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_SCR_SENT:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ struct bfa_fcs_port_s *port = scn->port;
+
+ switch (event) {
+ case SCNSM_EVENT_RSP_OK:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_online);
+ break;
+
+ case SCNSM_EVENT_RSP_ERROR:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr_retry);
+ bfa_timer_start(port->fcs->bfa, &scn->timer,
+ bfa_fcs_port_scn_timeout, scn,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ bfa_fcxp_discard(scn->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
+ bfa_fcs_port_scn_send_scr(scn, NULL);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ bfa_timer_stop(&scn->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_scn_private FCS SCN private functions
+ */
+
+/**
+ * This routine will be called to send a SCR command.
+ */
+static void
+bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_scn_s *scn = scn_cbarg;
+ struct bfa_fcs_port_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);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe,
+ bfa_fcs_port_scn_send_scr, scn);
+ 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),
+ bfa_lps_is_brcd_fabric(port->fabric->lps),
+ 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_port_scn_scr_response,
+ (void *)scn, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
+}
+
+static void
+bfa_fcs_port_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_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)cbarg;
+ struct bfa_fcs_port_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_port_scn_send_ls_acc(struct bfa_fcs_port_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);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_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_port_t.
+ * param[out] vport_status - pointer to return vport status in
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+static void
+bfa_fcs_port_scn_timeout(void *arg)
+{
+ struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_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_port_scn_init(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
+
+ scn->port = port;
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+}
+
+void
+bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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_port_scn_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_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_port_scn_portid_rscn(struct bfa_fcs_port_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_port_get_rport_by_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_port_scn_multiport_rscn(struct bfa_fcs_port_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_port_scn_process_rscn(struct bfa_fcs_port_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;
+ int i = 0;
+
+ num_entries =
+ (bfa_os_ntohs(rscn->payldlen) -
+ sizeof(u32)) / sizeof(rscn->event[0]);
+
+ bfa_trc(port->fcs, num_entries);
+
+ port->stats.num_rscn++;
+
+ bfa_fcs_port_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);
+
+ 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_port_scn_portid_rscn(port, rscn_pid);
+ }
+ break;
+
+ case FC_RSCN_FORMAT_FABRIC:
+ if (rscn->event[i].qualifier ==
+ FC_FABRIC_NAME_RSCN_EVENT) {
+ bfa_fcs_port_ms_fabric_rscn(port);
+ break;
+ }
+ /*
+ * !!!!!!!!! Fall Through !!!!!!!!!!!!!
+ */
+
+ case FC_RSCN_FORMAT_AREA:
+ case FC_RSCN_FORMAT_DOMAIN:
+ nsquery = BFA_TRUE;
+ bfa_fcs_port_scn_multiport_rscn(port,
+ rscn->event[i].format,
+ rscn_pid);
+ break;
+
+ default:
+ bfa_assert(0);
+ 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_port_ns_query(port);
+}
+
+
diff --git a/drivers/scsi/bfa/vfapi.c b/drivers/scsi/bfa/vfapi.c
new file mode 100644
index 000000000000..31d81fe2fc48
--- /dev/null
+++ b/drivers/scsi/bfa/vfapi.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * vfapi.c Fabric module implementation.
+ */
+
+#include "fcs_fabric.h"
+#include "fcs_trcmod.h"
+
+BFA_TRC_FILE(FCS, VFAPI);
+
+/**
+ * fcs_vf_api virtual fabrics API
+ */
+
+/**
+ * Enable VF mode.
+ *
+ * @param[in] fcs fcs module instance
+ * @param[in] vf_id default vf_id of port, FC_VF_ID_NULL
+ * to use standard default vf_id of 1.
+ *
+ * @retval BFA_STATUS_OK vf mode is enabled
+ * @retval BFA_STATUS_BUSY Port is active. Port must be disabled
+ * before VF mode can be enabled.
+ */
+bfa_status_t
+bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id)
+{
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Disable VF mode.
+ *
+ * @param[in] fcs fcs module instance
+ *
+ * @retval BFA_STATUS_OK vf mode is disabled
+ * @retval BFA_STATUS_BUSY VFs are present and being used. All
+ * VFs must be deleted before disabling
+ * VF mode.
+ */
+bfa_status_t
+bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs)
+{
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Create a new VF instance.
+ *
+ * A new VF is created using the given VF configuration. A VF is identified
+ * by VF id. No duplicate VF creation is allowed with the same VF id. Once
+ * a VF is created, VF is automatically started after link initialization
+ * and EVFP exchange is completed.
+ *
+ * param[in] vf - FCS vf data structure. Memory is
+ * allocated by caller (driver)
+ * param[in] fcs - FCS module
+ * param[in] vf_cfg - VF configuration
+ * param[in] vf_drv - Opaque handle back to the driver's
+ * virtual vf structure
+ *
+ * retval BFA_STATUS_OK VF creation is successful
+ * retval BFA_STATUS_FAILED VF creation failed
+ * retval BFA_STATUS_EEXIST A VF exists with the given vf_id
+ */
+bfa_status_t
+bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
+{
+ bfa_trc(fcs, vf_id);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Use this function to delete a BFA VF object. VF object should
+ * be stopped before this function call.
+ *
+ * param[in] vf - pointer to bfa_vf_t.
+ *
+ * retval BFA_STATUS_OK On vf deletion success
+ * retval BFA_STATUS_BUSY VF is not in a stopped state
+ * retval BFA_STATUS_INPROGRESS VF deletion in in progress
+ */
+bfa_status_t
+bfa_fcs_vf_delete(bfa_fcs_vf_t *vf)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Start participation in VF. This triggers login to the virtual fabric.
+ *
+ * param[in] vf - pointer to bfa_vf_t.
+ *
+ * return None
+ */
+void
+bfa_fcs_vf_start(bfa_fcs_vf_t *vf)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+}
+
+/**
+ * Logout with the virtual fabric.
+ *
+ * param[in] vf - pointer to bfa_vf_t.
+ *
+ * retval BFA_STATUS_OK On success.
+ * retval BFA_STATUS_INPROGRESS VF is being stopped.
+ */
+bfa_status_t
+bfa_fcs_vf_stop(bfa_fcs_vf_t *vf)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Returns attributes of the given VF.
+ *
+ * param[in] vf pointer to bfa_vf_t.
+ * param[out] vf_attr vf attributes returned
+ *
+ * return None
+ */
+void
+bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+}
+
+/**
+ * Return statistics associated with the given vf.
+ *
+ * param[in] vf pointer to bfa_vf_t.
+ * param[out] vf_stats vf statistics returned
+ *
+ * @return None
+ */
+void
+bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, struct bfa_vf_stats_s *vf_stats)
+{
+ bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s));
+ return;
+}
+
+void
+/**
+ * clear statistics associated with the given vf.
+ *
+ * param[in] vf pointer to bfa_vf_t.
+ *
+ * @return None
+ */
+bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf)
+{
+ bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s));
+ return;
+}
+
+/**
+ * Returns FCS vf structure for a given vf_id.
+ *
+ * param[in] vf_id - VF_ID
+ *
+ * return
+ * If lookup succeeds, retuns fcs vf object, otherwise returns NULL
+ */
+bfa_fcs_vf_t *
+bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id)
+{
+ bfa_trc(fcs, vf_id);
+ if (vf_id == FC_VF_ID_NULL)
+ return (&fcs->fabric);
+
+ /**
+ * @todo vf support
+ */
+
+ return NULL;
+}
+
+/**
+ * Returns driver VF structure for a given FCS vf.
+ *
+ * param[in] vf - pointer to bfa_vf_t
+ *
+ * return Driver VF structure
+ */
+struct bfad_vf_s *
+bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf)
+{
+ bfa_assert(vf);
+ bfa_trc(vf->fcs, vf->vf_id);
+ return vf->vf_drv;
+}
+
+/**
+ * Return the list of VFs configured.
+ *
+ * param[in] fcs fcs module instance
+ * param[out] vf_ids returned list of vf_ids
+ * param[in,out] nvfs in:size of vf_ids array,
+ * out:total elements present,
+ * actual elements returned is limited by the size
+ *
+ * return Driver VF structure
+ */
+void
+bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
+{
+ bfa_trc(fcs, *nvfs);
+}
+
+/**
+ * Return the list of all VFs visible from fabric.
+ *
+ * param[in] fcs fcs module instance
+ * param[out] vf_ids returned list of vf_ids
+ * param[in,out] nvfs in:size of vf_ids array,
+ * out:total elements present,
+ * actual elements returned is limited by the size
+ *
+ * return Driver VF structure
+ */
+void
+bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
+{
+ bfa_trc(fcs, *nvfs);
+}
+
+/**
+ * Return the list of local logical ports present in the given VF.
+ *
+ * param[in] vf vf for which logical ports are returned
+ * param[out] lpwwn returned logical port wwn list
+ * param[in,out] nlports in:size of lpwwn list;
+ * out:total elements present,
+ * actual elements returned is limited by the size
+ *
+ */
+void
+bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports)
+{
+ struct list_head *qe;
+ struct bfa_fcs_vport_s *vport;
+ int i;
+ struct bfa_fcs_s *fcs;
+
+ if (vf == NULL || lpwwn == NULL || *nlports == 0)
+ return;
+
+ fcs = vf->fcs;
+
+ bfa_trc(fcs, vf->vf_id);
+ bfa_trc(fcs, (u32) *nlports);
+
+ i = 0;
+ lpwwn[i++] = vf->bport.port_cfg.pwwn;
+
+ list_for_each(qe, &vf->vport_q) {
+ if (i >= *nlports)
+ break;
+
+ vport = (struct bfa_fcs_vport_s *) qe;
+ lpwwn[i++] = vport->lport.port_cfg.pwwn;
+ }
+
+ bfa_trc(fcs, i);
+ *nlports = i;
+ return;
+}
+
+
diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c
new file mode 100644
index 000000000000..c10af06c5714
--- /dev/null
+++ b/drivers/scsi/bfa/vport.c
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2005-2009 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.
+ */
+
+/**
+ * bfa_fcs_vport.c FCS virtual port state machine
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <fcbuild.h>
+#include "fcs_fabric.h"
+#include "fcs_lport.h"
+#include "fcs_vport.h"
+#include "fcs_trcmod.h"
+#include "fcs.h"
+#include <aen/bfa_aen_lport.h>
+
+BFA_TRC_FILE(FCS, VPORT);
+
+#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 */
+};
+
+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_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 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_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_assert(0);
+ }
+}
+
+/**
+ * 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_fcs_fabric_is_online(__vport_fabric(vport))
+ && 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_port_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_assert(0);
+ }
+}
+
+/**
+ * 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_port_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_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_assert(0);
+ }
+}
+
+/**
+ * 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_logo);
+ bfa_lps_discard(vport->lps);
+ bfa_fcs_vport_do_logo(vport);
+ break;
+
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
+ bfa_lps_discard(vport->lps);
+ break;
+
+ case BFA_FCS_VPORT_SM_RSP_OK:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_online);
+ bfa_fcs_port_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_assert(0);
+ }
+}
+
+/**
+ * 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_port_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_assert(0);
+ }
+}
+
+/**
+ * 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_port_delete(&vport->lport);
+ break;
+
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
+ bfa_lps_discard(vport->lps);
+ bfa_fcs_port_offline(&vport->lport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * 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_assert(0);
+ }
+}
+
+/**
+ * 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_uninit);
+ bfa_fcs_vport_free(vport);
+ 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_DELETE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * 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_lps_discard(vport->lps);
+ /*
+ * !!! 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_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_vport_private FCS virtual port private functions
+ */
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_fcs_vport_aen_post(bfa_fcs_lport_t *port, enum bfa_lport_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = port->fcs->logm;
+ enum bfa_port_role role = port->port_cfg.roles;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(port);
+ char lpwwn_ptr[BFA_STRING_32];
+ char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] =
+ { "Initiator", "Target", "IPFC" };
+
+ wwn2str(lpwwn_ptr, lpwwn);
+
+ bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
+
+ switch (event) {
+ case BFA_LPORT_AEN_NPIV_DUP_WWN:
+ bfa_log(logmod, BFA_AEN_LPORT_NPIV_DUP_WWN, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_NPIV_FABRIC_MAX:
+ bfa_log(logmod, BFA_AEN_LPORT_NPIV_FABRIC_MAX, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_NPIV_UNKNOWN:
+ bfa_log(logmod, BFA_AEN_LPORT_NPIV_UNKNOWN, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.lport.vf_id = port->fabric->vf_id;
+ aen_data.lport.roles = role;
+ aen_data.lport.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
+ aen_data.lport.lpwwn = lpwwn;
+}
+
+/**
+ * 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_pport_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 = bfa_lps_get_lsrjt_rsn(vport->lps);
+ u8 lsrjt_expl = bfa_lps_get_lsrjt_expl(vport->lps);
+
+ 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 (bfa_lps_get_lsrjt_expl(vport->lps)) {
+ 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) /* Print only once */
+ 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)
+{
+ bfa_fcs_fabric_delvport(__vport_fabric(vport), vport);
+ bfa_fcb_vport_delete(vport->vport_drv);
+ bfa_lps_delete(vport->lps);
+}
+
+
+
+/**
+ * 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++;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE);
+}
+
+/**
+ * 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++;
+}
+
+/**
+ * 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);
+}
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs)
+{
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+u32
+bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs)
+{
+ struct bfa_ioc_attr_s ioc_attr;
+
+ bfa_get_attr(fcs->bfa, &ioc_attr);
+
+ if (ioc_attr.pci_attr.device_id == BFA_PCI_DEVICE_ID_CT)
+ return (BFA_FCS_MAX_VPORTS_SUPP_CT);
+ else
+ return (BFA_FCS_MAX_VPORTS_SUPP_CB);
+}
+
+
+
+/**
+ * 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_port_cfg_s *vport_cfg,
+ struct bfad_vport_s *vport_drv)
+{
+ if (vport_cfg->pwwn == 0)
+ return (BFA_STATUS_INVALID_WWN);
+
+ if (bfa_fcs_port_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 (bfa_fcs_fabric_vport_count(&fcs->fabric) ==
+ bfa_fcs_vport_get_max(fcs))
+ 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;
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
+
+ bfa_fcs_lport_init(&vport->lport, fcs, vf_id, vport_cfg, vport);
+
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * 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.
+ *
+ * param[in] vport - pointer to bfa_fcs_vport_t.
+ *
+ * return None
+ */
+bfa_status_t
+bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport)
+{
+ 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;
+
+ bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s));
+
+ bfa_fcs_port_get_attr(&vport->lport, &attr->port_attr);
+ attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm);
+}
+
+/**
+ * Use this function to get vport's statistics.
+ *
+ * param[in] vport pointer to bfa_fcs_vport_t.
+ * param[out] stats pointer to return vport statistics in
+ *
+ * return None
+ */
+void
+bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
+ struct bfa_vport_stats_s *stats)
+{
+ *stats = vport->vport_stats;
+}
+
+/**
+ * Use this function to clear vport's statistics.
+ *
+ * param[in] vport pointer to bfa_fcs_vport_t.
+ *
+ * return None
+ */
+void
+bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport)
+{
+ bfa_os_memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
+}
+
+/**
+ * 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:
+ /*
+ * Initialiaze the V-Port fields
+ */
+ __vport_fcid(vport) = bfa_lps_get_pid(vport->lps);
+ 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 (bfa_lps_get_extstatus(vport->lps)) {
+ 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);
+}
+
+
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index d7576f28c6e9..5edde1a8c04d 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -100,6 +100,8 @@
#define CTX_OFFSET 0x10000
#define MAX_CID_CNT 0x4000
+#define BNX2I_570X_PAGE_SIZE_DEFAULT 4096
+
/* 5709 context registers */
#define BNX2_MQ_CONFIG2 0x00003d00
#define BNX2_MQ_CONFIG2_CONT_SZ (0x7L<<4)
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 41e1b0e7e2ef..5c8d7630c13e 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -2386,7 +2386,7 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3;
if (ctx_sz)
reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE
- + PAGE_SIZE *
+ + BNX2I_570X_PAGE_SIZE_DEFAULT *
(((cid_num - first_l4l5) / ctx_sz) + 256);
else
reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 9a7ba71f1af4..cafb888c2376 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1243,7 +1243,7 @@ bnx2i_session_create(struct iscsi_endpoint *ep,
cmds_max = BNX2I_SQ_WQES_MIN;
cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost,
- cmds_max, sizeof(struct bnx2i_cmd),
+ cmds_max, 0, sizeof(struct bnx2i_cmd),
initial_cmdsn, ISCSI_MAX_TARGET);
if (!cls_session)
return NULL;
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index c399f485aa7d..2631bddd255e 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -422,7 +422,7 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,
BUG_ON(hba != iscsi_host_priv(shost));
cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost,
- cmds_max,
+ cmds_max, 0,
sizeof(struct iscsi_tcp_task) +
sizeof(struct cxgb3i_task_data),
initial_cmdsn, ISCSI_MAX_TARGET);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 11c89311427e..268189d31d9c 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -500,8 +500,6 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
if (!ret)
goto done;
- err = SCSI_DH_OK;
-
switch (sense_hdr.sense_key) {
case NO_SENSE:
case ABORTED_COMMAND:
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b6af63ca980b..496764349c41 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1918,6 +1918,10 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
}
size = size>>16;
size *= 4;
+ if (size > MAX_MESSAGE_SIZE) {
+ rcode = -EINVAL;
+ goto cleanup;
+ }
/* Copy in the user's I2O command */
if (copy_from_user (msg, user_msg, size)) {
rcode = -EFAULT;
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 185e6bc4dd40..9e8fce0f0c1b 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -2900,7 +2900,7 @@ static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr)
eindex = handle;
estr->event_source = 0;
- if (eindex >= MAX_EVENTS) {
+ if (eindex < 0 || eindex >= MAX_EVENTS) {
spin_unlock_irqrestore(&ha->smp_lock, flags);
return eindex;
}
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index c596ab5f05c3..a0e7e711ff9d 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx/4xxx controller driver for Linux
- * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
static char driver_name[] = "hptiop";
static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
-static const char driver_ver[] = "v1.3 (071203)";
+static const char driver_ver[] = "v1.6 (090910)";
static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
@@ -115,9 +115,13 @@ static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
static int iop_intr_itl(struct hptiop_hba *hba)
{
struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
+ void __iomem *plx = hba->u.itl.plx;
u32 status;
int ret = 0;
+ if (plx && readl(plx + 0x11C5C) & 0xf)
+ writel(1, plx + 0x11C60);
+
status = readl(&iop->outbound_intstatus);
if (status & IOPMU_OUTBOUND_INT_MSG0) {
@@ -460,15 +464,25 @@ static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
{
+ struct pci_dev *pcidev = hba->pcidev;
hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
- if (hba->u.itl.iop)
- return 0;
- else
+ if (hba->u.itl.iop == NULL)
return -1;
+ if ((pcidev->device & 0xff00) == 0x4400) {
+ hba->u.itl.plx = hba->u.itl.iop;
+ hba->u.itl.iop = hptiop_map_pci_bar(hba, 2);
+ if (hba->u.itl.iop == NULL) {
+ iounmap(hba->u.itl.plx);
+ return -1;
+ }
+ }
+ return 0;
}
static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
{
+ if (hba->u.itl.plx)
+ iounmap(hba->u.itl.plx);
iounmap(hba->u.itl.iop);
}
@@ -1239,22 +1253,23 @@ static struct hptiop_adapter_ops hptiop_mv_ops = {
static struct pci_device_id hptiop_id_table[] = {
{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4311), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4400), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
index a0289f219752..0b871c0ae568 100644
--- a/drivers/scsi/hptiop.h
+++ b/drivers/scsi/hptiop.h
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx/4xxx controller driver for Linux
- * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -228,6 +228,7 @@ struct hptiop_hba {
union {
struct {
struct hpt_iopmu_itl __iomem *iop;
+ void __iomem *plx;
} itl;
struct {
struct hpt_iopmv_regs *regs;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 5f045505a1f4..76d294fc7846 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -4189,6 +4189,25 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
}
/**
+ * ipr_isr_eh - Interrupt service routine error handler
+ * @ioa_cfg: ioa config struct
+ * @msg: message to log
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_isr_eh(struct ipr_ioa_cfg *ioa_cfg, char *msg)
+{
+ ioa_cfg->errors_logged++;
+ dev_err(&ioa_cfg->pdev->dev, "%s\n", msg);
+
+ if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
+ ioa_cfg->sdt_state = GET_DUMP;
+
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+}
+
+/**
* ipr_isr - Interrupt service routine
* @irq: irq number
* @devp: pointer to ioa config struct
@@ -4203,6 +4222,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
volatile u32 int_reg, int_mask_reg;
u32 ioasc;
u16 cmd_index;
+ int num_hrrq = 0;
struct ipr_cmnd *ipr_cmd;
irqreturn_t rc = IRQ_NONE;
@@ -4233,13 +4253,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT;
if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
- ioa_cfg->errors_logged++;
- dev_err(&ioa_cfg->pdev->dev, "Invalid response handle from IOA\n");
-
- if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
- ioa_cfg->sdt_state = GET_DUMP;
-
- ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA");
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return IRQ_HANDLED;
}
@@ -4266,8 +4280,18 @@ static irqreturn_t ipr_isr(int irq, void *devp)
if (ipr_cmd != NULL) {
/* Clear the PCI interrupt */
- writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
- int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+ do {
+ writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+ } while (int_reg & IPR_PCII_HRRQ_UPDATED &&
+ num_hrrq++ < IPR_MAX_HRRQ_RETRIES);
+
+ if (int_reg & IPR_PCII_HRRQ_UPDATED) {
+ ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return IRQ_HANDLED;
+ }
+
} else
break;
}
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 163245a1c3e5..19bbcf39f0c9 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -144,6 +144,7 @@
#define IPR_IOA_MAX_SECTORS 32767
#define IPR_VSET_MAX_SECTORS 512
#define IPR_MAX_CDB_LEN 16
+#define IPR_MAX_HRRQ_RETRIES 3
#define IPR_DEFAULT_BUS_WIDTH 16
#define IPR_80MBs_SCSI_RATE ((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8))
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 2b1b834a098b..edc49ca49cea 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -811,7 +811,7 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
goto free_host;
cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost,
- cmds_max,
+ cmds_max, 0,
sizeof(struct iscsi_tcp_task) +
sizeof(struct iscsi_sw_tcp_hdrbuf),
initial_cmdsn, 0);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8dc73c489a17..f1a4246f890c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2436,7 +2436,7 @@ static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
*/
struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
- uint16_t cmds_max, int cmd_task_size,
+ uint16_t cmds_max, int dd_size, int cmd_task_size,
uint32_t initial_cmdsn, unsigned int id)
{
struct iscsi_host *ihost = shost_priv(shost);
@@ -2486,7 +2486,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
cls_session = iscsi_alloc_session(shost, iscsit,
- sizeof(struct iscsi_session));
+ sizeof(struct iscsi_session) +
+ dd_size);
if (!cls_session)
goto dec_session_count;
session = cls_session->dd_data;
@@ -2503,6 +2504,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
session->max_cmdsn = initial_cmdsn + 1;
session->max_r2t = 1;
session->tt = iscsit;
+ session->dd_data = cls_session->dd_data + sizeof(*session);
mutex_init(&session->eh_mutex);
spin_lock_init(&session->lock);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index b3381959acce..33cf988c8c8a 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -960,7 +960,6 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
}
}
- res = 0;
}
return res;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 61d089703806..c88f59f0ce30 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -56,8 +56,6 @@ static char *dif_op_str[] = {
"SCSI_PROT_WRITE_INSERT",
"SCSI_PROT_READ_PASS",
"SCSI_PROT_WRITE_PASS",
- "SCSI_PROT_READ_CONVERT",
- "SCSI_PROT_WRITE_CONVERT"
};
static void
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
@@ -1131,13 +1129,11 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)
ret_prof = LPFC_PROF_A1;
break;
- case SCSI_PROT_READ_CONVERT:
- case SCSI_PROT_WRITE_CONVERT:
+ case SCSI_PROT_READ_PASS:
+ case SCSI_PROT_WRITE_PASS:
ret_prof = LPFC_PROF_AST1;
break;
- case SCSI_PROT_READ_PASS:
- case SCSI_PROT_WRITE_PASS:
case SCSI_PROT_NORMAL:
default:
printk(KERN_ERR "Bad op/guard:%d/%d combination\n",
@@ -1157,8 +1153,6 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)
ret_prof = LPFC_PROF_C1;
break;
- case SCSI_PROT_READ_CONVERT:
- case SCSI_PROT_WRITE_CONVERT:
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
case SCSI_PROT_NORMAL:
@@ -1209,8 +1203,7 @@ lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
static int cnt;
if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
- op == SCSI_PROT_WRITE_PASS ||
- op == SCSI_PROT_WRITE_CONVERT)) {
+ op == SCSI_PROT_WRITE_PASS)) {
cnt++;
spt = page_address(sg_page(scsi_prot_sglist(sc))) +
@@ -1501,8 +1494,6 @@ lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc)
case SCSI_PROT_WRITE_STRIP:
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
- case SCSI_PROT_WRITE_CONVERT:
- case SCSI_PROT_READ_CONVERT:
ret = LPFC_PG_TYPE_DIF_BUF;
break;
default:
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig
index 4a86855c23b3..70c4c2467dd8 100644
--- a/drivers/scsi/mpt2sas/Kconfig
+++ b/drivers/scsi/mpt2sas/Kconfig
@@ -2,7 +2,7 @@
# Kernel configuration file for the MPT2SAS
#
# This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2008 LSI Corporation
+# Copyright (C) 2007-2009 LSI Corporation
# (mailto:DL-MPTFusionLinux@lsi.com)
# This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 7bb2ece8b2e4..f9f6c0839276 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.11
+ * mpi2.h Version: 02.00.12
*
* Version History
* ---------------
@@ -45,6 +45,13 @@
* 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT.
* Moved LUN field defines from mpi2_init.h.
* 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
+ * In all request and reply descriptors, replaced VF_ID
+ * field with MSIxIndex field.
+ * Removed DevHandle field from
+ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
+ * bytes reserved.
+ * Added RAID Accelerator functionality.
* --------------------------------------------------------------------------
*/
@@ -70,7 +77,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0B)
+#define MPI2_HEADER_VERSION_UNIT (0x0C)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -257,7 +264,7 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 DescriptorTypeDependent; /* 0x06 */
@@ -271,6 +278,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02)
#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08)
+#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A)
#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
@@ -279,7 +287,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 Reserved1; /* 0x06 */
@@ -293,7 +301,7 @@ typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 DevHandle; /* 0x06 */
@@ -306,7 +314,7 @@ typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 IoIndex; /* 0x06 */
@@ -315,14 +323,29 @@ typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
Mpi2SCSITargetRequestDescriptor_t,
MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t;
+
+/* RAID Accelerator Request Descriptor */
+typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR {
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+ U16 LMID; /* 0x04 */
+ U16 Reserved; /* 0x06 */
+} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
+ Mpi2RAIDAcceleratorRequestDescriptor_t,
+ MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t;
+
+
/* union of Request Descriptors */
typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
{
- MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
- MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
- MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
- MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
- U64 Words;
+ MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
+ MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
+ MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
+ MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
+ MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
+ U64 Words;
} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
@@ -333,19 +356,20 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 DescriptorTypeDependent1; /* 0x02 */
U32 DescriptorTypeDependent2; /* 0x04 */
} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR,
Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t;
/* defines for the ReplyFlags field */
-#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
-#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
-#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01)
-#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02)
-#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03)
-#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
+#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03)
+#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05)
+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
/* values for marking a reply descriptor as unused */
#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF)
@@ -355,7 +379,7 @@ typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U32 ReplyFrameAddress; /* 0x04 */
} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR,
@@ -368,10 +392,10 @@ typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 TaskTag; /* 0x04 */
- U16 DevHandle; /* 0x06 */
+ U16 Reserved1; /* 0x06 */
} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
Mpi2SCSIIOSuccessReplyDescriptor_t,
@@ -382,7 +406,7 @@ typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U8 SequenceNumber; /* 0x04 */
U8 Reserved1; /* 0x05 */
@@ -397,7 +421,7 @@ typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U8 VP_ID; /* 0x02 */
U8 Flags; /* 0x03 */
U16 InitiatorDevHandle; /* 0x04 */
@@ -411,15 +435,28 @@ typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F)
+/* RAID Accelerator Success Reply Descriptor */
+typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR {
+ U8 ReplyFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+ U32 Reserved; /* 0x04 */
+} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
+ Mpi2RAIDAcceleratorSuccessReplyDescriptor_t,
+ MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t;
+
+
/* union of Reply Descriptors */
typedef union _MPI2_REPLY_DESCRIPTORS_UNION
{
- MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
- MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
- MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
- MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
- MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
- U64 Words;
+ MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
+ MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
+ MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
+ MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
+ MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
+ MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
+ U64 Words;
} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
@@ -458,6 +495,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */
#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */
#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */
+#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/
@@ -555,12 +593,17 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0)
+/****************************************************************************
+* RAID Accelerator values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0)
/****************************************************************************
* IOCStatus flag to indicate that log info is available
****************************************************************************/
-#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000)
+#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000)
/****************************************************************************
* IOCLogInfo Types
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 2f27cf6d6c65..ab47c4679640 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.10
+ * mpi2_cnfg.h Version: 02.00.11
*
* Version History
* ---------------
@@ -95,6 +95,11 @@
* Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
* Added PortGroups, DmaGroup, and ControlGroup fields to
* SAS Device Page 0.
+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
+ * Unit Page 6.
+ * Added expander reduced functionality data to SAS
+ * Expander Page 0.
+ * Added SAS PHY Page 2 and SAS PHY Page 3.
* --------------------------------------------------------------------------
*/
@@ -723,6 +728,65 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001)
+/* IO Unit Page 5 */
+
+/*
+ * Upper layer code (drivers, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumDmaEngines at runtime.
+ */
+#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
+#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 {
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */
+ U64 RaidAcceleratorBufferSize; /* 0x0C */
+ U64 RaidAcceleratorControlBaseAddress; /* 0x14 */
+ U8 RAControlSize; /* 0x1C */
+ U8 NumDmaEngines; /* 0x1D */
+ U8 RAMinControlSize; /* 0x1E */
+ U8 RAMaxControlSize; /* 0x1F */
+ U32 Reserved1; /* 0x20 */
+ U32 Reserved2; /* 0x24 */
+ U32 Reserved3; /* 0x28 */
+ U32 DmaEngineCapabilities
+ [MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */
+} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5,
+ Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t;
+
+#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 5 DmaEngineCapabilities field */
+#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFF00)
+#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16)
+
+#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008)
+#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004)
+#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002)
+#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001)
+
+
+/* IO Unit Page 6 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 {
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U16 Flags; /* 0x04 */
+ U8 RAHostControlSize; /* 0x06 */
+ U8 Reserved0; /* 0x07 */
+ U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */
+ U32 Reserved1; /* 0x10 */
+ U32 Reserved2; /* 0x14 */
+ U32 Reserved3; /* 0x18 */
+} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6,
+ Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t;
+
+#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 6 Flags field */
+#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001)
+
+
/****************************************************************************
* IOC Config Pages
****************************************************************************/
@@ -1709,10 +1773,14 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
U64 ActiveZoneManagerSASAddress;/* 0x2C */
U16 ZoneLockInactivityLimit; /* 0x34 */
U16 Reserved1; /* 0x36 */
+ U8 TimeToReducedFunc; /* 0x38 */
+ U8 InitialTimeToReducedFunc; /* 0x39 */
+ U8 MaxReducedFuncTime; /* 0x3A */
+ U8 Reserved2; /* 0x3B */
} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0,
Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t;
-#define MPI2_SASEXPANDER0_PAGEVERSION (0x05)
+#define MPI2_SASEXPANDER0_PAGEVERSION (0x06)
/* values for SAS Expander Page 0 DiscoveryStatus field */
#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
@@ -1737,6 +1805,7 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001)
/* values for SAS Expander Page 0 Flags field */
+#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000)
#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000)
#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800)
#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400)
@@ -1944,6 +2013,133 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1
#define MPI2_SASPHY1_PAGEVERSION (0x01)
+/* SAS PHY Page 2 */
+
+typedef struct _MPI2_SASPHY2_PHY_EVENT {
+ U8 PhyEventCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 PhyEventInfo; /* 0x04 */
+} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT,
+ Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t;
+
+/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ */
+#ifndef MPI2_SASPHY2_PHY_EVENT_MAX
+#define MPI2_SASPHY2_PHY_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 NumPhyEvents; /* 0x0C */
+ U8 Reserved2; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX];
+ /* 0x10 */
+} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2,
+ Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t;
+
+#define MPI2_SASPHY2_PAGEVERSION (0x00)
+
+
+/* SAS PHY Page 3 */
+
+typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG {
+ U8 PhyEventCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U8 CounterType; /* 0x04 */
+ U8 ThresholdWindow; /* 0x05 */
+ U8 TimeUnits; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+ U32 EventThreshold; /* 0x08 */
+ U16 ThresholdFlags; /* 0x0C */
+ U16 Reserved4; /* 0x0E */
+} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG,
+ Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t;
+
+/* values for PhyEventCode field */
+#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00)
+#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01)
+#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02)
+#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03)
+#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04)
+#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05)
+#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06)
+#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20)
+#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22)
+#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23)
+#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26)
+#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27)
+#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28)
+#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29)
+#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A)
+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B)
+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C)
+#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D)
+#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43)
+#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44)
+#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63)
+#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0)
+#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2)
+
+/* values for the CounterType field */
+#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
+#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
+#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02)
+
+/* values for the TimeUnits field */
+#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00)
+#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01)
+#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02)
+#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03)
+
+/* values for the ThresholdFlags field */
+#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002)
+#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ */
+#ifndef MPI2_SASPHY3_PHY_EVENT_MAX
+#define MPI2_SASPHY3_PHY_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 NumPhyEvents; /* 0x0C */
+ U8 Reserved2; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig
+ [MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */
+} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3,
+ Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t;
+
+#define MPI2_SASPHY3_PAGEVERSION (0x00)
+
+
/****************************************************************************
* SAS Port Config Pages
****************************************************************************/
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
new file mode 100644
index 000000000000..65fcaa31cb30
--- /dev/null
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
@@ -0,0 +1,334 @@
+ ==============================
+ Fusion-MPT MPI 2.0 Header File Change History
+ ==============================
+
+ Copyright (c) 2000-2009 LSI Corporation.
+
+ ---------------------------------------
+ Header Set Release Version: 02.00.12
+ Header Set Release Date: 05-06-09
+ ---------------------------------------
+
+ Filename Current version Prior version
+ ---------- --------------- -------------
+ mpi2.h 02.00.12 02.00.11
+ mpi2_cnfg.h 02.00.11 02.00.10
+ mpi2_init.h 02.00.07 02.00.06
+ mpi2_ioc.h 02.00.11 02.00.10
+ mpi2_raid.h 02.00.03 02.00.03
+ mpi2_sas.h 02.00.02 02.00.02
+ mpi2_targ.h 02.00.03 02.00.03
+ mpi2_tool.h 02.00.03 02.00.02
+ mpi2_type.h 02.00.00 02.00.00
+ mpi2_ra.h 02.00.00
+ mpi2_history.txt 02.00.11 02.00.12
+
+
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+
+mpi2.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Moved ReplyPostHostIndex register to offset 0x6C of the
+ * MPI2_SYSTEM_INTERFACE_REGS and modified the define for
+ * MPI2_REPLY_POST_HOST_INDEX_OFFSET.
+ * Added union of request descriptors.
+ * Added union of reply descriptors.
+ * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added define for MPI2_VERSION_02_00.
+ * Fixed the size of the FunctionDependent5 field in the
+ * MPI2_DEFAULT_REPLY structure.
+ * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Removed the MPI-defined Fault Codes and extended the
+ * product specific codes up to 0xEFFF.
+ * Added a sixth key value for the WriteSequence register
+ * and changed the flush value to 0x0.
+ * Added message function codes for Diagnostic Buffer Post
+ * and Diagnsotic Release.
+ * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED
+ * Moved MPI2_VERSION_UNION from mpi2_ioc.h.
+ * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added #defines for marking a reply descriptor as unused.
+ * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Moved LUN field defines from mpi2_init.h.
+ * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
+ * In all request and reply descriptors, replaced VF_ID
+ * field with MSIxIndex field.
+ * Removed DevHandle field from
+ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
+ * bytes reserved.
+ * Added RAID Accelerator functionality.
+ * --------------------------------------------------------------------------
+
+mpi2_cnfg.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags.
+ * Added Manufacturing Page 11.
+ * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE
+ * define.
+ * 06-26-07 02.00.02 Adding generic structure for product-specific
+ * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS.
+ * Rework of BIOS Page 2 configuration page.
+ * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the
+ * forms.
+ * Added configuration pages IOC Page 8 and Driver
+ * Persistent Mapping Page 0.
+ * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated
+ * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1,
+ * RAID Physical Disk Pages 0 and 1, RAID Configuration
+ * Page 0).
+ * Added new value for AccessStatus field of SAS Device
+ * Page 0 (_SATA_NEEDS_INITIALIZATION).
+ * 10-31-07 02.00.04 Added missing SEPDevHandle field to
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for
+ * NVDATA.
+ * Modified IOC Page 7 to use masks and added field for
+ * SASBroadcastPrimitiveMasks.
+ * Added MPI2_CONFIG_PAGE_BIOS_4.
+ * Added MPI2_CONFIG_PAGE_LOG_0.
+ * 02-29-08 02.00.06 Modified various names to make them 32-character unique.
+ * Added SAS Device IDs.
+ * Updated Integrated RAID configuration pages including
+ * Manufacturing Page 4, IOC Page 6, and RAID Configuration
+ * Page 0.
+ * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA.
+ * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION.
+ * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING.
+ * Added missing MaxNumRoutedSasAddresses field to
+ * MPI2_CONFIG_PAGE_EXPANDER_0.
+ * Added SAS Port Page 0.
+ * Modified structure layout for
+ * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0.
+ * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use
+ * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array.
+ * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF
+ * to 0x000000FF.
+ * Added two new values for the Physical Disk Coercion Size
+ * bits in the Flags field of Manufacturing Page 4.
+ * Added product-specific Manufacturing pages 16 to 31.
+ * Modified Flags bits for controlling write cache on SATA
+ * drives in IO Unit Page 1.
+ * Added new bit to AdditionalControlFlags of SAS IO Unit
+ * Page 1 to control Invalid Topology Correction.
+ * Added SupportedPhysDisks field to RAID Volume Page 1 and
+ * added related defines.
+ * Added additional defines for RAID Volume Page 0
+ * VolumeStatusFlags field.
+ * Modified meaning of RAID Volume Page 0 VolumeSettings
+ * define for auto-configure of hot-swap drives.
+ * Added PhysDiskAttributes field (and related defines) to
+ * RAID Physical Disk Page 0.
+ * Added MPI2_SAS_PHYINFO_PHY_VACANT define.
+ * Added three new DiscoveryStatus bits for SAS IO Unit
+ * Page 0 and SAS Expander Page 0.
+ * Removed multiplexing information from SAS IO Unit pages.
+ * Added BootDeviceWaitTime field to SAS IO Unit Page 4.
+ * Removed Zone Address Resolved bit from PhyInfo and from
+ * Expander Page 0 Flags field.
+ * Added two new AccessStatus values to SAS Device Page 0
+ * for indicating routing problems. Added 3 reserved words
+ * to this page.
+ * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3.
+ * Inserted missing reserved field into structure for IOC
+ * Page 6.
+ * Added more pending task bits to RAID Volume Page 0
+ * VolumeStatusFlags defines.
+ * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define.
+ * Added a new DiscoveryStatus bit for SAS IO Unit Page 0
+ * and SAS Expander Page 0 to flag a downstream initiator
+ * when in simplified routing mode.
+ * Removed SATA Init Failure defines for DiscoveryStatus
+ * fields of SAS IO Unit Page 0 and SAS Expander Page 0.
+ * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
+ * Added PortGroups, DmaGroup, and ControlGroup fields to
+ * SAS Device Page 0.
+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
+ * Unit Page 6.
+ * Added expander reduced functionality data to SAS
+ * Expander Page 0.
+ * Added SAS PHY Page 2 and SAS PHY Page 3.
+ * --------------------------------------------------------------------------
+
+mpi2_init.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t.
+ * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines.
+ * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention.
+ * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY.
+ * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t.
+ * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO
+ * Control field Task Attribute flags.
+ * Moved LUN field defines to mpi2.h becasue they are
+ * common to many structures.
+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
+ * Query Asynchronous Event.
+ * Defined two new bits in the SlotStatus field of the SCSI
+ * Enclosure Processor Request and Reply.
+ * --------------------------------------------------------------------------
+
+mpi2_ioc.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to
+ * MaxTargets.
+ * Added TotalImageSize field to FWDownload Request.
+ * Added reserved words to FWUpload Request.
+ * 06-26-07 02.00.02 Added IR Configuration Change List Event.
+ * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit
+ * request and replaced it with
+ * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth.
+ * Replaced the MinReplyQueueDepth field of the IOCFacts
+ * reply with MaxReplyDescriptorPostQueueDepth.
+ * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum
+ * depth for the Reply Descriptor Post Queue.
+ * Added SASAddress field to Initiator Device Table
+ * Overflow Event data.
+ * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING
+ * for SAS Initiator Device Status Change Event data.
+ * Modified Reason Code defines for SAS Topology Change
+ * List Event data, including adding a bit for PHY Vacant
+ * status, and adding a mask for the Reason Code.
+ * Added define for
+ * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING.
+ * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID.
+ * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of
+ * the IOCFacts Reply.
+ * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ * Moved MPI2_VERSION_UNION to mpi2.h.
+ * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks
+ * instead of enables, and added SASBroadcastPrimitiveMasks
+ * field.
+ * Added Log Entry Added Event and related structure.
+ * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID.
+ * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET.
+ * Added MaxVolumes and MaxPersistentEntries fields to
+ * IOCFacts reply.
+ * Added ProtocalFlags and IOCCapabilities fields to
+ * MPI2_FW_IMAGE_HEADER.
+ * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT.
+ * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to
+ * a U16 (from a U32).
+ * Removed extra 's' from EventMasks name.
+ * 06-27-08 02.00.08 Fixed an offset in a comment.
+ * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST.
+ * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and
+ * renamed MinReplyFrameSize to ReplyFrameSize.
+ * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX.
+ * Added two new RAIDOperation values for Integrated RAID
+ * Operations Status Event data.
+ * Added four new IR Configuration Change List Event data
+ * ReasonCode values.
+ * Added two new ReasonCode defines for SAS Device Status
+ * Change Event data.
+ * Added three new DiscoveryStatus bits for the SAS
+ * Discovery event data.
+ * Added Multiplexing Status Change bit to the PhyStatus
+ * field of the SAS Topology Change List event data.
+ * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY.
+ * BootFlags are now product-specific.
+ * Added defines for the indivdual signature bytes
+ * for MPI2_INIT_IMAGE_FOOTER.
+ * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define.
+ * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR
+ * define.
+ * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
+ * define.
+ * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
+ * Added two new reason codes for SAS Device Status Change
+ * Event.
+ * Added new event: SAS PHY Counter.
+ * --------------------------------------------------------------------------
+
+mpi2_raid.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 08-31-07 02.00.01 Modifications to RAID Action request and reply,
+ * including the Actions and ActionData.
+ * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD.
+ * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
+ * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
+ * can be sized by the build environment.
+ * --------------------------------------------------------------------------
+
+mpi2_sas.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit
+ * Control Request.
+ * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control
+ * Request.
+ * --------------------------------------------------------------------------
+
+mpi2_targ.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to
+ * BufferPostFlags field of CommandBufferPostBase Request.
+ * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
+ * 10-02-08 02.00.03 Removed NextCmdBufferOffset from
+ * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
+ * Target Status Send Request only takes a single SGE for
+ * response data.
+ * --------------------------------------------------------------------------
+
+mpi2_tool.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release
+ * structures and defines.
+ * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
+ * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
+ * --------------------------------------------------------------------------
+
+mpi2_type.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * --------------------------------------------------------------------------
+
+mpi2_ra.h
+ * 05-06-09 02.00.00 Initial version.
+ * --------------------------------------------------------------------------
+
+mpi2_history.txt Parts list history
+
+Filename 02.00.12
+---------- --------
+mpi2.h 02.00.12
+mpi2_cnfg.h 02.00.11
+mpi2_init.h 02.00.07
+mpi2_ioc.h 02.00.11
+mpi2_raid.h 02.00.03
+mpi2_sas.h 02.00.02
+mpi2_targ.h 02.00.03
+mpi2_tool.h 02.00.03
+mpi2_type.h 02.00.00
+mpi2_ra.h 02.00.00
+
+Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
+mpi2_cnfg.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 02.00.06
+mpi2_init.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.04 02.00.03
+mpi2_ioc.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 02.00.06
+mpi2_raid.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.02 02.00.02
+mpi2_sas.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01
+mpi2_targ.h 02.00.03 02.00.03 02.00.02 02.00.02 02.00.02 02.00.02
+mpi2_tool.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+
+Filename 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_cnfg.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_init.h 02.00.02 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ioc.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_raid.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
+mpi2_sas.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00
+mpi2_targ.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
+mpi2_tool.h 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index f1115f0f0eb2..563e56d2e945 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2009 LSI Corporation.
*
*
* Name: mpi2_init.h
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.06
+ * mpi2_init.h Version: 02.00.07
*
* Version History
* ---------------
@@ -23,6 +23,10 @@
* Control field Task Attribute flags.
* Moved LUN field defines to mpi2.h becasue they are
* common to many structures.
+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
+ * Query Asynchronous Event.
+ * Defined two new bits in the SlotStatus field of the SCSI
+ * Enclosure Processor Request and Reply.
* --------------------------------------------------------------------------
*/
@@ -289,7 +293,11 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09)
-#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (0x0A)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A)
+
+/* obsolete TaskType name */
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \
+ (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT)
/* MsgFlags bits */
@@ -375,6 +383,8 @@ typedef struct _MPI2_SEP_REQUEST
#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100)
#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080)
#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
+#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010)
+#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004)
#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002)
#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001)
@@ -410,6 +420,8 @@ typedef struct _MPI2_SEP_REPLY
#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100)
#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080)
#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010)
+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004)
#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002)
#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index 8c5d81870c03..c294128bdeb4 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.10
+ * mpi2_ioc.h Version: 02.00.11
*
* Version History
* ---------------
@@ -79,6 +79,11 @@
* Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
* define.
* Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
+ * Added two new reason codes for SAS Device Status Change
+ * Event.
+ * Added new event: SAS PHY Counter.
* --------------------------------------------------------------------------
*/
@@ -261,6 +266,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY
/* ProductID field uses MPI2_FW_HEADER_PID_ */
/* IOCCapabilities */
+#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000)
+#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000)
#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000)
#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000)
#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800)
@@ -440,6 +447,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F)
#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020)
#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021)
+#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
/* Log Entry Added Event data */
@@ -502,17 +510,19 @@ typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t;
/* SAS Device Status Change Event data ReasonCode values */
-#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12)
/* Integrated RAID Operation Status Event data */
@@ -822,6 +832,37 @@ typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE
#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02)
+/* SAS PHY Counter Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER {
+ U64 TimeStamp; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 PhyEventCode; /* 0x0C */
+ U8 PhyNum; /* 0x0D */
+ U16 Reserved2; /* 0x0E */
+ U32 PhyEventInfo; /* 0x10 */
+ U8 CounterType; /* 0x14 */
+ U8 ThresholdWindow; /* 0x15 */
+ U8 TimeUnits; /* 0x16 */
+ U8 Reserved3; /* 0x17 */
+ U32 EventThreshold; /* 0x18 */
+ U16 ThresholdFlags; /* 0x1C */
+ U16 Reserved4; /* 0x1E */
+} MPI2_EVENT_DATA_SAS_PHY_COUNTER,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER,
+ Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t;
+
+/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the
+ * PhyEventCode field
+ * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the
+ * CounterType field
+ * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the
+ * TimeUnits field
+ * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the
+ * ThresholdFlags field
+ * */
+
+
/****************************************************************************
* EventAck message
****************************************************************************/
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 2ff4e936bd39..007e950f7bfa 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2009 LSI Corporation.
*
*
* Name: mpi2_tool.h
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.02
+ * mpi2_tool.h Version: 02.00.03
*
* Version History
* ---------------
@@ -17,6 +17,7 @@
* 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release
* structures and defines.
* 02-29-08 02.00.02 Modified various names to make them 32-character unique.
+ * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
* --------------------------------------------------------------------------
*/
@@ -32,7 +33,10 @@
/* defines for the Tools */
#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
+#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
+#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
+
/****************************************************************************
* Toolbox reply
@@ -112,6 +116,77 @@ typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST
/****************************************************************************
+* Toolbox ISTWI Read Write Tool
+****************************************************************************/
+
+/* Toolbox ISTWI Read Write Tool request message */
+typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U32 Reserved5; /* 0x0C */
+ U32 Reserved6; /* 0x10 */
+ U8 DevIndex; /* 0x14 */
+ U8 Action; /* 0x15 */
+ U8 SGLFlags; /* 0x16 */
+ U8 Reserved7; /* 0x17 */
+ U16 TxDataLength; /* 0x18 */
+ U16 RxDataLength; /* 0x1A */
+ U32 Reserved8; /* 0x1C */
+ U32 Reserved9; /* 0x20 */
+ U32 Reserved10; /* 0x24 */
+ U32 Reserved11; /* 0x28 */
+ U32 Reserved12; /* 0x2C */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */
+} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
+ Mpi2ToolboxIstwiReadWriteRequest_t,
+ MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t;
+
+/* values for the Action field */
+#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01)
+#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02)
+#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03)
+#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10)
+#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11)
+#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12)
+
+/* values for SGLFlags field are in the SGL section of mpi2.h */
+
+
+/* Toolbox ISTWI Read Write Tool reply message */
+typedef struct _MPI2_TOOLBOX_ISTWI_REPLY {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U16 Reserved5; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U8 DevIndex; /* 0x14 */
+ U8 Action; /* 0x15 */
+ U8 IstwiStatus; /* 0x16 */
+ U8 Reserved6; /* 0x17 */
+ U16 TxDataCount; /* 0x18 */
+ U16 RxDataCount; /* 0x1A */
+} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY,
+ Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t;
+
+
+/****************************************************************************
* Toolbox Beacon Tool request
****************************************************************************/
@@ -139,6 +214,61 @@ typedef struct _MPI2_TOOLBOX_BEACON_REQUEST
#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01)
+/****************************************************************************
+* Toolbox Diagnostic CLI Tool
+****************************************************************************/
+
+#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C)
+
+/* Toolbox Diagnostic CLI Tool request message */
+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 SGLFlags; /* 0x0C */
+ U8 Reserved5; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U32 DataLength; /* 0x10 */
+ U8 DiagnosticCliCommand
+ [MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x70 */
+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ Mpi2ToolboxDiagnosticCliRequest_t,
+ MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
+
+/* values for SGLFlags field are in the SGL section of mpi2.h */
+
+
+/* Toolbox Diagnostic CLI Tool reply message */
+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U16 Reserved5; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U32 ReturnedDataLength; /* 0x14 */
+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY,
+ Mpi2ToolboxDiagnosticCliReply_t,
+ MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t;
+
+
/*****************************************************************************
*
* Diagnostic Buffer Messages
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index d95d2f274cb3..670241efa4b5 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -63,7 +63,7 @@
static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
-#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */
+#define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */
static int max_queue_depth = -1;
module_param(max_queue_depth, int, 0);
@@ -543,13 +543,13 @@ mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
* _base_display_reply_info -
* @ioc: pointer to scsi command object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
* Return nothing.
*/
static void
-_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
@@ -572,22 +572,24 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
* mpt2sas_base_done - base internal command completion routine
* @ioc: pointer to scsi command object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+u8
+mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
- return;
+ return 1;
if (ioc->base_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
ioc->base_cmds.status |= MPT2_CMD_COMPLETE;
if (mpi_reply) {
@@ -596,18 +598,20 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
}
ioc->base_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->base_cmds.done);
+ return 1;
}
/**
* _base_async_event - main callback handler for firmware asyn events
* @ioc: pointer to scsi command object
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-static void
-_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+static u8
+_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
{
Mpi2EventNotificationReply_t *mpi_reply;
Mpi2EventAckRequest_t *ack_request;
@@ -615,9 +619,9 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (!mpi_reply)
- return;
+ return 1;
if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
- return;
+ return 1;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_base_display_event_data(ioc, mpi_reply);
#endif
@@ -635,16 +639,47 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
ack_request->Event = mpi_reply->Event;
ack_request->EventContext = mpi_reply->EventContext;
- ack_request->VF_ID = VF_ID;
- mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+ ack_request->VF_ID = 0; /* TODO */
+ ack_request->VP_ID = 0;
+ mpt2sas_base_put_smid_default(ioc, smid);
out:
/* scsih callback handler */
- mpt2sas_scsih_event_callback(ioc, VF_ID, reply);
+ mpt2sas_scsih_event_callback(ioc, msix_index, reply);
/* ctl callback handler */
- mpt2sas_ctl_event_callback(ioc, VF_ID, reply);
+ mpt2sas_ctl_event_callback(ioc, msix_index, reply);
+
+ return 1;
+}
+
+/**
+ * _base_get_cb_idx - obtain the callback index
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return callback index.
+ */
+static u8
+_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+ int i;
+ u8 cb_idx = 0xFF;
+
+ if (smid >= ioc->hi_priority_smid) {
+ if (smid < ioc->internal_smid) {
+ i = smid - ioc->hi_priority_smid;
+ cb_idx = ioc->hpr_lookup[i].cb_idx;
+ } else {
+ i = smid - ioc->internal_smid;
+ cb_idx = ioc->internal_lookup[i].cb_idx;
+ }
+ } else {
+ i = smid - 1;
+ cb_idx = ioc->scsi_lookup[i].cb_idx;
+ }
+ return cb_idx;
}
/**
@@ -680,7 +715,6 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
{
u32 him_register;
- writel(0, &ioc->chip->HostInterruptStatus);
him_register = readl(&ioc->chip->HostInterruptMask);
him_register &= ~MPI2_HIM_RIM;
writel(him_register, &ioc->chip->HostInterruptMask);
@@ -712,9 +746,10 @@ _base_interrupt(int irq, void *bus_id)
u16 smid;
u8 cb_idx;
u32 reply;
- u8 VF_ID;
+ u8 msix_index;
struct MPT2SAS_ADAPTER *ioc = bus_id;
Mpi2ReplyDescriptorsUnion_t *rpf;
+ u8 rc;
if (ioc->mask_interrupts)
return IRQ_NONE;
@@ -733,7 +768,7 @@ _base_interrupt(int irq, void *bus_id)
reply = 0;
cb_idx = 0xFF;
smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
- VF_ID = rpf->Default.VF_ID;
+ msix_index = rpf->Default.MSIxIndex;
if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
reply = le32_to_cpu
@@ -745,16 +780,18 @@ _base_interrupt(int irq, void *bus_id)
MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
goto next;
if (smid)
- cb_idx = ioc->scsi_lookup[smid - 1].cb_idx;
+ cb_idx = _base_get_cb_idx(ioc, smid);
if (smid && cb_idx != 0xFF) {
- mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply);
+ rc = mpt_callbacks[cb_idx](ioc, smid, msix_index,
+ reply);
if (reply)
- _base_display_reply_info(ioc, smid, VF_ID,
+ _base_display_reply_info(ioc, smid, msix_index,
reply);
- mpt2sas_base_free_smid(ioc, smid);
+ if (rc)
+ mpt2sas_base_free_smid(ioc, smid);
}
if (!smid)
- _base_async_event(ioc, VF_ID, reply);
+ _base_async_event(ioc, msix_index, reply);
/* reply free queue handling */
if (reply) {
@@ -1191,19 +1228,6 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
}
/**
- * mpt2sas_base_get_msg_frame_dma - obtain request mf pointer phys addr
- * @ioc: per adapter object
- * @smid: system request message index(smid zero is invalid)
- *
- * Returns phys pointer to message frame.
- */
-dma_addr_t
-mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return ioc->request_dma + (smid * ioc->request_sz);
-}
-
-/**
* mpt2sas_base_get_msg_frame - obtain request mf pointer
* @ioc: per adapter object
* @smid: system request message index(smid zero is invalid)
@@ -1258,7 +1282,7 @@ mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)
}
/**
- * mpt2sas_base_get_smid - obtain a free smid
+ * mpt2sas_base_get_smid - obtain a free smid from internal queue
* @ioc: per adapter object
* @cb_idx: callback index
*
@@ -1272,6 +1296,39 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
u16 smid;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ if (list_empty(&ioc->internal_free_list)) {
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
+ ioc->name, __func__);
+ return 0;
+ }
+
+ request = list_entry(ioc->internal_free_list.next,
+ struct request_tracker, tracker_list);
+ request->cb_idx = cb_idx;
+ smid = request->smid;
+ list_del(&request->tracker_list);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return smid;
+}
+
+/**
+ * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue
+ * @ioc: per adapter object
+ * @cb_idx: callback index
+ * @scmd: pointer to scsi command object
+ *
+ * Returns smid (zero is invalid)
+ */
+u16
+mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
+ struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+ struct request_tracker *request;
+ u16 smid;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
if (list_empty(&ioc->free_list)) {
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
@@ -1281,6 +1338,36 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
request = list_entry(ioc->free_list.next,
struct request_tracker, tracker_list);
+ request->scmd = scmd;
+ request->cb_idx = cb_idx;
+ smid = request->smid;
+ list_del(&request->tracker_list);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return smid;
+}
+
+/**
+ * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue
+ * @ioc: per adapter object
+ * @cb_idx: callback index
+ *
+ * Returns smid (zero is invalid)
+ */
+u16
+mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
+{
+ unsigned long flags;
+ struct request_tracker *request;
+ u16 smid;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ if (list_empty(&ioc->hpr_free_list)) {
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return 0;
+ }
+
+ request = list_entry(ioc->hpr_free_list.next,
+ struct request_tracker, tracker_list);
request->cb_idx = cb_idx;
smid = request->smid;
list_del(&request->tracker_list);
@@ -1300,10 +1387,32 @@ void
mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
unsigned long flags;
+ int i;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- ioc->scsi_lookup[smid - 1].cb_idx = 0xFF;
- list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list,
+ if (smid >= ioc->hi_priority_smid) {
+ if (smid < ioc->internal_smid) {
+ /* hi-priority */
+ i = smid - ioc->hi_priority_smid;
+ ioc->hpr_lookup[i].cb_idx = 0xFF;
+ list_add_tail(&ioc->hpr_lookup[i].tracker_list,
+ &ioc->hpr_free_list);
+ } else {
+ /* internal queue */
+ i = smid - ioc->internal_smid;
+ ioc->internal_lookup[i].cb_idx = 0xFF;
+ list_add_tail(&ioc->internal_lookup[i].tracker_list,
+ &ioc->internal_free_list);
+ }
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return;
+ }
+
+ /* scsiio queue */
+ i = smid - 1;
+ ioc->scsi_lookup[i].cb_idx = 0xFF;
+ ioc->scsi_lookup[i].scmd = NULL;
+ list_add_tail(&ioc->scsi_lookup[i].tracker_list,
&ioc->free_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
@@ -1352,21 +1461,19 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
* mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
* @handle: device handle
*
* Return nothing.
*/
void
-mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
- u16 handle)
+mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- descriptor.SCSIIO.VF_ID = vf_id;
+ descriptor.SCSIIO.MSIxIndex = 0; /* TODO */
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -1379,20 +1486,18 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
* mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
*
* Return nothing.
*/
void
-mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 vf_id)
+mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.HighPriority.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
- descriptor.HighPriority.VF_ID = vf_id;
+ descriptor.HighPriority.MSIxIndex = 0; /* TODO */
descriptor.HighPriority.SMID = cpu_to_le16(smid);
descriptor.HighPriority.LMID = 0;
descriptor.HighPriority.Reserved1 = 0;
@@ -1404,18 +1509,17 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid,
* mpt2sas_base_put_smid_default - Default, primarily used for config pages
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
*
* Return nothing.
*/
void
-mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
+mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- descriptor.Default.VF_ID = vf_id;
+ descriptor.Default.MSIxIndex = 0; /* TODO */
descriptor.Default.SMID = cpu_to_le16(smid);
descriptor.Default.LMID = 0;
descriptor.Default.DescriptorTypeDependent = 0;
@@ -1427,21 +1531,20 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
* mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
* @io_index: value used to track the IO
*
* Return nothing.
*/
void
mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 vf_id, u16 io_index)
+ u16 io_index)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.SCSITarget.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
- descriptor.SCSITarget.VF_ID = vf_id;
+ descriptor.SCSITarget.MSIxIndex = 0; /* TODO */
descriptor.SCSITarget.SMID = cpu_to_le16(smid);
descriptor.SCSITarget.LMID = 0;
descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
@@ -1717,6 +1820,8 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
}
kfree(ioc->scsi_lookup);
+ kfree(ioc->hpr_lookup);
+ kfree(ioc->internal_lookup);
}
@@ -1736,7 +1841,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
u16 num_of_reply_frames;
u16 chains_needed_per_io;
u32 sz, total_sz;
- u16 i;
u32 retry_sz;
u16 max_request_credit;
@@ -1764,7 +1868,10 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
facts->RequestCredit;
}
- ioc->request_depth = max_request_credit;
+
+ ioc->hba_queue_depth = max_request_credit;
+ ioc->hi_priority_depth = facts->HighPriorityCredit;
+ ioc->internal_depth = ioc->hi_priority_depth + 5;
/* request frame size */
ioc->request_sz = facts->IOCRequestFrameSize * 4;
@@ -1802,7 +1909,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
ioc->chains_needed_per_io = chains_needed_per_io;
/* reply free queue sizing - taking into account for events */
- num_of_reply_frames = ioc->request_depth + 32;
+ num_of_reply_frames = ioc->hba_queue_depth + 32;
/* number of replies frames can't be a multiple of 16 */
/* decrease number of reply frames by 1 */
@@ -1823,7 +1930,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
* frames
*/
- queue_size = ioc->request_depth + num_of_reply_frames + 1;
+ queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1;
/* round up to 16 byte boundary */
if (queue_size % 16)
queue_size += 16 - (queue_size % 16);
@@ -1837,60 +1944,85 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (queue_diff % 16)
queue_diff += 16 - (queue_diff % 16);
- /* adjust request_depth, reply_free_queue_depth,
+ /* adjust hba_queue_depth, reply_free_queue_depth,
* and queue_size
*/
- ioc->request_depth -= queue_diff;
+ ioc->hba_queue_depth -= queue_diff;
ioc->reply_free_queue_depth -= queue_diff;
queue_size -= queue_diff;
}
ioc->reply_post_queue_depth = queue_size;
- /* max scsi host queue depth */
- ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT;
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth"
- "(%d)\n", ioc->name, ioc->shost->can_queue));
-
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
"sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
"chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,
ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
ioc->chains_needed_per_io));
+ ioc->scsiio_depth = ioc->hba_queue_depth -
+ ioc->hi_priority_depth - ioc->internal_depth;
+
+ /* set the scsi host can_queue depth
+ * with some internal commands that could be outstanding
+ */
+ ioc->shost->can_queue = ioc->scsiio_depth - (2);
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: "
+ "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue));
+
/* contiguous pool for request and chains, 16 byte align, one extra "
* "frame for smid=0
*/
- ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth;
- sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+ ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
+ sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+
+ /* hi-priority queue */
+ sz += (ioc->hi_priority_depth * ioc->request_sz);
+
+ /* internal queue */
+ sz += (ioc->internal_depth * ioc->request_sz);
ioc->request_dma_sz = sz;
ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);
if (!ioc->request) {
printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
- "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kB)\n", ioc->name, ioc->request_depth,
+ "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
+ "total(%d kB)\n", ioc->name, ioc->hba_queue_depth,
ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
- if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH)
+ if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH)
goto out;
retry_sz += 64;
- ioc->request_depth = max_request_credit - retry_sz;
+ ioc->hba_queue_depth = max_request_credit - retry_sz;
goto retry_allocation;
}
if (retry_sz)
printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
- "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kb)\n", ioc->name, ioc->request_depth,
+ "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
+ "total(%d kb)\n", ioc->name, ioc->hba_queue_depth,
ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
- ioc->chain = ioc->request + ((ioc->request_depth + 1) *
+
+ /* hi-priority queue */
+ ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) *
+ ioc->request_sz);
+ ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) *
+ ioc->request_sz);
+
+ /* internal queue */
+ ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth *
+ ioc->request_sz);
+ ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
+ ioc->request_sz);
+
+ ioc->chain = ioc->internal + (ioc->internal_depth *
ioc->request_sz);
- ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) *
+ ioc->chain_dma = ioc->internal_dma + (ioc->internal_depth *
ioc->request_sz);
+
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
"depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->request, ioc->request_depth, ioc->request_sz,
- ((ioc->request_depth + 1) * ioc->request_sz)/1024));
+ ioc->request, ioc->hba_queue_depth, ioc->request_sz,
+ (ioc->hba_queue_depth * ioc->request_sz)/1024));
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
"(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
@@ -1899,7 +2031,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
ioc->name, (unsigned long long) ioc->request_dma));
total_sz += sz;
- ioc->scsi_lookup = kcalloc(ioc->request_depth,
+ ioc->scsi_lookup = kcalloc(ioc->scsiio_depth,
sizeof(struct request_tracker), GFP_KERNEL);
if (!ioc->scsi_lookup) {
printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
@@ -1907,12 +2039,38 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
goto out;
}
- /* initialize some bits */
- for (i = 0; i < ioc->request_depth; i++)
- ioc->scsi_lookup[i].smid = i + 1;
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): "
+ "depth(%d)\n", ioc->name, ioc->request,
+ ioc->scsiio_depth));
+
+ /* initialize hi-priority queue smid's */
+ ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
+ sizeof(struct request_tracker), GFP_KERNEL);
+ if (!ioc->hpr_lookup) {
+ printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n",
+ ioc->name);
+ goto out;
+ }
+ ioc->hi_priority_smid = ioc->scsiio_depth + 1;
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): "
+ "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority,
+ ioc->hi_priority_depth, ioc->hi_priority_smid));
+
+ /* initialize internal queue smid's */
+ ioc->internal_lookup = kcalloc(ioc->internal_depth,
+ sizeof(struct request_tracker), GFP_KERNEL);
+ if (!ioc->internal_lookup) {
+ printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n",
+ ioc->name);
+ goto out;
+ }
+ ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth;
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): "
+ "depth(%d), start smid(%d)\n", ioc->name, ioc->internal,
+ ioc->internal_depth, ioc->internal_smid));
/* sense buffers, 4 byte align */
- sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE;
+ sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE;
ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,
0);
if (!ioc->sense_dma_pool) {
@@ -1929,7 +2087,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
}
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"sense pool(0x%p): depth(%d), element_size(%d), pool_size"
- "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth,
+ "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth,
SCSI_SENSE_BUFFERSIZE, sz/1024));
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n",
ioc->name, (unsigned long long)ioc->sense_dma));
@@ -2304,7 +2462,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
&ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+ if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
printk(MPT2SAS_ERR_FMT "doorbell handshake "
"int failed (line=%d)\n", ioc->name, __LINE__);
return -EFAULT;
@@ -2454,7 +2612,8 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
ioc->ioc_link_reset_in_progress = 1;
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
@@ -2555,7 +2714,8 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->base_cmds.smid = smid;
memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
@@ -2701,13 +2861,12 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/**
* _base_send_ioc_init - send ioc_init to firmware
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
Mpi2IOCInitRequest_t mpi_request;
Mpi2IOCInitReply_t mpi_reply;
@@ -2719,7 +2878,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
- mpi_request.VF_ID = VF_ID;
+ mpi_request.VF_ID = 0; /* TODO */
+ mpi_request.VP_ID = 0;
mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
@@ -2795,13 +2955,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
/**
* _base_send_port_enable - send port_enable(discovery stuff) to firmware
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
Mpi2PortEnableRequest_t *mpi_request;
u32 ioc_state;
@@ -2829,9 +2988,11 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
ioc->base_cmds.smid = smid;
memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
- mpi_request->VF_ID = VF_ID;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
- mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
300*HZ);
if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
@@ -2892,13 +3053,12 @@ _base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)
/**
* _base_event_notification - send event notification
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
Mpi2EventNotificationRequest_t *mpi_request;
unsigned long timeleft;
@@ -2926,11 +3086,13 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
ioc->base_cmds.smid = smid;
memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
- mpi_request->VF_ID = VF_ID;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
mpi_request->EventMasks[i] =
le32_to_cpu(ioc->event_masks[i]);
- mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n",
@@ -2981,7 +3143,7 @@ mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)
return;
mutex_lock(&ioc->base_cmds.mutex);
- _base_event_notification(ioc, 0, CAN_SLEEP);
+ _base_event_notification(ioc, CAN_SLEEP);
mutex_unlock(&ioc->base_cmds.mutex);
}
@@ -3006,7 +3168,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
ioc->name));
- writel(0, &ioc->chip->HostInterruptStatus);
count = 0;
do {
@@ -3160,30 +3321,60 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
/**
* _base_make_ioc_operational - put controller in OPERATIONAL state
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- int sleep_flag)
+_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
int r, i;
unsigned long flags;
u32 reply_address;
+ u16 smid;
+ struct _tr_list *delayed_tr, *delayed_tr_next;
dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
+ /* clean the delayed target reset list */
+ list_for_each_entry_safe(delayed_tr, delayed_tr_next,
+ &ioc->delayed_tr_list, list) {
+ list_del(&delayed_tr->list);
+ kfree(delayed_tr);
+ }
+
/* initialize the scsi lookup free list */
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
INIT_LIST_HEAD(&ioc->free_list);
- for (i = 0; i < ioc->request_depth; i++) {
+ smid = 1;
+ for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
ioc->scsi_lookup[i].cb_idx = 0xFF;
+ ioc->scsi_lookup[i].smid = smid;
+ ioc->scsi_lookup[i].scmd = NULL;
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
&ioc->free_list);
}
+
+ /* hi-priority queue */
+ INIT_LIST_HEAD(&ioc->hpr_free_list);
+ smid = ioc->hi_priority_smid;
+ for (i = 0; i < ioc->hi_priority_depth; i++, smid++) {
+ ioc->hpr_lookup[i].cb_idx = 0xFF;
+ ioc->hpr_lookup[i].smid = smid;
+ list_add_tail(&ioc->hpr_lookup[i].tracker_list,
+ &ioc->hpr_free_list);
+ }
+
+ /* internal queue */
+ INIT_LIST_HEAD(&ioc->internal_free_list);
+ smid = ioc->internal_smid;
+ for (i = 0; i < ioc->internal_depth; i++, smid++) {
+ ioc->internal_lookup[i].cb_idx = 0xFF;
+ ioc->internal_lookup[i].smid = smid;
+ list_add_tail(&ioc->internal_lookup[i].tracker_list,
+ &ioc->internal_free_list);
+ }
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
/* initialize Reply Free Queue */
@@ -3196,7 +3387,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
for (i = 0; i < ioc->reply_post_queue_depth; i++)
ioc->reply_post_free[i].Words = ULLONG_MAX;
- r = _base_send_ioc_init(ioc, VF_ID, sleep_flag);
+ r = _base_send_ioc_init(ioc, sleep_flag);
if (r)
return r;
@@ -3207,14 +3398,14 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
writel(0, &ioc->chip->ReplyPostHostIndex);
_base_unmask_interrupts(ioc);
- r = _base_event_notification(ioc, VF_ID, sleep_flag);
+ r = _base_event_notification(ioc, sleep_flag);
if (r)
return r;
if (sleep_flag == CAN_SLEEP)
_base_static_config_pages(ioc);
- r = _base_send_port_enable(ioc, VF_ID, sleep_flag);
+ r = _base_send_port_enable(ioc, sleep_flag);
if (r)
return r;
@@ -3278,6 +3469,17 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
if (r)
goto out_free_resources;
+ ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
+ sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
+ if (!ioc->pfacts)
+ goto out_free_resources;
+
+ for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
+ r = _base_get_port_facts(ioc, i, CAN_SLEEP);
+ if (r)
+ goto out_free_resources;
+ }
+
r = _base_allocate_memory_pools(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
@@ -3286,7 +3488,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
/* base internal command bits */
mutex_init(&ioc->base_cmds.mutex);
- init_completion(&ioc->base_cmds.done);
ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->base_cmds.status = MPT2_CMD_NOT_USED;
@@ -3294,7 +3495,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->transport_cmds.mutex);
- init_completion(&ioc->transport_cmds.done);
/* task management internal command bits */
ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
@@ -3310,7 +3510,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->ctl_cmds.mutex);
- init_completion(&ioc->ctl_cmds.done);
for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
ioc->event_masks[i] = -1;
@@ -3327,18 +3526,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
_base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL);
_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
-
- ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
- sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
- if (!ioc->pfacts)
- goto out_free_resources;
-
- for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
- r = _base_get_port_facts(ioc, i, CAN_SLEEP);
- if (r)
- goto out_free_resources;
- }
- r = _base_make_ioc_operational(ioc, 0, CAN_SLEEP);
+ r = _base_make_ioc_operational(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
@@ -3466,7 +3654,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/* pending command count */
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- for (i = 0; i < ioc->request_depth; i++)
+ for (i = 0; i < ioc->scsiio_depth; i++)
if (ioc->scsi_lookup[i].cb_idx != 0xFF)
ioc->pending_io_count++;
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
@@ -3490,7 +3678,7 @@ int
mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
enum reset_type type)
{
- int r, i;
+ int r;
unsigned long flags;
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
@@ -3513,9 +3701,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
if (r)
goto out;
_base_reset_handler(ioc, MPT2_IOC_AFTER_RESET);
- for (i = 0 ; i < ioc->facts.NumberOfPorts; i++)
- r = _base_make_ioc_operational(ioc, ioc->pfacts[i].VF_ID,
- sleep_flag);
+ r = _base_make_ioc_operational(ioc, sleep_flag);
if (!r)
_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
out:
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 2faab1e690e9..0cf6bc236e4d 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -69,10 +69,10 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "01.100.06.00"
-#define MPT2SAS_MAJOR_VERSION 01
+#define MPT2SAS_DRIVER_VERSION "02.100.03.00"
+#define MPT2SAS_MAJOR_VERSION 02
#define MPT2SAS_MINOR_VERSION 100
-#define MPT2SAS_BUILD_VERSION 06
+#define MPT2SAS_BUILD_VERSION 03
#define MPT2SAS_RELEASE_VERSION 00
/*
@@ -264,6 +264,13 @@ struct _internal_cmd {
* SAS Topology Structures
*/
+#define MPTSAS_STATE_TR_SEND 0x0001
+#define MPTSAS_STATE_TR_COMPLETE 0x0002
+#define MPTSAS_STATE_CNTRL_SEND 0x0004
+#define MPTSAS_STATE_CNTRL_COMPLETE 0x0008
+
+#define MPT2SAS_REQ_SAS_CNTRL 0x0010
+
/**
* struct _sas_device - attached device information
* @list: sas device list
@@ -300,6 +307,7 @@ struct _sas_device {
u16 slot;
u8 hidden_raid_component;
u8 responding;
+ u16 state;
};
/**
@@ -436,6 +444,17 @@ struct request_tracker {
struct list_head tracker_list;
};
+/**
+ * struct _tr_list - target reset list
+ * @handle: device handle
+ * @state: state machine
+ */
+struct _tr_list {
+ struct list_head list;
+ u16 handle;
+ u16 state;
+};
+
typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
/**
@@ -510,8 +529,9 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @config_page_sz: config page size
* @config_page: reserve memory for config page payload
* @config_page_dma:
+ * @hba_queue_depth: hba request queue depth
* @sge_size: sg element size for either 32/64 bit
- * @request_depth: hba request queue depth
+ * @scsiio_depth: SCSI_IO queue depth
* @request_sz: per request frame size
* @request: pool of request frames
* @request_dma:
@@ -528,6 +548,18 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @chains_needed_per_io: max chains per io
* @chain_offset_value_for_main_message: location 1st sg in main
* @chain_depth: total chains allocated
+ * @hi_priority_smid:
+ * @hi_priority:
+ * @hi_priority_dma:
+ * @hi_priority_depth:
+ * @hpr_lookup:
+ * @hpr_free_list:
+ * @internal_smid:
+ * @internal:
+ * @internal_dma:
+ * @internal_depth:
+ * @internal_lookup:
+ * @internal_free_list:
* @sense: pool of sense
* @sense_dma:
* @sense_dma_pool:
@@ -597,6 +629,8 @@ struct MPT2SAS_ADAPTER {
u8 ctl_cb_idx;
u8 base_cb_idx;
u8 config_cb_idx;
+ u8 tm_tr_cb_idx;
+ u8 tm_sas_control_cb_idx;
struct _internal_cmd base_cmds;
struct _internal_cmd transport_cmds;
struct _internal_cmd tm_cmds;
@@ -643,9 +677,10 @@ struct MPT2SAS_ADAPTER {
void *config_page;
dma_addr_t config_page_dma;
- /* request */
+ /* scsiio request */
+ u16 hba_queue_depth;
u16 sge_size;
- u16 request_depth;
+ u16 scsiio_depth;
u16 request_sz;
u8 *request;
dma_addr_t request_dma;
@@ -665,6 +700,22 @@ struct MPT2SAS_ADAPTER {
u16 chain_offset_value_for_main_message;
u16 chain_depth;
+ /* hi-priority queue */
+ u16 hi_priority_smid;
+ u8 *hi_priority;
+ dma_addr_t hi_priority_dma;
+ u16 hi_priority_depth;
+ struct request_tracker *hpr_lookup;
+ struct list_head hpr_free_list;
+
+ /* internal queue */
+ u16 internal_smid;
+ u8 *internal;
+ dma_addr_t internal_dma;
+ u16 internal_depth;
+ struct request_tracker *internal_lookup;
+ struct list_head internal_free_list;
+
/* sense */
u8 *sense;
dma_addr_t sense_dma;
@@ -690,6 +741,8 @@ struct MPT2SAS_ADAPTER {
struct dma_pool *reply_post_free_dma_pool;
u32 reply_post_host_index;
+ struct list_head delayed_tr_list;
+
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -701,7 +754,7 @@ struct MPT2SAS_ADAPTER {
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
};
-typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
@@ -720,22 +773,28 @@ int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr);
-dma_addr_t mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
+ u16 smid);
+
+/* hi-priority queue */
+u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
+u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
+ struct scsi_cmnd *scmd);
u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid,
u16 handle);
-void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
+void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 vf_id, u16 io_index);
-void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
+ u16 io_index);
+void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_initialize_callback_handler(void);
u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func);
void mpt2sas_base_release_callback_handler(u8 cb_idx);
-void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply);
void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr);
u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked);
@@ -749,6 +808,8 @@ int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
/* scsih shared API */
+u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+ u32 reply);
void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
u8 type, u16 smid_task, ulong timeout);
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
@@ -760,11 +821,11 @@ struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAP
struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address(
struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
/* config shared API */
-void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply);
int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);
int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
@@ -817,14 +878,17 @@ extern struct device_attribute *mpt2sas_host_attrs[];
extern struct device_attribute *mpt2sas_dev_attrs[];
void mpt2sas_ctl_init(void);
void mpt2sas_ctl_exit(void);
-void mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply);
void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
-void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
+u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+ u32 reply);
void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventNotificationReply_t *mpi_reply);
/* transport shared API */
-void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply);
struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,
u16 handle, u16 parent_handle);
void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
@@ -838,6 +902,8 @@ void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle,
extern struct sas_function_template mpt2sas_transport_functions;
extern struct scsi_transport_template *mpt2sas_transport_template;
extern int scsi_internal_device_block(struct scsi_device *sdev);
+extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc,
+ u8 msix_index, u32 reply);
extern int scsi_internal_device_unblock(struct scsi_device *sdev);
#endif /* MPT2SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index ab8c560865d8..594a389c6526 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -2,7 +2,7 @@
* This module provides common API for accessing firmware configuration pages
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -227,23 +227,25 @@ _config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
* mpt2sas_config_done - config page completion routine
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using _config_request.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+u8
+mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->config_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->config_cmds.smid != smid)
- return;
+ return 1;
ioc->config_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
@@ -257,6 +259,7 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
#endif
ioc->config_cmds.smid = USHORT_MAX;
complete(&ioc->config_cmds.done);
+ return 1;
}
/**
@@ -303,6 +306,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
retry_count = 0;
memset(&mem, 0, sizeof(struct config_request));
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
+
if (config_page) {
mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion;
mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber;
@@ -380,7 +386,7 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
_config_display_some_debug(ioc, smid, "config_request", NULL);
#endif
init_completion(&ioc->config_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid, config_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
timeout*HZ);
if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) {
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index c2a51018910f..57d724633906 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -219,23 +219,25 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
* mpt2sas_ctl_done - ctl module completion routine
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using ioc->ctl_cb_idx.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+u8
+mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->ctl_cmds.smid != smid)
- return;
+ return 1;
ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
@@ -247,6 +249,7 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
#endif
ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->ctl_cmds.done);
+ return 1;
}
/**
@@ -328,22 +331,25 @@ mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
/**
* mpt2sas_ctl_event_callback - firmware event handler (called at ISR time)
* @ioc: per adapter object
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: interrupt.
*
* This function merely adds a new work task into ioc->firmware_event_thread.
* The tasks are worked from _firmware_event_work in user context.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+u8
+mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+ u32 reply)
{
Mpi2EventNotificationReply_t *mpi_reply;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
+ return 1;
}
/**
@@ -507,7 +513,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
handle = le16_to_cpu(tm_request->DevHandle);
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- for (i = ioc->request_depth; i && !found; i--) {
+ for (i = ioc->scsiio_depth; i && !found; i--) {
scmd = ioc->scsi_lookup[i - 1].scmd;
if (scmd == NULL || scmd->device == NULL ||
scmd->device->hostdata == NULL)
@@ -614,7 +620,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
@@ -737,7 +743,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
(u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
- mpt2sas_base_put_smid_scsi_io(ioc, smid, 0,
+ mpt2sas_base_put_smid_scsi_io(ioc, smid,
le16_to_cpu(mpi_request->FunctionDependent1));
break;
}
@@ -759,8 +765,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
mutex_lock(&ioc->tm_cmds.mutex);
mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
tm_request->DevHandle));
- mpt2sas_base_put_smid_hi_priority(ioc, smid,
- mpi_request->VF_ID);
+ mpt2sas_base_put_smid_hi_priority(ioc, smid);
break;
}
case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -781,7 +786,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
ioc->ioc_link_reset_in_progress = 1;
ioc->ignore_loginfos = 1;
}
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
@@ -795,11 +800,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
ioc->ioc_link_reset_in_progress = 1;
ioc->ignore_loginfos = 1;
}
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
break;
}
default:
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
break;
}
@@ -807,6 +812,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
timeout = MPT2_IOCTL_DEFAULT_TIMEOUT;
else
timeout = karg.timeout;
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
timeout*HZ);
if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
@@ -1371,6 +1377,8 @@ _ctl_diag_register(void __user *arg, enum block_state state)
mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags);
mpi_request->BufferAddress = cpu_to_le64(request_data_dma);
mpi_request->BufferLength = cpu_to_le32(request_data_sz);
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
"dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
@@ -1380,7 +1388,8 @@ _ctl_diag_register(void __user *arg, enum block_state state)
mpi_request->ProductSpecific[i] =
cpu_to_le32(ioc->product_specific[buffer_type][i]);
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -1643,8 +1652,11 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;
mpi_request->BufferType = buffer_type;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -1902,8 +1914,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
mpi_request->ProductSpecific[i] =
cpu_to_le32(ioc->product_specific[buffer_type][i]);
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -2069,6 +2084,7 @@ static long
_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
+
lock_kernel();
ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
unlock_kernel();
@@ -2143,6 +2159,7 @@ static long
_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
+
lock_kernel();
if (cmd == MPT2COMMAND32)
ret = _ctl_compat_mpt_command(file, cmd, arg);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
index 4da11435533f..211f296dd191 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
index ad325096e842..5308a25cb307 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h
@@ -2,7 +2,7 @@
* Logging Support for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 774b34525bba..86ab32d7ab15 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -2,7 +2,7 @@
* Scsi Host Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -79,6 +79,9 @@ static u8 transport_cb_idx = -1;
static u8 config_cb_idx = -1;
static int mpt_ids;
+static u8 tm_tr_cb_idx = -1 ;
+static u8 tm_sas_control_cb_idx = -1;
+
/* command line options */
static u32 logging_level;
MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
@@ -109,6 +112,7 @@ struct sense_info {
* @work: work object (ioc->fault_reset_work_q)
* @ioc: per adapter object
* @VF_ID: virtual function id
+ * @VP_ID: virtual port id
* @host_reset_handling: handling events during host reset
* @ignore: flag meaning this event has been marked to ignore
* @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
@@ -121,6 +125,7 @@ struct fw_event_work {
struct work_struct work;
struct MPT2SAS_ADAPTER *ioc;
u8 VF_ID;
+ u8 VP_ID;
u8 host_reset_handling;
u8 ignore;
u16 event;
@@ -138,8 +143,10 @@ struct fw_event_work {
* @lun: lun number
* @cdb_length: cdb length
* @cdb: cdb contents
- * @valid_reply: flag set for reply message
* @timeout: timeout for this command
+ * @VF_ID: virtual function id
+ * @VP_ID: virtual port id
+ * @valid_reply: flag set for reply message
* @sense_length: sense length
* @ioc_status: ioc status
* @scsi_state: scsi state
@@ -161,6 +168,8 @@ struct _scsi_io_transfer {
u8 cdb_length;
u8 cdb[32];
u8 timeout;
+ u8 VF_ID;
+ u8 VP_ID;
u8 valid_reply;
/* the following bits are only valid when 'valid_reply = 1' */
u32 sense_length;
@@ -756,66 +765,16 @@ _scsih_is_end_device(u32 device_info)
}
/**
- * _scsih_scsi_lookup_get - returns scmd entry
+ * mptscsih_get_scsi_lookup - returns scmd entry
* @ioc: per adapter object
* @smid: system request message index
- * Context: This function will acquire ioc->scsi_lookup_lock.
*
* Returns the smid stored scmd pointer.
*/
static struct scsi_cmnd *
_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
- unsigned long flags;
- struct scsi_cmnd *scmd;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- scmd = ioc->scsi_lookup[smid - 1].scmd;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return scmd;
-}
-
-/**
- * mptscsih_getclear_scsi_lookup - returns scmd entry
- * @ioc: per adapter object
- * @smid: system request message index
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * Returns the smid stored scmd pointer, as well as clearing the scmd pointer.
- */
-static struct scsi_cmnd *
-_scsih_scsi_lookup_getclear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- unsigned long flags;
- struct scsi_cmnd *scmd;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- scmd = ioc->scsi_lookup[smid - 1].scmd;
- ioc->scsi_lookup[smid - 1].scmd = NULL;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return scmd;
-}
-
-/**
- * _scsih_scsi_lookup_set - updates scmd entry in lookup
- * @ioc: per adapter object
- * @smid: system request message index
- * @scmd: pointer to scsi command object
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * This will save scmd pointer in the scsi_lookup array.
- *
- * Return nothing.
- */
-static void
-_scsih_scsi_lookup_set(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- struct scsi_cmnd *scmd)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- ioc->scsi_lookup[smid - 1].scmd = scmd;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return ioc->scsi_lookup[smid - 1].scmd;
}
/**
@@ -838,9 +797,9 @@ _scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
smid = 0;
- for (i = 0; i < ioc->request_depth; i++) {
+ for (i = 0; i < ioc->scsiio_depth; i++) {
if (ioc->scsi_lookup[i].scmd == scmd) {
- smid = i + 1;
+ smid = ioc->scsi_lookup[i].smid;
goto out;
}
}
@@ -869,7 +828,7 @@ _scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
found = 0;
- for (i = 0 ; i < ioc->request_depth; i++) {
+ for (i = 0 ; i < ioc->scsiio_depth; i++) {
if (ioc->scsi_lookup[i].scmd &&
(ioc->scsi_lookup[i].scmd->device->id == id &&
ioc->scsi_lookup[i].scmd->device->channel == channel)) {
@@ -903,7 +862,7 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
found = 0;
- for (i = 0 ; i < ioc->request_depth; i++) {
+ for (i = 0 ; i < ioc->scsiio_depth; i++) {
if (ioc->scsi_lookup[i].scmd &&
(ioc->scsi_lookup[i].scmd->device->id == id &&
ioc->scsi_lookup[i].scmd->device->channel == channel &&
@@ -1113,7 +1072,7 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
}
/**
- * _scsih_change_queue_depth - changing device queue tag type
+ * _scsih_change_queue_type - changing device queue tag type
* @sdev: scsi device struct
* @tag_type: requested tag type
*
@@ -1679,23 +1638,24 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
* _scsih_tm_done - tm completion routine
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using scsih_issue_tm.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-static void
-_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+static u8
+_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->tm_cmds.smid != smid)
- return;
+ return 1;
ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
@@ -1704,6 +1664,7 @@ _scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
}
ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->tm_cmds.done);
+ return 1;
}
/**
@@ -1790,7 +1751,6 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
u16 smid = 0;
u32 ioc_state;
unsigned long timeleft;
- u8 VF_ID = 0;
if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
@@ -1817,7 +1777,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
goto issue_host_reset;
}
- smid = mpt2sas_base_get_smid(ioc, ioc->tm_cb_idx);
+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
@@ -1825,7 +1785,8 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
}
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
- " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid));
+ " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
+ smid_task));
ioc->tm_cmds.status = MPT2_CMD_PENDING;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->tm_cmds.smid = smid;
@@ -1834,10 +1795,12 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = type;
mpi_request->TaskMID = cpu_to_le16(smid_task);
+ mpi_request->VP_ID = 0; /* TODO */
+ mpi_request->VF_ID = 0;
int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
mpt2sas_scsih_set_tm_flag(ioc, handle);
init_completion(&ioc->tm_cmds.done);
- mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID);
+ mpt2sas_base_put_smid_hi_priority(ioc, smid);
timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
mpt2sas_scsih_clear_tm_flag(ioc, handle);
if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
@@ -2075,7 +2038,7 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
}
/**
- * _scsih_abort - eh threads main host reset routine
+ * _scsih_host_reset - eh threads main host reset routine
* @sdev: scsi device struct
*
* Returns SUCCESS if command aborted else FAILED
@@ -2354,6 +2317,231 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _scsih_tm_tr_send - send task management request
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt time.
+ *
+ * This code is to initiate the device removal handshake protocal
+ * with controller firmware. This function will issue target reset
+ * using high priority request queue. It will send a sas iounit
+ * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
+ *
+ * This is designed to send muliple task management request at the same
+ * time to the fifo. If the fifo is full, we will append the request,
+ * and process it in a future completion.
+ */
+static void
+_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ Mpi2SCSITaskManagementRequest_t *mpi_request;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
+ u16 smid;
+ struct _sas_device *sas_device;
+ unsigned long flags;
+ struct _tr_list *delayed_tr;
+
+ if (ioc->shost_recovery) {
+ printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+ __func__, ioc->name);
+ return;
+ }
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
+ ioc->name, __func__);
+ return;
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ /* skip is hidden raid component */
+ if (sas_device->hidden_raid_component)
+ return;
+
+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
+ if (!smid) {
+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
+ if (!delayed_tr)
+ return;
+ INIT_LIST_HEAD(&delayed_tr->list);
+ delayed_tr->handle = handle;
+ delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
+ list_add_tail(&delayed_tr->list,
+ &ioc->delayed_tr_list);
+ if (sas_device->starget)
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget, "DELAYED:tr:handle(0x%04x), "
+ "(open)\n", sas_device->handle));
+ return;
+ }
+
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
+ sas_target_priv_data->tm_busy = 1;
+ dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
+ "tr:handle(0x%04x), (open)\n", sas_device->handle));
+ }
+
+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ mpi_request->DevHandle = cpu_to_le16(handle);
+ mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+ sas_device->state |= MPTSAS_STATE_TR_SEND;
+ sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
+ mpt2sas_base_put_smid_hi_priority(ioc, smid);
+}
+
+
+
+/**
+ * _scsih_sas_control_complete - completion routine
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_index: MSIX table index supplied by the OS
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: interrupt time.
+ *
+ * This is the sas iounit controll completion routine.
+ * This code is part of the code to initiate the device removal
+ * handshake protocal with controller firmware.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+ u8 msix_index, u32 reply)
+{
+ unsigned long flags;
+ u16 handle;
+ struct _sas_device *sas_device;
+ Mpi2SasIoUnitControlReply_t *mpi_reply =
+ mpt2sas_base_get_reply_virt_addr(ioc, reply);
+
+ handle = le16_to_cpu(mpi_reply->DevHandle);
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
+ ioc->name, __func__);
+ return 1;
+ }
+ sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ if (sas_device->starget)
+ dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
+ "sc_complete:handle(0x%04x), "
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
+ handle, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo)));
+ return 1;
+}
+
+/**
+ * _scsih_tm_tr_complete -
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_index: MSIX table index supplied by the OS
+ * @reply: reply message frame(lower 32bit addr)
+ * Context: interrupt time.
+ *
+ * This is the target reset completion routine.
+ * This code is part of the code to initiate the device removal
+ * handshake protocal with controller firmware.
+ * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply)
+{
+ unsigned long flags;
+ u16 handle;
+ struct _sas_device *sas_device;
+ Mpi2SCSITaskManagementReply_t *mpi_reply =
+ mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ Mpi2SasIoUnitControlRequest_t *mpi_request;
+ u16 smid_sas_ctrl;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct _tr_list *delayed_tr;
+ u8 rc;
+
+ handle = le16_to_cpu(mpi_reply->DevHandle);
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
+ ioc->name, __func__);
+ return 1;
+ }
+ sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ if (sas_device->starget)
+ dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
+ "tr_complete:handle(0x%04x), (%s) ioc_status(0x%04x), "
+ "loginfo(0x%08x), completed(%d)\n",
+ sas_device->handle, (sas_device->state &
+ MPT2SAS_REQ_SAS_CNTRL) ? "open" : "active",
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo),
+ le32_to_cpu(mpi_reply->TerminationCount)));
+
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
+ sas_target_priv_data->tm_busy = 0;
+ }
+
+ if (!list_empty(&ioc->delayed_tr_list)) {
+ delayed_tr = list_entry(ioc->delayed_tr_list.next,
+ struct _tr_list, list);
+ mpt2sas_base_free_smid(ioc, smid);
+ if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
+ _scsih_tm_tr_send(ioc, delayed_tr->handle);
+ list_del(&delayed_tr->list);
+ kfree(delayed_tr);
+ rc = 0; /* tells base_interrupt not to free mf */
+ } else
+ rc = 1;
+
+
+ if (!(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
+ return rc;
+
+ if (ioc->shost_recovery) {
+ printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+ __func__, ioc->name);
+ return rc;
+ }
+
+ smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
+ if (!smid_sas_ctrl) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ return rc;
+ }
+
+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
+ memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
+ mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+ mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
+ mpi_request->DevHandle = mpi_reply->DevHandle;
+ sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
+ mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
+ return rc;
+}
+
+/**
* _scsih_check_topo_delete_events - sanity check on topo events
* @ioc: per adapter object
* @event_data: the event data payload
@@ -2375,6 +2563,21 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
u16 expander_handle;
struct _sas_node *sas_expander;
unsigned long flags;
+ int i, reason_code;
+ u16 handle;
+
+ for (i = 0 ; i < event_data->NumEntries; i++) {
+ if (event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
+ continue;
+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
+ if (!handle)
+ continue;
+ reason_code = event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_RC_MASK;
+ if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
+ _scsih_tm_tr_send(ioc, handle);
+ }
expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
if (expander_handle < ioc->sas_hba.num_phys) {
@@ -2433,8 +2636,8 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
u16 smid;
u16 count = 0;
- for (smid = 1; smid <= ioc->request_depth; smid++) {
- scmd = _scsih_scsi_lookup_getclear(ioc, smid);
+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
+ scmd = _scsih_scsi_lookup_get(ioc, smid);
if (!scmd)
continue;
count++;
@@ -2616,7 +2819,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
- smid = mpt2sas_base_get_smid(ioc, ioc->scsi_io_cb_idx);
+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
@@ -2643,7 +2846,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
-
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
mpi_request->LUN);
memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
@@ -2657,8 +2861,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
}
}
- _scsih_scsi_lookup_set(ioc, smid, scmd);
- mpt2sas_base_put_smid_scsi_io(ioc, smid, 0,
+ mpt2sas_base_put_smid_scsi_io(ioc, smid,
sas_device_priv_data->sas_target->handle);
return 0;
@@ -2954,15 +3157,16 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
* _scsih_io_done - scsi request callback
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
- * Callback handler when using scsih_qcmd.
+ * Callback handler when using _scsih_qcmd.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-static void
-_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+static u8
+_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
{
Mpi2SCSIIORequest_t *mpi_request;
Mpi2SCSIIOReply_t *mpi_reply;
@@ -2976,9 +3180,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
u32 response_code;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- scmd = _scsih_scsi_lookup_getclear(ioc, smid);
+ scmd = _scsih_scsi_lookup_get(ioc, smid);
if (scmd == NULL)
- return;
+ return 1;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
@@ -3134,6 +3338,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
out:
scsi_dma_unmap(scmd);
scmd->scsi_done(scmd);
+ return 1;
}
/**
@@ -3398,9 +3603,8 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
}
}
- sas_address = le64_to_cpu(expander_pg0.SASAddress);
-
spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ sas_address = le64_to_cpu(expander_pg0.SASAddress);
sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@@ -3666,6 +3870,12 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
if (ioc->remove_host)
goto out;
+ if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
+ "target_reset handle(0x%04x)\n", ioc->name, handle));
+ goto skip_tr;
+ }
+
/* Target Reset to flush out all the outstanding IO */
device_handle = (sas_device->hidden_raid_component) ?
sas_device->volume_handle : handle;
@@ -3682,6 +3892,13 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
if (ioc->shost_recovery)
goto out;
}
+ skip_tr:
+
+ if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
+ "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
+ goto out;
+ }
/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
@@ -3690,7 +3907,8 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request.DevHandle = handle;
- mpi_request.VF_ID = 0;
+ mpi_request.VF_ID = 0; /* TODO */
+ mpi_request.VP_ID = 0;
if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
&mpi_request)) != 0) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -3800,15 +4018,12 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_topology_change_event - handle topology changes
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
- * fw_event:
+ * @fw_event: The fw_event_work object
* Context: user.
*
*/
static void
-_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasTopologyChangeList_t *event_data,
+_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
int i;
@@ -3818,6 +4033,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
struct _sas_node *sas_expander;
unsigned long flags;
u8 link_rate_;
+ Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
@@ -3851,15 +4067,16 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
}
if (ioc->shost_recovery)
return;
- if (event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
+ phy_number = event_data->StartPhyNum + i;
+ reason_code = event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_RC_MASK;
+ if ((event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
+ MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
continue;
handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
if (!handle)
continue;
- phy_number = event_data->StartPhyNum + i;
- reason_code = event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_RC_MASK;
link_rate_ = event_data->PHY[i].LinkRate >> 4;
switch (reason_code) {
case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
@@ -3971,19 +4188,19 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_device_status_change_event - handle device status change
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasDeviceStatusChange_t *event_data)
+_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_device_status_change_event_debug(ioc, event_data);
+ _scsih_sas_device_status_change_event_debug(ioc,
+ fw_event->event_data);
#endif
}
@@ -4026,34 +4243,33 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
- u8 VF_ID, Mpi2EventDataSasEnclDevStatusChange_t *event_data)
+ struct fw_event_work *fw_event)
{
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_enclosure_dev_status_change_event_debug(ioc,
- event_data);
+ fw_event->event_data);
#endif
}
/**
* _scsih_sas_broadcast_primative_event - handle broadcast events
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasBroadcastPrimitive_t *event_data)
+_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
struct scsi_cmnd *scmd;
u16 smid, handle;
@@ -4062,11 +4278,12 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
u32 termination_count;
u32 query_count;
Mpi2SCSITaskManagementReply_t *mpi_reply;
-
+#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
+ Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
+#endif
dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
"phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
event_data->PortWidth));
-
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
@@ -4074,7 +4291,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
termination_count = 0;
query_count = 0;
mpi_reply = ioc->tm_cmds.reply;
- for (smid = 1; smid <= ioc->request_depth; smid++) {
+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
scmd = _scsih_scsi_lookup_get(ioc, smid);
if (!scmd)
continue;
@@ -4121,23 +4338,25 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
/**
* _scsih_sas_discovery_event - handle discovery events
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasDiscovery_t *event_data)
+_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
+ Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
(event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
"start" : "stop");
if (event_data->DiscoveryStatus)
- printk(MPT2SAS_DEBUG_FMT ", discovery_status(0x%08x)",
- ioc->name, le32_to_cpu(event_data->DiscoveryStatus));
+ printk("discovery_status(0x%08x)",
+ le32_to_cpu(event_data->DiscoveryStatus));
printk("\n");
}
#endif
@@ -4488,19 +4707,19 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_ir_config_change_event - handle ir configuration change events
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrConfigChangeList_t *event_data)
+_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
Mpi2EventIrConfigElement_t *element;
int i;
u8 foreign_config;
+ Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
@@ -4543,14 +4762,14 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
/**
* _scsih_sas_ir_volume_event - IR volume event
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrVolume_t *event_data)
+_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
u64 wwid;
unsigned long flags;
@@ -4559,6 +4778,7 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
u32 state;
int rc;
struct MPT2SAS_TARGET *sas_target_priv_data;
+ Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
return;
@@ -4628,14 +4848,14 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
/**
* _scsih_sas_ir_physical_disk_event - PD event
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrPhysicalDisk_t *event_data)
+_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
u16 handle;
u32 state;
@@ -4644,6 +4864,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status;
+ Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
return;
@@ -4743,33 +4964,33 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_ir_operation_status_event - handle RAID operation events
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrOperationStatus_t *event_data)
+_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_ir_operation_status_event_debug(ioc, event_data);
+ _scsih_sas_ir_operation_status_event_debug(ioc,
+ fw_event->event_data);
#endif
}
/**
* _scsih_task_set_full - handle task set full
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Throttle back qdepth.
*/
static void
-_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataTaskSetFull_t *event_data)
+_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
+ *fw_event)
{
unsigned long flags;
struct _sas_device *sas_device;
@@ -4780,6 +5001,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
u16 handle;
int id, channel;
u64 sas_address;
+ Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
current_depth = le16_to_cpu(event_data->CurrentDepth);
handle = le16_to_cpu(event_data->DevHandle);
@@ -4868,6 +5090,10 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
if (sas_device->sas_address == sas_address &&
sas_device->slot == slot && sas_device->starget) {
sas_device->responding = 1;
+ sas_device->state = 0;
+ starget = sas_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->tm_busy = 0;
starget_printk(KERN_INFO, sas_device->starget,
"handle(0x%04x), sas_addr(0x%016llx), enclosure "
"logical id(0x%016llx), slot(%d)\n", handle,
@@ -4880,8 +5106,6 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
sas_device->handle);
sas_device->handle = handle;
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
sas_target_priv_data->handle = handle;
goto out;
}
@@ -5227,44 +5451,38 @@ _firmware_event_work(struct work_struct *work)
switch (fw_event->event) {
case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- _scsih_sas_topology_change_event(ioc, fw_event->VF_ID,
- fw_event->event_data, fw_event);
+ _scsih_sas_topology_change_event(ioc, fw_event);
break;
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
- _scsih_sas_device_status_change_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_device_status_change_event(ioc,
+ fw_event);
break;
case MPI2_EVENT_SAS_DISCOVERY:
- _scsih_sas_discovery_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_discovery_event(ioc,
+ fw_event);
break;
case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- _scsih_sas_broadcast_primative_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_broadcast_primative_event(ioc,
+ fw_event);
break;
case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
_scsih_sas_enclosure_dev_status_change_event(ioc,
- fw_event->VF_ID, fw_event->event_data);
+ fw_event);
break;
case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- _scsih_sas_ir_config_change_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_config_change_event(ioc, fw_event);
break;
case MPI2_EVENT_IR_VOLUME:
- _scsih_sas_ir_volume_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_volume_event(ioc, fw_event);
break;
case MPI2_EVENT_IR_PHYSICAL_DISK:
- _scsih_sas_ir_physical_disk_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_physical_disk_event(ioc, fw_event);
break;
case MPI2_EVENT_IR_OPERATION_STATUS:
- _scsih_sas_ir_operation_status_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_operation_status_event(ioc, fw_event);
break;
case MPI2_EVENT_TASK_SET_FULL:
- _scsih_task_set_full(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_task_set_full(ioc, fw_event);
break;
}
_scsih_fw_event_free(ioc, fw_event);
@@ -5273,17 +5491,19 @@ _firmware_event_work(struct work_struct *work)
/**
* mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
* @ioc: per adapter object
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: interrupt.
*
* This function merely adds a new work task into ioc->firmware_event_thread.
* The tasks are worked from _firmware_event_work in user context.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+u8
+mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+ u32 reply)
{
struct fw_event_work *fw_event;
Mpi2EventNotificationReply_t *mpi_reply;
@@ -5294,11 +5514,11 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
spin_lock_irqsave(&ioc->fw_event_lock, flags);
if (ioc->fw_events_off || ioc->remove_host) {
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- return;
+ return 1;
}
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
event = le16_to_cpu(mpi_reply->Event);
switch (event) {
@@ -5312,7 +5532,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
if (baen_data->Primitive !=
MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
ioc->broadcast_aen_busy)
- return;
+ return 1;
ioc->broadcast_aen_busy = 1;
break;
}
@@ -5334,14 +5554,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
break;
default: /* ignore the rest */
- return;
+ return 1;
}
fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
if (!fw_event) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
- return;
+ return 1;
}
fw_event->event_data =
kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
@@ -5349,15 +5569,17 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
kfree(fw_event);
- return;
+ return 1;
}
memcpy(fw_event->event_data, mpi_reply->EventData,
mpi_reply->EventDataLength*4);
fw_event->ioc = ioc;
- fw_event->VF_ID = VF_ID;
+ fw_event->VF_ID = mpi_reply->VF_ID;
+ fw_event->VP_ID = mpi_reply->VP_ID;
fw_event->event = event;
_scsih_fw_event_add(ioc, fw_event);
+ return 1;
}
/* shost template */
@@ -5617,7 +5839,7 @@ _scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
}
/**
- * _scsih_probe_sas - reporting raid volumes to sas transport
+ * _scsih_probe_sas - reporting sas devices to sas transport
* @ioc: per adapter object
*
* Called during initial loading of the driver.
@@ -5714,6 +5936,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->base_cb_idx = base_cb_idx;
ioc->transport_cb_idx = transport_cb_idx;
ioc->config_cb_idx = config_cb_idx;
+ ioc->tm_tr_cb_idx = tm_tr_cb_idx;
+ ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
ioc->logging_level = logging_level;
/* misc semaphores and spin locks */
spin_lock_init(&ioc->ioc_reset_in_progress_lock);
@@ -5729,6 +5953,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->fw_event_list);
INIT_LIST_HEAD(&ioc->raid_device_list);
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
+ INIT_LIST_HEAD(&ioc->delayed_tr_list);
/* init shost parameters */
shost->max_cmd_len = 16;
@@ -5745,6 +5970,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION);
+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
/* event thread */
snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
@@ -5894,6 +6120,11 @@ _scsih_init(void)
/* ctl module callback handler */
ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
+ tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
+ _scsih_tm_tr_complete);
+ tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
+ _scsih_sas_control_complete);
+
mpt2sas_ctl_init();
error = pci_register_driver(&scsih_driver);
@@ -5924,6 +6155,9 @@ _scsih_exit(void)
mpt2sas_base_release_callback_handler(config_cb_idx);
mpt2sas_base_release_callback_handler(ctl_cb_idx);
+ mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
+ mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
+
mpt2sas_ctl_exit();
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 742324a0a11e..eb98188c7f3f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -2,7 +2,7 @@
* SAS Transport Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -212,25 +212,26 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
* mpt2sas_transport_done - internal transport layer callback handler.
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
* Callback handler when sending internal generated transport cmds.
* The callback index passed is `ioc->transport_cb_idx`
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+u8
+mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->transport_cmds.smid != smid)
- return;
+ return 1;
ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
if (mpi_reply) {
memcpy(ioc->transport_cmds.reply, mpi_reply,
@@ -239,6 +240,7 @@ mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
}
ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->transport_cmds.done);
+ return 1;
}
/* report manufacture request structure */
@@ -369,6 +371,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
mpi_request->PhysicalPort = 0xFF;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
sas_address_le = (u64 *)&mpi_request->SASAddress;
*sas_address_le = cpu_to_le64(sas_address);
mpi_request->RequestDataLength = sizeof(struct rep_manu_request);
@@ -396,7 +400,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
"send to sas_addr(0x%016llx)\n", ioc->name,
(unsigned long long)sas_address));
- mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
10*HZ);
@@ -1106,6 +1111,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
mpi_request->PhysicalPort = 0xFF;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
*((u64 *)&mpi_request->SASAddress) = (rphy) ?
cpu_to_le64(rphy->identify.sas_address) :
cpu_to_le64(ioc->sas_hba.sas_address);
@@ -1147,7 +1154,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
- mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
10*HZ);
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h
index f8cb9defb961..1849da1f030d 100644
--- a/drivers/scsi/mvsas/mv_defs.h
+++ b/drivers/scsi/mvsas/mv_defs.h
@@ -25,6 +25,8 @@
#ifndef _MV_DEFS_H_
#define _MV_DEFS_H_
+#define PCI_DEVICE_ID_ARECA_1300 0x1300
+#define PCI_DEVICE_ID_ARECA_1320 0x1320
enum chip_flavors {
chip_6320,
@@ -32,6 +34,8 @@ enum chip_flavors {
chip_6485,
chip_9480,
chip_9180,
+ chip_1300,
+ chip_1320
};
/* driver compile-time configuration */
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 8646a19f999d..c790d45876c4 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -32,6 +32,8 @@ static const struct mvs_chip_info mvs_chips[] = {
[chip_6485] = { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
[chip_9180] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
[chip_9480] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
+ [chip_1300] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
+ [chip_1320] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
};
#define SOC_SAS_NUM 2
@@ -653,6 +655,8 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = {
{ PCI_VDEVICE(MARVELL, 0x6485), chip_6485 },
{ PCI_VDEVICE(MARVELL, 0x9480), chip_9480 },
{ PCI_VDEVICE(MARVELL, 0x9180), chip_9180 },
+ { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 },
+ { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 },
{ } /* terminate list */
};
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 4302f06e4ec9..0a97bc9074bb 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -46,6 +46,7 @@
#include <linux/mutex.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_cmnd.h>
@@ -684,7 +685,7 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)
struct pmcraid_instance *pinstance = cmd->drv_inst;
unsigned long lock_flags;
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"Adapter being reset due to command timeout.\n");
/* Command timeouts result in hard reset sequence. The command that got
@@ -815,8 +816,9 @@ static void pmcraid_erp_done(struct pmcraid_cmd *cmd)
if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) {
scsi_cmd->result |= (DID_ERROR << 16);
- pmcraid_err("command CDB[0] = %x failed with IOASC: 0x%08X\n",
- cmd->ioa_cb->ioarcb.cdb[0], ioasc);
+ scmd_printk(KERN_INFO, scsi_cmd,
+ "command CDB[0] = %x failed with IOASC: 0x%08X\n",
+ cmd->ioa_cb->ioarcb.cdb[0], ioasc);
}
/* if we had allocated sense buffers for request sense, copy the sense
@@ -1069,7 +1071,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam
ioarcb->data_transfer_length = cpu_to_le32(rcb_size);
- ioadl[0].flags |= cpu_to_le32(IOADL_FLAGS_READ_LAST);
+ ioadl[0].flags |= IOADL_FLAGS_READ_LAST;
ioadl[0].data_len = cpu_to_le32(rcb_size);
ioadl[0].address = cpu_to_le32(dma);
@@ -1541,13 +1543,13 @@ static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance)
if (pinstance->ldn.hcam->notification_lost ==
HOSTRCB_NOTIFICATIONS_LOST)
- dev_err(&pinstance->pdev->dev, "Error notifications lost\n");
+ dev_info(&pinstance->pdev->dev, "Error notifications lost\n");
ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc);
if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET ||
ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) {
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"UnitAttention due to IOA Bus Reset\n");
scsi_report_bus_reset(
pinstance->host,
@@ -1584,7 +1586,7 @@ static void pmcraid_process_ccn(struct pmcraid_cmd *cmd)
atomic_read(&pinstance->ccn.ignore) == 1) {
return;
} else if (ioasc) {
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc);
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
@@ -1634,7 +1636,7 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
return;
}
} else {
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc);
}
/* send netlink message for HCAM notification if enabled */
@@ -1822,7 +1824,6 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance)
scsi_dma_unmap(scsi_cmd);
pmcraid_return_cmd(cmd);
-
pmcraid_info("failing(%d) CDB[0] = %x result: %x\n",
le32_to_cpu(resp) >> 2,
cmd->ioa_cb->ioarcb.cdb[0],
@@ -2250,7 +2251,7 @@ static void pmcraid_request_sense(struct pmcraid_cmd *cmd)
ioadl->address = cpu_to_le64(cmd->sense_buffer_dma);
ioadl->data_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
- ioadl->flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC);
+ ioadl->flags = IOADL_FLAGS_LAST_DESC;
/* request sense might be called as part of error response processing
* which runs in tasklets context. It is possible that mid-layer might
@@ -2514,7 +2515,8 @@ static int pmcraid_reset_device(
res = scsi_cmd->device->hostdata;
if (!res) {
- pmcraid_err("reset_device: NULL resource pointer\n");
+ sdev_printk(KERN_ERR, scsi_cmd->device,
+ "reset_device: NULL resource pointer\n");
return FAILED;
}
@@ -2752,8 +2754,8 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
pinstance =
(struct pmcraid_instance *)scsi_cmd->device->host->hostdata;
- dev_err(&pinstance->pdev->dev,
- "I/O command timed out, aborting it.\n");
+ scmd_printk(KERN_INFO, scsi_cmd,
+ "I/O command timed out, aborting it.\n");
res = scsi_cmd->device->hostdata;
@@ -2824,7 +2826,8 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
*/
static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
{
- pmcraid_err("Doing device reset due to an I/O command timeout.\n");
+ scmd_printk(KERN_INFO, scmd,
+ "resetting device due to an I/O command timeout.\n");
return pmcraid_reset_device(scmd,
PMCRAID_INTERNAL_TIMEOUT,
RESET_DEVICE_LUN);
@@ -2832,7 +2835,8 @@ static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd)
{
- pmcraid_err("Doing bus reset due to an I/O command timeout.\n");
+ scmd_printk(KERN_INFO, scmd,
+ "Doing bus reset due to an I/O command timeout.\n");
return pmcraid_reset_device(scmd,
PMCRAID_RESET_BUS_TIMEOUT,
RESET_DEVICE_BUS);
@@ -2840,7 +2844,8 @@ static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd)
static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd)
{
- pmcraid_err("Doing target reset due to an I/O command timeout.\n");
+ scmd_printk(KERN_INFO, scmd,
+ "Doing target reset due to an I/O command timeout.\n");
return pmcraid_reset_device(scmd,
PMCRAID_INTERNAL_TIMEOUT,
RESET_DEVICE_TARGET);
@@ -2988,11 +2993,11 @@ static int pmcraid_build_ioadl(
nseg = scsi_dma_map(scsi_cmd);
if (nseg < 0) {
- dev_err(&pinstance->pdev->dev, "scsi_map_dma failed!\n");
+ scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n");
return -1;
} else if (nseg > PMCRAID_MAX_IOADLS) {
scsi_dma_unmap(scsi_cmd);
- dev_err(&pinstance->pdev->dev,
+ scmd_printk(KERN_ERR, scsi_cmd,
"sg count is (%d) more than allowed!\n", nseg);
return -1;
}
@@ -3012,7 +3017,7 @@ static int pmcraid_build_ioadl(
ioadl[i].flags = 0;
}
/* setup last descriptor */
- ioadl[i - 1].flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC);
+ ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC;
return 0;
}
@@ -3382,7 +3387,7 @@ static int pmcraid_build_passthrough_ioadls(
}
/* setup the last descriptor */
- ioadl[i - 1].flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC);
+ ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC;
return 0;
}
@@ -5040,7 +5045,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
rc = pci_enable_device(pdev);
if (rc) {
- pmcraid_err("pmcraid: Enable device failed\n");
+ dev_err(&pdev->dev, "resume: Enable device failed\n");
return rc;
}
@@ -5054,7 +5059,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc != 0) {
- dev_err(&pdev->dev, "Failed to set PCI DMA mask\n");
+ dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n");
goto disable_device;
}
@@ -5063,7 +5068,8 @@ static int pmcraid_resume(struct pci_dev *pdev)
rc = pmcraid_register_interrupt_handler(pinstance);
if (rc) {
- pmcraid_err("resume: couldn't register interrupt handlers\n");
+ dev_err(&pdev->dev,
+ "resume: couldn't register interrupt handlers\n");
rc = -ENODEV;
goto release_host;
}
@@ -5080,7 +5086,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
* state.
*/
if (pmcraid_reset_bringup(pinstance)) {
- pmcraid_err("couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA \n");
rc = -ENODEV;
goto release_tasklets;
}
@@ -5187,7 +5193,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
LIST_HEAD(old_res);
if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED)
- dev_err(&pinstance->pdev->dev, "Require microcode download\n");
+ pmcraid_err("IOA requires microcode download\n");
/* resource list is protected by pinstance->resource_lock.
* init_res_table can be called from probe (user-thread) or runtime
@@ -5224,8 +5230,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
if (!found) {
if (list_empty(&pinstance->free_res_q)) {
- dev_err(&pinstance->pdev->dev,
- "Too many devices attached\n");
+ pmcraid_err("Too many devices attached\n");
break;
}
@@ -5309,7 +5314,7 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd)
cpu_to_le32(sizeof(struct pmcraid_config_table));
ioadl = &(ioarcb->add_data.u.ioadl[0]);
- ioadl->flags = cpu_to_le32(IOADL_FLAGS_LAST_DESC);
+ ioadl->flags = IOADL_FLAGS_LAST_DESC;
ioadl->address = cpu_to_le64(pinstance->cfg_table_bus_addr);
ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_config_table));
@@ -5442,7 +5447,7 @@ static int __devinit pmcraid_probe(
rc = pmcraid_register_interrupt_handler(pinstance);
if (rc) {
- pmcraid_err("couldn't register interrupt handler\n");
+ dev_err(&pdev->dev, "couldn't register interrupt handler\n");
goto out_scsi_host_put;
}
@@ -5466,7 +5471,7 @@ static int __devinit pmcraid_probe(
*/
pmcraid_info("starting IOA initialization sequence\n");
if (pmcraid_reset_bringup(pinstance)) {
- pmcraid_err("couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA \n");
rc = 1;
goto out_release_bufs;
}
@@ -5534,7 +5539,6 @@ static struct pci_driver pmcraid_driver = {
.shutdown = pmcraid_shutdown
};
-
/**
* pmcraid_init - module load entry point
*/
@@ -5566,7 +5570,6 @@ static int __init pmcraid_init(void)
goto out_unreg_chrdev;
}
-
error = pmcraid_netlink_init();
if (error)
@@ -5584,6 +5587,7 @@ static int __init pmcraid_init(void)
out_unreg_chrdev:
unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS);
+
out_init:
return error;
}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 42b799abba57..e07b3617f019 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -568,7 +568,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
if (req == NULL) {
qla_printk(KERN_WARNING, ha, "could not allocate memory"
"for request que\n");
- goto que_failed;
+ goto failed;
}
req->length = REQUEST_ENTRY_CNT_24XX;
@@ -632,6 +632,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
que_failed:
qla25xx_free_req_que(base_vha, req);
+failed:
return 0;
}
@@ -659,7 +660,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
if (rsp == NULL) {
qla_printk(KERN_WARNING, ha, "could not allocate memory for"
" response que\n");
- goto que_failed;
+ goto failed;
}
rsp->length = RESPONSE_ENTRY_CNT_MQ;
@@ -728,6 +729,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
que_failed:
qla25xx_free_rsp_que(base_vha, rsp);
+failed:
return 0;
}
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index b6e03074cb8f..dd098cad337b 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -241,10 +241,7 @@ scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
*/
struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
{
- struct scsi_cmnd *cmd;
- unsigned char *buf;
-
- cmd = scsi_host_alloc_command(shost, gfp_mask);
+ struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask);
if (unlikely(!cmd)) {
unsigned long flags;
@@ -258,9 +255,15 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
spin_unlock_irqrestore(&shost->free_list_lock, flags);
if (cmd) {
+ void *buf, *prot;
+
buf = cmd->sense_buffer;
+ prot = cmd->prot_sdb;
+
memset(cmd, 0, sizeof(*cmd));
+
cmd->sense_buffer = buf;
+ cmd->prot_sdb = prot;
}
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index fb9af207d61d..c4103bef41b5 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -50,6 +50,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsicam.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_dbg.h>
#include "sd.h"
#include "scsi_logging.h"
@@ -64,6 +65,7 @@ static const char * scsi_debug_version_date = "20070104";
#define PARAMETER_LIST_LENGTH_ERR 0x1a
#define INVALID_OPCODE 0x20
#define ADDR_OUT_OF_RANGE 0x21
+#define INVALID_COMMAND_OPCODE 0x20
#define INVALID_FIELD_IN_CDB 0x24
#define INVALID_FIELD_IN_PARAM_LIST 0x26
#define POWERON_RESET 0x29
@@ -180,7 +182,7 @@ static int sdebug_sectors_per; /* sectors per cylinder */
#define SDEBUG_SENSE_LEN 32
#define SCSI_DEBUG_CANQUEUE 255
-#define SCSI_DEBUG_MAX_CMD_LEN 16
+#define SCSI_DEBUG_MAX_CMD_LEN 32
struct sdebug_dev_info {
struct list_head dev_list;
@@ -296,9 +298,25 @@ static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
}
static void get_data_transfer_info(unsigned char *cmd,
- unsigned long long *lba, unsigned int *num)
+ unsigned long long *lba, unsigned int *num,
+ u32 *ei_lba)
{
+ *ei_lba = 0;
+
switch (*cmd) {
+ case VARIABLE_LENGTH_CMD:
+ *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
+ (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
+ (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
+ (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
+
+ *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
+ (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
+
+ *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
+ (u32)cmd[28] << 24;
+ break;
+
case WRITE_16:
case READ_16:
*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
@@ -1589,7 +1607,7 @@ static int do_device_access(struct scsi_cmnd *scmd,
}
static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
- unsigned int sectors)
+ unsigned int sectors, u32 ei_lba)
{
unsigned int i, resid;
struct scatterlist *psgl;
@@ -1636,13 +1654,23 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
return 0x01;
}
- if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
+ if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
printk(KERN_ERR "%s: REF check failed on sector %lu\n",
__func__, (unsigned long)sector);
dif_errors++;
return 0x03;
}
+
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
+ printk(KERN_ERR "%s: REF check failed on sector %lu\n",
+ __func__, (unsigned long)sector);
+ dif_errors++;
+ return 0x03;
+ }
+
+ ei_lba++;
}
resid = sectors * 8; /* Bytes of protection data to copy into sgl */
@@ -1670,7 +1698,8 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
}
static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
- unsigned int num, struct sdebug_dev_info *devip)
+ unsigned int num, struct sdebug_dev_info *devip,
+ u32 ei_lba)
{
unsigned long iflags;
int ret;
@@ -1699,7 +1728,7 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
- int prot_ret = prot_verify_read(SCpnt, lba, num);
+ int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
if (prot_ret) {
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
@@ -1735,7 +1764,7 @@ void dump_sector(unsigned char *buf, int len)
}
static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
- unsigned int sectors)
+ unsigned int sectors, u32 ei_lba)
{
int i, j, ret;
struct sd_dif_tuple *sdt;
@@ -1749,11 +1778,6 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
sector = do_div(tmp_sec, sdebug_store_sectors);
- if (((SCpnt->cmnd[1] >> 5) & 7) != 1) {
- printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n");
- return 0;
- }
-
BUG_ON(scsi_sg_count(SCpnt) == 0);
BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
@@ -1808,7 +1832,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
goto out;
}
- if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
+ if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
be32_to_cpu(sdt->ref_tag)
!= (start_sec & 0xffffffff)) {
printk(KERN_ERR
@@ -1819,6 +1843,16 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
goto out;
}
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ be32_to_cpu(sdt->ref_tag) != ei_lba) {
+ printk(KERN_ERR
+ "%s: REF check failed on sector %lu\n",
+ __func__, (unsigned long)sector);
+ ret = 0x03;
+ dump_sector(daddr, scsi_debug_sector_size);
+ goto out;
+ }
+
/* Would be great to copy this in bigger
* chunks. However, for the sake of
* correctness we need to verify each sector
@@ -1832,6 +1866,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
sector = 0; /* Force wrap */
start_sec++;
+ ei_lba++;
daddr += scsi_debug_sector_size;
ppage_offset += sizeof(struct sd_dif_tuple);
}
@@ -1853,7 +1888,8 @@ out:
}
static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
- unsigned int num, struct sdebug_dev_info *devip)
+ unsigned int num, struct sdebug_dev_info *devip,
+ u32 ei_lba)
{
unsigned long iflags;
int ret;
@@ -1864,7 +1900,7 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
- int prot_ret = prot_verify_write(SCpnt, lba, num);
+ int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
if (prot_ret) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
@@ -2872,11 +2908,12 @@ static int __init scsi_debug_init(void)
case SD_DIF_TYPE0_PROTECTION:
case SD_DIF_TYPE1_PROTECTION:
+ case SD_DIF_TYPE2_PROTECTION:
case SD_DIF_TYPE3_PROTECTION:
break;
default:
- printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n");
+ printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
return -EINVAL;
}
@@ -3121,6 +3158,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
int len, k;
unsigned int num;
unsigned long long lba;
+ u32 ei_lba;
int errsts = 0;
int target = SCpnt->device->id;
struct sdebug_dev_info *devip = NULL;
@@ -3254,14 +3292,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
case READ_16:
case READ_12:
case READ_10:
+ /* READ{10,12,16} and DIF Type 2 are natural enemies */
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ cmd[1] & 0xe0) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_COMMAND_OPCODE, 0);
+ errsts = check_condition_result;
+ break;
+ }
+
+ if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
+ scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ (cmd[1] & 0xe0) == 0)
+ printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
+
+ /* fall through */
case READ_6:
+read:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_fake_rw)
break;
- get_data_transfer_info(cmd, &lba, &num);
- errsts = resp_read(SCpnt, lba, num, devip);
+ get_data_transfer_info(cmd, &lba, &num, &ei_lba);
+ errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
THRESHOLD_EXCEEDED, 0);
@@ -3288,14 +3342,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
case WRITE_16:
case WRITE_12:
case WRITE_10:
+ /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ cmd[1] & 0xe0) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_COMMAND_OPCODE, 0);
+ errsts = check_condition_result;
+ break;
+ }
+
+ if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
+ scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ (cmd[1] & 0xe0) == 0)
+ printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
+
+ /* fall through */
case WRITE_6:
+write:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_fake_rw)
break;
- get_data_transfer_info(cmd, &lba, &num);
- errsts = resp_write(SCpnt, lba, num, devip);
+ get_data_transfer_info(cmd, &lba, &num, &ei_lba);
+ errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
THRESHOLD_EXCEEDED, 0);
@@ -3341,15 +3411,38 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
break;
if (scsi_debug_fake_rw)
break;
- get_data_transfer_info(cmd, &lba, &num);
- errsts = resp_read(SCpnt, lba, num, devip);
+ get_data_transfer_info(cmd, &lba, &num, &ei_lba);
+ errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
if (errsts)
break;
- errsts = resp_write(SCpnt, lba, num, devip);
+ errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
if (errsts)
break;
errsts = resp_xdwriteread(SCpnt, lba, num, devip);
break;
+ case VARIABLE_LENGTH_CMD:
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
+
+ if ((cmd[10] & 0xe0) == 0)
+ printk(KERN_ERR
+ "Unprotected RD/WR to DIF device\n");
+
+ if (cmd[9] == READ_32) {
+ BUG_ON(SCpnt->cmd_len < 32);
+ goto read;
+ }
+
+ if (cmd[9] == WRITE_32) {
+ BUG_ON(SCpnt->cmd_len < 32);
+ goto write;
+ }
+ }
+
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ errsts = check_condition_result;
+ break;
+
default:
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 877204daf549..1b0060b791e8 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -725,6 +725,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
case NEEDS_RETRY:
case FAILED:
break;
+ case ADD_TO_MLQUEUE:
+ rtn = NEEDS_RETRY;
+ break;
default:
rtn = FAILED;
break;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index c44783801402..0547a7f44d42 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -317,6 +317,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
out_device_destroy:
scsi_device_set_state(sdev, SDEV_DEL);
transport_destroy_device(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
out:
if (display_failure_msg)
@@ -957,6 +958,7 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev)
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
}
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index fde54537d715..5c7eb63a19d1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -864,10 +864,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
goto clean_device;
}
- /* take a reference for the sdev_dev; this is
- * released by the sdev_class .release */
- get_device(&sdev->sdev_gendev);
-
/* create queue files, which may be writable, depending on the host */
if (sdev->host->hostt->change_queue_depth)
error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);
@@ -917,6 +913,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
device_del(&sdev->sdev_gendev);
transport_destroy_device(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
return error;
@@ -1065,7 +1062,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
device_initialize(&sdev->sdev_dev);
- sdev->sdev_dev.parent = &sdev->sdev_gendev;
+ sdev->sdev_dev.parent = get_device(&sdev->sdev_gendev);
sdev->sdev_dev.class = &sdev_class;
dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index b98885de6876..c6f70dae9b2e 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -3586,6 +3586,7 @@ enum fc_dispatch_result {
/**
* fc_bsg_host_dispatch - process fc host bsg requests and dispatch to LLDD
+ * @q: fc host request queue
* @shost: scsi host rport attached to
* @job: bsg job to be processed
*/
@@ -3655,6 +3656,7 @@ fc_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost,
fail_host_msg:
/* return the errno failure code as the only status */
BUG_ON(job->reply_len < sizeof(uint32_t));
+ job->reply->reply_payload_rcv_len = 0;
job->reply->result = ret;
job->reply_len = sizeof(uint32_t);
fc_bsg_jobdone(job);
@@ -3693,6 +3695,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)
/**
* fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD
+ * @q: rport request queue
* @shost: scsi host rport attached to
* @rport: rport request destined to
* @job: bsg job to be processed
@@ -3739,6 +3742,7 @@ check_bidi:
fail_rport_msg:
/* return the errno failure code as the only status */
BUG_ON(job->reply_len < sizeof(uint32_t));
+ job->reply->reply_payload_rcv_len = 0;
job->reply->result = ret;
job->reply_len = sizeof(uint32_t);
fc_bsg_jobdone(job);
@@ -3795,6 +3799,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost,
/* check if we have the msgcode value at least */
if (job->request_len < sizeof(uint32_t)) {
BUG_ON(job->reply_len < sizeof(uint32_t));
+ job->reply->reply_payload_rcv_len = 0;
job->reply->result = -ENOMSG;
job->reply_len = sizeof(uint32_t);
fc_bsg_jobdone(job);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 8dd96dcd716c..9093c7261f33 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -116,6 +116,9 @@ static DEFINE_IDA(sd_index_ida);
* object after last put) */
static DEFINE_MUTEX(sd_ref_mutex);
+struct kmem_cache *sd_cdb_cache;
+mempool_t *sd_cdb_pool;
+
static const char *sd_cache_types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
@@ -370,6 +373,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
mutex_unlock(&sd_ref_mutex);
}
+static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif)
+{
+ unsigned int prot_op = SCSI_PROT_NORMAL;
+ unsigned int dix = scsi_prot_sg_count(scmd);
+
+ if (scmd->sc_data_direction == DMA_FROM_DEVICE) {
+ if (dif && dix)
+ prot_op = SCSI_PROT_READ_PASS;
+ else if (dif && !dix)
+ prot_op = SCSI_PROT_READ_STRIP;
+ else if (!dif && dix)
+ prot_op = SCSI_PROT_READ_INSERT;
+ } else {
+ if (dif && dix)
+ prot_op = SCSI_PROT_WRITE_PASS;
+ else if (dif && !dix)
+ prot_op = SCSI_PROT_WRITE_INSERT;
+ else if (!dif && dix)
+ prot_op = SCSI_PROT_WRITE_STRIP;
+ }
+
+ scsi_set_prot_op(scmd, prot_op);
+ scsi_set_prot_type(scmd, dif);
+}
+
/**
* sd_init_command - build a scsi (read or write) command from
* information in the request structure.
@@ -388,6 +416,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
sector_t threshold;
unsigned int this_count = blk_rq_sectors(rq);
int ret, host_dif;
+ unsigned char protect;
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
ret = scsi_setup_blk_pc_cmnd(sdp, rq);
@@ -520,13 +549,49 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
/* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
if (host_dif)
- SCpnt->cmnd[1] = 1 << 5;
+ protect = 1 << 5;
else
- SCpnt->cmnd[1] = 0;
+ protect = 0;
- if (block > 0xffffffff) {
+ if (host_dif == SD_DIF_TYPE2_PROTECTION) {
+ SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC);
+
+ if (unlikely(SCpnt->cmnd == NULL)) {
+ ret = BLKPREP_DEFER;
+ goto out;
+ }
+
+ SCpnt->cmd_len = SD_EXT_CDB_SIZE;
+ memset(SCpnt->cmnd, 0, SCpnt->cmd_len);
+ SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD;
+ SCpnt->cmnd[7] = 0x18;
+ SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32;
+ SCpnt->cmnd[10] = protect | (blk_fua_rq(rq) ? 0x8 : 0);
+
+ /* LBA */
+ SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
+ SCpnt->cmnd[13] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
+ SCpnt->cmnd[14] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
+ SCpnt->cmnd[15] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0;
+ SCpnt->cmnd[16] = (unsigned char) (block >> 24) & 0xff;
+ SCpnt->cmnd[17] = (unsigned char) (block >> 16) & 0xff;
+ SCpnt->cmnd[18] = (unsigned char) (block >> 8) & 0xff;
+ SCpnt->cmnd[19] = (unsigned char) block & 0xff;
+
+ /* Expected Indirect LBA */
+ SCpnt->cmnd[20] = (unsigned char) (block >> 24) & 0xff;
+ SCpnt->cmnd[21] = (unsigned char) (block >> 16) & 0xff;
+ SCpnt->cmnd[22] = (unsigned char) (block >> 8) & 0xff;
+ SCpnt->cmnd[23] = (unsigned char) block & 0xff;
+
+ /* Transfer length */
+ SCpnt->cmnd[28] = (unsigned char) (this_count >> 24) & 0xff;
+ SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff;
+ SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff;
+ SCpnt->cmnd[31] = (unsigned char) this_count & 0xff;
+ } else if (block > 0xffffffff) {
SCpnt->cmnd[0] += READ_16 - READ_6;
- SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
+ SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0);
SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
@@ -547,7 +612,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
this_count = 0xffff;
SCpnt->cmnd[0] += READ_10 - READ_6;
- SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
+ SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0);
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
@@ -578,8 +643,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
/* If DIF or DIX is enabled, tell HBA how to handle request */
if (host_dif || scsi_prot_sg_count(SCpnt))
- sd_dif_op(SCpnt, host_dif, scsi_prot_sg_count(SCpnt),
- sdkp->protection_type);
+ sd_prot_op(SCpnt, host_dif);
/*
* We shouldn't disconnect in the middle of a sector, so with a dumb
@@ -1023,6 +1087,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)
int result = SCpnt->result;
unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt);
struct scsi_sense_hdr sshdr;
+ struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);
int sense_valid = 0;
int sense_deferred = 0;
@@ -1084,6 +1149,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)
if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
sd_dif_complete(SCpnt, good_bytes);
+ if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type)
+ == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd)
+ mempool_free(SCpnt->cmnd, sd_cdb_pool);
+
return good_bytes;
}
@@ -1238,34 +1307,28 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
u8 type;
if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0)
- type = 0;
- else
- type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
+ return;
- sdkp->protection_type = type;
+ type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
- switch (type) {
- case SD_DIF_TYPE0_PROTECTION:
- case SD_DIF_TYPE1_PROTECTION:
- case SD_DIF_TYPE3_PROTECTION:
- break;
+ if (type == sdkp->protection_type || !sdkp->first_scan)
+ return;
- case SD_DIF_TYPE2_PROTECTION:
- sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 " \
- "protection which is currently unsupported. " \
- "Disabling disk!\n");
- goto disable;
+ sdkp->protection_type = type;
- default:
- sd_printk(KERN_ERR, sdkp, "formatted with unknown " \
- "protection type %d. Disabling disk!\n", type);
- goto disable;
+ if (type > SD_DIF_TYPE3_PROTECTION) {
+ sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \
+ "protection type %u. Disabling disk!\n", type);
+ sdkp->capacity = 0;
+ return;
}
- return;
-
-disable:
- sdkp->capacity = 0;
+ if (scsi_host_dif_capable(sdp->host, type))
+ sd_printk(KERN_NOTICE, sdkp,
+ "Enabling DIF Type %u protection\n", type);
+ else
+ sd_printk(KERN_NOTICE, sdkp,
+ "Disabling DIF Type %u protection\n", type);
}
static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
@@ -2300,8 +2363,24 @@ static int __init init_sd(void)
if (err)
goto err_out_class;
+ sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE,
+ 0, 0, NULL);
+ if (!sd_cdb_cache) {
+ printk(KERN_ERR "sd: can't init extended cdb cache\n");
+ goto err_out_class;
+ }
+
+ sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache);
+ if (!sd_cdb_pool) {
+ printk(KERN_ERR "sd: can't init extended cdb pool\n");
+ goto err_out_cache;
+ }
+
return 0;
+err_out_cache:
+ kmem_cache_destroy(sd_cdb_cache);
+
err_out_class:
class_unregister(&sd_disk_class);
err_out:
@@ -2321,6 +2400,9 @@ static void __exit exit_sd(void)
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
+ mempool_destroy(sd_cdb_pool);
+ kmem_cache_destroy(sd_cdb_cache);
+
scsi_unregister_driver(&sd_template.gendrv);
class_unregister(&sd_disk_class);
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 8474b5bad3fe..e374804d26fb 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -37,6 +37,11 @@
*/
#define SD_LAST_BUGGY_SECTORS 8
+enum {
+ SD_EXT_CDB_SIZE = 32, /* Extended CDB size */
+ SD_MEMPOOL_SIZE = 2, /* CDB pool size */
+};
+
struct scsi_disk {
struct scsi_driver *driver; /* always &sd_template */
struct scsi_device *device;
@@ -101,16 +106,12 @@ struct sd_dif_tuple {
#ifdef CONFIG_BLK_DEV_INTEGRITY
-extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int, unsigned int);
extern void sd_dif_config_host(struct scsi_disk *);
extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int);
extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
#else /* CONFIG_BLK_DEV_INTEGRITY */
-static inline void sd_dif_op(struct scsi_cmnd *cmd, unsigned int a, unsigned int b, unsigned int c)
-{
-}
static inline void sd_dif_config_host(struct scsi_disk *disk)
{
}
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 82f14a9482d0..88da97745710 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -320,15 +320,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
dif = 0; dix = 1;
}
- if (type) {
- if (dif)
- sd_printk(KERN_NOTICE, sdkp,
- "Enabling DIF Type %d protection\n", type);
- else
- sd_printk(KERN_NOTICE, sdkp,
- "Disabling DIF Type %d protection\n", type);
- }
-
if (!dix)
return;
@@ -360,62 +351,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
}
/*
- * DIF DMA operation magic decoder ring.
- */
-void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsigned int type)
-{
- int csum_convert, prot_op;
-
- prot_op = 0;
-
- /* Convert checksum? */
- if (scsi_host_get_guard(scmd->device->host) != SHOST_DIX_GUARD_CRC)
- csum_convert = 1;
- else
- csum_convert = 0;
-
- BUG_ON(dif && (scmd->cmnd[0] == READ_6 || scmd->cmnd[0] == WRITE_6));
-
- switch (scmd->cmnd[0]) {
- case READ_6:
- case READ_10:
- case READ_12:
- case READ_16:
- if (dif && dix)
- if (csum_convert)
- prot_op = SCSI_PROT_READ_CONVERT;
- else
- prot_op = SCSI_PROT_READ_PASS;
- else if (dif && !dix)
- prot_op = SCSI_PROT_READ_STRIP;
- else if (!dif && dix)
- prot_op = SCSI_PROT_READ_INSERT;
-
- break;
-
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- case WRITE_16:
- if (dif && dix)
- if (csum_convert)
- prot_op = SCSI_PROT_WRITE_CONVERT;
- else
- prot_op = SCSI_PROT_WRITE_PASS;
- else if (dif && !dix)
- prot_op = SCSI_PROT_WRITE_INSERT;
- else if (!dif && dix)
- prot_op = SCSI_PROT_WRITE_STRIP;
-
- break;
- }
-
- scsi_set_prot_op(scmd, prot_op);
- if (dif)
- scsi_set_prot_type(scmd, type);
-}
-
-/*
* The virtual start sector is the one that was originally submitted
* by the block layer. Due to partitioning, MD/DM cloning, etc. the
* actual physical start sector is likely to be different. Remap
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 747a5e5c1276..040f751809ea 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1708,11 +1708,6 @@ static int sg_finish_rem_req(Sg_request * srp)
Sg_scatter_hold *req_schp = &srp->data;
SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", (int) srp->res_used));
- if (srp->res_used)
- sg_unlink_reserve(sfp, srp);
- else
- sg_remove_scat(req_schp);
-
if (srp->rq) {
if (srp->bio)
ret = blk_rq_unmap_user(srp->bio);
@@ -1720,6 +1715,11 @@ static int sg_finish_rem_req(Sg_request * srp)
blk_put_request(srp->rq);
}
+ if (srp->res_used)
+ sg_unlink_reserve(sfp, srp);
+ else
+ sg_remove_scat(req_schp);
+
sg_remove_request(sfp, srp);
return ret;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index eb61f7a70e1d..d6f340f48a3b 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -684,14 +684,20 @@ static void get_sectorsize(struct scsi_cd *cd)
cd->capacity = 0x1fffff;
sector_size = 2048; /* A guess, just in case */
} else {
-#if 0
- if (cdrom_get_last_written(&cd->cdi,
- &cd->capacity))
-#endif
- cd->capacity = 1 + ((buffer[0] << 24) |
- (buffer[1] << 16) |
- (buffer[2] << 8) |
- buffer[3]);
+ long last_written;
+
+ cd->capacity = 1 + ((buffer[0] << 24) | (buffer[1] << 16) |
+ (buffer[2] << 8) | buffer[3]);
+ /*
+ * READ_CAPACITY doesn't return the correct size on
+ * certain UDF media. If last_written is larger, use
+ * it instead.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=9668
+ */
+ if (!cdrom_get_last_written(&cd->cdi, &last_written))
+ cd->capacity = max_t(long, cd->capacity, last_written);
+
sector_size = (buffer[4] << 24) |
(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
switch (sector_size) {
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index b33d04250bbc..12d58a7ed6bc 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2859,11 +2859,8 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
ioctl_result = st_int_ioctl(STp, MTBSF, 1);
if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
- int old_block_size = STp->block_size;
STp->block_size = arg & MT_ST_BLKSIZE_MASK;
if (STp->block_size != 0) {
- if (old_block_size == 0)
- normalize_buffer(STp->buffer);
(STp->buffer)->buffer_blocks =
(STp->buffer)->buffer_size / STp->block_size;
}
OpenPOWER on IntegriCloud