summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2016-04-18 09:18:55 (GMT)
committerJiri Kosina <jkosina@suse.cz>2016-04-18 09:18:55 (GMT)
commit9938b04472d5c59f8bd8152a548533a8599596a2 (patch)
tree0fc8318100878c5e446076613ec02a97aa179119 /drivers/scsi
parentbd7ced98812dbb906950d8b0ec786f14f631cede (diff)
parentc3b46c73264b03000d1e18b22f5caf63332547c9 (diff)
downloadlinux-9938b04472d5c59f8bd8152a548533a8599596a2.tar.xz
Merge branch 'master' into for-next
Sync with Linus' tree so that patches against newer codebase can be applied. Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/3w-xxxx.c3
-rw-r--r--drivers/scsi/53c700.c11
-rw-r--r--drivers/scsi/FlashPoint.c2
-rw-r--r--drivers/scsi/Kconfig24
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/NCR5380.c2859
-rw-r--r--drivers/scsi/NCR5380.h87
-rw-r--r--drivers/scsi/aacraid/aachba.c292
-rw-r--r--drivers/scsi/aacraid/aacraid.h32
-rw-r--r--drivers/scsi/aacraid/commctrl.c13
-rw-r--r--drivers/scsi/aacraid/comminit.c153
-rw-r--r--drivers/scsi/aacraid/commsup.c182
-rw-r--r--drivers/scsi/aacraid/dpcsup.c2
-rw-r--r--drivers/scsi/aacraid/linit.c350
-rw-r--r--drivers/scsi/aacraid/rx.c1
-rw-r--r--drivers/scsi/aacraid/sa.c1
-rw-r--r--drivers/scsi/aacraid/src.c94
-rw-r--r--drivers/scsi/advansys.c8
-rw-r--r--drivers/scsi/aha1542.c3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h4
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c1
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h5
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h5
-rw-r--r--drivers/scsi/aic7xxx/queue.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c3
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h49
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h14
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c209
-rw-r--r--drivers/scsi/arm/acornscsi.c3
-rw-r--r--drivers/scsi/arm/cumana_1.c31
-rw-r--r--drivers/scsi/arm/fas216.c2
-rw-r--r--drivers/scsi/arm/oak.c27
-rw-r--r--drivers/scsi/atari_NCR5380.c2263
-rw-r--r--drivers/scsi/atari_scsi.c102
-rw-r--r--drivers/scsi/atp870u.c3635
-rw-r--r--drivers/scsi/atp870u.h4
-rw-r--r--drivers/scsi/be2iscsi/Kconfig1
-rw-r--r--drivers/scsi/be2iscsi/be.h24
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c867
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h148
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c66
-rw-r--r--drivers/scsi/be2iscsi/be_main.c387
-rw-r--r--drivers/scsi/be2iscsi/be_main.h30
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c597
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h9
-rw-r--r--drivers/scsi/bfa/bfa.h7
-rw-r--r--drivers/scsi/bfa/bfa_core.c26
-rw-r--r--drivers/scsi/bfa/bfa_cs.h48
-rw-r--r--drivers/scsi/bfa/bfa_defs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs_fcs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h7
-rw-r--r--drivers/scsi/bfa/bfa_fc.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h9
-rw-r--r--drivers/scsi/bfa/bfa_fcs_fcpim.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c9
-rw-r--r--drivers/scsi/bfa/bfa_fcs_rport.c7
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c7
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c7
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c11
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h7
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c7
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c7
-rw-r--r--drivers/scsi/bfa/bfa_modules.h7
-rw-r--r--drivers/scsi/bfa/bfa_plog.h7
-rw-r--r--drivers/scsi/bfa/bfa_port.c7
-rw-r--r--drivers/scsi/bfa/bfa_port.h7
-rw-r--r--drivers/scsi/bfa/bfa_svc.c7
-rw-r--r--drivers/scsi/bfa/bfa_svc.h7
-rw-r--r--drivers/scsi/bfa/bfad.c24
-rw-r--r--drivers/scsi/bfa/bfad_attr.c75
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c7
-rw-r--r--drivers/scsi/bfa/bfad_bsg.h7
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c7
-rw-r--r--drivers/scsi/bfa/bfad_drv.h9
-rw-r--r--drivers/scsi/bfa/bfad_im.c37
-rw-r--r--drivers/scsi/bfa/bfad_im.h7
-rw-r--r--drivers/scsi/bfa/bfi.h7
-rw-r--r--drivers/scsi/bfa/bfi_ms.h7
-rw-r--r--drivers/scsi/bfa/bfi_reg.h9
-rw-r--r--drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h6
-rw-r--r--drivers/scsi/bnx2fc/Kconfig5
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h9
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_constants.h6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_debug.c6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_debug.h6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_els.c10
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c35
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c111
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c12
-rw-r--r--drivers/scsi/csiostor/csio_scsi.c2
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/Kbuild2
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c2
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/Kbuild2
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c2
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.h17
-rw-r--r--drivers/scsi/cxlflash/common.h11
-rw-r--r--drivers/scsi/cxlflash/main.c278
-rw-r--r--drivers/scsi/cxlflash/main.h10
-rw-r--r--drivers/scsi/cxlflash/superpipe.c203
-rw-r--r--drivers/scsi/cxlflash/superpipe.h1
-rw-r--r--drivers/scsi/cxlflash/vlun.c2
-rw-r--r--drivers/scsi/device_handler/Kconfig8
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c1179
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c7
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c42
-rw-r--r--drivers/scsi/dmx3191d.c33
-rw-r--r--drivers/scsi/dpt_i2o.c3
-rw-r--r--drivers/scsi/dtc.c115
-rw-r--r--drivers/scsi/dtc.h45
-rw-r--r--drivers/scsi/esas2r/esas2r_ioctl.c5
-rw-r--r--drivers/scsi/esas2r/esas2r_main.c1
-rw-r--r--drivers/scsi/esp_scsi.c1
-rw-r--r--drivers/scsi/fcoe/fcoe.c6
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c3
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c36
-rw-r--r--drivers/scsi/fdomain.c2
-rw-r--r--drivers/scsi/fnic/fnic_main.c8
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c13
-rw-r--r--drivers/scsi/g_NCR5380.c408
-rw-r--r--drivers/scsi/g_NCR5380.h66
-rw-r--r--drivers/scsi/gdth.c7
-rw-r--r--drivers/scsi/gdth_proc.c11
-rw-r--r--drivers/scsi/hisi_sas/Kconfig8
-rw-r--r--drivers/scsi/hisi_sas/Makefile2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h332
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c1418
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c1880
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c2214
-rw-r--r--drivers/scsi/hosts.c47
-rw-r--r--drivers/scsi/hpsa.c1461
-rw-r--r--drivers/scsi/hpsa.h50
-rw-r--r--drivers/scsi/hpsa_cmd.h46
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c4
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c132
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h1
-rw-r--r--drivers/scsi/ibmvscsi/viosrp.h26
-rw-r--r--drivers/scsi/imm.c57
-rw-r--r--drivers/scsi/initio.c16
-rw-r--r--drivers/scsi/ipr.c189
-rw-r--r--drivers/scsi/ipr.h26
-rw-r--r--drivers/scsi/isci/init.c5
-rw-r--r--drivers/scsi/iscsi_boot_sysfs.c5
-rw-r--r--drivers/scsi/iscsi_tcp.c54
-rw-r--r--drivers/scsi/iscsi_tcp.h4
-rw-r--r--drivers/scsi/libfc/fc_npiv.c2
-rw-r--r--drivers/scsi/libiscsi_tcp.c29
-rw-r--r--drivers/scsi/lpfc/lpfc.h16
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c48
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c1864
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c492
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c70
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h184
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h52
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c203
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c134
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c61
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c66
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c8
-rw-r--r--drivers/scsi/mac53c94.c2
-rw-r--r--drivers/scsi/mac_scsi.c117
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c4
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h405
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c1487
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c30
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c1675
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h166
-rw-r--r--drivers/scsi/mesh.c2
-rw-r--r--drivers/scsi/mpt2sas/Kconfig67
-rw-r--r--drivers/scsi/mpt2sas/Makefile7
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h1170
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h3068
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h461
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h1708
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h366
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_sas.h288
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h481
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_type.h61
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c4899
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h1235
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c1527
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c3101
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h419
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_debug.h182
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c8855
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c2173
-rw-r--r--drivers/scsi/mpt3sas/Kconfig27
-rw-r--r--drivers/scsi/mpt3sas/Makefile3
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2.h82
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h127
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_init.h22
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_ioc.h117
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_raid.h5
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_sas.h10
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_tool.h5
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_type.h5
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c858
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h274
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c42
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c282
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.h6
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_debug.h16
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c1806
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c43
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_warpdrive.c344
-rw-r--r--drivers/scsi/mvsas/mv_94xx.c134
-rw-r--r--drivers/scsi/mvsas/mv_94xx.h71
-rw-r--r--drivers/scsi/mvsas/mv_init.c9
-rw-r--r--drivers/scsi/mvsas/mv_sas.c17
-rw-r--r--drivers/scsi/mvsas/mv_sas.h5
-rw-r--r--drivers/scsi/mvumi.c14
-rw-r--r--drivers/scsi/osd/osd_initiator.c8
-rw-r--r--drivers/scsi/pas16.c116
-rw-r--r--drivers/scsi/pas16.h40
-rw-r--r--drivers/scsi/pm8001/pm8001_defs.h2
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c216
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h6
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c34
-rw-r--r--drivers/scsi/pmcraid.c6
-rw-r--r--drivers/scsi/ppa.c46
-rw-r--r--drivers/scsi/qla2xxx/Kconfig3
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c201
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h34
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c163
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h140
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c161
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h14
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h20
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c187
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c188
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c134
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c292
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c185
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c70
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c770
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h95
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.c16
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c342
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c6
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c8
-rw-r--r--drivers/scsi/qlogicpti.c4
-rw-r--r--drivers/scsi/scsi.c50
-rw-r--r--drivers/scsi/scsi_common.c12
-rw-r--r--drivers/scsi/scsi_debug.c23
-rw-r--r--drivers/scsi/scsi_devinfo.c5
-rw-r--r--drivers/scsi/scsi_dh.c72
-rw-r--r--drivers/scsi/scsi_error.c2
-rw-r--r--drivers/scsi/scsi_lib.c194
-rw-r--r--drivers/scsi/scsi_pm.c30
-rw-r--r--drivers/scsi/scsi_priv.h3
-rw-r--r--drivers/scsi/scsi_sas_internal.h2
-rw-r--r--drivers/scsi/scsi_scan.c43
-rw-r--r--drivers/scsi/scsi_sysfs.c250
-rw-r--r--drivers/scsi/scsi_transport_fc.c12
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c2
-rw-r--r--drivers/scsi/scsi_transport_sas.c32
-rw-r--r--drivers/scsi/sd.c121
-rw-r--r--drivers/scsi/sd.h8
-rw-r--r--drivers/scsi/ses.c52
-rw-r--r--drivers/scsi/sg.c13
-rw-r--r--drivers/scsi/sim710.c3
-rw-r--r--drivers/scsi/snic/snic_ctl.c2
-rw-r--r--drivers/scsi/snic/snic_main.c10
-rw-r--r--drivers/scsi/sr.c4
-rw-r--r--drivers/scsi/st.c163
-rw-r--r--drivers/scsi/st.h2
-rw-r--r--drivers/scsi/stex.c174
-rw-r--r--drivers/scsi/storvsc_drv.c626
-rw-r--r--drivers/scsi/sun3_scsi.c141
-rw-r--r--drivers/scsi/t128.c102
-rw-r--r--drivers/scsi/t128.h39
-rw-r--r--drivers/scsi/ufs/Kconfig3
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c1044
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h77
-rw-r--r--drivers/scsi/ufs/ufs.h35
-rw-r--r--drivers/scsi/ufs/ufs_quirks.h151
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c117
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.h41
-rw-r--r--drivers/scsi/ufs/ufshcd.c1341
-rw-r--r--drivers/scsi/ufs/ufshcd.h191
-rw-r--r--drivers/scsi/ufs/ufshci.h4
-rw-r--r--drivers/scsi/ufs/unipro.h22
-rw-r--r--drivers/scsi/vmw_pvscsi.c45
-rw-r--r--drivers/scsi/vmw_pvscsi.h2
301 files changed, 29642 insertions, 44522 deletions
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 2940bd7..25aba16 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1045,6 +1045,9 @@ static int tw_chrdev_open(struct inode *inode, struct file *file)
static const struct file_operations tw_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = tw_chrdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = tw_chrdev_ioctl,
+#endif
.open = tw_chrdev_open,
.release = NULL,
.llseek = noop_llseek,
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index a209c34..d4c2856 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -325,7 +325,6 @@ NCR_700_detect(struct scsi_host_template *tpnt,
tpnt->slave_destroy = NCR_700_slave_destroy;
tpnt->slave_alloc = NCR_700_slave_alloc;
tpnt->change_queue_depth = NCR_700_change_queue_depth;
- tpnt->use_blk_tags = 1;
if(tpnt->name == NULL)
tpnt->name = "53c700";
@@ -1107,7 +1106,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
BUG();
}
if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
- struct scsi_cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]);
+ struct scsi_cmnd *SCp;
+
+ SCp = scsi_host_find_tag(SDp->host, hostdata->msgin[2]);
if(unlikely(SCp == NULL)) {
printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n",
host->host_no, reselection_id, lun, hostdata->msgin[2]);
@@ -1119,7 +1120,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
"reselection is tag %d, slot %p(%d)\n",
hostdata->msgin[2], slot, slot->tag);
} else {
- struct scsi_cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG);
+ struct scsi_cmnd *SCp;
+
+ SCp = scsi_host_find_tag(SDp->host, SCSI_NO_TAG);
if(unlikely(SCp == NULL)) {
sdev_printk(KERN_ERR, SDp,
"no saved request for untagged cmd\n");
@@ -1823,7 +1826,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
slot->tag, slot);
} else {
slot->tag = SCSI_NO_TAG;
- /* must populate current_cmnd for scsi_find_tag to work */
+ /* must populate current_cmnd for scsi_host_find_tag to work */
SCp->device->current_cmnd = SCp;
}
/* sanity check: some of the commands generated by the mid-layer
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index 5c74e4c..867b864 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -2136,7 +2136,7 @@ static unsigned char FPT_SccbMgr_bad_isr(u32 p_port, unsigned char p_card,
*
*---------------------------------------------------------------------*/
-static void FPT_SccbMgrTableInitAll()
+static void FPT_SccbMgrTableInitAll(void)
{
unsigned char thisCard;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d2f480b..e80768f 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -194,6 +194,7 @@ config CHR_DEV_SCH
config SCSI_ENCLOSURE
tristate "SCSI Enclosure Support"
depends on SCSI && ENCLOSURE_SERVICES
+ depends on m || SCSI_SAS_ATTRS != m
help
Enclosures are devices sitting on or in SCSI backplanes that
manage devices. If you have a disk cage, the chances are that
@@ -364,6 +365,7 @@ config SCSI_HPSA
tristate "HP Smart Array SCSI driver"
depends on PCI && SCSI
select CHECK_SIGNATURE
+ select SCSI_SAS_ATTRS
help
This driver supports HP Smart Array Controllers (circa 2009).
It is a SCSI alternative to the cciss driver, which is a block
@@ -473,6 +475,7 @@ config SCSI_AACRAID
source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
source "drivers/scsi/aic94xx/Kconfig"
+source "drivers/scsi/hisi_sas/Kconfig"
source "drivers/scsi/mvsas/Kconfig"
config SCSI_MVUMI
@@ -499,6 +502,7 @@ config SCSI_ADVANSYS
tristate "AdvanSys SCSI support"
depends on SCSI
depends on ISA || EISA || PCI
+ depends on ISA_DMA_API || !ISA
help
This is a driver for all SCSI host adapters manufactured by
AdvanSys. It is documented in the kernel source in
@@ -534,7 +538,6 @@ config SCSI_ARCMSR
source "drivers/scsi/esas2r/Kconfig"
source "drivers/scsi/megaraid/Kconfig.megaraid"
-source "drivers/scsi/mpt2sas/Kconfig"
source "drivers/scsi/mpt3sas/Kconfig"
source "drivers/scsi/ufs/Kconfig"
@@ -593,6 +596,7 @@ config XEN_SCSI_FRONTEND
config HYPERV_STORAGE
tristate "Microsoft Hyper-V virtual storage driver"
depends on SCSI && HYPERV
+ depends on m || SCSI_FC_ATTRS != m
default HYPERV
help
Select this option to enable the Hyper-V virtual storage driver.
@@ -1103,6 +1107,7 @@ config SCSI_IPR
tristate "IBM Power Linux RAID adapter support"
depends on PCI && SCSI && ATA
select FW_LOADER
+ select IRQ_POLL
---help---
This driver supports the IBM Power Linux family RAID adapters.
This includes IBM pSeries 5712, 5703, 5709, and 570A, as well
@@ -1617,23 +1622,6 @@ config ATARI_SCSI
ST-DMA, replacing ACSI). It does NOT support other schemes, like
in the Hades (without DMA).
-config ATARI_SCSI_TOSHIBA_DELAY
- bool "Long delays for Toshiba CD-ROMs"
- depends on ATARI_SCSI
- help
- This option increases the delay after a SCSI arbitration to
- accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
- use a Toshiba CD-ROM drive; otherwise, the option is not needed and
- would impact performance a bit, so say N.
-
-config ATARI_SCSI_RESET_BOOT
- bool "Reset SCSI-devices at boottime"
- depends on ATARI_SCSI
- help
- Reset the devices on your Atari whenever it boots. This makes the
- boot process fractionally longer but may assist recovery from errors
- that leave the devices with SCSI operations partway completed.
-
config MAC_SCSI
tristate "Macintosh NCR5380 SCSI"
depends on MAC && SCSI=y
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1a8c9b5..862ab4e 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -106,7 +106,6 @@ obj-$(CONFIG_CXLFLASH) += cxlflash/
obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
-obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/
obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/
obj-$(CONFIG_SCSI_UFSHCD) += ufs/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
@@ -158,6 +157,7 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o
obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o
obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas/
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index a777e5c..3eff2a6 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -1,17 +1,17 @@
-/*
+/*
* NCR 5380 generic driver routines. These should make it *trivial*
- * to implement 5380 SCSI drivers under Linux with a non-trantor
- * architecture.
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
*
- * Note that these routines also work with NR53c400 family chips.
+ * Note that these routines also work with NR53c400 family chips.
*
* Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
*
- * For more information, please consult
+ * For more information, please consult
*
* NCR 5380 Family
* SCSI Protocol Controller
@@ -25,84 +25,28 @@
*/
/*
- * Revision 1.10 1998/9/2 Alan Cox
- * (alan@lxorguk.ukuu.org.uk)
- * Fixed up the timer lockups reported so far. Things still suck. Looking
- * forward to 2.3 and per device request queues. Then it'll be possible to
- * SMP thread this beast and improve life no end.
-
- * Revision 1.9 1997/7/27 Ronald van Cuijlenborg
- * (ronald.van.cuijlenborg@tip.nl or nutty@dds.nl)
- * (hopefully) fixed and enhanced USLEEP
- * added support for DTC3181E card (for Mustek scanner)
- *
-
- * Revision 1.8 Ingmar Baumgart
- * (ingmar@gonzo.schwaben.de)
- * added support for NCR53C400a card
- *
-
- * Revision 1.7 1996/3/2 Ray Van Tassle (rayvt@comm.mot.com)
- * added proc_info
- * added support needed for DTC 3180/3280
- * fixed a couple of bugs
- *
-
- * Revision 1.5 1994/01/19 09:14:57 drew
- * Fixed udelay() hack that was being used on DATAOUT phases
- * instead of a proper wait for the final handshake.
- *
- * Revision 1.4 1994/01/19 06:44:25 drew
- * *** empty log message ***
- *
- * Revision 1.3 1994/01/19 05:24:40 drew
- * Added support for TCR LAST_BYTE_SENT bit.
- *
- * Revision 1.2 1994/01/15 06:14:11 drew
- * REAL DMA support, bug fixes.
- *
- * Revision 1.1 1994/01/15 06:00:54 drew
- * Initial revision
- *
+ * With contributions from Ray Van Tassle, Ingmar Baumgart,
+ * Ronald van Cuijlenborg, Alan Cox and others.
*/
/*
- * Further development / testing that should be done :
+ * Further development / testing that should be done :
* 1. Cleanup the NCR5380_transfer_dma function and DMA operation complete
- * code so that everything does the same thing that's done at the
- * end of a pseudo-DMA read operation.
+ * code so that everything does the same thing that's done at the
+ * end of a pseudo-DMA read operation.
*
* 2. Fix REAL_DMA (interrupt driven, polled works fine) -
- * basically, transfer size needs to be reduced by one
- * and the last byte read as is done with PSEUDO_DMA.
- *
- * 4. Test SCSI-II tagged queueing (I have no devices which support
- * tagged queueing)
- *
- * 5. Test linked command handling code after Eric is ready with
- * the high level code.
+ * basically, transfer size needs to be reduced by one
+ * and the last byte read as is done with PSEUDO_DMA.
+ *
+ * 4. Test SCSI-II tagged queueing (I have no devices which support
+ * tagged queueing)
*/
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_transport_spi.h>
-
-#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x,y) {printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
-#define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
-#else
-#define LIST(x,y)
-#define REMOVE(w,x,y,z)
-#endif
#ifndef notyet
-#undef LINKED
#undef REAL_DMA
#endif
-#ifdef REAL_DMA_POLL
-#undef READ_OVERRUNS
-#define READ_OVERRUNS
-#endif
-
#ifdef BOARD_REQUIRES_NO_DELAY
#define io_recovery_delay(x)
#else
@@ -112,44 +56,28 @@
/*
* Design
*
- * This is a generic 5380 driver. To use it on a different platform,
+ * This is a generic 5380 driver. To use it on a different platform,
* one simply writes appropriate system specific macros (ie, data
- * transfer - some PC's will use the I/O bus, 68K's must use
+ * transfer - some PC's will use the I/O bus, 68K's must use
* memory mapped) and drops this file in their 'C' wrapper.
*
- * (Note from hch: unfortunately it was not enough for the different
- * m68k folks and instead of improving this driver they copied it
- * and hacked it up for their needs. As a consequence they lost
- * most updates to this driver. Maybe someone will fix all these
- * drivers to use a common core one day..)
- *
- * As far as command queueing, two queues are maintained for
+ * As far as command queueing, two queues are maintained for
* each 5380 in the system - commands that haven't been issued yet,
- * and commands that are currently executing. This means that an
- * unlimited number of commands may be queued, letting
- * more commands propagate from the higher driver levels giving higher
- * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
- * allowing multiple commands to propagate all the way to a SCSI-II device
+ * and commands that are currently executing. This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
* while a command is already executing.
*
*
- * Issues specific to the NCR5380 :
+ * Issues specific to the NCR5380 :
*
- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
- * piece of hardware that requires you to sit in a loop polling for
- * the REQ signal as long as you are connected. Some devices are
- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
- * while doing long seek operations.
- *
- * The workaround for this is to keep track of devices that have
- * disconnected. If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
- *
- * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done. An algorithm based
- * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected. Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * while doing long seek operations. [...] These
* broken devices are the exception rather than the rule and I'd rather
* spend my time optimizing for the normal case.
*
@@ -159,23 +87,23 @@
* which is started from a workqueue for each NCR5380 host in the
* system. It attempts to establish I_T_L or I_T_L_Q nexuses by
* removing the commands from the issue queue and calling
- * NCR5380_select() if a nexus is not established.
+ * NCR5380_select() if a nexus is not established.
*
* Once a nexus is established, the NCR5380_information_transfer()
* phase goes through the various phases as instructed by the target.
* if the target goes into MSG IN and sends a DISCONNECT message,
* the command structure is placed into the per instance disconnected
- * queue, and NCR5380_main tries to find more work. If the target is
+ * queue, and NCR5380_main tries to find more work. If the target is
* idle for too long, the system will try to sleep.
*
* If a command has disconnected, eventually an interrupt will trigger,
* calling NCR5380_intr() which will in turn call NCR5380_reselect
* to reestablish a nexus. This will run main if necessary.
*
- * On command termination, the done function will be called as
+ * On command termination, the done function will be called as
* appropriate.
*
- * SCSI pointers are maintained in the SCp field of SCSI command
+ * SCSI pointers are maintained in the SCp field of SCSI command
* structures, being initialized after the command is connected
* in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
* Note that in violation of the standard, an implicit SAVE POINTERS operation
@@ -185,73 +113,48 @@
/*
* Using this file :
* This file a skeleton Linux SCSI driver for the NCR 5380 series
- * of chips. To use it, you write an architecture specific functions
+ * of chips. To use it, you write an architecture specific functions
* and macros and include this file in your driver.
*
- * These macros control options :
- * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be
- * defined.
- *
+ * These macros control options :
+ * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be
+ * defined.
+ *
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
+ * for commands that return with a CHECK CONDITION status.
*
* DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
- * transceivers.
+ * transceivers.
*
* DONT_USE_INTR - if defined, never use interrupts, even if we probe or
- * override-configure an IRQ.
- *
- * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
- * bytes at a time. Since interrupts are disabled by default during
- * these transfers, we might need this to give reasonable interrupt
- * service time if the transfer size gets too large.
- *
- * LINKED - if defined, linked commands are supported.
+ * override-configure an IRQ.
*
* PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
*
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
*
* REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't
- * rely on phase mismatch and EOP interrupts to determine end
- * of phase.
- *
- * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You
- * only really want to use this if you're having a problem with
- * dropped characters during high speed communications, and even
- * then, you're going to be better off twiddling with transfersize
- * in the high level code.
- *
- * Defaults for these will be provided although the user may want to adjust
- * these to allocate CPU resources to the SCSI driver or "real" code.
- *
- * USLEEP_SLEEP - amount of time, in jiffies, to sleep
- *
- * USLEEP_POLL - amount of time, in jiffies, to poll
+ * rely on phase mismatch and EOP interrupts to determine end
+ * of phase.
*
* These macros MUST be defined :
- * NCR5380_local_declare() - declare any local variables needed for your
- * transfer routines.
*
- * NCR5380_setup(instance) - initialize any local variables needed from a given
- * instance of the host adapter for NCR5380_{read,write,pread,pwrite}
- *
* NCR5380_read(register) - read from the specified register
*
- * NCR5380_write(register, value) - write to the specific register
+ * NCR5380_write(register, value) - write to the specific register
*
- * NCR5380_implementation_fields - additional fields needed for this
- * specific implementation of the NCR5380
+ * NCR5380_implementation_fields - additional fields needed for this
+ * specific implementation of the NCR5380
*
* Either real DMA *or* pseudo DMA may be implemented
- * REAL functions :
+ * REAL functions :
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
- * Note that the DMA setup functions should return the number of bytes
- * that they were able to program the controller for.
+ * Note that the DMA setup functions should return the number of bytes
+ * that they were able to program the controller for.
*
- * Also note that generic i386/PC versions of these macros are
- * available as NCR5380_i386_dma_write_setup,
- * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ * Also note that generic i386/PC versions of these macros are
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
*
* NCR5380_dma_write_setup(instance, src, count) - initialize
* NCR5380_dma_read_setup(instance, dst, count) - initialize
@@ -262,25 +165,25 @@
* NCR5380_pread(instance, dst, count);
*
* The generic driver is initialized by calling NCR5380_init(instance),
- * after setting the appropriate host specific fields and ID. If the
+ * after setting the appropriate host specific fields and ID. If the
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
* possible) function may be used.
*/
-static int do_abort(struct Scsi_Host *host);
-static void do_reset(struct Scsi_Host *host);
+static int do_abort(struct Scsi_Host *);
+static void do_reset(struct Scsi_Host *);
-/*
- * initialize_SCp - init the scsi pointer field
- * @cmd: command block to set up
+/**
+ * initialize_SCp - init the scsi pointer field
+ * @cmd: command block to set up
*
- * Set up the internal fields in the SCSI command.
+ * Set up the internal fields in the SCSI command.
*/
static inline void initialize_SCp(struct scsi_cmnd *cmd)
{
- /*
- * Initialize the Scsi Pointer field so that all of the commands in the
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
* various queues are valid.
*/
@@ -295,120 +198,123 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.ptr = NULL;
cmd->SCp.this_residual = 0;
}
+
+ cmd->SCp.Status = 0;
+ cmd->SCp.Message = 0;
}
/**
- * NCR5380_poll_politely - wait for NCR5380 status bits
- * @instance: controller to poll
- * @reg: 5380 register to poll
- * @bit: Bitmask to check
- * @val: Value required to exit
- *
- * Polls the NCR5380 in a reasonably efficient manner waiting for
- * an event to occur, after a short quick poll we begin giving the
- * CPU back in non IRQ contexts
- *
- * Returns the value of the register or a negative error code.
+ * NCR5380_poll_politely2 - wait for two chip register values
+ * @instance: controller to poll
+ * @reg1: 5380 register to poll
+ * @bit1: Bitmask to check
+ * @val1: Expected value
+ * @reg2: Second 5380 register to poll
+ * @bit2: Second bitmask to check
+ * @val2: Second expected value
+ * @wait: Time-out in jiffies
+ *
+ * Polls the chip in a reasonably efficient manner waiting for an
+ * event to occur. After a short quick poll we begin to yield the CPU
+ * (if possible). In irq contexts the time-out is arbitrarily limited.
+ * Callers may hold locks as long as they are held in irq mode.
+ *
+ * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT.
*/
-
-static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, int val, int t)
+
+static int NCR5380_poll_politely2(struct Scsi_Host *instance,
+ int reg1, int bit1, int val1,
+ int reg2, int bit2, int val2, int wait)
{
- NCR5380_local_declare();
- int n = 500; /* At about 8uS a cycle for the cpu access */
- unsigned long end = jiffies + t;
- int r;
-
- NCR5380_setup(instance);
-
- while( n-- > 0)
- {
- r = NCR5380_read(reg);
- if((r & bit) == val)
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long deadline = jiffies + wait;
+ unsigned long n;
+
+ /* Busy-wait for up to 10 ms */
+ n = min(10000U, jiffies_to_usecs(wait));
+ n *= hostdata->accesses_per_ms;
+ n /= 2000;
+ do {
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
return 0;
cpu_relax();
- }
-
- /* t time yet ? */
- while(time_before(jiffies, end))
- {
- r = NCR5380_read(reg);
- if((r & bit) == val)
+ } while (n--);
+
+ if (irqs_disabled() || in_interrupt())
+ return -ETIMEDOUT;
+
+ /* Repeatedly sleep for 1 ms until deadline */
+ while (time_is_after_jiffies(deadline)) {
+ schedule_timeout_uninterruptible(1);
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
return 0;
- if(!in_interrupt())
- cond_resched();
- else
- cpu_relax();
}
+
return -ETIMEDOUT;
}
-static struct {
- unsigned char value;
- const char *name;
-} phases[] __maybe_unused = {
- {PHASE_DATAOUT, "DATAOUT"},
- {PHASE_DATAIN, "DATAIN"},
- {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"},
- {PHASE_MSGOUT, "MSGOUT"},
- {PHASE_MSGIN, "MSGIN"},
- {PHASE_UNKNOWN, "UNKNOWN"}
-};
+static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
+ int reg, int bit, int val, int wait)
+{
+ return NCR5380_poll_politely2(instance, reg, bit, val,
+ reg, bit, val, wait);
+}
#if NDEBUG
static struct {
unsigned char mask;
const char *name;
-} signals[] = {
- {SR_DBP, "PARITY"},
- {SR_RST, "RST"},
- {SR_BSY, "BSY"},
- {SR_REQ, "REQ"},
- {SR_MSG, "MSG"},
- {SR_CD, "CD"},
- {SR_IO, "IO"},
- {SR_SEL, "SEL"},
+} signals[] = {
+ {SR_DBP, "PARITY"},
+ {SR_RST, "RST"},
+ {SR_BSY, "BSY"},
+ {SR_REQ, "REQ"},
+ {SR_MSG, "MSG"},
+ {SR_CD, "CD"},
+ {SR_IO, "IO"},
+ {SR_SEL, "SEL"},
{0, NULL}
-},
+},
basrs[] = {
- {BASR_ATN, "ATN"},
- {BASR_ACK, "ACK"},
+ {BASR_ATN, "ATN"},
+ {BASR_ACK, "ACK"},
{0, NULL}
-},
-icrs[] = {
- {ICR_ASSERT_RST, "ASSERT RST"},
- {ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"},
- {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"},
- {ICR_ASSERT_DATA, "ASSERT DATA"},
+},
+icrs[] = {
+ {ICR_ASSERT_RST, "ASSERT RST"},
+ {ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"},
+ {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"},
+ {ICR_ASSERT_DATA, "ASSERT DATA"},
{0, NULL}
-},
-mrs[] = {
- {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
- {MR_TARGET, "MODE TARGET"},
- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
- {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
- {MR_MONITOR_BSY, "MODE MONITOR BSY"},
- {MR_DMA_MODE, "MODE DMA"},
- {MR_ARBITRATE, "MODE ARBITRATION"},
+},
+mrs[] = {
+ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
+ {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
+ {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
+ {MR_ENABLE_EOP_INTR, "MODE EOP INTR"},
+ {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+ {MR_DMA_MODE, "MODE DMA"},
+ {MR_ARBITRATE, "MODE ARBITRATION"},
{0, NULL}
};
/**
- * NCR5380_print - print scsi bus signals
- * @instance: adapter state to dump
+ * NCR5380_print - print scsi bus signals
+ * @instance: adapter state to dump
*
- * Print the SCSI bus signals for debugging purposes
- *
- * Locks: caller holds hostdata lock (not essential)
+ * Print the SCSI bus signals for debugging purposes
*/
static void NCR5380_print(struct Scsi_Host *instance)
{
- NCR5380_local_declare();
unsigned char status, data, basr, mr, icr, i;
- NCR5380_setup(instance);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
@@ -435,117 +341,56 @@ static void NCR5380_print(struct Scsi_Host *instance)
printk("\n");
}
+static struct {
+ unsigned char value;
+ const char *name;
+} phases[] = {
+ {PHASE_DATAOUT, "DATAOUT"},
+ {PHASE_DATAIN, "DATAIN"},
+ {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"},
+ {PHASE_MSGOUT, "MSGOUT"},
+ {PHASE_MSGIN, "MSGIN"},
+ {PHASE_UNKNOWN, "UNKNOWN"}
+};
-/*
- * NCR5380_print_phase - show SCSI phase
- * @instance: adapter to dump
- *
- * Print the current SCSI phase for debugging purposes
+/**
+ * NCR5380_print_phase - show SCSI phase
+ * @instance: adapter to dump
*
- * Locks: none
+ * Print the current SCSI phase for debugging purposes
*/
static void NCR5380_print_phase(struct Scsi_Host *instance)
{
- NCR5380_local_declare();
unsigned char status;
int i;
- NCR5380_setup(instance);
status = NCR5380_read(STATUS_REG);
if (!(status & SR_REQ))
- printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no);
+ shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n");
else {
- for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
- printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i)
+ ;
+ shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name);
}
}
#endif
-/*
- * These need tweaking, and would probably work best as per-device
- * flags initialized differently for disk, tape, cd, etc devices.
- * People with broken devices are free to experiment as to what gives
- * the best results for them.
- *
- * USLEEP_SLEEP should be a minimum seek time.
- *
- * USLEEP_POLL should be a maximum rotational latency.
- */
-#ifndef USLEEP_SLEEP
-/* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP msecs_to_jiffies(20)
-#endif
-/* 300 RPM (floppy speed) */
-#ifndef USLEEP_POLL
-#define USLEEP_POLL msecs_to_jiffies(200)
-#endif
-#ifndef USLEEP_WAITLONG
-/* RvC: (reasonable time to wait on select error) */
-#define USLEEP_WAITLONG USLEEP_SLEEP
-#endif
-/*
- * Function : int should_disconnect (unsigned char cmd)
- *
- * Purpose : decide whether a command would normally disconnect or
- * not, since if it won't disconnect we should go to sleep.
- *
- * Input : cmd - opcode of SCSI command
- *
- * Returns : DISCONNECT_LONG if we should disconnect for a really long
- * time (ie always, sleep, look for REQ active, sleep),
- * DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal
- * time-to-data delay, DISCONNECT_NONE if this command would return
- * immediately.
- *
- * Future sleep algorithms based on time to data can exploit
- * something like this so they can differentiate between "normal"
- * (ie, read, write, seek) and unusual commands (ie, * format).
- *
- * Note : We don't deal with commands that handle an immediate disconnect,
- *
- */
-
-static int should_disconnect(unsigned char cmd)
-{
- switch (cmd) {
- case READ_6:
- case WRITE_6:
- case SEEK_6:
- case READ_10:
- case WRITE_10:
- case SEEK_10:
- return DISCONNECT_TIME_TO_DATA;
- case FORMAT_UNIT:
- case SEARCH_HIGH:
- case SEARCH_LOW:
- case SEARCH_EQUAL:
- return DISCONNECT_LONG;
- default:
- return DISCONNECT_NONE;
- }
-}
-
-static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout)
-{
- hostdata->time_expires = jiffies + timeout;
- schedule_delayed_work(&hostdata->coroutine, timeout);
-}
-
-
-static int probe_irq __initdata = 0;
+static int probe_irq __initdata;
/**
- * probe_intr - helper for IRQ autoprobe
- * @irq: interrupt number
- * @dev_id: unused
- * @regs: unused
+ * probe_intr - helper for IRQ autoprobe
+ * @irq: interrupt number
+ * @dev_id: unused
+ * @regs: unused
*
- * Set a flag to indicate the IRQ in question was received. This is
- * used by the IRQ probe code.
+ * Set a flag to indicate the IRQ in question was received. This is
+ * used by the IRQ probe code.
*/
-
+
static irqreturn_t __init probe_intr(int irq, void *dev_id)
{
probe_irq = irq;
@@ -553,24 +398,20 @@ static irqreturn_t __init probe_intr(int irq, void *dev_id)
}
/**
- * NCR5380_probe_irq - find the IRQ of an NCR5380
- * @instance: NCR5380 controller
- * @possible: bitmask of ISA IRQ lines
- *
- * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
- * and then looking to see what interrupt actually turned up.
+ * NCR5380_probe_irq - find the IRQ of an NCR5380
+ * @instance: NCR5380 controller
+ * @possible: bitmask of ISA IRQ lines
*
- * Locks: none, irqs must be enabled on entry
+ * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
+ * and then looking to see what interrupt actually turned up.
*/
static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
int possible)
{
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned long timeout;
int trying_irqs, i, mask;
- NCR5380_setup(instance);
for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1)
if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
@@ -581,7 +422,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
/*
* A interrupt is triggered whenever BSY = false, SEL = true
- * and a bit set in the SELECT_ENABLE_REG is asserted on the
+ * and a bit set in the SELECT_ENABLE_REG is asserted on the
* SCSI bus.
*
* Note that the bus is only driven when the phase control signals
@@ -596,7 +437,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
while (probe_irq == NO_IRQ && time_before(jiffies, timeout))
schedule_timeout_uninterruptible(1);
-
+
NCR5380_write(SELECT_ENABLE_REG, 0);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -608,12 +449,10 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
}
/**
- * NCR58380_info - report driver and host information
- * @instance: relevant scsi host instance
+ * NCR58380_info - report driver and host information
+ * @instance: relevant scsi host instance
*
- * For use as the host template info() handler.
- *
- * Locks: none
+ * For use as the host template info() handler.
*/
static const char *NCR5380_info(struct Scsi_Host *instance)
@@ -633,20 +472,14 @@ static void prepare_info(struct Scsi_Host *instance)
"can_queue %d, cmd_per_lun %d, "
"sg_tablesize %d, this_id %d, "
"flags { %s%s%s}, "
-#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
- "USLEEP_POLL %lu, USLEEP_WAITLONG %lu, "
-#endif
"options { %s} ",
instance->hostt->name, instance->io_port, instance->n_io_port,
instance->base, instance->irq,
instance->can_queue, instance->cmd_per_lun,
instance->sg_tablesize, instance->this_id,
- hostdata->flags & FLAG_NCR53C400 ? "NCR53C400 " : "",
- hostdata->flags & FLAG_DTC3181E ? "DTC3181E " : "",
+ hostdata->flags & FLAG_NO_DMA_FIXUP ? "NO_DMA_FIXUP " : "",
hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
-#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
- USLEEP_POLL, USLEEP_WAITLONG,
-#endif
+ hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "",
#ifdef AUTOPROBE_IRQ
"AUTOPROBE_IRQ "
#endif
@@ -665,46 +498,10 @@ static void prepare_info(struct Scsi_Host *instance)
#ifdef PSEUDO_DMA
"PSEUDO_DMA "
#endif
-#ifdef UNSAFE
- "UNSAFE "
-#endif
-#ifdef NCR53C400
- "NCR53C400 "
-#endif
"");
}
-/**
- * NCR5380_print_status - dump controller info
- * @instance: controller to dump
- *
- * Print commands in the various queues, called from NCR5380_abort
- * and NCR5380_debug to aid debugging.
- *
- * Locks: called functions disable irqs
- */
-
-static void NCR5380_print_status(struct Scsi_Host *instance)
-{
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
-}
-
#ifdef PSEUDO_DMA
-/******************************************/
-/*
- * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written
- */
-
static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
char *buffer, int length)
{
@@ -714,104 +511,41 @@ static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
hostdata->spin_max_w = 0;
return 0;
}
-#endif
-
-static
-void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m);
-static
-void lprint_command(unsigned char *cmd, struct seq_file *m);
-static
-void lprint_opcode(int opcode, struct seq_file *m);
static int __maybe_unused NCR5380_show_info(struct seq_file *m,
- struct Scsi_Host *instance)
+ struct Scsi_Host *instance)
{
- struct NCR5380_hostdata *hostdata;
- struct scsi_cmnd *ptr;
-
- hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
-#ifdef PSEUDO_DMA
seq_printf(m, "Highwater I/O busy spin counts: write %d, read %d\n",
hostdata->spin_max_w, hostdata->spin_max_r);
-#endif
- spin_lock_irq(instance->host_lock);
- if (!hostdata->connected)
- seq_printf(m, "scsi%d: no currently connected command\n", instance->host_no);
- else
- lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
- seq_printf(m, "scsi%d: issue_queue\n", instance->host_no);
- for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
- lprint_Scsi_Cmnd(ptr, m);
-
- seq_printf(m, "scsi%d: disconnected_queue\n", instance->host_no);
- for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
- lprint_Scsi_Cmnd(ptr, m);
- spin_unlock_irq(instance->host_lock);
return 0;
}
-
-static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
-{
- seq_printf(m, "scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
- seq_puts(m, " command = ");
- lprint_command(cmd->cmnd, m);
-}
-
-static void lprint_command(unsigned char *command, struct seq_file *m)
-{
- int i, s;
- lprint_opcode(command[0], m);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- seq_printf(m, "%02x ", command[i]);
- seq_putc(m, '\n');
-}
-
-static void lprint_opcode(int opcode, struct seq_file *m)
-{
- seq_printf(m, "%2d (0x%02x)", opcode, opcode);
-}
-
+#endif
/**
- * NCR5380_init - initialise an NCR5380
- * @instance: adapter to configure
- * @flags: control flags
- *
- * Initializes *instance and corresponding 5380 chip,
- * with flags OR'd into the initial flags value.
+ * NCR5380_init - initialise an NCR5380
+ * @instance: adapter to configure
+ * @flags: control flags
*
- * Notes : I assume that the host, hostno, and id bits have been
- * set correctly. I don't care about the irq and other fields.
+ * Initializes *instance and corresponding 5380 chip,
+ * with flags OR'd into the initial flags value.
*
- * Returns 0 for success
+ * Notes : I assume that the host, hostno, and id bits have been
+ * set correctly. I don't care about the irq and other fields.
*
- * Locks: interrupts must be enabled when we are called
+ * Returns 0 for success
*/
static int NCR5380_init(struct Scsi_Host *instance, int flags)
{
- NCR5380_local_declare();
- int i, pass;
- unsigned long timeout;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-
- if(in_interrupt())
- printk(KERN_ERR "NCR5380_init called with interrupts off!\n");
- /*
- * On NCR53C400 boards, NCR5380 registers are mapped 8 past
- * the base address.
- */
-
-#ifdef NCR53C400
- if (flags & FLAG_NCR53C400)
- instance->NCR5380_instance_name += NCR53C400_address_adjust;
-#endif
-
- NCR5380_setup(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int i;
+ unsigned long deadline;
- hostdata->aborted = 0;
+ hostdata->host = instance;
hostdata->id_mask = 1 << instance->this_id;
+ hostdata->id_higher_mask = 0;
for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
if (i > hostdata->id_mask)
hostdata->id_higher_mask |= i;
@@ -820,21 +554,21 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
#ifdef REAL_DMA
hostdata->dmalen = 0;
#endif
- hostdata->targets_present = 0;
+ spin_lock_init(&hostdata->lock);
hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
-
- INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main);
-
- /* The CHECK code seems to break the 53C400. Will check it later maybe */
- if (flags & FLAG_NCR53C400)
- hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags;
- else
- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags;
+ hostdata->sensing = NULL;
+ INIT_LIST_HEAD(&hostdata->autosense);
+ INIT_LIST_HEAD(&hostdata->unissued);
+ INIT_LIST_HEAD(&hostdata->disconnected);
- hostdata->host = instance;
- hostdata->time_expires = 0;
+ hostdata->flags = flags;
+
+ INIT_WORK(&hostdata->main_task, NCR5380_main);
+ hostdata->work_q = alloc_workqueue("ncr5380_%d",
+ WQ_UNBOUND | WQ_MEM_RECLAIM,
+ 1, instance->host_no);
+ if (!hostdata->work_q)
+ return -ENOMEM;
prepare_info(instance);
@@ -843,43 +577,69 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
-#ifdef NCR53C400
- if (hostdata->flags & FLAG_NCR53C400) {
- NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
- }
-#endif
+ /* Calibrate register polling loop */
+ i = 0;
+ deadline = jiffies + 1;
+ do {
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ deadline += msecs_to_jiffies(256);
+ do {
+ NCR5380_read(STATUS_REG);
+ ++i;
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ hostdata->accesses_per_ms = i / 256;
- /*
- * Detect and correct bus wedge problems.
- *
- * If the system crashed, it may have crashed in a state
- * where a SCSI command was still executing, and the
- * SCSI bus is not in a BUS FREE STATE.
- *
- * If this is the case, we'll try to abort the currently
- * established nexus which we know nothing about, and that
- * failing, do a hard reset of the SCSI bus
- */
+ return 0;
+}
+
+/**
+ * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
+ * @instance: adapter to check
+ *
+ * If the system crashed, it may have crashed with a connected target and
+ * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
+ * currently established nexus, which we know nothing about. Failing that
+ * do a bus reset.
+ *
+ * Note that a bus reset will cause the chip to assert IRQ.
+ *
+ * Returns 0 if successful, otherwise -ENXIO.
+ */
+
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int pass;
for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
switch (pass) {
case 1:
case 3:
case 5:
- printk(KERN_INFO "scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no);
- timeout = jiffies + 5 * HZ;
- NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, 0, 5*HZ);
+ shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
+ NCR5380_poll_politely(instance,
+ STATUS_REG, SR_BSY, 0, 5 * HZ);
break;
case 2:
- printk(KERN_WARNING "scsi%d: bus busy, attempting abort\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
do_abort(instance);
break;
case 4:
- printk(KERN_WARNING "scsi%d: bus busy, attempting reset\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
do_reset(instance);
+ /* Wait after a reset; the SCSI standard calls for
+ * 250ms, we wait 500ms to be on the safe side.
+ * But some Toshiba CD-ROMs need ten times that.
+ */
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ msleep(2500);
+ else
+ msleep(500);
break;
case 6:
- printk(KERN_ERR "scsi%d: bus locked solid or invalid override\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "bus locked solid\n");
return -ENXIO;
}
}
@@ -887,450 +647,519 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
}
/**
- * NCR5380_exit - remove an NCR5380
- * @instance: adapter to remove
+ * NCR5380_exit - remove an NCR5380
+ * @instance: adapter to remove
+ *
+ * Assumes that no more work can be queued (e.g. by NCR5380_intr).
*/
static void NCR5380_exit(struct Scsi_Host *instance)
{
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
- cancel_delayed_work_sync(&hostdata->coroutine);
+ cancel_work_sync(&hostdata->main_task);
+ destroy_workqueue(hostdata->work_q);
}
/**
- * NCR5380_queue_command - queue a command
- * @cmd: SCSI command
- * @done: completion handler
- *
- * cmd is added to the per instance issue_queue, with minor
- * twiddling done to the host specific fields of cmd. If the
- * main coroutine is not running, it is restarted.
+ * complete_cmd - finish processing a command and return it to the SCSI ML
+ * @instance: the host instance
+ * @cmd: command to complete
+ */
+
+static void complete_cmd(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
+
+ if (hostdata->sensing == cmd) {
+ /* Autosense processing ends here */
+ if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ set_host_byte(cmd, DID_ERROR);
+ } else
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->sensing = NULL;
+ }
+
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
+
+ cmd->scsi_done(cmd);
+}
+
+/**
+ * NCR5380_queue_command - queue a command
+ * @instance: the relevant SCSI adapter
+ * @cmd: SCSI command
*
- * Locks: host lock taken by caller
+ * cmd is added to the per-instance issue queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
+ * main coroutine is not running, it is restarted.
*/
-static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
+static int NCR5380_queue_command(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
{
- struct Scsi_Host *instance = cmd->device->host;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- struct scsi_cmnd *tmp;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+ unsigned long flags;
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
- printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no);
+ shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
cmd->result = (DID_ERROR << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
return 0;
}
-#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
-
- /*
- * We use the host_scribble field as a pointer to the next command
- * in a queue
- */
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
- cmd->host_scribble = NULL;
- cmd->scsi_done = done;
cmd->result = 0;
- /*
- * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
* commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
+ * clear the contingent allegiance condition that exists and the
* sense data is only guaranteed to be valid while the condition exists.
*/
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (struct scsi_cmnd *) tmp->host_scribble);
- LIST(cmd, tmp);
- tmp->host_scribble = (unsigned char *) cmd;
- }
- dprintk(NDEBUG_QUEUES, "scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ list_add(&ncmd->list, &hostdata->unissued);
+ else
+ list_add_tail(&ncmd->list, &hostdata->unissued);
+
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+
+ dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
+ cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
- /* Run the coroutine if it isn't already running. */
/* Kick off command processing */
- schedule_delayed_work(&hostdata->coroutine, 0);
+ queue_work(hostdata->work_q, &hostdata->main_task);
return 0;
}
-static DEF_SCSI_QCMD(NCR5380_queue_command)
+/**
+ * dequeue_next_cmd - dequeue a command for processing
+ * @instance: the scsi host instance
+ *
+ * Priority is given to commands on the autosense queue. These commands
+ * need autosense because of a CHECK CONDITION result.
+ *
+ * Returns a command pointer if a command is found for a target that is
+ * not already busy. Otherwise returns NULL.
+ */
+
+static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *cmd;
+
+ if (hostdata->sensing || list_empty(&hostdata->autosense)) {
+ list_for_each_entry(ncmd, &hostdata->unissued, list) {
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
+ cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
+
+ if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) {
+ list_del(&ncmd->list);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from issue queue\n", cmd);
+ return cmd;
+ }
+ }
+ } else {
+ /* Autosense processing begins here */
+ ncmd = list_first_entry(&hostdata->autosense,
+ struct NCR5380_cmd, list);
+ list_del(&ncmd->list);
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from autosense queue\n", cmd);
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+ hostdata->sensing = cmd;
+ return cmd;
+ }
+ return NULL;
+}
+
+static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
+ if (hostdata->sensing == cmd) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ list_add(&ncmd->list, &hostdata->autosense);
+ hostdata->sensing = NULL;
+ } else
+ list_add(&ncmd->list, &hostdata->unissued);
+}
/**
- * NCR5380_main - NCR state machines
- *
- * NCR5380_main is a coroutine that runs as long as more work can
- * be done on the NCR5380 host adapters in a system. Both
- * NCR5380_queue_command() and NCR5380_intr() will try to start it
- * in case it is not running.
- *
- * Locks: called as its own thread with no locks held. Takes the
- * host lock and called routines may take the isa dma lock.
+ * NCR5380_main - NCR state machines
+ *
+ * NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
*/
static void NCR5380_main(struct work_struct *work)
{
struct NCR5380_hostdata *hostdata =
- container_of(work, struct NCR5380_hostdata, coroutine.work);
+ container_of(work, struct NCR5380_hostdata, main_task);
struct Scsi_Host *instance = hostdata->host;
- struct scsi_cmnd *tmp, *prev;
int done;
-
- spin_lock_irq(instance->host_lock);
+
do {
- /* Lock held here */
done = 1;
- if (!hostdata->connected && !hostdata->selecting) {
- dprintk(NDEBUG_MAIN, "scsi%d : not connected\n", instance->host_no);
- /*
- * Search through the issue_queue for a command destined
- * for a target that's not busy.
- */
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
- {
- if (prev != tmp)
- dprintk(NDEBUG_LISTS, "MAIN tmp=%p target=%d busy=%d lun=%llu\n", tmp, tmp->device->id, hostdata->busy[tmp->device->id], tmp->device->lun);
- /* When we find one, remove it from the issue queue. */
- if (!(hostdata->busy[tmp->device->id] &
- (1 << (u8)(tmp->device->lun & 0xff)))) {
- if (prev) {
- REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
- prev->host_scribble = tmp->host_scribble;
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble);
- hostdata->issue_queue = (struct scsi_cmnd *) tmp->host_scribble;
- }
- tmp->host_scribble = NULL;
- /*
- * Attempt to establish an I_T_L nexus here.
- * On success, instance->hostdata->connected is set.
- * On failure, we must add the command back to the
- * issue queue so we can keep trying.
- */
- dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, "scsi%d : main() : command for target %d lun %llu removed from issue_queue\n", instance->host_no, tmp->device->id, tmp->device->lun);
-
- /*
- * A successful selection is defined as one that
- * leaves us with the command connected and
- * in hostdata->connected, OR has terminated the
- * command.
- *
- * With successful commands, we fall through
- * and see if we can do an information transfer,
- * with failures we will restart.
- */
- hostdata->selecting = NULL;
- /* RvC: have to preset this to indicate a new command is being performed */
+ spin_lock_irq(&hostdata->lock);
+ while (!hostdata->connected && !hostdata->selecting) {
+ struct scsi_cmnd *cmd = dequeue_next_cmd(instance);
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
+ if (!cmd)
+ break;
- if (!NCR5380_select(instance, tmp)) {
- break;
- } else {
- LIST(tmp, hostdata->issue_queue);
- tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = tmp;
- done = 0;
- dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, "scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no);
- }
- /* lock held here still */
- } /* if target/lun is not busy */
- } /* for */
- /* exited locked */
- } /* if (!hostdata->connected) */
- if (hostdata->selecting) {
- tmp = (struct scsi_cmnd *) hostdata->selecting;
- /* Selection will drop and retake the lock */
- if (!NCR5380_select(instance, tmp)) {
- /* Ok ?? */
+ dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+
+ if (!NCR5380_select(instance, cmd)) {
+ dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
} else {
- /* RvC: device failed, so we wait a long time
- this is needed for Mustek scanners, that
- do not respond to commands immediately
- after a scan */
- printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->device->id);
- LIST(tmp, hostdata->issue_queue);
- tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = tmp;
- NCR5380_set_timer(hostdata, USLEEP_WAITLONG);
+ dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
+ "main: select failed, returning %p to queue\n", cmd);
+ requeue_cmd(instance, cmd);
}
- } /* if hostdata->selecting */
+ }
if (hostdata->connected
#ifdef REAL_DMA
&& !hostdata->dmalen
#endif
- && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
) {
- dprintk(NDEBUG_MAIN, "scsi%d : main() : performing information transfer\n", instance->host_no);
+ dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n");
NCR5380_information_transfer(instance);
- dprintk(NDEBUG_MAIN, "scsi%d : main() : done set false\n", instance->host_no);
done = 0;
- } else
- break;
+ }
+ spin_unlock_irq(&hostdata->lock);
+ if (!done)
+ cond_resched();
} while (!done);
-
- spin_unlock_irq(instance->host_lock);
}
#ifndef DONT_USE_INTR
/**
- * NCR5380_intr - generic NCR5380 irq handler
- * @irq: interrupt number
- * @dev_id: device info
- *
- * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- * from the disconnected queue, and restarting NCR5380_main()
- * as required.
- *
- * Locks: takes the needed instance locks
+ * NCR5380_intr - generic NCR5380 irq handler
+ * @irq: interrupt number
+ * @dev_id: device info
+ *
+ * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
+ *
+ * The chip can assert IRQ in any of six different conditions. The IRQ flag
+ * is then cleared by reading the Reset Parity/Interrupt Register (RPIR).
+ * Three of these six conditions are latched in the Bus and Status Register:
+ * - End of DMA (cleared by ending DMA Mode)
+ * - Parity error (cleared by reading RPIR)
+ * - Loss of BSY (cleared by reading RPIR)
+ * Two conditions have flag bits that are not latched:
+ * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode)
+ * - Bus reset (non-maskable)
+ * The remaining condition has no flag bit at all:
+ * - Selection/reselection
+ *
+ * Hence, establishing the cause(s) of any interrupt is partly guesswork.
+ * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor
+ * claimed that "the design of the [DP8490] interrupt logic ensures
+ * interrupts will not be lost (they can be on the DP5380)."
+ * The L5380/53C80 datasheet from LOGIC Devices has more details.
+ *
+ * Checking for bus reset by reading RST is futile because of interrupt
+ * latency, but a bus reset will reset chip logic. Checking for parity error
+ * is unnecessary because that interrupt is never enabled. A Loss of BSY
+ * condition will clear DMA Mode. We can tell when this occurs because the
+ * the Busy Monitor interrupt is enabled together with DMA Mode.
*/
-static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
- NCR5380_local_declare();
struct Scsi_Host *instance = dev_id;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- int done;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int handled = 0;
unsigned char basr;
unsigned long flags;
- dprintk(NDEBUG_INTR, "scsi : NCR5380 irq %d triggered\n",
- instance->irq);
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ if (basr & BASR_IRQ) {
+ unsigned char mr = NCR5380_read(MODE_REG);
+ unsigned char sr = NCR5380_read(STATUS_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
+ irq, basr, sr, mr);
- do {
- done = 1;
- spin_lock_irqsave(instance->host_lock, flags);
- /* Look for pending interrupts */
- NCR5380_setup(instance);
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- /* XXX dispatch to appropriate routine if found and done=0 */
- if (basr & BASR_IRQ) {
- NCR5380_dprint(NDEBUG_INTR, instance);
- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
- done = 0;
- dprintk(NDEBUG_INTR, "scsi%d : SEL interrupt\n", instance->host_no);
- NCR5380_reselect(instance);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if (basr & BASR_PARITY_ERROR) {
- dprintk(NDEBUG_INTR, "scsi%d : PARITY interrupt\n", instance->host_no);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
- dprintk(NDEBUG_INTR, "scsi%d : RESET interrupt\n", instance->host_no);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else {
#if defined(REAL_DMA)
- /*
- * We should only get PHASE MISMATCH and EOP interrupts
- * if we have DMA enabled, so do a sanity check based on
- * the current setting of the MODE register.
- */
+ if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
+ /* Probably End of DMA, Phase Mismatch or Loss of BSY.
+ * We ack IRQ after clearing Mode Register. Workarounds
+ * for End of DMA errata need to happen in DMA Mode.
+ */
- if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) {
- int transferred;
+ dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
- if (!hostdata->connected)
- panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno);
+ int transferred;
- transferred = (hostdata->dmalen - NCR5380_dma_residual(instance));
- hostdata->connected->SCp.this_residual -= transferred;
- hostdata->connected->SCp.ptr += transferred;
- hostdata->dmalen = 0;
+ if (!hostdata->connected)
+ panic("scsi%d : DMA interrupt with no connected cmd\n",
+ instance->hostno);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-
- /* FIXME: we need to poll briefly then defer a workqueue task ! */
- NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2*HZ);
+ transferred = hostdata->dmalen - NCR5380_dma_residual(instance);
+ hostdata->connected->SCp.this_residual -= transferred;
+ hostdata->connected->SCp.ptr += transferred;
+ hostdata->dmalen = 0;
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- }
-#else
- dprintk(NDEBUG_INTR, "scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-#endif
+ /* FIXME: we need to poll briefly then defer a workqueue task ! */
+ NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2 * HZ);
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else
+#endif /* REAL_DMA */
+ if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
+ (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
+ /* Probably reselected */
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n");
+
+ if (!hostdata->connected) {
+ NCR5380_reselect(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
}
- } /* if BASR_IRQ */
- spin_unlock_irqrestore(instance->host_lock, flags);
- if(!done)
- schedule_delayed_work(&hostdata->coroutine, 0);
- } while (!done);
- return IRQ_HANDLED;
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ } else {
+ /* Probably Bus Reset */
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
+ }
+ handled = 1;
+ } else {
+ shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n");
+ }
+
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+
+ return IRQ_RETVAL(handled);
}
-#endif
+#endif
-/*
+/*
* Function : int NCR5380_select(struct Scsi_Host *instance,
- * struct scsi_cmnd *cmd)
+ * struct scsi_cmnd *cmd)
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
- *
- * Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute.
- *
- * Returns : -1 if selection could not execute for some reason,
- * 0 if selection succeeded or failed because the target
- * did not respond.
- *
- * Side effects :
- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
- * with registers as they should have been on entry - ie
- * SELECT_ENABLE will be set appropriately, the NCR5380
- * will cease to drive any SCSI bus signals.
- *
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
- * SELECT interrupt will be disabled.
- *
- * If failed (no target) : cmd->scsi_done() will be called, and the
- * cmd->result host byte set to DID_BAD_TARGET.
- *
- * Locks: caller holds hostdata lock in IRQ mode
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute.
+ *
+ * Returns cmd if selection failed but should be retried,
+ * NULL if selection failed and should not be retried, or
+ * NULL if selection succeeded (hostdata->connected == cmd).
+ *
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
+ *
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
+ *
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
*/
-
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
{
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char tmp[3], phase;
unsigned char *data;
int len;
- unsigned long timeout;
- unsigned char value;
int err;
- NCR5380_setup(instance);
-
- if (hostdata->selecting)
- goto part2;
-
- hostdata->restart_select = 0;
NCR5380_dprint(NDEBUG_ARBITRATION, instance);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id);
+ dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
+ instance->this_id);
- /*
- * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+ /*
+ * Arbitration and selection phases are slow and involve dropping the
+ * lock, so we have to watch out for EH. An exception handler may
+ * change 'selecting' to NULL. This function will then return NULL
+ * so that the caller will forget about 'cmd'. (During information
+ * transfer phases, EH may change 'connected' to NULL.)
+ */
+ hostdata->selecting = cmd;
+
+ /*
+ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
* data bus during SELECTION.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /*
+ /*
* Start arbitration.
*/
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(MODE_REG, MR_ARBITRATE);
+ /* The chip now waits for BUS FREE phase. Then after the 800 ns
+ * Bus Free Delay, arbitration will begin.
+ */
- /* We can be relaxed here, interrupts are on, we are
- in workqueue context, the birds are singing in the trees */
- spin_unlock_irq(instance->host_lock);
- err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ);
- spin_lock_irq(instance->host_lock);
+ spin_unlock_irq(&hostdata->lock);
+ err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0,
+ INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
+ ICR_ARBITRATION_PROGRESS, HZ);
+ spin_lock_irq(&hostdata->lock);
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
+ /* Reselection interrupt */
+ goto out;
+ }
+ if (!hostdata->selecting) {
+ /* Command was aborted */
+ NCR5380_write(MODE_REG, MR_BASE);
+ goto out;
+ }
if (err < 0) {
- printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__);
NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- goto failed;
+ shost_printk(KERN_ERR, instance,
+ "select: arbitration timeout\n");
+ goto out;
}
+ spin_unlock_irq(&hostdata->lock);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : arbitration complete\n", instance->host_no);
-
- /*
- * The arbitration delay is 2.2us, but this is a minimum and there is
- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
- * the integral nature of udelay().
- *
- */
-
+ /* The SCSI-2 arbitration delay is 2.4 us */
udelay(3);
/* Check for lost arbitration */
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
- NCR5380_write(MODE_REG, MR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no);
- goto failed;
- }
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
-
- if (!(hostdata->flags & FLAG_DTC3181E) &&
- /* RvC: DTC3181E has some trouble with this
- * so we simply removed it. Seems to work with
- * only Mustek scanner attached
- */
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no);
- goto failed;
+ dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n");
+ spin_lock_irq(&hostdata->lock);
+ goto out;
}
- /*
- * Again, bus clear + bus settle time is 1.2us, however, this is
+
+ /* After/during arbitration, BSY should be asserted.
+ * IBM DPES-31080 Version S31Q works now
+ * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman)
+ */
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
+
+ /*
+ * Again, bus clear + bus settle time is 1.2us, however, this is
* a minimum so we'll udelay ceil(1.2)
*/
- udelay(2);
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ udelay(15);
+ else
+ udelay(2);
+
+ spin_lock_irq(&hostdata->lock);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : won arbitration\n", instance->host_no);
+ /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
+ goto out;
+
+ if (!hostdata->selecting) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ goto out;
+ }
- /*
- * Now that we have won arbitration, start Selection process, asserting
+ dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
+
+ /*
+ * Now that we have won arbitration, start Selection process, asserting
* the host and target ID's on the SCSI bus.
*/
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << scmd_id(cmd))));
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd)));
- /*
+ /*
* Raise ATN while SEL is true before BSY goes false from arbitration,
* since this is the only way to guarantee that we'll get a MESSAGE OUT
* phase immediately after selection.
*/
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL);
NCR5380_write(MODE_REG, MR_BASE);
- /*
+ /*
* Reselect interrupts must be turned off prior to the dropping of BSY,
* otherwise we will trigger an interrupt.
*/
NCR5380_write(SELECT_ENABLE_REG, 0);
+ spin_unlock_irq(&hostdata->lock);
+
/*
- * The initiator shall then wait at least two deskew delays and release
+ * The initiator shall then wait at least two deskew delays and release
* the BSY signal.
*/
- udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
/* Reset BSY */
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL);
- /*
+ /*
* Something weird happens when we cease to drive BSY - looks
- * like the board/chip is letting us do another read before the
+ * like the board/chip is letting us do another read before the
* appropriate propagation delay has expired, and we're confusing
* a BSY signal from ourselves as the target's response to SELECTION.
*
* A small delay (the 'C++' frontend breaks the pipeline with an
* unnecessary jump, making it work on my 386-33/Trantor T128, the
- * tighter 'C' code breaks and requires this) solves the problem -
- * the 1 us delay is arbitrary, and only used because this delay will
- * be the same on other platforms and since it works here, it should
+ * tighter 'C' code breaks and requires this) solves the problem -
+ * the 1 us delay is arbitrary, and only used because this delay will
+ * be the same on other platforms and since it works here, it should
* work there.
*
* wingel suggests that this could be due to failing to wait
@@ -1339,50 +1168,43 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
udelay(1);
- dprintk(NDEBUG_SELECTION, "scsi%d : selecting target %d\n", instance->host_no, scmd_id(cmd));
+ dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd));
- /*
- * The SCSI specification calls for a 250 ms timeout for the actual
+ /*
+ * The SCSI specification calls for a 250 ms timeout for the actual
* selection.
*/
- timeout = jiffies + msecs_to_jiffies(250);
-
- /*
- * XXX very interesting - we're seeing a bounce where the BSY we
- * asserted is being reflected / still asserted (propagation delay?)
- * and it's detecting as true. Sigh.
- */
-
- hostdata->select_time = 0; /* we count the clock ticks at which we polled */
- hostdata->selecting = cmd;
+ err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY,
+ msecs_to_jiffies(250));
-part2:
- /* RvC: here we enter after a sleeping period, or immediately after
- execution of part 1
- we poll only once ech clock tick */
- value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO);
-
- if (!value && (hostdata->select_time < HZ/4)) {
- /* RvC: we still must wait for a device response */
- hostdata->select_time++; /* after 25 ticks the device has failed */
- NCR5380_set_timer(hostdata, 1);
- return 0; /* RvC: we return here with hostdata->selecting set,
- to go to sleep */
- }
-
- hostdata->selecting = NULL;/* clear this pointer, because we passed the
- waiting period */
if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+ spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_reselect(instance);
- printk("scsi%d : reselection after won arbitration?\n", instance->host_no);
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
+ goto out;
+ }
+
+ if (err < 0) {
+ spin_lock_irq(&hostdata->lock);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
+ /* Can't touch cmd if it has been reclaimed by the scsi ML */
+ if (hostdata->selecting) {
+ cmd->result = DID_BAD_TARGET << 16;
+ complete_cmd(instance, cmd);
+ dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
+ cmd = NULL;
+ }
+ goto out;
}
- /*
- * No less than two deskew delays after the initiator detects the
- * BSY signal is true, it shall release the SEL signal and may
+
+ /*
+ * No less than two deskew delays after the initiator detects the
+ * BSY signal is true, it shall release the SEL signal and may
* change the DATA BUS. -wingel
*/
@@ -1390,53 +1212,38 @@ part2:
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << scmd_id(cmd))) {
- printk(KERN_DEBUG "scsi%d : weirdness\n", instance->host_no);
- if (hostdata->restart_select)
- printk(KERN_DEBUG "\trestart select\n");
- NCR5380_dprint(NDEBUG_SELECTION, instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- cmd->result = DID_BAD_TARGET << 16;
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- dprintk(NDEBUG_SELECTION, "scsi%d : target did not respond within 250ms\n", instance->host_no);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return 0;
- }
- hostdata->targets_present |= (1 << scmd_id(cmd));
-
/*
- * Since we followed the SCSI spec, and raised ATN while SEL
+ * Since we followed the SCSI spec, and raised ATN while SEL
* was true but before BSY was false during selection, the information
* transfer phase should be a MESSAGE OUT phase so that we can send the
* IDENTIFY message.
- *
+ *
* If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
* message (2 bytes) with a tag ID that we increment with every command
* until it wraps back to 0.
*
* XXX - it turns out that there are some broken SCSI-II devices,
- * which claim to support tagged queuing but fail when more than
- * some number of commands are issued at once.
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
*/
/* Wait for start of REQ/ACK handshake */
- spin_unlock_irq(instance->host_lock);
err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
- spin_lock_irq(instance->host_lock);
-
- if(err) {
- printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
+ spin_lock_irq(&hostdata->lock);
+ if (err < 0) {
+ shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- goto failed;
+ goto out;
+ }
+ if (!hostdata->selecting) {
+ do_abort(instance);
+ goto out;
}
- dprintk(NDEBUG_SELECTION, "scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id);
+ dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
+ scmd_id(cmd));
tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);
len = 1;
@@ -1446,104 +1253,82 @@ part2:
data = tmp;
phase = PHASE_MSGOUT;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_SELECTION, "scsi%d : nexus established.\n", instance->host_no);
+ dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
/* XXX need to handle errors here */
+
hostdata->connected = cmd;
- hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF));
+ hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
initialize_SCp(cmd);
- return 0;
-
- /* Selection failed */
-failed:
- return -1;
+ cmd = NULL;
+out:
+ if (!hostdata->selecting)
+ return NULL;
+ hostdata->selecting = NULL;
+ return cmd;
}
-/*
- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using polled I/O
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
- *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
* Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes or transferred or exit
- * is in same phase.
+ * maximum number of bytes, 0 if all bytes are transferred or exit
+ * is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
* XXX Note : handling for bus free may be useful.
*/
/*
- * Note : this code is not as quick as it could be, however it
+ * Note : this code is not as quick as it could be, however it
* IS 100% reliable, and for the actual data transfer where speed
* counts, we will always do a pseudo DMA or DMA transfer.
*/
-static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
- NCR5380_local_declare();
+static int NCR5380_transfer_pio(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
unsigned char p = *phase, tmp;
int c = *count;
unsigned char *d = *data;
- /*
- * RvC: some administrative data to process polling time
- */
- int break_allowed = 0;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- NCR5380_setup(instance);
- if (!(p & SR_IO))
- dprintk(NDEBUG_PIO, "scsi%d : pio write %d bytes\n", instance->host_no, c);
- else
- dprintk(NDEBUG_PIO, "scsi%d : pio read %d bytes\n", instance->host_no, c);
-
- /*
- * The NCR5380 chip will only drive the SCSI bus when the
+ /*
+ * The NCR5380 chip will only drive the SCSI bus when the
* phase specified in the appropriate bits of the TARGET COMMAND
* REGISTER match the STATUS REGISTER
*/
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
- /* RvC: don't know if this is necessary, but other SCSI I/O is short
- * so breaks are not necessary there
- */
- if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) {
- break_allowed = 1;
- }
do {
- /*
- * Wait for assertion of REQ, after which the phase bits will be
- * valid
- */
-
- /* RvC: we simply poll once, after that we stop temporarily
- * and let the device buffer fill up
- * if breaking is not allowed, we keep polling as long as needed
+ /*
+ * Wait for assertion of REQ, after which the phase bits will be
+ * valid
*/
- /* FIXME */
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed);
- if (!(tmp & SR_REQ)) {
- /* timeout condition */
- NCR5380_set_timer(hostdata, USLEEP_SLEEP);
+ if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
break;
- }
- dprintk(NDEBUG_HANDSHAKE, "scsi%d : REQ detected\n", instance->host_no);
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
/* Check for phase mismatch */
- if ((tmp & PHASE_MASK) != p) {
- dprintk(NDEBUG_HANDSHAKE, "scsi%d : phase mismatch\n", instance->host_no);
- NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance);
+ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
+ dsprintk(NDEBUG_PIO, instance, "phase mismatch\n");
+ NCR5380_dprint_phase(NDEBUG_PIO, instance);
break;
}
+
/* Do actual transfer from SCSI bus to / from memory */
if (!(p & SR_IO))
NCR5380_write(OUTPUT_DATA_REG, *d);
@@ -1552,7 +1337,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
++d;
- /*
+ /*
* The SCSI standard suggests that in MSGOUT phase, the initiator
* should drop ATN on the last byte of the message phase
* after REQ has been asserted for the handshake but before
@@ -1563,29 +1348,34 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
if (!((p & SR_MSG) && c > 1)) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
} else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
}
} else {
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
}
- /* FIXME - if this fails bus reset ?? */
- NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 5*HZ);
- dprintk(NDEBUG_HANDSHAKE, "scsi%d : req false, handshake complete\n", instance->host_no);
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
+ break;
+
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
/*
- * We have several special cases to consider during REQ/ACK handshaking :
- * 1. We were in MSGOUT phase, and we are on the last byte of the
- * message. ATN must be dropped as ACK is dropped.
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
*
- * 2. We are in a MSGIN phase, and we are on the last byte of the
- * message. We must exit with ACK asserted, so that the calling
- * code may raise ATN before dropping ACK to reject the message.
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
*
* 3. ACK and ATN are clear and the target may proceed as normal.
*/
@@ -1597,12 +1387,16 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
}
} while (--c);
- dprintk(NDEBUG_PIO, "scsi%d : residual %d\n", instance->host_no, c);
+ dsprintk(NDEBUG_PIO, instance, "residual %d\n", c);
*count = c;
*data = d;
tmp = NCR5380_read(STATUS_REG);
- if (tmp & SR_REQ)
+ /* The phase read from the bus is valid if either REQ is (already)
+ * asserted or if ACK hasn't been released yet. The latter applies if
+ * we're in MSG IN, DATA IN or STATUS and all bytes have been received.
+ */
+ if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
*phase = tmp & PHASE_MASK;
else
*phase = PHASE_UNKNOWN;
@@ -1614,79 +1408,80 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
}
/**
- * do_reset - issue a reset command
- * @host: adapter to reset
+ * do_reset - issue a reset command
+ * @instance: adapter to reset
*
- * Issue a reset sequence to the NCR5380 and try and get the bus
- * back into sane shape.
+ * Issue a reset sequence to the NCR5380 and try and get the bus
+ * back into sane shape.
*
- * Locks: caller holds queue lock
+ * This clears the reset interrupt flag because there may be no handler for
+ * it. When the driver is initialized, the NCR5380_intr() handler has not yet
+ * been installed. And when in EH we may have released the ST DMA interrupt.
*/
-
-static void do_reset(struct Scsi_Host *host) {
- NCR5380_local_declare();
- NCR5380_setup(host);
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+static void do_reset(struct Scsi_Host *instance)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
- udelay(25);
+ udelay(50);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ local_irq_restore(flags);
}
-/*
- * Function : do_abort (Scsi_Host *host)
- *
- * Purpose : abort the currently established nexus. Should only be
- * called from a routine which can drop into a
- *
- * Returns : 0 on success, -1 on failure.
- *
- * Locks: queue lock held by caller
- * FIXME: sort this out and get new_eh running
+/**
+ * do_abort - abort the currently established nexus by going to
+ * MESSAGE OUT phase and sending an ABORT message.
+ * @instance: relevant scsi host instance
+ *
+ * Returns 0 on success, -1 on failure.
*/
-static int do_abort(struct Scsi_Host *host) {
- NCR5380_local_declare();
+static int do_abort(struct Scsi_Host *instance)
+{
unsigned char *msgptr, phase, tmp;
int len;
int rc;
- NCR5380_setup(host);
-
/* Request message out phase */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- /*
- * Wait for the target to indicate a valid phase by asserting
- * REQ. Once this happens, we'll have either a MSGOUT phase
- * and can immediately send the ABORT message, or we'll have some
+ /*
+ * Wait for the target to indicate a valid phase by asserting
+ * REQ. Once this happens, we'll have either a MSGOUT phase
+ * and can immediately send the ABORT message, or we'll have some
* other phase and will have to source/sink data.
- *
+ *
* We really don't care what value was on the bus or what value
* the target sees, so we just handshake.
*/
- rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, SR_REQ, 60 * HZ);
-
- if(rc < 0)
- return -1;
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
+ if (rc < 0)
+ goto timeout;
+
+ tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
- tmp = (unsigned char)rc;
-
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, 0, 3*HZ);
+ if (tmp != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ);
+ if (rc < 0)
+ goto timeout;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if(rc == -1)
- return -1;
}
+
tmp = ABORT;
msgptr = &tmp;
len = 1;
phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+ NCR5380_transfer_pio(instance, &phase, &len, &msgptr);
/*
* If we got here, and the command completed successfully,
@@ -1694,32 +1489,37 @@ static int do_abort(struct Scsi_Host *host) {
*/
return len ? -1 : 0;
+
+timeout:
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
}
#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)
-/*
- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using either real
- * or pseudo DMA.
+ * or pseudo DMA.
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
- *
- * Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes or transferred or exit
- * is in same phase.
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
*
- * Also, *phase, *count, *data are modified in place.
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes or transferred or exit
+ * is in same phase.
*
- * Locks: io_request lock held by caller
+ * Also, *phase, *count, *data are modified in place.
*/
-static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
- NCR5380_local_declare();
+static int NCR5380_transfer_dma(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
register int c = *count;
register unsigned char p = *phase;
register unsigned char *d = *data;
@@ -1730,54 +1530,47 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
unsigned char saved_data = 0, overrun = 0, residue;
#endif
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-
- NCR5380_setup(instance);
-
if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
*phase = tmp;
return -1;
}
#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
-#ifdef READ_OVERRUNS
if (p & SR_IO) {
- c -= 2;
+ if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS))
+ c -= 2;
}
-#endif
- dprintk(NDEBUG_DMA, "scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c);
+
+ dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+ (p & SR_IO) ? "receive" : "send", c, *data);
#endif
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
#ifdef REAL_DMA
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
#elif defined(REAL_DMA_POLL)
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
#else
/*
* Note : on my sample board, watch-dog timeouts occurred when interrupts
- * were not disabled for the duration of a single DMA transfer, from
+ * were not disabled for the duration of a single DMA transfer, from
* before the setting of DMA mode to after transfer of the last byte.
*/
-#if defined(PSEUDO_DMA) && defined(UNSAFE)
- spin_unlock_irq(instance->host_lock);
-#endif
- /* KLL May need eop and parity in 53c400 */
- if (hostdata->flags & FLAG_NCR53C400)
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE |
- MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR |
- MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+ if (hostdata->flags & FLAG_NO_DMA_FIXUP)
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
else
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
#endif /* def REAL_DMA */
dprintk(NDEBUG_DMA, "scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
- /*
- * On the PAS16 at least I/O recovery delays are not needed here.
- * Everyone else seems to want them.
+ /*
+ * On the PAS16 at least I/O recovery delays are not needed here.
+ * Everyone else seems to want them.
*/
if (p & SR_IO) {
@@ -1797,49 +1590,49 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER)));
/*
- At this point, either we've completed DMA, or we have a phase mismatch,
- or we've unexpectedly lost BUSY (which is a real error).
-
- For write DMAs, we want to wait until the last byte has been
- transferred out over the bus before we turn off DMA mode. Alas, there
- seems to be no terribly good way of doing this on a 5380 under all
- conditions. For non-scatter-gather operations, we can wait until REQ
- and ACK both go false, or until a phase mismatch occurs. Gather-writes
- are nastier, since the device will be expecting more data than we
- are prepared to send it, and REQ will remain asserted. On a 53C8[01] we
- could test LAST BIT SENT to assure transfer (I imagine this is precisely
- why this signal was added to the newer chips) but on the older 538[01]
- this signal does not exist. The workaround for this lack is a watchdog;
- we bail out of the wait-loop after a modest amount of wait-time if
- the usual exit conditions are not met. Not a terribly clean or
- correct solution :-%
-
- Reads are equally tricky due to a nasty characteristic of the NCR5380.
- If the chip is in DMA mode for an READ, it will respond to a target's
- REQ by latching the SCSI data into the INPUT DATA register and asserting
- ACK, even if it has _already_ been notified by the DMA controller that
- the current DMA transfer has completed! If the NCR5380 is then taken
- out of DMA mode, this already-acknowledged byte is lost.
-
- This is not a problem for "one DMA transfer per command" reads, because
- the situation will never arise... either all of the data is DMA'ed
- properly, or the target switches to MESSAGE IN phase to signal a
- disconnection (either operation bringing the DMA to a clean halt).
- However, in order to handle scatter-reads, we must work around the
- problem. The chosen fix is to DMA N-2 bytes, then check for the
- condition before taking the NCR5380 out of DMA mode. One or two extra
- bytes are transferred via PIO as necessary to fill out the original
- request.
+ * At this point, either we've completed DMA, or we have a phase mismatch,
+ * or we've unexpectedly lost BUSY (which is a real error).
+ *
+ * For DMA sends, we want to wait until the last byte has been
+ * transferred out over the bus before we turn off DMA mode. Alas, there
+ * seems to be no terribly good way of doing this on a 5380 under all
+ * conditions. For non-scatter-gather operations, we can wait until REQ
+ * and ACK both go false, or until a phase mismatch occurs. Gather-sends
+ * are nastier, since the device will be expecting more data than we
+ * are prepared to send it, and REQ will remain asserted. On a 53C8[01] we
+ * could test Last Byte Sent to assure transfer (I imagine this is precisely
+ * why this signal was added to the newer chips) but on the older 538[01]
+ * this signal does not exist. The workaround for this lack is a watchdog;
+ * we bail out of the wait-loop after a modest amount of wait-time if
+ * the usual exit conditions are not met. Not a terribly clean or
+ * correct solution :-%
+ *
+ * DMA receive is equally tricky due to a nasty characteristic of the NCR5380.
+ * If the chip is in DMA receive mode, it will respond to a target's
+ * REQ by latching the SCSI data into the INPUT DATA register and asserting
+ * ACK, even if it has _already_ been notified by the DMA controller that
+ * the current DMA transfer has completed! If the NCR5380 is then taken
+ * out of DMA mode, this already-acknowledged byte is lost. This is
+ * not a problem for "one DMA transfer per READ command", because
+ * the situation will never arise... either all of the data is DMA'ed
+ * properly, or the target switches to MESSAGE IN phase to signal a
+ * disconnection (either operation bringing the DMA to a clean halt).
+ * However, in order to handle scatter-receive, we must work around the
+ * problem. The chosen fix is to DMA N-2 bytes, then check for the
+ * condition before taking the NCR5380 out of DMA mode. One or two extra
+ * bytes are transferred via PIO as necessary to fill out the original
+ * request.
*/
if (p & SR_IO) {
-#ifdef READ_OVERRUNS
- udelay(10);
- if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) {
- saved_data = NCR5380_read(INPUT_DATA_REGISTER);
- overrun = 1;
+ if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) {
+ udelay(10);
+ if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) ==
+ (BASR_PHASE_MATCH | BASR_ACK)) {
+ saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+ overrun = 1;
+ }
}
-#endif
} else {
int limit = 100;
while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) {
@@ -1850,7 +1643,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
}
}
- dprintk(NDEBUG_DMA, "scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG));
+ dsprintk(NDEBUG_DMA, "polled DMA transfer complete, basr 0x%02x, sr 0x%02x\n",
+ tmp, NCR5380_read(STATUS_REG));
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1861,8 +1655,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
*data += c;
*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
-#ifdef READ_OVERRUNS
- if (*phase == p && (p & SR_IO) && residue == 0) {
+ if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS) &&
+ *phase == p && (p & SR_IO) && residue == 0) {
if (overrun) {
dprintk(NDEBUG_DMA, "Got an input overrun, using saved byte\n");
**data = saved_data;
@@ -1877,7 +1671,6 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
NCR5380_transfer_pio(instance, phase, &cnt, data);
*count -= toPIO - cnt;
}
-#endif
dprintk(NDEBUG_DMA, "Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count));
return 0;
@@ -1886,95 +1679,64 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
return 0;
#else /* defined(REAL_DMA_POLL) */
if (p & SR_IO) {
-#ifdef DMA_WORKS_RIGHT
- foo = NCR5380_pread(instance, d, c);
-#else
- int diff = 1;
- if (hostdata->flags & FLAG_NCR53C400) {
- diff = 0;
- }
- if (!(foo = NCR5380_pread(instance, d, c - diff))) {
+ foo = NCR5380_pread(instance, d,
+ hostdata->flags & FLAG_NO_DMA_FIXUP ? c : c - 1);
+ if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
/*
- * We can't disable DMA mode after successfully transferring
+ * We can't disable DMA mode after successfully transferring
* what we plan to be the last byte, since that would open up
- * a race condition where if the target asserted REQ before
+ * a race condition where if the target asserted REQ before
* we got the DMA mode reset, the NCR5380 would have latched
* an additional byte into the INPUT DATA register and we'd
* have dropped it.
- *
- * The workaround was to transfer one fewer bytes than we
- * intended to with the pseudo-DMA read function, wait for
+ *
+ * The workaround was to transfer one fewer bytes than we
+ * intended to with the pseudo-DMA read function, wait for
* the chip to latch the last byte, read it, and then disable
* pseudo-DMA mode.
- *
+ *
* After REQ is asserted, the NCR5380 asserts DRQ and ACK.
* REQ is deasserted when ACK is asserted, and not reasserted
* until ACK goes false. Since the NCR5380 won't lower ACK
* until DACK is asserted, which won't happen unless we twiddle
- * the DMA port or we take the NCR5380 out of DMA mode, we
- * can guarantee that we won't handshake another extra
+ * the DMA port or we take the NCR5380 out of DMA mode, we
+ * can guarantee that we won't handshake another extra
* byte.
*/
- if (!(hostdata->flags & FLAG_NCR53C400)) {
- while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
- /* Wait for clean handshake */
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+ if (NCR5380_poll_politely(instance, BUS_AND_STATUS_REG,
+ BASR_DRQ, BASR_DRQ, HZ) < 0) {
+ foo = -1;
+ shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
}
+ if (NCR5380_poll_politely(instance, STATUS_REG,
+ SR_REQ, 0, HZ) < 0) {
+ foo = -1;
+ shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
+ }
+ d[c - 1] = NCR5380_read(INPUT_DATA_REG);
}
-#endif
} else {
-#ifdef DMA_WORKS_RIGHT
foo = NCR5380_pwrite(instance, d, c);
-#else
- int timeout;
- dprintk(NDEBUG_C400_PWRITE, "About to pwrite %d bytes\n", c);
- if (!(foo = NCR5380_pwrite(instance, d, c))) {
+ if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
/*
- * Wait for the last byte to be sent. If REQ is being asserted for
- * the byte we're interested, we'll ACK it and it will go false.
+ * Wait for the last byte to be sent. If REQ is being asserted for
+ * the byte we're interested, we'll ACK it and it will go false.
*/
- if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
- timeout = 20000;
- while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH));
-
- if (!timeout)
- dprintk(NDEBUG_LAST_BYTE_SENT, "scsi%d : timed out on last byte\n", instance->host_no);
-
- if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
- hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
- if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
- hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
- dprintk(NDEBUG_LAST_BYTE_SENT, "scsi%d : last byte sent works\n", instance->host_no);
- }
- }
- } else {
- dprintk(NDEBUG_C400_PWRITE, "Waiting for LASTBYTE\n");
- while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
- dprintk(NDEBUG_C400_PWRITE, "Got LASTBYTE\n");
+ if (NCR5380_poll_politely2(instance,
+ BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,
+ BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) {
+ foo = -1;
+ shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
}
}
-#endif
}
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) {
- dprintk(NDEBUG_C400_PWRITE, "53C400w: Checking for IRQ\n");
- if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
- dprintk(NDEBUG_C400_PWRITE, "53C400w: got it, reading reset interrupt reg\n");
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else {
- printk("53C400w: IRQ NOT THERE!\n");
- }
- }
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
*data = d + c;
*count = 0;
*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
-#if defined(PSEUDO_DMA) && defined(UNSAFE)
- spin_lock_irq(instance->host_lock);
-#endif /* defined(REAL_DMA_POLL) */
return foo;
#endif /* def REAL_DMA */
}
@@ -1983,40 +1745,34 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
/*
* Function : NCR5380_information_transfer (struct Scsi_Host *instance)
*
- * Purpose : run through the various SCSI phases and do as the target
- * directs us to. Operates on the currently connected command,
- * instance->connected.
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to. Operates on the currently connected command,
+ * instance->connected.
*
* Inputs : instance, instance for which we are doing commands
*
- * Side effects : SCSI things happen, the disconnected queue will be
- * modified if a command disconnects, *instance->connected will
- * change.
+ * Side effects : SCSI things happen, the disconnected queue will be
+ * modified if a command disconnects, *instance->connected will
+ * change.
*
- * XXX Note : we need to watch for bus free or a reset condition here
- * to recover from an unexpected bus free condition.
- *
- * Locks: io_request_lock held by caller in IRQ mode
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
*/
-static void NCR5380_information_transfer(struct Scsi_Host *instance) {
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+static void NCR5380_information_transfer(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char msgout = NOP;
int sink = 0;
int len;
-#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
int transfersize;
-#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
- struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
- /* RvC: we need to set the end of the polling time */
- unsigned long poll_time = jiffies + USLEEP_POLL;
+ struct scsi_cmnd *cmd;
- NCR5380_setup(instance);
+ while ((cmd = hostdata->connected)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
- while (1) {
tmp = NCR5380_read(STATUS_REG);
/* We only have a valid SCSI phase when REQ is asserted */
if (tmp & SR_REQ) {
@@ -2028,24 +1784,29 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
if (sink && (phase != PHASE_MSGOUT)) {
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
sink = 0;
continue;
}
+
switch (phase) {
- case PHASE_DATAIN:
case PHASE_DATAOUT:
#if (NDEBUG & NDEBUG_NO_DATAOUT)
- printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no);
+ shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
+ hostdata->connected = NULL;
return;
#endif
- /*
+ case PHASE_DATAIN:
+ /*
* If there is no room left in the current buffer in the
* scatter-gather list, move onto the next one.
*/
@@ -2055,10 +1816,13 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- dprintk(NDEBUG_INFORMATION, "scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual);
+ dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
+ cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
}
+
/*
- * The preferred transfer method is going to be
+ * The preferred transfer method is going to be
* PSEUDO-DMA for systems that are strictly PIO,
* since we can let the hardware do the handshaking.
*
@@ -2068,51 +1832,43 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
*/
#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
- /* KLL
- * PSEUDO_DMA is defined here. If this is the g_NCR5380
- * driver then it will always be defined, so the
- * FLAG_NO_PSEUDO_DMA is used to inhibit PDMA in the base
- * NCR5380 case. I think this is a fairly clean solution.
- * We supplement these 2 if's with the flag.
- */
-#ifdef NCR5380_dma_xfer_len
- if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
-#else
- transfersize = cmd->transfersize;
-
-#ifdef LIMIT_TRANSFERSIZE /* If we have problems with interrupt service */
- if (transfersize > 512)
- transfersize = 512;
-#endif /* LIMIT_TRANSFERSIZE */
-
- if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) {
- /* Limit transfers to 32K, for xx400 & xx406
- * pseudoDMA that transfers in 128 bytes blocks. */
- if (transfersize > 32 * 1024)
- transfersize = 32 * 1024;
-#endif
+ transfersize = 0;
+ if (!cmd->device->borken &&
+ !(hostdata->flags & FLAG_NO_PSEUDO_DMA))
+ transfersize = NCR5380_dma_xfer_len(instance, cmd, phase);
+
+ if (transfersize) {
len = transfersize;
- if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) {
+ if (NCR5380_transfer_dma(instance, &phase,
+ &len, (unsigned char **)&cmd->SCp.ptr)) {
/*
- * If the watchdog timer fires, all future accesses to this
- * device will use the polled-IO.
+ * If the watchdog timer fires, all future
+ * accesses to this device will use the
+ * polled-IO.
*/
scmd_printk(KERN_INFO, cmd,
- "switching to slow handshake\n");
+ "switching to slow handshake\n");
cmd->device->borken = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else
cmd->SCp.this_residual -= transfersize - len;
} else
#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
- NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **)
- &cmd->SCp.ptr);
- break;
+ {
+ /* Break up transfer into 3 ms chunks,
+ * presuming 6 accesses per handshake.
+ */
+ transfersize = min((unsigned long)cmd->SCp.this_residual,
+ hostdata->accesses_per_ms / 2);
+ len = transfersize;
+ NCR5380_transfer_pio(instance, &phase, &len,
+ (unsigned char **)&cmd->SCp.ptr);
+ cmd->SCp.this_residual -= transfersize - len;
+ }
+ return;
case PHASE_MSGIN:
len = 1;
data = &tmp;
@@ -2120,101 +1876,42 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
cmd->SCp.Message = tmp;
switch (tmp) {
- /*
- * Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- *
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands.
- */
-#ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked command complete.\n", instance->host_no, cmd->device->id, cmd->device->lun);
- /*
- * Sanity check : A linked command should only terminate with
- * one of these messages if there are more linked commands
- * available.
- */
- if (!cmd->next_link) {
- printk("scsi%d : target %d lun %llu linked command complete, no next_link\n" instance->host_no, cmd->device->id, cmd->device->lun);
- sink = 1;
- do_abort(instance);
- return;
- }
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked request done, calling scsi_done().\n", instance->host_no, cmd->device->id, cmd->device->lun);
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
-#endif /* def LINKED */
case ABORT:
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
sink = 1;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- hostdata->connected = NULL;
- dprintk(NDEBUG_QUEUES, "scsi%d : command for target %d, lun %llu completed\n", instance->host_no, cmd->device->id, cmd->device->lun);
- hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
-
- /*
- * I'm not sure what the correct thing to do here is :
- *
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- *
- * If it was a REQUEST SENSE command, we need some way
- * to differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the result
- * code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed
- */
-
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (status_byte(cmd->SCp.Status) != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "COMMAND COMPLETE %p target %d lun %llu\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
- if ((cmd->cmnd[0] == REQUEST_SENSE) &&
- hostdata->ses.cmd_len) {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- hostdata->ses.cmd_len = 0 ;
- }
-
- if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
- scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
-
- dprintk(NDEBUG_AUTOSENSE, "scsi%d : performing request sense\n", instance->host_no);
+ hostdata->connected = NULL;
- LIST(cmd, hostdata->issue_queue);
- cmd->host_scribble = (unsigned char *)
- hostdata->issue_queue;
- hostdata->issue_queue = (struct scsi_cmnd *) cmd;
- dprintk(NDEBUG_QUEUES, "scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no);
- } else {
- cmd->scsi_done(cmd);
+ cmd->result &= ~0xffff;
+ cmd->result |= cmd->SCp.Status;
+ cmd->result |= cmd->SCp.Message << 8;
+
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ complete_cmd(instance, cmd);
+ else {
+ if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION ||
+ cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) {
+ dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
+ cmd);
+ list_add_tail(&ncmd->list,
+ &hostdata->autosense);
+ } else
+ complete_cmd(instance, cmd);
}
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Restore phase bits to 0 so an interrupted selection,
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
@@ -2229,38 +1926,33 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
default:
break;
}
- case DISCONNECT:{
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- cmd->device->disconnect = 1;
- LIST(cmd, hostdata->disconnected_queue);
- cmd->host_scribble = (unsigned char *)
- hostdata->disconnected_queue;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = cmd;
- dprintk(NDEBUG_QUEUES, "scsi%d : command for target %d lun %llu was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->device->id, cmd->device->lun);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /* Wait for bus free to avoid nasty timeouts - FIXME timeout !*/
- /* NCR538_poll_politely(instance, STATUS_REG, SR_BSY, 0, 30 * HZ); */
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
- return;
- }
- /*
+ break;
+ case DISCONNECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ hostdata->connected = NULL;
+ list_add(&ncmd->list, &hostdata->disconnected);
+ dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
+ instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
+
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return;
+ /*
* The SCSI data pointer is *IMPLICITLY* saved on a disconnect
- * operation, in violation of the SCSI spec so we can safely
+ * operation, in violation of the SCSI spec so we can safely
* ignore SAVE/RESTORE pointers calls.
*
- * Unfortunately, some disks violate the SCSI spec and
+ * Unfortunately, some disks violate the SCSI spec and
* don't issue the required SAVE_POINTERS message before
- * disconnecting, and we have to break spec to remain
+ * disconnecting, and we have to break spec to remain
* compatible.
*/
case SAVE_POINTERS:
@@ -2269,31 +1961,28 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
break;
case EXTENDED_MESSAGE:
-/*
- * Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't
- * include first two bytes)
- * 2 code
- * 3..length+1 arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since spi_print_msg() wants the whole thing.
- */
+ /*
+ * Start the message buffer with the EXTENDED_MESSAGE
+ * byte, since spi_print_msg() wants the whole thing.
+ */
extended_msg[0] = EXTENDED_MESSAGE;
/* Accept first byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_EXTENDED, "scsi%d : receiving extended message\n", instance->host_no);
+
+ spin_unlock_irq(&hostdata->lock);
+
+ dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n");
len = 2;
data = extended_msg + 1;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
+ dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
+ (int)extended_msg[1],
+ (int)extended_msg[2]);
- dprintk(NDEBUG_EXTENDED, "scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2]);
-
- if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) {
+ if (!len && extended_msg[1] > 0 &&
+ extended_msg[1] <= sizeof(extended_msg) - 2) {
/* Accept third byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
len = extended_msg[1] - 1;
@@ -2301,7 +1990,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d : message received, residual %d\n", instance->host_no, len);
+ dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
+ len);
switch (extended_msg[2]) {
case EXTENDED_SDTR:
@@ -2311,34 +2001,42 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
tmp = 0;
}
} else if (len) {
- printk("scsi%d: error receiving extended message\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "error receiving extended message\n");
tmp = 0;
} else {
- printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]);
+ shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n",
+ extended_msg[2], extended_msg[1]);
tmp = 0;
}
+
+ spin_lock_irq(&hostdata->lock);
+ if (!hostdata->connected)
+ return;
+
/* Fall through to reject message */
- /*
- * If we get something weird that we aren't expecting,
+ /*
+ * If we get something weird that we aren't expecting,
* reject it.
*/
default:
if (!tmp) {
- printk("scsi%d: rejecting message ", instance->host_no);
+ shost_printk(KERN_ERR, instance, "rejecting message ");
spi_print_msg(extended_msg);
printk("\n");
} else if (tmp != EXTENDED_MESSAGE)
scmd_printk(KERN_INFO, cmd,
- "rejecting unknown message %02x\n",tmp);
+ "rejecting unknown message %02x\n",
+ tmp);
else
scmd_printk(KERN_INFO, cmd,
- "rejecting unknown extended message code %02x, length %d\n", extended_msg[1], extended_msg[0]);
+ "rejecting unknown extended message code %02x, length %d\n",
+ extended_msg[1], extended_msg[0]);
msgout = MESSAGE_REJECT;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
break;
- } /* switch (tmp) */
+ } /* switch (tmp) */
break;
case PHASE_MSGOUT:
len = 1;
@@ -2346,10 +2044,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
hostdata->last_message = msgout;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
- hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
}
@@ -2358,17 +2055,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
case PHASE_CMDOUT:
len = cmd->cmd_len;
data = cmd->cmnd;
- /*
- * XXX for performance reasons, on machines with a
- * PSEUDO-DMA architecture we should probably
- * use the dma transfer function.
+ /*
+ * XXX for performance reasons, on machines with a
+ * PSEUDO-DMA architecture we should probably
+ * use the dma transfer function.
*/
NCR5380_transfer_pio(instance, &phase, &len, &data);
- if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) {
- NCR5380_set_timer(hostdata, USLEEP_SLEEP);
- dprintk(NDEBUG_USLEEP, "scsi%d : issued command, sleeping until %lu\n", instance->host_no, hostdata->time_expires);
- return;
- }
break;
case PHASE_STATIN:
len = 1;
@@ -2377,46 +2069,37 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
cmd->SCp.Status = tmp;
break;
default:
- printk("scsi%d : unknown phase\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "unknown phase\n");
NCR5380_dprint(NDEBUG_ANY, instance);
- } /* switch(phase) */
- } /* if (tmp * SR_REQ) */
- else {
- /* RvC: go to sleep if polling time expired
- */
- if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) {
- NCR5380_set_timer(hostdata, USLEEP_SLEEP);
- dprintk(NDEBUG_USLEEP, "scsi%d : poll timed out, sleeping until %lu\n", instance->host_no, hostdata->time_expires);
- return;
- }
+ } /* switch(phase) */
+ } else {
+ spin_unlock_irq(&hostdata->lock);
+ NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+ spin_lock_irq(&hostdata->lock);
}
- } /* while (1) */
+ }
}
/*
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
- * Purpose : does reselection, initializing the instance->connected
- * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
- * nexus has been reestablished,
- *
- * Inputs : instance - this instance of the NCR5380.
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
*
- * Locks: io_request_lock held by caller if IRQ driven
+ * Inputs : instance - this instance of the NCR5380.
*/
-static void NCR5380_reselect(struct Scsi_Host *instance) {
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
- instance->hostdata;
+static void NCR5380_reselect(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char target_mask;
unsigned char lun, phase;
int len;
unsigned char msg[3];
unsigned char *data;
- struct scsi_cmnd *tmp = NULL, *prev;
- int abort = 0;
- NCR5380_setup(instance);
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *tmp;
/*
* Disable arbitration, etc. since the host adapter obviously
@@ -2424,12 +2107,12 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
*/
NCR5380_write(MODE_REG, MR_BASE);
- hostdata->restart_select = 1;
target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
- dprintk(NDEBUG_SELECTION, "scsi%d : reselect\n", instance->host_no);
- /*
+ dsprintk(NDEBUG_RESELECTION, instance, "reselect\n");
+
+ /*
* At this point, we have detected that our SCSI ID is on the bus,
* SEL is true and BSY was false for at least one bus settle delay
* (400 ns).
@@ -2439,103 +2122,110 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
*/
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
- /* FIXME: timeout too long, must fail to workqueue */
- if(NCR5380_poll_politely(instance, STATUS_REG, SR_SEL, 0, 2*HZ)<0)
- abort = 1;
-
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return;
+ }
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/*
* Wait for target to go into MSGIN.
- * FIXME: timeout needed and fail to work queeu
*/
- if(NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 2*HZ))
- abort = 1;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+ do_abort(instance);
+ return;
+ }
len = 1;
data = msg;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
+ if (len) {
+ do_abort(instance);
+ return;
+ }
+
if (!(msg[0] & 0x80)) {
- printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no);
+ shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
spi_print_msg(msg);
- abort = 1;
- } else {
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- lun = (msg[0] & 0x07);
+ printk("\n");
+ do_abort(instance);
+ return;
+ }
+ lun = msg[0] & 0x07;
- /*
- * We need to add code for SCSI-II to track which devices have
- * I_T_L_Q nexuses established, and which have simple I_T_L
- * nexuses so we can chose to do additional data transfer.
- */
+ /*
+ * We need to add code for SCSI-II to track which devices have
+ * I_T_L_Q nexuses established, and which have simple I_T_L
+ * nexuses so we can chose to do additional data transfer.
+ */
- /*
- * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
- * just reestablished, and remove it from the disconnected queue.
- */
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just reestablished, and remove it from the disconnected queue.
+ */
+ tmp = NULL;
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)
- ) {
- if (prev) {
- REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
- prev->host_scribble = tmp->host_scribble;
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
- hostdata->disconnected_queue = (struct scsi_cmnd *) tmp->host_scribble;
- }
- tmp->host_scribble = NULL;
- break;
- }
- if (!tmp) {
- printk(KERN_ERR "scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
- /*
- * Since we have an established nexus that we can't do anything with,
- * we must abort it.
- */
- abort = 1;
+ if (target_mask == (1 << scmd_id(cmd)) &&
+ lun == (u8)cmd->device->lun) {
+ list_del(&ncmd->list);
+ tmp = cmd;
+ break;
}
}
- if (abort) {
- do_abort(instance);
+ if (tmp) {
+ dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
+ "reselect: removed %p from disconnected queue\n", tmp);
} else {
- hostdata->connected = tmp;
- dprintk(NDEBUG_RESELECTION, "scsi%d : nexus established, target = %d, lun = %llu, tag = %d\n", instance->host_no, tmp->device->id, tmp->device->lun, tmp->tag);
+ shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
+ target_mask, lun);
+ /*
+ * Since we have an established nexus that we can't do anything
+ * with, we must abort it.
+ */
+ do_abort(instance);
+ return;
}
+
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ hostdata->connected = tmp;
+ dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n",
+ scmd_id(tmp), tmp->device->lun, tmp->tag);
}
/*
* Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
*
* Purpose : called by interrupt handler when DMA finishes or a phase
- * mismatch occurs (which would finish the DMA transfer).
+ * mismatch occurs (which would finish the DMA transfer).
*
* Inputs : instance - this instance of the NCR5380.
*
* Returns : pointer to the scsi_cmnd structure for which the I_T_L
- * nexus has been reestablished, on failure NULL is returned.
+ * nexus has been reestablished, on failure NULL is returned.
*/
#ifdef REAL_DMA
static void NCR5380_dma_complete(NCR5380_instance * instance) {
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int transferred;
- NCR5380_setup(instance);
/*
* XXX this might not be right.
*
* Wait for final byte to transfer, ie wait for ACK to go false.
*
- * We should use the Last Byte Sent bit, unfortunately this is
+ * We should use the Last Byte Sent bit, unfortunately this is
* not available on the 5380/5381 (only the various CMOS chips)
*
* FIXME: timeout, and need to handle long timeout/irq case
@@ -2543,7 +2233,6 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ);
- NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/*
@@ -2560,190 +2249,228 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
}
#endif /* def REAL_DMA */
-/*
- * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
+/**
+ * list_find_cmd - test for presence of a command in a linked list
+ * @haystack: list of commands
+ * @needle: command to search for
+ */
+
+static bool list_find_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
+{
+ struct NCR5380_cmd *ncmd;
+
+ list_for_each_entry(ncmd, haystack, list)
+ if (NCR5380_to_scmd(ncmd) == needle)
+ return true;
+ return false;
+}
+
+/**
+ * list_remove_cmd - remove a command from linked list
+ * @haystack: list of commands
+ * @needle: command to remove
+ */
+
+static bool list_del_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
+{
+ if (list_find_cmd(haystack, needle)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle);
+
+ list_del(&ncmd->list);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * NCR5380_abort - scsi host eh_abort_handler() method
+ * @cmd: the command to be aborted
+ *
+ * Try to abort a given command by removing it from queues and/or sending
+ * the target an abort message. This may not succeed in causing a target
+ * to abort the command. Nonetheless, the low-level driver must forget about
+ * the command because the mid-layer reclaims it and it may be re-issued.
*
- * Purpose : abort a command
+ * The normal path taken by a command is as follows. For EH we trace this
+ * same path to locate and abort the command.
*
- * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
- * used.
+ * unissued -> selecting -> [unissued -> selecting ->]... connected ->
+ * [disconnected -> connected ->]...
+ * [autosense -> connected ->] done
*
- * Returns : SUCCESS - success, FAILED on failure.
+ * If cmd was not found at all then presumably it has already been completed,
+ * in which case return SUCCESS to try to avoid further EH measures.
*
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
- * a problem, we could implement longjmp() / setjmp(), setjmp()
- * called where the loop started in NCR5380_main().
+ * If the command has not completed yet, we must not fail to find it.
+ * We have no option but to forget the aborted command (even if it still
+ * lacks sense data). The mid-layer may re-issue a command that is in error
+ * recovery (see scsi_send_eh_cmnd), but the logic and data structures in
+ * this driver are such that a command can appear on one queue only.
*
- * Locks: host lock taken by caller
+ * The lock protects driver data structures, but EH handlers also use it
+ * to serialize their own execution and prevent their own re-entry.
*/
static int NCR5380_abort(struct scsi_cmnd *cmd)
{
- NCR5380_local_declare();
struct Scsi_Host *instance = cmd->device->host;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- struct scsi_cmnd *tmp, **prev;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long flags;
+ int result = SUCCESS;
- scmd_printk(KERN_WARNING, cmd, "aborting command\n");
+ spin_lock_irqsave(&hostdata->lock, flags);
- NCR5380_print_status(instance);
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
- NCR5380_setup(instance);
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from issue queue\n", cmd);
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
+ goto out;
+ }
- dprintk(NDEBUG_ABORT, "scsi%d : abort called\n", instance->host_no);
- dprintk(NDEBUG_ABORT, " basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG));
+ if (hostdata->selecting == cmd) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: cmd %p == selecting\n", cmd);
+ hostdata->selecting = NULL;
+ cmd->result = DID_ABORT << 16;
+ complete_cmd(instance, cmd);
+ goto out;
+ }
-#if 0
-/*
- * Case 1 : If the command is the currently executing command,
- * we'll set the aborted flag and return control so that
- * information transfer routine can exit cleanly.
- */
+ if (list_del_cmd(&hostdata->disconnected, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from disconnected list\n", cmd);
+ /* Can't call NCR5380_select() and send ABORT because that
+ * means releasing the lock. Need a bus reset.
+ */
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
+ }
if (hostdata->connected == cmd) {
- dprintk(NDEBUG_ABORT, "scsi%d : aborting connected command\n", instance->host_no);
- hostdata->aborted = 1;
-/*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN);
-/*
- * Since we can't change phases until we've completed the current
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
-
-/*
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
-
- return SUCCESS;
- }
+ dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+ hostdata->connected = NULL;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
#endif
-
-/*
- * Case 2 : If the command hasn't been issued yet, we simply remove it
- * from the issue queue.
- */
-
- dprintk(NDEBUG_ABORT, "scsi%d : abort going into loop.\n", instance->host_no);
- for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue), tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, tmp->host_scribble);
- (*prev) = (struct scsi_cmnd *) tmp->host_scribble;
- tmp->host_scribble = NULL;
- tmp->result = DID_ABORT << 16;
- dprintk(NDEBUG_ABORT, "scsi%d : abort removed command from issue queue.\n", instance->host_no);
- tmp->scsi_done(tmp);
- return SUCCESS;
+ if (do_abort(instance)) {
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
}
-#if (NDEBUG & NDEBUG_ABORT)
- /* KLL */
- else if (prev == tmp)
- printk(KERN_ERR "scsi%d : LOOP\n", instance->host_no);
-#endif
-
-/*
- * Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
-
- if (hostdata->connected) {
- dprintk(NDEBUG_ABORT, "scsi%d : abort failed, command connected.\n", instance->host_no);
- return FAILED;
+ set_host_byte(cmd, DID_ABORT);
+ complete_cmd(instance, cmd);
+ goto out;
}
-/*
- * Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select(). The easiest way to implement this
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that
- * device reselected.
- *
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- dprintk(NDEBUG_ABORT, "scsi%d : aborting disconnected command.\n", instance->host_no);
+ if (list_del_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from sense queue\n", cmd);
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ }
- if (NCR5380_select(instance, cmd))
- return FAILED;
- dprintk(NDEBUG_ABORT, "scsi%d : nexus reestablished.\n", instance->host_no);
+out:
+ if (result == FAILED)
+ dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
+ else
+ dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
- do_abort(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
- for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue), tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, tmp->host_scribble);
- *prev = (struct scsi_cmnd *) tmp->host_scribble;
- tmp->host_scribble = NULL;
- tmp->result = DID_ABORT << 16;
- tmp->scsi_done(tmp);
- return SUCCESS;
- }
- }
-/*
- * Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
- printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n"
- " before abortion\n", instance->host_no);
- return FAILED;
+ return result;
}
-/*
- * Function : int NCR5380_bus_reset (struct scsi_cmnd *cmd)
- *
- * Purpose : reset the SCSI bus.
- *
- * Returns : SUCCESS
+/**
+ * NCR5380_bus_reset - reset the SCSI bus
+ * @cmd: SCSI command undergoing EH
*
- * Locks: host lock taken by caller
+ * Returns SUCCESS
*/
static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
{
struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int i;
+ unsigned long flags;
+ struct NCR5380_cmd *ncmd;
+
+ spin_lock_irqsave(&hostdata->lock, flags);
- NCR5380_local_declare();
- NCR5380_setup(instance);
- NCR5380_print_status(instance);
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
- spin_lock_irq(instance->host_lock);
do_reset(instance);
- spin_unlock_irq(instance->host_lock);
+
+ /* reset NCR registers */
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; so clear the low-level status here to avoid
+ * conflicts when the mid-level code tries to wake up the affected
+ * commands!
+ */
+
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ }
+
+ if (hostdata->selecting) {
+ hostdata->selecting->result = DID_RESET << 16;
+ complete_cmd(instance, hostdata->selecting);
+ hostdata->selecting = NULL;
+ }
+
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+ INIT_LIST_HEAD(&hostdata->disconnected);
+
+ list_for_each_entry(ncmd, &hostdata->autosense, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+ INIT_LIST_HEAD(&hostdata->autosense);
+
+ if (hostdata->connected) {
+ set_host_byte(hostdata->connected, DID_RESET);
+ complete_cmd(instance, hostdata->connected);
+ hostdata->connected = NULL;
+ }
+
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
return SUCCESS;
}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 162112d..a792886 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -22,8 +22,13 @@
#ifndef NCR5380_H
#define NCR5380_H
+#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_transport_spi.h>
#define NDEBUG_ARBITRATION 0x1
#define NDEBUG_AUTOSENSE 0x2
@@ -158,8 +163,7 @@
/* Write any value to this register to start an ini mode DMA receive */
#define START_DMA_INITIATOR_RECEIVE_REG 7 /* wo */
-#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */
-
+/* NCR 53C400(A) Control Status Register bits: */
#define CSR_RESET 0x80 /* wo Resets 53c400 */
#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */
#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */
@@ -176,16 +180,6 @@
#define CSR_BASE CSR_53C80_INTR
#endif
-/* Number of 128-byte blocks to be transferred */
-#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */
-
-/* Resume transfer after disconnect */
-#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */
-
-/* Access to host buffer stack */
-#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */
-
-
/* Note : PHASE_* macros are based on the values of the STATUS register */
#define PHASE_MASK (SR_MSG | SR_CD | SR_IO)
@@ -205,16 +199,6 @@
#define PHASE_SR_TO_TCR(phase) ((phase) >> 2)
-/*
- * The internal should_disconnect() function returns these based on the
- * expected length of a disconnect if a device supports disconnect/
- * reconnect.
- */
-
-#define DISCONNECT_NONE 0
-#define DISCONNECT_TIME_TO_DATA 1
-#define DISCONNECT_LONG 2
-
/*
* "Special" value for the (unsigned char) command tag, to indicate
* I_T_L nexus instead of I_T_L_Q.
@@ -236,15 +220,11 @@
#define NO_IRQ 0
#endif
-#define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */
-#define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */
-#define FLAG_NCR53C400 4 /* NCR53c400 */
+#define FLAG_NO_DMA_FIXUP 1 /* No DMA errata workarounds */
#define FLAG_NO_PSEUDO_DMA 8 /* Inhibit DMA */
-#define FLAG_DTC3181E 16 /* DTC3181E */
#define FLAG_LATE_DMA_SETUP 32 /* Setup NCR before DMA H/W */
#define FLAG_TAGGED_QUEUING 64 /* as X3T9.2 spelled it */
-
-#ifndef ASM
+#define FLAG_TOSHIBA_DELAY 128 /* Allow for borken CD-ROMs */
#ifdef SUPPORT_TAGS
struct tag_alloc {
@@ -258,33 +238,24 @@ struct NCR5380_hostdata {
NCR5380_implementation_fields; /* implementation specific */
struct Scsi_Host *host; /* Host backpointer */
unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */
- unsigned char targets_present; /* targets we have connected
- to, so we can call a select
- failure a retryable condition */
- volatile unsigned char busy[8]; /* index = target, bit = lun */
+ unsigned char busy[8]; /* index = target, bit = lun */
#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
- volatile int dma_len; /* requested length of DMA */
+ int dma_len; /* requested length of DMA */
#endif
- volatile unsigned char last_message; /* last message OUT */
- volatile struct scsi_cmnd *connected; /* currently connected command */
- volatile struct scsi_cmnd *issue_queue; /* waiting to be issued */
- volatile struct scsi_cmnd *disconnected_queue; /* waiting for reconnect */
- volatile int restart_select; /* we have disconnected,
- used to restart
- NCR5380_select() */
- volatile unsigned aborted:1; /* flag, says aborted */
+ unsigned char last_message; /* last message OUT */
+ struct scsi_cmnd *connected; /* currently connected cmnd */
+ struct scsi_cmnd *selecting; /* cmnd to be connected */
+ struct list_head unissued; /* waiting to be issued */
+ struct list_head autosense; /* priority issue queue */
+ struct list_head disconnected; /* waiting for reconnect */
+ spinlock_t lock; /* protects this struct */
int flags;
- unsigned long time_expires; /* in jiffies, set prior to sleeping */
- int select_time; /* timer in select for target response */
- volatile struct scsi_cmnd *selecting;
- struct delayed_work coroutine; /* our co-routine */
struct scsi_eh_save ses;
+ struct scsi_cmnd *sensing;
char info[256];
int read_overruns; /* number of bytes to cut from a
* transfer to handle chip overruns */
- int retain_dma_intr;
struct work_struct main_task;
- volatile int main_running;
#ifdef SUPPORT_TAGS
struct tag_alloc TagAlloc[8][8]; /* 8 targets and 8 LUNs */
#endif
@@ -292,10 +263,23 @@ struct NCR5380_hostdata {
unsigned spin_max_r;
unsigned spin_max_w;
#endif
+ struct workqueue_struct *work_q;
+ unsigned long accesses_per_ms; /* chip register accesses per ms */
};
#ifdef __KERNEL__
+struct NCR5380_cmd {
+ struct list_head list;
+};
+
+#define NCR5380_CMD_SIZE (sizeof(struct NCR5380_cmd))
+
+static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
+{
+ return ((struct scsi_cmnd *)ncmd_ptr) - 1;
+}
+
#ifndef NDEBUG
#define NDEBUG (0)
#endif
@@ -304,6 +288,11 @@ struct NCR5380_hostdata {
do { if ((NDEBUG) & (flg)) \
printk(KERN_DEBUG fmt, ## __VA_ARGS__); } while (0)
+#define dsprintk(flg, host, fmt, ...) \
+ do { if ((NDEBUG) & (flg)) \
+ shost_printk(KERN_DEBUG, host, fmt, ## __VA_ARGS__); \
+ } while (0)
+
#if NDEBUG
#define NCR5380_dprint(flg, arg) \
do { if ((NDEBUG) & (flg)) NCR5380_print(arg); } while (0)
@@ -320,6 +309,7 @@ static void NCR5380_print(struct Scsi_Host *instance);
static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible);
#endif
static int NCR5380_init(struct Scsi_Host *instance, int flags);
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *);
static void NCR5380_exit(struct Scsi_Host *instance);
static void NCR5380_information_transfer(struct Scsi_Host *instance);
#ifndef DONT_USE_INTR
@@ -328,7 +318,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id);
static void NCR5380_main(struct work_struct *work);
static const char *NCR5380_info(struct Scsi_Host *instance);
static void NCR5380_reselect(struct Scsi_Host *instance);
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd);
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *);
#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
#endif
@@ -443,5 +433,4 @@ static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance)
#endif /* defined(i386) || defined(__alpha__) */
#endif /* defined(REAL_DMA) */
#endif /* __KERNEL__ */
-#endif /* ndef ASM */
#endif /* NCR5380_H */
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 9b3dd6e..7dfd0fa 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -259,7 +259,7 @@ MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the"
" 0=off, 1=on");
module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(msi, "IRQ handling."
- " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)");
+ " 0=PIC(default), 1=MSI, 2=MSI-X)");
module_param(startup_timeout, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for"
" adapter to have it's kernel up and\n"
@@ -323,7 +323,6 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
return 0;
}
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
@@ -331,7 +330,6 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
if (unlikely(!device || !scsi_device_online(device))) {
dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
return 0;
}
return 1;
@@ -541,7 +539,6 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -557,7 +554,8 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
- if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext)
return -ENOMEM;
aac_fib_init(cmd_fibcontext);
@@ -570,7 +568,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
status = aac_fib_send(ContainerCommand,
cmd_fibcontext,
- sizeof (struct aac_get_name),
+ sizeof(struct aac_get_name_resp),
FsaNormal,
0, 1,
(fib_callback)get_container_name_callback,
@@ -586,7 +584,6 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
aac_fib_complete(cmd_fibcontext);
- aac_fib_free(cmd_fibcontext);
return -1;
}
@@ -1024,7 +1021,6 @@ static void get_container_serial_callback(void *context, struct fib * fibptr)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -1040,7 +1036,8 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
- if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext)
return -ENOMEM;
aac_fib_init(cmd_fibcontext);
@@ -1052,7 +1049,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
status = aac_fib_send(ContainerCommand,
cmd_fibcontext,
- sizeof (struct aac_get_serial),
+ sizeof(struct aac_get_serial_resp),
FsaNormal,
0, 1,
(fib_callback) get_container_serial_callback,
@@ -1068,7 +1065,6 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
aac_fib_complete(cmd_fibcontext);
- aac_fib_free(cmd_fibcontext);
return -1;
}
@@ -1869,7 +1865,6 @@ static void io_callback(void *context, struct fib * fibptr)
break;
}
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -1954,7 +1949,8 @@ static int aac_read(struct scsi_cmnd * scsicmd)
/*
* Alocate and initialize a Fib
*/
- if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext) {
printk(KERN_WARNING "aac_read: fib allocation failed\n");
return -1;
}
@@ -2051,7 +2047,8 @@ static int aac_write(struct scsi_cmnd * scsicmd)
/*
* Allocate and initialize a Fib then setup a BlockWrite command
*/
- if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext) {
/* FIB temporarily unavailable,not catastrophic failure */
/* scsicmd->result = DID_ERROR << 16;
@@ -2285,7 +2282,7 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd)
/*
* Allocate and initialize a Fib
*/
- cmd_fibcontext = aac_fib_alloc(aac);
+ cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd);
if (!cmd_fibcontext)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -2977,11 +2974,16 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
return;
BUG_ON(fibptr == NULL);
-
dev = fibptr->dev;
- srbreply = (struct aac_srb_reply *) fib_data(fibptr);
+ scsi_dma_unmap(scsicmd);
+ /* expose physical device if expose_physicald flag is on */
+ if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
+ && expose_physicals > 0)
+ aac_expose_phy_device(scsicmd);
+
+ srbreply = (struct aac_srb_reply *) fib_data(fibptr);
scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */
if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
@@ -2994,147 +2996,157 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
*/
scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
- le32_to_cpu(srbreply->data_xfer_length));
- }
-
- scsi_dma_unmap(scsicmd);
-
- /* expose physical device if expose_physicald flag is on */
- if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
- && expose_physicals > 0)
- aac_expose_phy_device(scsicmd);
+ /*
+ * First check the fib status
+ */
- /*
- * First check the fib status
- */
+ if (le32_to_cpu(srbreply->status) != ST_OK) {
+ int len;
- if (le32_to_cpu(srbreply->status) != ST_OK){
- int len;
- printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
- len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
- SCSI_SENSE_BUFFERSIZE);
- scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
- }
+ printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
+ len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+ SCSI_SENSE_BUFFERSIZE);
+ scsicmd->result = DID_ERROR << 16
+ | COMMAND_COMPLETE << 8
+ | SAM_STAT_CHECK_CONDITION;
+ memcpy(scsicmd->sense_buffer,
+ srbreply->sense_data, len);
+ }
- /*
- * Next check the srb status
- */
- switch( (le32_to_cpu(srbreply->srb_status))&0x3f){
- case SRB_STATUS_ERROR_RECOVERY:
- case SRB_STATUS_PENDING:
- case SRB_STATUS_SUCCESS:
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
- break;
- case SRB_STATUS_DATA_OVERRUN:
- switch(scsicmd->cmnd[0]){
- case READ_6:
- case WRITE_6:
- case READ_10:
- case WRITE_10:
- case READ_12:
- case WRITE_12:
- case READ_16:
- case WRITE_16:
- if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) {
- printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
- } else {
- printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
+ /*
+ * Next check the srb status
+ */
+ switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
+ case SRB_STATUS_ERROR_RECOVERY:
+ case SRB_STATUS_PENDING:
+ case SRB_STATUS_SUCCESS:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SRB_STATUS_DATA_OVERRUN:
+ switch (scsicmd->cmnd[0]) {
+ case READ_6:
+ case WRITE_6:
+ case READ_10:
+ case WRITE_10:
+ case READ_12:
+ case WRITE_12:
+ case READ_16:
+ case WRITE_16:
+ if (le32_to_cpu(srbreply->data_xfer_length)
+ < scsicmd->underflow)
+ printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
+ else
+ printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
+ scsicmd->result = DID_ERROR << 16
+ | COMMAND_COMPLETE << 8;
+ break;
+ case INQUIRY: {
+ scsicmd->result = DID_OK << 16
+ | COMMAND_COMPLETE << 8;
+ break;
+ }
+ default:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ break;
}
- scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
break;
- case INQUIRY: {
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ case SRB_STATUS_ABORTED:
+ scsicmd->result = DID_ABORT << 16 | ABORT << 8;
break;
- }
- default:
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ case SRB_STATUS_ABORT_FAILED:
+ /*
+ * Not sure about this one - but assuming the
+ * hba was trying to abort for some reason
+ */
+ scsicmd->result = DID_ERROR << 16 | ABORT << 8;
+ break;
+ case SRB_STATUS_PARITY_ERROR:
+ scsicmd->result = DID_PARITY << 16
+ | MSG_PARITY_ERROR << 8;
+ break;
+ case SRB_STATUS_NO_DEVICE:
+ case SRB_STATUS_INVALID_PATH_ID:
+ case SRB_STATUS_INVALID_TARGET_ID:
+ case SRB_STATUS_INVALID_LUN:
+ case SRB_STATUS_SELECTION_TIMEOUT:
+ scsicmd->result = DID_NO_CONNECT << 16
+ | COMMAND_COMPLETE << 8;
break;
- }
- break;
- case SRB_STATUS_ABORTED:
- scsicmd->result = DID_ABORT << 16 | ABORT << 8;
- break;
- case SRB_STATUS_ABORT_FAILED:
- // Not sure about this one - but assuming the hba was trying to abort for some reason
- scsicmd->result = DID_ERROR << 16 | ABORT << 8;
- break;
- case SRB_STATUS_PARITY_ERROR:
- scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8;
- break;
- case SRB_STATUS_NO_DEVICE:
- case SRB_STATUS_INVALID_PATH_ID:
- case SRB_STATUS_INVALID_TARGET_ID:
- case SRB_STATUS_INVALID_LUN:
- case SRB_STATUS_SELECTION_TIMEOUT:
- scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
- break;
- case SRB_STATUS_COMMAND_TIMEOUT:
- case SRB_STATUS_TIMEOUT:
- scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8;
- break;
+ case SRB_STATUS_COMMAND_TIMEOUT:
+ case SRB_STATUS_TIMEOUT:
+ scsicmd->result = DID_TIME_OUT << 16
+ | COMMAND_COMPLETE << 8;
+ break;
- case SRB_STATUS_BUSY:
- scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
- break;
+ case SRB_STATUS_BUSY:
+ scsicmd->result = DID_BUS_BUSY << 16
+ | COMMAND_COMPLETE << 8;
+ break;
- case SRB_STATUS_BUS_RESET:
- scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8;
- break;
+ case SRB_STATUS_BUS_RESET:
+ scsicmd->result = DID_RESET << 16
+ | COMMAND_COMPLETE << 8;
+ break;
- case SRB_STATUS_MESSAGE_REJECTED:
- scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8;
- break;
- case SRB_STATUS_REQUEST_FLUSHED:
- case SRB_STATUS_ERROR:
- case SRB_STATUS_INVALID_REQUEST:
- case SRB_STATUS_REQUEST_SENSE_FAILED:
- case SRB_STATUS_NO_HBA:
- case SRB_STATUS_UNEXPECTED_BUS_FREE:
- case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
- case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
- case SRB_STATUS_DELAYED_RETRY:
- case SRB_STATUS_BAD_FUNCTION:
- case SRB_STATUS_NOT_STARTED:
- case SRB_STATUS_NOT_IN_USE:
- case SRB_STATUS_FORCE_ABORT:
- case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
- default:
+ case SRB_STATUS_MESSAGE_REJECTED:
+ scsicmd->result = DID_ERROR << 16
+ | MESSAGE_REJECT << 8;
+ break;
+ case SRB_STATUS_REQUEST_FLUSHED:
+ case SRB_STATUS_ERROR:
+ case SRB_STATUS_INVALID_REQUEST:
+ case SRB_STATUS_REQUEST_SENSE_FAILED:
+ case SRB_STATUS_NO_HBA:
+ case SRB_STATUS_UNEXPECTED_BUS_FREE:
+ case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
+ case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+ case SRB_STATUS_DELAYED_RETRY:
+ case SRB_STATUS_BAD_FUNCTION:
+ case SRB_STATUS_NOT_STARTED:
+ case SRB_STATUS_NOT_IN_USE:
+ case SRB_STATUS_FORCE_ABORT:
+ case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
+ default:
#ifdef AAC_DETAILED_STATUS_INFO
- printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
- le32_to_cpu(srbreply->srb_status) & 0x3F,
- aac_get_status_string(
- le32_to_cpu(srbreply->srb_status) & 0x3F),
- scsicmd->cmnd[0],
- le32_to_cpu(srbreply->scsi_status));
+ printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
+ le32_to_cpu(srbreply->srb_status) & 0x3F,
+ aac_get_status_string(
+ le32_to_cpu(srbreply->srb_status) & 0x3F),
+ scsicmd->cmnd[0],
+ le32_to_cpu(srbreply->scsi_status));
#endif
- if ((scsicmd->cmnd[0] == ATA_12)
- || (scsicmd->cmnd[0] == ATA_16)) {
- if (scsicmd->cmnd[2] & (0x01 << 5)) {
- scsicmd->result = DID_OK << 16
- | COMMAND_COMPLETE << 8;
+ if ((scsicmd->cmnd[0] == ATA_12)
+ || (scsicmd->cmnd[0] == ATA_16)) {
+ if (scsicmd->cmnd[2] & (0x01 << 5)) {
+ scsicmd->result = DID_OK << 16
+ | COMMAND_COMPLETE << 8;
break;
+ } else {
+ scsicmd->result = DID_ERROR << 16
+ | COMMAND_COMPLETE << 8;
+ break;
+ }
} else {
scsicmd->result = DID_ERROR << 16
- | COMMAND_COMPLETE << 8;
+ | COMMAND_COMPLETE << 8;
break;
}
- } else {
- scsicmd->result = DID_ERROR << 16
- | COMMAND_COMPLETE << 8;
- break;
}
- }
- if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
- int len;
- scsicmd->result |= SAM_STAT_CHECK_CONDITION;
- len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
- SCSI_SENSE_BUFFERSIZE);
+ if (le32_to_cpu(srbreply->scsi_status)
+ == SAM_STAT_CHECK_CONDITION) {
+ int len;
+
+ scsicmd->result |= SAM_STAT_CHECK_CONDITION;
+ len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+ SCSI_SENSE_BUFFERSIZE);
#ifdef AAC_DETAILED_STATUS_INFO
- printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
- le32_to_cpu(srbreply->status), len);
+ printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
+ le32_to_cpu(srbreply->status), len);
#endif
- memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+ memcpy(scsicmd->sense_buffer,
+ srbreply->sense_data, len);
+ }
}
/*
* OR in the scsi status (already shifted up a bit)
@@ -3142,7 +3154,6 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
scsicmd->scsi_done(scsicmd);
}
@@ -3172,9 +3183,10 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
/*
* Allocate and initialize a Fib then setup a BlockWrite command
*/
- if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
+ cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+ if (!cmd_fibcontext)
return -1;
- }
+
status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
/*
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 40fe65c..efa493c 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
* D E F I N E S
*----------------------------------------------------------------------------*/
-#define AAC_MAX_MSIX 8 /* vectors */
+#define AAC_MAX_MSIX 32 /* vectors */
#define AAC_PCI_MSI_ENABLE 0x8000
enum {
@@ -62,7 +62,7 @@ enum {
#define PMC_GLOBAL_INT_BIT0 0x00000001
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 40709
+# define AAC_DRIVER_BUILD 41052
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -94,6 +94,13 @@ enum {
#define aac_phys_to_logical(x) ((x)+1)
#define aac_logical_to_phys(x) ((x)?(x)-1:0)
+/*
+ * These macros are for keeping track of
+ * character device state.
+ */
+#define AAC_CHARDEV_UNREGISTERED (-1)
+#define AAC_CHARDEV_NEEDS_REINIT (-2)
+
/* #define AAC_DETAILED_STATUS_INFO */
struct diskparm
@@ -547,6 +554,7 @@ struct adapter_ops
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
int (*adapter_restart)(struct aac_dev *dev, int bled);
+ void (*adapter_start)(struct aac_dev *dev);
/* Transport operations */
int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
irq_handler_t adapter_intr;
@@ -843,6 +851,10 @@ struct src_registers {
&((AEP)->regs.src.bar0->CSR))
#define src_writel(AEP, CSR, value) writel(value, \
&((AEP)->regs.src.bar0->CSR))
+#if defined(writeq)
+#define src_writeq(AEP, CSR, value) writeq(value, \
+ &((AEP)->regs.src.bar0->CSR))
+#endif
#define SRC_ODR_SHIFT 12
#define SRC_IDR_SHIFT 9
@@ -939,6 +951,7 @@ struct fib {
*/
struct list_head fiblink;
void *data;
+ u32 vector_no;
struct hw_fib *hw_fib_va; /* Actual shared object */
dma_addr_t hw_fib_pa; /* physical address of hw_fib*/
};
@@ -1118,6 +1131,7 @@ struct aac_dev
struct fib *free_fib;
spinlock_t fib_lock;
+ struct mutex ioctl_mutex;
struct aac_queue_block *queues;
/*
* The user API will use an IOCTL to register itself to receive
@@ -1162,6 +1176,11 @@ struct aac_dev
struct fsa_dev_info *fsa_dev;
struct task_struct *thread;
int cardtype;
+ /*
+ *This lock will protect the two 32-bit
+ *writes to the Inbound Queue
+ */
+ spinlock_t iq_lock;
/*
* The following is the device specific extension.
@@ -1224,6 +1243,7 @@ struct aac_dev
struct msix_entry msixentry[AAC_MAX_MSIX];
struct aac_msix_ctx aac_msix[AAC_MAX_MSIX]; /* context */
u8 adapter_shutdown;
+ u32 handle_pci_error;
};
#define aac_adapter_interrupt(dev) \
@@ -1247,6 +1267,9 @@ struct aac_dev
#define aac_adapter_restart(dev,bled) \
(dev)->a_ops.adapter_restart(dev,bled)
+#define aac_adapter_start(dev) \
+ ((dev)->a_ops.adapter_start(dev))
+
#define aac_adapter_ioremap(dev, size) \
(dev)->a_ops.adapter_ioremap(dev, size)
@@ -2097,8 +2120,12 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
#define AAC_OWNER_ERROR_HANDLER 0x103
#define AAC_OWNER_FIRMWARE 0x106
+int aac_acquire_irq(struct aac_dev *dev);
+void aac_free_irq(struct aac_dev *dev);
const char *aac_driverinfo(struct Scsi_Host *);
+void aac_fib_vector_assign(struct aac_dev *dev);
struct fib *aac_fib_alloc(struct aac_dev *dev);
+struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd);
int aac_fib_setup(struct aac_dev *dev);
void aac_fib_map_free(struct aac_dev *dev);
void aac_fib_free(struct fib * context);
@@ -2127,6 +2154,7 @@ int aac_sa_init(struct aac_dev *dev);
int aac_src_init(struct aac_dev *dev);
int aac_srcv_init(struct aac_dev *dev);
int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
+void aac_define_int_mode(struct aac_dev *dev);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index,
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 54195a1..4b3bb52 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -855,13 +855,20 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
{
int status;
+ mutex_lock(&dev->ioctl_mutex);
+
+ if (dev->adapter_shutdown) {
+ status = -EACCES;
+ goto cleanup;
+ }
+
/*
* HBA gets first crack
*/
status = aac_dev_ioctl(dev, cmd, arg);
if (status != -ENOTTY)
- return status;
+ goto cleanup;
switch (cmd) {
case FSACTL_MINIPORT_REV_CHECK:
@@ -890,6 +897,10 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
status = -ENOTTY;
break;
}
+
+cleanup:
+ mutex_unlock(&dev->ioctl_mutex);
+
return status;
}
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 45db84a..2b4e753 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -43,8 +43,6 @@
#include "aacraid.h"
-static void aac_define_int_mode(struct aac_dev *dev);
-
struct aac_common aac_config = {
.irq_mod = 1
};
@@ -214,8 +212,11 @@ int aac_send_shutdown(struct aac_dev * dev)
return -ENOMEM;
aac_fib_init(fibctx);
- cmd = (struct aac_close *) fib_data(fibctx);
+ mutex_lock(&dev->ioctl_mutex);
+ dev->adapter_shutdown = 1;
+ mutex_unlock(&dev->ioctl_mutex);
+ cmd = (struct aac_close *) fib_data(fibctx);
cmd->command = cpu_to_le32(VM_CloseAll);
cmd->cid = cpu_to_le32(0xfffffffe);
@@ -231,7 +232,6 @@ int aac_send_shutdown(struct aac_dev * dev)
/* FIB should be freed only after getting the response from the F/W */
if (status != -ERESTARTSYS)
aac_fib_free(fibctx);
- dev->adapter_shutdown = 1;
if ((dev->pdev->device == PMC_DEVICE_S7 ||
dev->pdev->device == PMC_DEVICE_S8 ||
dev->pdev->device == PMC_DEVICE_S9) &&
@@ -338,6 +338,74 @@ static int aac_comm_init(struct aac_dev * dev)
return 0;
}
+void aac_define_int_mode(struct aac_dev *dev)
+{
+ int i, msi_count, min_msix;
+
+ msi_count = i = 0;
+ /* max. vectors from GET_COMM_PREFERRED_SETTINGS */
+ if (dev->max_msix == 0 ||
+ dev->pdev->device == PMC_DEVICE_S6 ||
+ dev->sync_mode) {
+ dev->max_msix = 1;
+ dev->vector_cap =
+ dev->scsi_host_ptr->can_queue +
+ AAC_NUM_MGT_FIB;
+ return;
+ }
+
+ /* Don't bother allocating more MSI-X vectors than cpus */
+ msi_count = min(dev->max_msix,
+ (unsigned int)num_online_cpus());
+
+ dev->max_msix = msi_count;
+
+ if (msi_count > AAC_MAX_MSIX)
+ msi_count = AAC_MAX_MSIX;
+
+ for (i = 0; i < msi_count; i++)
+ dev->msixentry[i].entry = i;
+
+ if (msi_count > 1 &&
+ pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) {
+ min_msix = 2;
+ i = pci_enable_msix_range(dev->pdev,
+ dev->msixentry,
+ min_msix,
+ msi_count);
+ if (i > 0) {
+ dev->msi_enabled = 1;
+ msi_count = i;
+ } else {
+ dev->msi_enabled = 0;
+ printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
+ dev->name, dev->id, i);
+ }
+ }
+
+ if (!dev->msi_enabled) {
+ msi_count = 1;
+ i = pci_enable_msi(dev->pdev);
+
+ if (!i) {
+ dev->msi_enabled = 1;
+ dev->msi = 1;
+ } else {
+ printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n",
+ dev->name, dev->id, i);
+ }
+ }
+
+ if (!dev->msi_enabled)
+ dev->max_msix = msi_count = 1;
+ else {
+ if (dev->max_msix > msi_count)
+ dev->max_msix = msi_count;
+ }
+ dev->vector_cap =
+ (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) /
+ msi_count;
+}
struct aac_dev *aac_init_adapter(struct aac_dev *dev)
{
u32 status[5];
@@ -350,6 +418,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
dev->management_fib_count = 0;
spin_lock_init(&dev->manage_lock);
spin_lock_init(&dev->sync_lock);
+ spin_lock_init(&dev->iq_lock);
dev->max_fib_size = sizeof(struct hw_fib);
dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
- sizeof(struct aac_fibhdr)
@@ -508,79 +577,3 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
return dev;
}
-static void aac_define_int_mode(struct aac_dev *dev)
-{
-
- int i, msi_count;
-
- msi_count = i = 0;
- /* max. vectors from GET_COMM_PREFERRED_SETTINGS */
- if (dev->max_msix == 0 ||
- dev->pdev->device == PMC_DEVICE_S6 ||
- dev->sync_mode) {
- dev->max_msix = 1;
- dev->vector_cap =
- dev->scsi_host_ptr->can_queue +
- AAC_NUM_MGT_FIB;
- return;
- }
-
- msi_count = min(dev->max_msix,
- (unsigned int)num_online_cpus());
-
- dev->max_msix = msi_count;
-
- if (msi_count > AAC_MAX_MSIX)
- msi_count = AAC_MAX_MSIX;
-
- for (i = 0; i < msi_count; i++)
- dev->msixentry[i].entry = i;
-
- if (msi_count > 1 &&
- pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) {
- i = pci_enable_msix(dev->pdev,
- dev->msixentry,
- msi_count);
- /* Check how many MSIX vectors are allocated */
- if (i >= 0) {
- dev->msi_enabled = 1;
- if (i) {
- msi_count = i;
- if (pci_enable_msix(dev->pdev,
- dev->msixentry,
- msi_count)) {
- dev->msi_enabled = 0;
- printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
- dev->name, dev->id, i);
- }
- }
- } else {
- dev->msi_enabled = 0;
- printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
- dev->name, dev->id, i);
- }
- }
-
- if (!dev->msi_enabled) {
- msi_count = 1;
- i = pci_enable_msi(dev->pdev);
-
- if (!i) {
- dev->msi_enabled = 1;
- dev->msi = 1;
- } else {
- printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n",
- dev->name, dev->id, i);
- }
- }
-
- if (!dev->msi_enabled)
- dev->max_msix = msi_count = 1;
- else {
- if (dev->max_msix > msi_count)
- dev->max_msix = msi_count;
- }
- dev->vector_cap =
- (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) /
- msi_count;
-}
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 4da5749..511bbc5 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -83,13 +83,38 @@ static int fib_map_alloc(struct aac_dev *dev)
void aac_fib_map_free(struct aac_dev *dev)
{
- pci_free_consistent(dev->pdev,
- dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
- dev->hw_fib_va, dev->hw_fib_pa);
+ if (dev->hw_fib_va && dev->max_fib_size) {
+ pci_free_consistent(dev->pdev,
+ (dev->max_fib_size *
+ (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)),
+ dev->hw_fib_va, dev->hw_fib_pa);
+ }
dev->hw_fib_va = NULL;
dev->hw_fib_pa = 0;
}
+void aac_fib_vector_assign(struct aac_dev *dev)
+{
+ u32 i = 0;
+ u32 vector = 1;
+ struct fib *fibptr = NULL;
+
+ for (i = 0, fibptr = &dev->fibs[i];
+ i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
+ i++, fibptr++) {
+ if ((dev->max_msix == 1) ||
+ (i > ((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1)
+ - dev->vector_cap))) {
+ fibptr->vector_no = 0;
+ } else {
+ fibptr->vector_no = vector;
+ vector++;
+ if (vector == dev->max_msix)
+ vector = 1;
+ }
+ }
+}
+
/**
* aac_fib_setup - setup the fibs
* @dev: Adapter to set up
@@ -137,6 +162,7 @@ int aac_fib_setup(struct aac_dev * dev)
i++, fibptr++)
{
fibptr->flags = 0;
+ fibptr->size = sizeof(struct fib);
fibptr->dev = dev;
fibptr->hw_fib_va = hw_fib;
fibptr->data = (void *) fibptr->hw_fib_va->data;
@@ -151,18 +177,49 @@ int aac_fib_setup(struct aac_dev * dev)
hw_fib_pa = hw_fib_pa +
dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
}
+
+ /*
+ *Assign vector numbers to fibs
+ */
+ aac_fib_vector_assign(dev);
+
/*
* Add the fib chain to the free list
*/
dev->fibs[dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1].next = NULL;
/*
- * Enable this to debug out of queue space
- */
- dev->free_fib = &dev->fibs[0];
+ * Set 8 fibs aside for management tools
+ */
+ dev->free_fib = &dev->fibs[dev->scsi_host_ptr->can_queue];
return 0;
}
/**
+ * aac_fib_alloc_tag-allocate a fib using tags
+ * @dev: Adapter to allocate the fib for
+ *
+ * Allocate a fib from the adapter fib pool using tags
+ * from the blk layer.
+ */
+
+struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd)
+{
+ struct fib *fibptr;
+
+ fibptr = &dev->fibs[scmd->request->tag];
+ /*
+ * Null out fields that depend on being zero at the start of
+ * each I/O
+ */
+ fibptr->hw_fib_va->header.XferState = 0;
+ fibptr->type = FSAFS_NTC_FIB_CONTEXT;
+ fibptr->callback_data = NULL;
+ fibptr->callback = NULL;
+
+ return fibptr;
+}
+
+/**
* aac_fib_alloc - allocate a fib
* @dev: Adapter to allocate the fib for
*
@@ -1270,13 +1327,12 @@ retry_next:
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
{
int index, quirks;
- int retval, i;
+ int retval;
struct Scsi_Host *host;
struct scsi_device *dev;
struct scsi_cmnd *command;
struct scsi_cmnd *command_list;
int jafo = 0;
- int cpu;
/*
* Assumptions:
@@ -1339,35 +1395,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
aac->comm_phys = 0;
kfree(aac->queues);
aac->queues = NULL;
- cpu = cpumask_first(cpu_online_mask);
- if (aac->pdev->device == PMC_DEVICE_S6 ||
- aac->pdev->device == PMC_DEVICE_S7 ||
- aac->pdev->device == PMC_DEVICE_S8 ||
- aac->pdev->device == PMC_DEVICE_S9) {
- if (aac->max_msix > 1) {
- for (i = 0; i < aac->max_msix; i++) {
- if (irq_set_affinity_hint(
- aac->msixentry[i].vector,
- NULL)) {
- printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n",
- aac->name,
- aac->id,
- cpu);
- }
- cpu = cpumask_next(cpu,
- cpu_online_mask);
- free_irq(aac->msixentry[i].vector,
- &(aac->aac_msix[i]));
- }
- pci_disable_msix(aac->pdev);
- } else {
- free_irq(aac->pdev->irq, &(aac->aac_msix[0]));
- }
- } else {
- free_irq(aac->pdev->irq, aac);
- }
- if (aac->msi)
- pci_disable_msi(aac->pdev);
+ aac_free_irq(aac);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
quirks = aac_get_driver_ident(index)->quirks;
@@ -1978,3 +2006,83 @@ int aac_command_thread(void *data)
dev->aif_thread = 0;
return 0;
}
+
+int aac_acquire_irq(struct aac_dev *dev)
+{
+ int i;
+ int j;
+ int ret = 0;
+ int cpu;
+
+ cpu = cpumask_first(cpu_online_mask);
+ if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
+ for (i = 0; i < dev->max_msix; i++) {
+ dev->aac_msix[i].vector_no = i;
+ dev->aac_msix[i].dev = dev;
+ if (request_irq(dev->msixentry[i].vector,
+ dev->a_ops.adapter_intr,
+ 0, "aacraid", &(dev->aac_msix[i]))) {
+ printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
+ dev->name, dev->id, i);
+ for (j = 0 ; j < i ; j++)
+ free_irq(dev->msixentry[j].vector,
+ &(dev->aac_msix[j]));
+ pci_disable_msix(dev->pdev);
+ ret = -1;
+ }
+ if (irq_set_affinity_hint(dev->msixentry[i].vector,
+ get_cpu_mask(cpu))) {
+ printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n",
+ dev->name, dev->id, cpu);
+ }
+ cpu = cpumask_next(cpu, cpu_online_mask);
+ }
+ } else {
+ dev->aac_msix[0].vector_no = 0;
+ dev->aac_msix[0].dev = dev;
+
+ if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
+ IRQF_SHARED, "aacraid",
+ &(dev->aac_msix[0])) < 0) {
+ if (dev->msi)
+ pci_disable_msi(dev->pdev);
+ printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+ dev->name, dev->id);
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+void aac_free_irq(struct aac_dev *dev)
+{
+ int i;
+ int cpu;
+
+ cpu = cpumask_first(cpu_online_mask);
+ if (dev->pdev->device == PMC_DEVICE_S6 ||
+ dev->pdev->device == PMC_DEVICE_S7 ||
+ dev->pdev->device == PMC_DEVICE_S8 ||
+ dev->pdev->device == PMC_DEVICE_S9) {
+ if (dev->max_msix > 1) {
+ for (i = 0; i < dev->max_msix; i++) {
+ if (irq_set_affinity_hint(
+ dev->msixentry[i].vector, NULL)) {
+ printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n",
+ dev->name, dev->id, cpu);
+ }
+ cpu = cpumask_next(cpu, cpu_online_mask);
+ free_irq(dev->msixentry[i].vector,
+ &(dev->aac_msix[i]));
+ }
+ } else {
+ free_irq(dev->pdev->irq, &(dev->aac_msix[0]));
+ }
+ } else {
+ free_irq(dev->pdev->irq, dev);
+ }
+ if (dev->msi)
+ pci_disable_msi(dev->pdev);
+ else if (dev->max_msix > 1)
+ pci_disable_msix(dev->pdev);
+}
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index da9d993..d677b52 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -394,7 +394,6 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
fib->callback(fib->callback_data, fib);
} else {
aac_fib_complete(fib);
- aac_fib_free(fib);
}
} else {
unsigned long flagv;
@@ -416,7 +415,6 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
fib->done = 0;
spin_unlock_irqrestore(&fib->event_lock, flagv);
aac_fib_complete(fib);
- aac_fib_free(fib);
}
}
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 9eec027..ff6caab 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -38,6 +38,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <linux/pci-aspm.h>
#include <linux/slab.h>
#include <linux/mutex.h>
@@ -79,7 +80,7 @@ MODULE_VERSION(AAC_DRIVER_FULL_VERSION);
static DEFINE_MUTEX(aac_mutex);
static LIST_HEAD(aac_devices);
-static int aac_cfg_major = -1;
+static int aac_cfg_major = AAC_CHARDEV_UNREGISTERED;
char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
/*
@@ -451,9 +452,12 @@ static int aac_slave_configure(struct scsi_device *sdev)
else if (depth < 2)
depth = 2;
scsi_change_queue_depth(sdev, depth);
- } else
+ } else {
scsi_change_queue_depth(sdev, 1);
+ sdev->tagged_supported = 1;
+ }
+
return 0;
}
@@ -700,23 +704,18 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
static long aac_cfg_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret;
- struct aac_dev *aac;
- aac = (struct aac_dev *)file->private_data;
- if (!capable(CAP_SYS_RAWIO) || aac->adapter_shutdown)
+ struct aac_dev *aac = (struct aac_dev *)file->private_data;
+
+ if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- mutex_lock(&aac_mutex);
- ret = aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
- mutex_unlock(&aac_mutex);
- return ret;
+ return aac_do_ioctl(aac, cmd, (void __user *)arg);
}
#ifdef CONFIG_COMPAT
static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg)
{
long ret;
- mutex_lock(&aac_mutex);
switch (cmd) {
case FSACTL_MINIPORT_REV_CHECK:
case FSACTL_SENDFIB:
@@ -750,7 +749,6 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
ret = -ENOIOCTLCMD;
break;
}
- mutex_unlock(&aac_mutex);
return ret;
}
@@ -1075,6 +1073,8 @@ static void __aac_shutdown(struct aac_dev * aac)
int i;
int cpu;
+ aac_send_shutdown(aac);
+
if (aac->aif_thread) {
int i;
/* Clear out events first */
@@ -1086,7 +1086,6 @@ static void __aac_shutdown(struct aac_dev * aac)
}
kthread_stop(aac->thread);
}
- aac_send_shutdown(aac);
aac_adapter_disable_int(aac);
cpu = cpumask_first(cpu_online_mask);
if (aac->pdev->device == PMC_DEVICE_S6 ||
@@ -1120,6 +1119,13 @@ static void __aac_shutdown(struct aac_dev * aac)
else if (aac->max_msix > 1)
pci_disable_msix(aac->pdev);
}
+static void aac_init_char(void)
+{
+ aac_cfg_major = register_chrdev(0, "aac", &aac_cfg_fops);
+ if (aac_cfg_major < 0) {
+ pr_err("aacraid: unable to register \"aac\" device.\n");
+ }
+}
static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -1132,6 +1138,12 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
u64 dmamask;
extern int aac_sync_mode;
+ /*
+ * Only series 7 needs freset.
+ */
+ if (pdev->device == PMC_DEVICE_S7)
+ pdev->needs_freset = 1;
+
list_for_each_entry(aac, &aac_devices, entry) {
if (aac->id > unique_id)
break;
@@ -1171,6 +1183,9 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
shost->max_cmd_len = 16;
shost->use_cmd_list = 1;
+ if (aac_cfg_major == AAC_CHARDEV_NEEDS_REINIT)
+ aac_init_char();
+
aac = (struct aac_dev *)shost->hostdata;
aac->base_start = pci_resource_start(pdev, 0);
aac->scsi_host_ptr = shost;
@@ -1185,6 +1200,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_free_host;
spin_lock_init(&aac->fib_lock);
+ mutex_init(&aac->ioctl_mutex);
/*
* Map in the registers from the adapter.
*/
@@ -1296,6 +1312,9 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_deinit;
scsi_scan_host(shost);
+ pci_enable_pcie_error_reporting(pdev);
+ pci_save_state(pdev);
+
return 0;
out_deinit:
@@ -1317,6 +1336,165 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
return error;
}
+static void aac_release_resources(struct aac_dev *aac)
+{
+ int i;
+
+ aac_adapter_disable_int(aac);
+ if (aac->pdev->device == PMC_DEVICE_S6 ||
+ aac->pdev->device == PMC_DEVICE_S7 ||
+ aac->pdev->device == PMC_DEVICE_S8 ||
+ aac->pdev->device == PMC_DEVICE_S9) {
+ if (aac->max_msix > 1) {
+ for (i = 0; i < aac->max_msix; i++)
+ free_irq(aac->msixentry[i].vector,
+ &(aac->aac_msix[i]));
+ } else {
+ free_irq(aac->pdev->irq, &(aac->aac_msix[0]));
+ }
+ } else {
+ free_irq(aac->pdev->irq, aac);
+ }
+ if (aac->msi)
+ pci_disable_msi(aac->pdev);
+ else if (aac->max_msix > 1)
+ pci_disable_msix(aac->pdev);
+
+}
+
+static int aac_acquire_resources(struct aac_dev *dev)
+{
+ int i, j;
+ int instance = dev->id;
+ const char *name = dev->name;
+ unsigned long status;
+ /*
+ * First clear out all interrupts. Then enable the one's that we
+ * can handle.
+ */
+ while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)
+ || status == 0xffffffff)
+ msleep(20);
+
+ aac_adapter_disable_int(dev);
+ aac_adapter_enable_int(dev);
+
+
+ if ((dev->pdev->device == PMC_DEVICE_S7 ||
+ dev->pdev->device == PMC_DEVICE_S8 ||
+ dev->pdev->device == PMC_DEVICE_S9))
+ aac_define_int_mode(dev);
+
+ if (dev->msi_enabled)
+ aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
+
+ if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
+ for (i = 0; i < dev->max_msix; i++) {
+ dev->aac_msix[i].vector_no = i;
+ dev->aac_msix[i].dev = dev;
+
+ if (request_irq(dev->msixentry[i].vector,
+ dev->a_ops.adapter_intr,
+ 0, "aacraid", &(dev->aac_msix[i]))) {
+ printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
+ name, instance, i);
+ for (j = 0 ; j < i ; j++)
+ free_irq(dev->msixentry[j].vector,
+ &(dev->aac_msix[j]));
+ pci_disable_msix(dev->pdev);
+ goto error_iounmap;
+ }
+ }
+ } else {
+ dev->aac_msix[0].vector_no = 0;
+ dev->aac_msix[0].dev = dev;
+
+ if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
+ IRQF_SHARED, "aacraid",
+ &(dev->aac_msix[0])) < 0) {
+ if (dev->msi)
+ pci_disable_msi(dev->pdev);
+ printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+ name, instance);
+ goto error_iounmap;
+ }
+ }
+
+ aac_adapter_enable_int(dev);
+
+ /*max msix may change after EEH
+ * Re-assign vectors to fibs
+ */
+ aac_fib_vector_assign(dev);
+
+ if (!dev->sync_mode) {
+ /* After EEH recovery or suspend resume, max_msix count
+ * may change, therfore updating in init as well.
+ */
+ aac_adapter_start(dev);
+ dev->init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
+ }
+ return 0;
+
+error_iounmap:
+ return -1;
+
+}
+
+#if (defined(CONFIG_PM))
+static int aac_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
+
+ scsi_block_requests(shost);
+ aac_send_shutdown(aac);
+
+ aac_release_resources(aac);
+
+ pci_set_drvdata(pdev, shost);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int aac_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
+ int r;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, PCI_D0, 0);
+ pci_restore_state(pdev);
+ r = pci_enable_device(pdev);
+
+ if (r)
+ goto fail_device;
+
+ pci_set_master(pdev);
+ if (aac_acquire_resources(aac))
+ goto fail_device;
+ /*
+ * reset this flag to unblock ioctl() as it was set at
+ * aac_send_shutdown() to block ioctls from upperlayer
+ */
+ aac->adapter_shutdown = 0;
+ scsi_unblock_requests(shost);
+
+ return 0;
+
+fail_device:
+ printk(KERN_INFO "%s%d: resume failed.\n", aac->name, aac->id);
+ scsi_host_put(shost);
+ pci_disable_device(pdev);
+ return -ENODEV;
+}
+#endif
+
static void aac_shutdown(struct pci_dev *dev)
{
struct Scsi_Host *shost = pci_get_drvdata(dev);
@@ -1347,16 +1525,153 @@ static void aac_remove_one(struct pci_dev *pdev)
pci_disable_device(pdev);
if (list_empty(&aac_devices)) {
unregister_chrdev(aac_cfg_major, "aac");
- aac_cfg_major = -1;
+ aac_cfg_major = AAC_CHARDEV_NEEDS_REINIT;
+ }
+}
+
+static void aac_flush_ios(struct aac_dev *aac)
+{
+ int i;
+ struct scsi_cmnd *cmd;
+
+ for (i = 0; i < aac->scsi_host_ptr->can_queue; i++) {
+ cmd = (struct scsi_cmnd *)aac->fibs[i].callback_data;
+ if (cmd && (cmd->SCp.phase == AAC_OWNER_FIRMWARE)) {
+ scsi_dma_unmap(cmd);
+
+ if (aac->handle_pci_error)
+ cmd->result = DID_NO_CONNECT << 16;
+ else
+ cmd->result = DID_RESET << 16;
+
+ cmd->scsi_done(cmd);
+ }
+ }
+}
+
+static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev,
+ enum pci_channel_state error)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct aac_dev *aac = shost_priv(shost);
+
+ dev_err(&pdev->dev, "aacraid: PCI error detected %x\n", error);
+
+ switch (error) {
+ case pci_channel_io_normal:
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ aac->handle_pci_error = 1;
+
+ scsi_block_requests(aac->scsi_host_ptr);
+ aac_flush_ios(aac);
+ aac_release_resources(aac);
+
+ pci_disable_pcie_error_reporting(pdev);
+ aac_adapter_ioremap(aac, 0);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ aac->handle_pci_error = 1;
+
+ aac_flush_ios(aac);
+ return PCI_ERS_RESULT_DISCONNECT;
}
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t aac_pci_mmio_enabled(struct pci_dev *pdev)
+{
+ dev_err(&pdev->dev, "aacraid: PCI error - mmio enabled\n");
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t aac_pci_slot_reset(struct pci_dev *pdev)
+{
+ dev_err(&pdev->dev, "aacraid: PCI error - slot reset\n");
+ pci_restore_state(pdev);
+ if (pci_enable_device(pdev)) {
+ dev_warn(&pdev->dev,
+ "aacraid: failed to enable slave\n");
+ goto fail_device;
+ }
+
+ pci_set_master(pdev);
+
+ if (pci_enable_device_mem(pdev)) {
+ dev_err(&pdev->dev, "pci_enable_device_mem failed\n");
+ goto fail_device;
+ }
+
+ return PCI_ERS_RESULT_RECOVERED;
+
+fail_device:
+ dev_err(&pdev->dev, "aacraid: PCI error - slot reset failed\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+}
+
+
+static void aac_pci_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct scsi_device *sdev = NULL;
+ struct aac_dev *aac = (struct aac_dev *)shost_priv(shost);
+
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+
+ if (aac_adapter_ioremap(aac, aac->base_size)) {
+
+ dev_err(&pdev->dev, "aacraid: ioremap failed\n");
+ /* remap failed, go back ... */
+ aac->comm_interface = AAC_COMM_PRODUCER;
+ if (aac_adapter_ioremap(aac, AAC_MIN_FOOTPRINT_SIZE)) {
+ dev_warn(&pdev->dev,
+ "aacraid: unable to map adapter.\n");
+
+ return;
+ }
+ }
+
+ msleep(10000);
+
+ aac_acquire_resources(aac);
+
+ /*
+ * reset this flag to unblock ioctl() as it was set
+ * at aac_send_shutdown() to block ioctls from upperlayer
+ */
+ aac->adapter_shutdown = 0;
+ aac->handle_pci_error = 0;
+
+ shost_for_each_device(sdev, shost)
+ if (sdev->sdev_state == SDEV_OFFLINE)
+ sdev->sdev_state = SDEV_RUNNING;
+ scsi_unblock_requests(aac->scsi_host_ptr);
+ scsi_scan_host(aac->scsi_host_ptr);
+ pci_save_state(pdev);
+
+ dev_err(&pdev->dev, "aacraid: PCI error - resume\n");
}
+static struct pci_error_handlers aac_pci_err_handler = {
+ .error_detected = aac_pci_error_detected,
+ .mmio_enabled = aac_pci_mmio_enabled,
+ .slot_reset = aac_pci_slot_reset,
+ .resume = aac_pci_resume,
+};
+
static struct pci_driver aac_pci_driver = {
.name = AAC_DRIVERNAME,
.id_table = aac_pci_tbl,
.probe = aac_probe_one,
.remove = aac_remove_one,
+#if (defined(CONFIG_PM))
+ .suspend = aac_suspend,
+ .resume = aac_resume,
+#endif
.shutdown = aac_shutdown,
+ .err_handler = &aac_pci_err_handler,
};
static int __init aac_init(void)
@@ -1370,11 +1685,8 @@ static int __init aac_init(void)
if (error < 0)
return error;
- aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops);
- if (aac_cfg_major < 0) {
- printk(KERN_WARNING
- "aacraid: unable to register \"aac\" device.\n");
- }
+ aac_init_char();
+
return 0;
}
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 9570612..ac16380 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -623,6 +623,7 @@ int _aac_rx_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health;
dev->a_ops.adapter_restart = aac_rx_restart_adapter;
+ dev->a_ops.adapter_start = aac_rx_start_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index e66477c..869aea2 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -372,6 +372,7 @@ int aac_sa_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dev->a_ops.adapter_check_health = aac_sa_check_health;
dev->a_ops.adapter_restart = aac_sa_restart_adapter;
+ dev->a_ops.adapter_start = aac_sa_start_adapter;
dev->a_ops.adapter_intr = aac_sa_intr;
dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
dev->a_ops.adapter_ioremap = aac_sa_ioremap;
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index e63cf9f..bc0203f 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -156,8 +156,8 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
break;
if (dev->msi_enabled && dev->max_msix > 1)
atomic_dec(&dev->rrq_outstanding[vector_no]);
- aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
dev->host_rrq[index++] = 0;
+ aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
if (index == (vector_no + 1) * dev->vector_cap)
index = vector_no * dev->vector_cap;
dev->host_rrq_idx[vector_no] = index;
@@ -447,37 +447,25 @@ static int aac_src_deliver_message(struct fib *fib)
u32 fibsize;
dma_addr_t address;
struct aac_fib_xporthdr *pFibX;
+#if !defined(writeq)
+ unsigned long flags;
+#endif
+
u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
+ u16 vector_no;
atomic_inc(&q->numpending);
if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest &&
dev->max_msix > 1) {
- u_int16_t vector_no, first_choice = 0xffff;
-
- vector_no = dev->fibs_pushed_no % dev->max_msix;
- do {
- vector_no += 1;
- if (vector_no == dev->max_msix)
- vector_no = 1;
- if (atomic_read(&dev->rrq_outstanding[vector_no]) <
- dev->vector_cap)
- break;
- if (0xffff == first_choice)
- first_choice = vector_no;
- else if (vector_no == first_choice)
- break;
- } while (1);
- if (vector_no == first_choice)
- vector_no = 0;
- atomic_inc(&dev->rrq_outstanding[vector_no]);
- if (dev->fibs_pushed_no == 0xffffffff)
- dev->fibs_pushed_no = 0;
- else
- dev->fibs_pushed_no++;
+ vector_no = fib->vector_no;
fib->hw_fib_va->header.Handle += (vector_no << 16);
+ } else {
+ vector_no = 0;
}
+ atomic_inc(&dev->rrq_outstanding[vector_no]);
+
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
/* Calculate the amount to the fibsize bits */
fibsize = (hdr_size + 127) / 128 - 1;
@@ -511,10 +499,14 @@ static int aac_src_deliver_message(struct fib *fib)
return -EINVAL;
address |= fibsize;
}
-
+#if defined(writeq)
+ src_writeq(dev, MUnit.IQ_L, (u64)address);
+#else
+ spin_lock_irqsave(&fib->dev->iq_lock, flags);
src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff);
src_writel(dev, MUnit.IQ_L, address & 0xffffffff);
-
+ spin_unlock_irqrestore(&fib->dev->iq_lock, flags);
+#endif
return 0;
}
@@ -726,6 +718,7 @@ int aac_src_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
dev->a_ops.adapter_check_health = aac_src_check_health;
dev->a_ops.adapter_restart = aac_src_restart_adapter;
+ dev->a_ops.adapter_start = aac_src_start_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
@@ -741,7 +734,7 @@ int aac_src_init(struct aac_dev *dev)
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1)
goto error_iounmap;
- dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
+ dev->msi = !pci_enable_msi(dev->pdev);
dev->aac_msix[0].vector_no = 0;
dev->aac_msix[0].dev = dev;
@@ -789,9 +782,7 @@ int aac_srcv_init(struct aac_dev *dev)
unsigned long status;
int restart = 0;
int instance = dev->id;
- int i, j;
const char *name = dev->name;
- int cpu;
dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
dev->a_ops.adapter_comm = aac_src_select_comm;
@@ -892,6 +883,7 @@ int aac_srcv_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
dev->a_ops.adapter_check_health = aac_src_check_health;
dev->a_ops.adapter_restart = aac_src_restart_adapter;
+ dev->a_ops.adapter_start = aac_src_start_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
@@ -908,48 +900,10 @@ int aac_srcv_init(struct aac_dev *dev)
goto error_iounmap;
if (dev->msi_enabled)
aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
- if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
- cpu = cpumask_first(cpu_online_mask);
- for (i = 0; i < dev->max_msix; i++) {
- dev->aac_msix[i].vector_no = i;
- dev->aac_msix[i].dev = dev;
-
- if (request_irq(dev->msixentry[i].vector,
- dev->a_ops.adapter_intr,
- 0,
- "aacraid",
- &(dev->aac_msix[i]))) {
- printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
- name, instance, i);
- for (j = 0 ; j < i ; j++)
- free_irq(dev->msixentry[j].vector,
- &(dev->aac_msix[j]));
- pci_disable_msix(dev->pdev);
- goto error_iounmap;
- }
- if (irq_set_affinity_hint(
- dev->msixentry[i].vector,
- get_cpu_mask(cpu))) {
- printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n",
- name, instance, cpu);
- }
- cpu = cpumask_next(cpu, cpu_online_mask);
- }
- } else {
- dev->aac_msix[0].vector_no = 0;
- dev->aac_msix[0].dev = dev;
-
- if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED,
- "aacraid",
- &(dev->aac_msix[0])) < 0) {
- if (dev->msi)
- pci_disable_msi(dev->pdev);
- printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
- name, instance);
- goto error_iounmap;
- }
- }
+
+ if (aac_acquire_irq(dev))
+ goto error_iounmap;
+
dev->dbg_base = dev->base_start;
dev->dbg_base_mapped = dev->base;
dev->dbg_size = dev->base_size;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 4305178..febbd83 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -7803,7 +7803,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
return ASC_BUSY;
}
scsiqp->sense_addr = cpu_to_le32(sense_addr);
- scsiqp->sense_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
+ scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
/* Build ADV_SCSI_REQ_Q */
@@ -10819,7 +10819,6 @@ static struct scsi_host_template advansys_template = {
* by enabling clustering, I/O throughput increases as well.
*/
.use_clustering = ENABLE_CLUSTERING,
- .use_blk_tags = 1,
};
static int advansys_wide_init_chip(struct Scsi_Host *shost)
@@ -11211,11 +11210,6 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
/* Set maximum number of queues the adapter can handle. */
shost->can_queue = adv_dvc_varp->max_host_qng;
}
- ret = scsi_init_shared_tag_map(shost, shost->can_queue);
- if (ret) {
- shost_printk(KERN_ERR, shost, "init tag map failed\n");
- goto err_free_dma;
- }
/*
* Set the maximum number of scatter-gather elements the
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 5b8b293..7db448e 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -403,6 +403,9 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
cptr = kmalloc(sizeof(*cptr) * sg_count, GFP_KERNEL | GFP_DMA);
if (!cptr)
return SCSI_MLQUEUE_HOST_BUSY;
+ } else {
+ sg_count = 0;
+ cptr = NULL;
}
/* Use the outgoing mailboxes in a round-robin fashion, because this
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index df2e0e5..d47b527 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -624,7 +624,7 @@ struct scb {
};
TAILQ_HEAD(scb_tailq, scb);
-LIST_HEAD(scb_list, scb);
+BSD_LIST_HEAD(scb_list, scb);
struct scb_data {
/*
@@ -1069,7 +1069,7 @@ struct ahd_softc {
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ BSD_LIST_HEAD(, scb) pending_scbs;
/*
* Current register window mode information.
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index ce96a0b..2588b8f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -925,7 +925,6 @@ struct scsi_host_template aic79xx_driver_template = {
.slave_configure = ahd_linux_slave_configure,
.target_alloc = ahd_linux_target_alloc,
.target_destroy = ahd_linux_target_destroy,
- .use_blk_tags = 1,
};
/******************************** Bus DMA *************************************/
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index c58fa33..728193a 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -65,11 +65,6 @@
/* Core SCSI definitions */
#define AIC_LIB_PREFIX ahd
-/* Name space conflict with BSD queue macros */
-#ifdef LIST_HEAD
-#undef LIST_HEAD
-#endif
-
#include "cam.h"
#include "queue.h"
#include "scsi_message.h"
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index f695774..4ce4e90 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -916,7 +916,7 @@ struct ahc_softc {
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ BSD_LIST_HEAD(, scb) pending_scbs;
/*
* Counting lock for deferring the release of additional
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index a2f2c77..fc6a831 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -812,7 +812,6 @@ struct scsi_host_template aic7xxx_driver_template = {
.slave_configure = ahc_linux_slave_configure,
.target_alloc = ahc_linux_target_alloc,
.target_destroy = ahc_linux_target_destroy,
- .use_blk_tags = 1,
};
/**************************** Tasklet Handler *********************************/
@@ -1337,6 +1336,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
case AHC_DEV_Q_TAGGED:
scsi_change_queue_depth(sdev,
dev->openings + dev->active);
+ break;
default:
/*
* We allow the OS to queue 2 untagged transactions to
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index bc4cca9..54c7028 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -82,11 +82,6 @@
/* Core SCSI definitions */
#define AIC_LIB_PREFIX ahc
-/* Name space conflict with BSD queue macros */
-#ifdef LIST_HEAD
-#undef LIST_HEAD
-#endif
-
#include "cam.h"
#include "queue.h"
#include "scsi_message.h"
diff --git a/drivers/scsi/aic7xxx/queue.h b/drivers/scsi/aic7xxx/queue.h
index 8adf800..ba60298 100644
--- a/drivers/scsi/aic7xxx/queue.h
+++ b/drivers/scsi/aic7xxx/queue.h
@@ -246,7 +246,7 @@ struct { \
/*
* List declarations.
*/
-#define LIST_HEAD(name, type) \
+#define BSD_LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index f6c336b..662b232 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -73,7 +73,6 @@ static struct scsi_host_template aic94xx_sht = {
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -704,10 +703,10 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
{
int err;
+ scsi_remove_host(asd_ha->sas_ha.core.shost);
err = sas_unregister_ha(&asd_ha->sas_ha);
sas_remove_host(asd_ha->sas_ha.core.shost);
- scsi_remove_host(asd_ha->sas_ha.core.shost);
scsi_host_put(asd_ha->sas_ha.core.shost);
kfree(asd_ha->sas_ha.sas_phy);
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
index 912e6b7..101072c 100644
--- a/drivers/scsi/aic94xx/aic94xx_sas.h
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -327,46 +327,9 @@ struct scb_header {
#define LUN_SIZE 8
-/* See SAS spec, task IU
- */
-struct ssp_task_iu {
- u8 lun[LUN_SIZE]; /* BE */
- u16 _r_a;
- u8 tmf;
- u8 _r_b;
- __be16 tag; /* BE */
- u8 _r_c[14];
-} __attribute__ ((packed));
-
-/* See SAS spec, command IU
- */
-struct ssp_command_iu {
- u8 lun[LUN_SIZE];
- u8 _r_a;
- u8 efb_prio_attr; /* enable first burst, task prio & attr */
-#define EFB_MASK 0x80
-#define TASK_PRIO_MASK 0x78
-#define TASK_ATTR_MASK 0x07
-
- u8 _r_b;
- u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */
- union {
- u8 cdb[16];
- struct {
- __le64 long_cdb_addr; /* bus address, LE */
- __le32 long_cdb_size; /* LE */
- u8 _r_c[3];
- u8 eol_ds; /* eol:6,6, ds:5,4 */
- } long_cdb; /* sequencer extension */
- };
-} __attribute__ ((packed));
-
-struct xfer_rdy_iu {
- __be32 requested_offset; /* BE */
- __be32 write_data_len; /* BE */
- __be32 _r_a;
-} __attribute__ ((packed));
-
+#define EFB_MASK 0x80
+#define TASK_PRIO_MASK 0x78
+#define TASK_ATTR_MASK 0x07
/* ---------- SCB tasks ---------- */
/* This is both ssp_task and long_ssp_task
@@ -511,7 +474,7 @@ struct abort_task {
u8 proto_conn_rate;
__le32 _r_a;
struct ssp_frame_hdr ssp_frame;
- struct ssp_task_iu ssp_task;
+ struct ssp_tmf_iu ssp_task;
__le16 sister_scb;
__le16 conn_handle;
u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
@@ -549,7 +512,7 @@ struct clear_nexus {
u8 _r_b[3];
u8 conn_mask;
u8 _r_c[19];
- struct ssp_task_iu ssp_task; /* LUN and TAG */
+ struct ssp_tmf_iu ssp_task; /* LUN and TAG */
__le16 _r_d;
__le16 conn_handle;
__le64 _r_e;
@@ -562,7 +525,7 @@ struct initiate_ssp_tmf {
u8 proto_conn_rate;
__le32 _r_a;
struct ssp_frame_hdr ssp_frame;
- struct ssp_task_iu ssp_task;
+ struct ssp_tmf_iu ssp_task;
__le16 sister_scb;
__le16 conn_handle;
u8 flags; /* itnl override and suspend data tx */
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index 3bcaaac..cf99f8c 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -52,7 +52,7 @@ struct device_attribute;
#define ARCMSR_MAX_FREECCB_NUM 320
#define ARCMSR_MAX_OUTSTANDING_CMD 255
#endif
-#define ARCMSR_DRIVER_VERSION "v1.30.00.04-20140919"
+#define ARCMSR_DRIVER_VERSION "v1.30.00.22-20151126"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -74,6 +74,9 @@ struct device_attribute;
#ifndef PCI_DEVICE_ID_ARECA_1214
#define PCI_DEVICE_ID_ARECA_1214 0x1214
#endif
+#ifndef PCI_DEVICE_ID_ARECA_1203
+ #define PCI_DEVICE_ID_ARECA_1203 0x1203
+#endif
/*
**********************************************************************************
**
@@ -245,6 +248,12 @@ struct FIRMWARE_INFO
/* window of "instruction flags" from iop to driver */
#define ARCMSR_IOP2DRV_DOORBELL 0x00020408
#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL_1203 0x00021870
+#define ARCMSR_IOP2DRV_DOORBELL_MASK_1203 0x00021874
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL_1203 0x00021878
+#define ARCMSR_DRV2IOP_DOORBELL_MASK_1203 0x0002187C
/* ARECA FLAG LANGUAGE */
/* ioctl transfer */
#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001
@@ -288,6 +297,9 @@ struct FIRMWARE_INFO
#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00
/* iop message_rwbuffer for message command */
#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
+
+#define MEM_BASE0(x) (u32 __iomem *)((unsigned long)acb->mem_base0 + x)
+#define MEM_BASE1(x) (u32 __iomem *)((unsigned long)acb->mem_base1 + x)
/*
************************************************************************
** SPEC. for Areca HBC adapter
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 333db59..7640498 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -114,6 +114,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
@@ -157,6 +158,8 @@ static struct pci_device_id arcmsr_device_id_table[] = {
.driver_data = ACB_ADAPTER_TYPE_B},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202),
.driver_data = ACB_ADAPTER_TYPE_B},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1203),
+ .driver_data = ACB_ADAPTER_TYPE_B},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210),
.driver_data = ACB_ADAPTER_TYPE_A},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214),
@@ -495,6 +498,91 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
}
}
+static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb)
+{
+ bool rtn = true;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
+ struct pci_dev *pdev = acb->pdev;
+
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg;
+ acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
+ dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent) {
+ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle2 = dma_coherent_handle;
+ acb->dma_coherent2 = dma_coherent;
+ reg = (struct MessageUnit_B *)dma_coherent;
+ acb->pmuB = reg;
+ if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) {
+ reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203);
+ reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203);
+ reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203);
+ reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203);
+ } else {
+ reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL);
+ reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK);
+ reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL);
+ reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK);
+ }
+ reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER);
+ reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER);
+ reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER);
+ }
+ break;
+ case ACB_ADAPTER_TYPE_D: {
+ struct MessageUnit_D *reg;
+
+ acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
+ dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent) {
+ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle2 = dma_coherent_handle;
+ acb->dma_coherent2 = dma_coherent;
+ reg = (struct MessageUnit_D *)dma_coherent;
+ acb->pmuD = reg;
+ reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID);
+ reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION);
+ reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK);
+ reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET);
+ reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST);
+ reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS);
+ reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE);
+ reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0);
+ reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1);
+ reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0);
+ reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1);
+ reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL);
+ reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL);
+ reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE);
+ reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW);
+ reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH);
+ reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER);
+ reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW);
+ reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH);
+ reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER);
+ reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER);
+ reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE);
+ reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE);
+ reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER);
+ reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER);
+ reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER);
+ }
+ break;
+ default:
+ break;
+ }
+ return rtn;
+}
+
static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
@@ -739,9 +827,12 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if(!error){
goto pci_release_regs;
}
+ error = arcmsr_alloc_io_queue(acb);
+ if (!error)
+ goto unmap_pci_region;
error = arcmsr_get_firmware_spec(acb);
if(!error){
- goto unmap_pci_region;
+ goto free_hbb_mu;
}
error = arcmsr_alloc_ccb_pool(acb);
if(error){
@@ -2622,9 +2713,6 @@ static bool arcmsr_hbaA_get_config(struct AdapterControlBlock *acb)
static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
- struct pci_dev *pdev = acb->pdev;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle;
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
char *acb_device_map = acb->device_map;
@@ -2636,30 +2724,16 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
/*firm_version,21,84-99*/
int count;
- acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
- dma_coherent = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
- &dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent){
- printk(KERN_NOTICE
- "arcmsr%d: dma_alloc_coherent got error for hbb mu\n",
- acb->host->host_no);
- return false;
- }
- acb->dma_coherent_handle2 = dma_coherent_handle;
- acb->dma_coherent2 = dma_coherent;
- reg = (struct MessageUnit_B *)dma_coherent;
- acb->pmuB = reg;
- reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
- reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
- reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
- reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
- reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
- reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
- reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]); /*firm_model,15,60-67*/
iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]); /*firm_version,17,68-83*/
iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]); /*firm_version,21,84-99*/
+ arcmsr_wait_firmware_ready(acb);
+ writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+ if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+ printk(KERN_ERR "arcmsr%d: can't set driver mode.\n", acb->host->host_no);
+ return false;
+ }
writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
@@ -2694,15 +2768,15 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
acb->firm_model,
acb->firm_version);
- acb->signature = readl(&reg->message_rwbuffer[1]);
+ acb->signature = readl(&reg->message_rwbuffer[0]);
/*firm_signature,1,00-03*/
- acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
+ acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
+ acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
+ acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
+ acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
/*firm_ide_channels,4,16-19*/
acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
/*firm_ide_channels,4,16-19*/
@@ -2777,70 +2851,8 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
char __iomem *iop_firm_version;
char __iomem *iop_device_map;
u32 count;
- struct MessageUnit_D *reg;
- void *dma_coherent2;
- dma_addr_t dma_coherent_handle2;
- struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit_D *reg = acb->pmuD;
- acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
- dma_coherent2 = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
- &dma_coherent_handle2, GFP_KERNEL);
- if (!dma_coherent2) {
- pr_notice("DMA allocation failed...\n");
- return false;
- }
- memset(dma_coherent2, 0, acb->roundup_ccbsize);
- acb->dma_coherent_handle2 = dma_coherent_handle2;
- acb->dma_coherent2 = dma_coherent2;
- reg = (struct MessageUnit_D *)dma_coherent2;
- acb->pmuD = reg;
- reg->chip_id = acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID;
- reg->cpu_mem_config = acb->mem_base0 +
- ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION;
- reg->i2o_host_interrupt_mask = acb->mem_base0 +
- ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK;
- reg->sample_at_reset = acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET;
- reg->reset_request = acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST;
- reg->host_int_status = acb->mem_base0 +
- ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS;
- reg->pcief0_int_enable = acb->mem_base0 +
- ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE;
- reg->inbound_msgaddr0 = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_MESSAGE0;
- reg->inbound_msgaddr1 = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_MESSAGE1;
- reg->outbound_msgaddr0 = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_MESSAGE0;
- reg->outbound_msgaddr1 = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_MESSAGE1;
- reg->inbound_doorbell = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_DOORBELL;
- reg->outbound_doorbell = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_DOORBELL;
- reg->outbound_doorbell_enable = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE;
- reg->inboundlist_base_low = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW;
- reg->inboundlist_base_high = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH;
- reg->inboundlist_write_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER;
- reg->outboundlist_base_low = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW;
- reg->outboundlist_base_high = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH;
- reg->outboundlist_copy_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER;
- reg->outboundlist_read_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER;
- reg->outboundlist_interrupt_cause = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE;
- reg->outboundlist_interrupt_enable = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE;
- reg->message_wbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER;
- reg->message_rbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER;
- reg->msgcode_rwbuffer = acb->mem_base0 +
- ARCMSR_ARC1214_MESSAGE_RWBUFFER;
iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
iop_device_map = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
@@ -2855,8 +2867,6 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
pr_notice("arcmsr%d: wait get adapter firmware "
"miscellaneous data timeout\n", acb->host->host_no);
- dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
- acb->dma_coherent2, acb->dma_coherent_handle2);
return false;
}
count = 8;
@@ -2880,15 +2890,15 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
iop_device_map++;
count--;
}
- acb->signature = readl(&reg->msgcode_rwbuffer[1]);
+ acb->signature = readl(&reg->msgcode_rwbuffer[0]);
/*firm_signature,1,00-03*/
- acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
+ acb->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
+ acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
+ acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
+ acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
/*firm_hd_channels,4,16-19*/
acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
@@ -3998,6 +4008,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1160:
case PCI_DEVICE_ID_ARECA_1170:
case PCI_DEVICE_ID_ARECA_1201:
+ case PCI_DEVICE_ID_ARECA_1203:
case PCI_DEVICE_ID_ARECA_1220:
case PCI_DEVICE_ID_ARECA_1230:
case PCI_DEVICE_ID_ARECA_1260:
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index deaaf84..12b8829 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -677,7 +677,8 @@ int round_period(unsigned int period)
* Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
*/
static
-unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
+unsigned char __maybe_unused calc_sync_xfer(unsigned int period,
+ unsigned int offset)
{
return sync_xfer_table[round_period(period)].reg_value |
((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index d28d6c0..221f18c 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -4,9 +4,7 @@
* Copyright 1995-2002, Russell King
*/
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/ioport.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/init.h>
@@ -15,15 +13,14 @@
#include <scsi/scsi_host.h>
-#include <scsi/scsicam.h>
-
#define PSEUDO_DMA
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
-#define NCR5380_read(reg) cumanascsi_read(_instance, reg)
-#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
+#define NCR5380_read(reg) cumanascsi_read(instance, reg)
+#define NCR5380_write(reg, value) cumanascsi_write(instance, reg, value)
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
+
#define NCR5380_intr cumanascsi_intr
#define NCR5380_queue_command cumanascsi_queue_command
#define NCR5380_info cumanascsi_info
@@ -211,6 +208,8 @@ static struct scsi_host_template cumanascsi_template = {
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
.proc_name = "CumanaSCSI-1",
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int cumanascsi1_probe(struct expansion_card *ec,
@@ -240,23 +239,21 @@ static int cumanascsi1_probe(struct expansion_card *ec,
host->irq = ec->irq;
- NCR5380_init(host, 0);
+ ret = NCR5380_init(host, 0);
+ if (ret)
+ goto out_unmap;
+
+ NCR5380_maybe_reset_bus(host);
priv(host)->ctrl = 0;
writeb(0, priv(host)->base + CTRL);
- host->n_io_port = 255;
- if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
- ret = -EBUSY;
- goto out_unmap;
- }
-
ret = request_irq(host->irq, cumanascsi_intr, 0,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, host->irq, ret);
- goto out_unmap;
+ goto out_exit;
}
ret = scsi_add_host(host, &ec->dev);
@@ -268,6 +265,8 @@ static int cumanascsi1_probe(struct expansion_card *ec,
out_free_irq:
free_irq(host->irq, host);
+ out_exit:
+ NCR5380_exit(host);
out_unmap:
iounmap(priv(host)->base);
iounmap(priv(host)->dma);
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index decdc71..2438879 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -98,6 +98,7 @@ static int level_mask = LOG_ERROR;
module_param(level_mask, int, 0644);
+#ifndef MODULE
static int __init fas216_log_setup(char *str)
{
char *s;
@@ -138,6 +139,7 @@ static int __init fas216_log_setup(char *str)
}
__setup("fas216_logging=", fas216_log_setup);
+#endif
static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg)
{
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 7c6fa14..1fab1d18 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -5,9 +5,7 @@
*/
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/ioport.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/init.h>
@@ -20,14 +18,16 @@
#define DONT_USE_INTR
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
-#define NCR5380_local_declare() void __iomem *_base
-#define NCR5380_setup(host) _base = priv(host)->base
-#define NCR5380_read(reg) readb(_base + ((reg) << 2))
-#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
+#define NCR5380_read(reg) \
+ readb(priv(instance)->base + ((reg) << 2))
+#define NCR5380_write(reg, value) \
+ writeb(value, priv(instance)->base + ((reg) << 2))
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
+
#define NCR5380_queue_command oakscsi_queue_command
#define NCR5380_info oakscsi_info
-#define NCR5380_show_info oakscsi_show_info
#define NCR5380_implementation_fields \
void __iomem *base
@@ -103,7 +103,6 @@ printk("reading %p len %d\n", addr, len);
static struct scsi_host_template oakscsi_template = {
.module = THIS_MODULE,
- .show_info = oakscsi_show_info,
.name = "Oak 16-bit SCSI",
.info = oakscsi_info,
.queuecommand = oakscsi_queue_command,
@@ -115,6 +114,8 @@ static struct scsi_host_template oakscsi_template = {
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
.proc_name = "oakscsi",
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
@@ -142,15 +143,21 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
host->irq = NO_IRQ;
host->n_io_port = 255;
- NCR5380_init(host, 0);
+ ret = NCR5380_init(host, 0);
+ if (ret)
+ goto out_unmap;
+
+ NCR5380_maybe_reset_bus(host);
ret = scsi_add_host(host, &ec->dev);
if (ret)
- goto out_unmap;
+ goto out_exit;
scsi_scan_host(host);
goto out;
+ out_exit:
+ NCR5380_exit(host);
out_unmap:
iounmap(priv(host)->base);
unreg:
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index db87ece..389825b 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -1,15 +1,15 @@
/*
* NCR 5380 generic driver routines. These should make it *trivial*
- * to implement 5380 SCSI drivers under Linux with a non-trantor
- * architecture.
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
*
- * Note that these routines also work with NR53c400 family chips.
+ * Note that these routines also work with NR53c400 family chips.
*
* Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
*
* For more information, please consult
*
@@ -24,84 +24,10 @@
* 1+ (800) 334-5454
*/
-/*
- * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
- * this file, too:
- *
- * - Some of the debug statements were incorrect (undefined variables and the
- * like). I fixed that.
- *
- * - In information_transfer(), I think a #ifdef was wrong. Looking at the
- * possible DMA transfer size should also happen for REAL_DMA. I added this
- * in the #if statement.
- *
- * - When using real DMA, information_transfer() should return in a DATAOUT
- * phase after starting the DMA. It has nothing more to do.
- *
- * - The interrupt service routine should run main after end of DMA, too (not
- * only after RESELECTION interrupts). Additionally, it should _not_ test
- * for more interrupts after running main, since a DMA process may have
- * been started and interrupts are turned on now. The new int could happen
- * inside the execution of NCR5380_intr(), leading to recursive
- * calls.
- *
- * - I've added a function merge_contiguous_buffers() that tries to
- * merge scatter-gather buffers that are located at contiguous
- * physical addresses and can be processed with the same DMA setup.
- * Since most scatter-gather operations work on a page (4K) of
- * 4 buffers (1K), in more than 90% of all cases three interrupts and
- * DMA setup actions are saved.
- *
- * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
- * and USLEEP, because these were messing up readability and will never be
- * needed for Atari SCSI.
- *
- * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
- * stuff), and 'main' is executed in a bottom half if awoken by an
- * interrupt.
- *
- * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
- * constructs. In my eyes, this made the source rather unreadable, so I
- * finally replaced that by the *_PRINTK() macros.
- *
- */
-
-/*
- * Further development / testing that should be done :
- * 1. Test linked command handling code after Eric is ready with
- * the high level code.
- */
+/* Ported to Atari by Roman Hodek and others. */
/* Adapted for the sun3 by Sam Creasey. */
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_transport_spi.h>
-
-#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x, y) \
- do { \
- printk("LINE:%d Adding %p to %p\n", \
- __LINE__, (void*)(x), (void*)(y)); \
- if ((x) == (y)) \
- udelay(5); \
- } while (0)
-#define REMOVE(w, x, y, z) \
- do { \
- printk("LINE:%d Removing: %p->%p %p->%p \n", \
- __LINE__, (void*)(w), (void*)(x), \
- (void*)(y), (void*)(z)); \
- if ((x) == (y)) \
- udelay(5); \
- } while (0)
-#else
-#define LIST(x,y)
-#define REMOVE(w,x,y,z)
-#endif
-
-#ifndef notyet
-#undef LINKED
-#endif
-
/*
* Design
*
@@ -126,17 +52,7 @@
* piece of hardware that requires you to sit in a loop polling for
* the REQ signal as long as you are connected. Some devices are
* brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
- * while doing long seek operations.
- *
- * The workaround for this is to keep track of devices that have
- * disconnected. If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
- *
- * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done. An algorithm based
- * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
+ * while doing long seek operations. [...] These
* broken devices are the exception rather than the rule and I'd rather
* spend my time optimizing for the normal case.
*
@@ -177,12 +93,10 @@
*
* These macros control options :
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
+ * for commands that return with a CHECK CONDITION status.
*
* DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
- * transceivers.
- *
- * LINKED - if defined, linked commands are supported.
+ * transceivers.
*
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
*
@@ -195,17 +109,17 @@
* NCR5380_write(register, value) - write to the specific register
*
* NCR5380_implementation_fields - additional fields needed for this
- * specific implementation of the NCR5380
+ * specific implementation of the NCR5380
*
* Either real DMA *or* pseudo DMA may be implemented
* REAL functions :
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
* Note that the DMA setup functions should return the number of bytes
- * that they were able to program the controller for.
+ * that they were able to program the controller for.
*
* Also note that generic i386/PC versions of these macros are
- * available as NCR5380_i386_dma_write_setup,
- * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
*
* NCR5380_dma_write_setup(instance, src, count) - initialize
* NCR5380_dma_read_setup(instance, dst, count) - initialize
@@ -221,18 +135,8 @@
* possible) function may be used.
*/
-/* Macros ease life... :-) */
-#define SETUP_HOSTDATA(in) \
- struct NCR5380_hostdata *hostdata = \
- (struct NCR5380_hostdata *)(in)->hostdata
-#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-
-#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble)
-#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next))
-#define NEXTADDR(cmd) ((struct scsi_cmnd **)&(cmd)->host_scribble)
-
-#define HOSTNO instance->host_no
-#define H_NO(cmd) (cmd)->device->host->host_no
+static int do_abort(struct Scsi_Host *);
+static void do_reset(struct Scsi_Host *);
#ifdef SUPPORT_TAGS
@@ -251,9 +155,7 @@
* cannot know it in advance :-( We just see a QUEUE_FULL status being
* returned. So, in this case, the driver internal queue size assumption is
* reduced to the number of active tags if QUEUE_FULL is returned by the
- * target. The command is returned to the mid-level, but with status changed
- * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
- * correctly.
+ * target.
*
* We're also not allowed running tagged commands as long as an untagged
* command is active. And REQUEST SENSE commands after a contingent allegiance
@@ -304,7 +206,8 @@ static void __init init_tags(struct NCR5380_hostdata *hostdata)
static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
{
u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
if (hostdata->busy[cmd->device->id] & (1 << lun))
return 1;
@@ -314,8 +217,8 @@ static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
return 0;
if (hostdata->TagAlloc[scmd_id(cmd)][lun].nr_allocated >=
hostdata->TagAlloc[scmd_id(cmd)][lun].queue_size) {
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d: no free tags\n",
- H_NO(cmd), cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %d: no free tags\n",
+ scmd_id(cmd), lun);
return 1;
}
return 0;
@@ -330,7 +233,8 @@ static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
{
u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
/* If we or the target don't support tagged queuing, allocate the LUN for
* an untagged command.
@@ -340,18 +244,16 @@ static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
!cmd->device->tagged_supported) {
cmd->tag = TAG_NONE;
hostdata->busy[cmd->device->id] |= (1 << lun);
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d now allocated by untagged "
- "command\n", H_NO(cmd), cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %d now allocated by untagged command\n",
+ scmd_id(cmd), lun);
} else {
struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
set_bit(cmd->tag, ta->allocated);
ta->nr_allocated++;
- dprintk(NDEBUG_TAGS, "scsi%d: using tag %d for target %d lun %d "
- "(now %d tags in use)\n",
- H_NO(cmd), cmd->tag, cmd->device->id,
- lun, ta->nr_allocated);
+ dsprintk(NDEBUG_TAGS, instance, "using tag %d for target %d lun %d (%d tags allocated)\n",
+ cmd->tag, scmd_id(cmd), lun, ta->nr_allocated);
}
}
@@ -363,21 +265,22 @@ static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
static void cmd_free_tag(struct scsi_cmnd *cmd)
{
u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
if (cmd->tag == TAG_NONE) {
hostdata->busy[cmd->device->id] &= ~(1 << lun);
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d untagged cmd finished\n",
- H_NO(cmd), cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %d untagged cmd freed\n",
+ scmd_id(cmd), lun);
} else if (cmd->tag >= MAX_TAGS) {
- printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
- H_NO(cmd), cmd->tag);
+ shost_printk(KERN_NOTICE, instance,
+ "trying to free bad tag %d!\n", cmd->tag);
} else {
struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
clear_bit(cmd->tag, ta->allocated);
ta->nr_allocated--;
- dprintk(NDEBUG_TAGS, "scsi%d: freed tag %d for target %d lun %d\n",
- H_NO(cmd), cmd->tag, cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "freed tag %d for target %d lun %d\n",
+ cmd->tag, scmd_id(cmd), lun);
}
}
@@ -401,17 +304,15 @@ static void free_all_tags(struct NCR5380_hostdata *hostdata)
#endif /* SUPPORT_TAGS */
-
-/*
- * Function: void merge_contiguous_buffers( struct scsi_cmnd *cmd )
- *
- * Purpose: Try to merge several scatter-gather requests into one DMA
- * transfer. This is possible if the scatter buffers lie on
- * physical contiguous addresses.
- *
- * Parameters: struct scsi_cmnd *cmd
- * The command to work on. The first scatter buffer's data are
- * assumed to be already transferred into ptr/this_residual.
+/**
+ * merge_contiguous_buffers - coalesce scatter-gather list entries
+ * @cmd: command requesting IO
+ *
+ * Try to merge several scatter-gather buffers into one DMA transfer.
+ * This is possible if the scatter buffers lie on physically
+ * contiguous addresses. The first scatter-gather buffer's data are
+ * assumed to be already transferred into cmd->SCp.this_residual.
+ * Every buffer merged avoids an interrupt and a DMA setup operation.
*/
static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
@@ -463,9 +364,7 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- /* ++roman: Try to merge some scatter-buffers if they are at
- * contiguous physical addresses.
- */
+
merge_contiguous_buffers(cmd);
} else {
cmd->SCp.buffer = NULL;
@@ -473,31 +372,110 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.ptr = NULL;
cmd->SCp.this_residual = 0;
}
+
+ cmd->SCp.Status = 0;
+ cmd->SCp.Message = 0;
}
-#include <linux/delay.h>
+/**
+ * NCR5380_poll_politely2 - wait for two chip register values
+ * @instance: controller to poll
+ * @reg1: 5380 register to poll
+ * @bit1: Bitmask to check
+ * @val1: Expected value
+ * @reg2: Second 5380 register to poll
+ * @bit2: Second bitmask to check
+ * @val2: Second expected value
+ * @wait: Time-out in jiffies
+ *
+ * Polls the chip in a reasonably efficient manner waiting for an
+ * event to occur. After a short quick poll we begin to yield the CPU
+ * (if possible). In irq contexts the time-out is arbitrarily limited.
+ * Callers may hold locks as long as they are held in irq mode.
+ *
+ * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT.
+ */
+
+static int NCR5380_poll_politely2(struct Scsi_Host *instance,
+ int reg1, int bit1, int val1,
+ int reg2, int bit2, int val2, int wait)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long deadline = jiffies + wait;
+ unsigned long n;
+
+ /* Busy-wait for up to 10 ms */
+ n = min(10000U, jiffies_to_usecs(wait));
+ n *= hostdata->accesses_per_ms;
+ n /= 2000;
+ do {
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
+ return 0;
+ cpu_relax();
+ } while (n--);
+
+ if (irqs_disabled() || in_interrupt())
+ return -ETIMEDOUT;
+
+ /* Repeatedly sleep for 1 ms until deadline */
+ while (time_is_after_jiffies(deadline)) {
+ schedule_timeout_uninterruptible(1);
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
+ int reg, int bit, int val, int wait)
+{
+ return NCR5380_poll_politely2(instance, reg, bit, val,
+ reg, bit, val, wait);
+}
#if NDEBUG
static struct {
unsigned char mask;
const char *name;
} signals[] = {
- { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
- { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
- { SR_SEL, "SEL" }, {0, NULL}
-}, basrs[] = {
- {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
-}, icrs[] = {
- {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {SR_DBP, "PARITY"},
+ {SR_RST, "RST"},
+ {SR_BSY, "BSY"},
+ {SR_REQ, "REQ"},
+ {SR_MSG, "MSG"},
+ {SR_CD, "CD"},
+ {SR_IO, "IO"},
+ {SR_SEL, "SEL"},
{0, NULL}
-}, mrs[] = {
- {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
- "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+},
+basrs[] = {
+ {BASR_ATN, "ATN"},
+ {BASR_ACK, "ACK"},
+ {0, NULL}
+},
+icrs[] = {
+ {ICR_ASSERT_RST, "ASSERT RST"},
+ {ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"},
+ {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"},
+ {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {0, NULL}
+},
+mrs[] = {
+ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
+ {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
+ {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
+ {MR_ENABLE_EOP_INTR, "MODE EOP INTR"},
{MR_MONITOR_BSY, "MODE MONITOR BSY"},
- {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+ {MR_DMA_MODE, "MODE DMA"},
+ {MR_ARBITRATE, "MODE ARBITRATION"},
{0, NULL}
};
@@ -511,15 +489,13 @@ static struct {
static void NCR5380_print(struct Scsi_Host *instance)
{
unsigned char status, data, basr, mr, icr, i;
- unsigned long flags;
- local_irq_save(flags);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
mr = NCR5380_read(MODE_REG);
icr = NCR5380_read(INITIATOR_COMMAND_REG);
basr = NCR5380_read(BUS_AND_STATUS_REG);
- local_irq_restore(flags);
+
printk("STATUS_REG: %02x ", status);
for (i = 0; signals[i].mask; ++i)
if (status & signals[i].mask)
@@ -543,8 +519,12 @@ static struct {
unsigned char value;
const char *name;
} phases[] = {
- {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+ {PHASE_DATAOUT, "DATAOUT"},
+ {PHASE_DATAIN, "DATAIN"},
+ {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"},
+ {PHASE_MSGOUT, "MSGOUT"},
+ {PHASE_MSGIN, "MSGIN"},
{PHASE_UNKNOWN, "UNKNOWN"}
};
@@ -553,8 +533,6 @@ static struct {
* @instance: adapter to dump
*
* Print the current SCSI phase for debugging purposes
- *
- * Locks: none
*/
static void NCR5380_print_phase(struct Scsi_Host *instance)
@@ -564,54 +542,21 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
status = NCR5380_read(STATUS_REG);
if (!(status & SR_REQ))
- printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+ shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n");
else {
for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
(phases[i].value != (status & PHASE_MASK)); ++i)
;
- printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+ shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name);
}
}
-
#endif
-/*
- * ++roman: New scheme of calling NCR5380_main()
- *
- * If we're not in an interrupt, we can call our main directly, it cannot be
- * already running. Else, we queue it on a task queue, if not 'main_running'
- * tells us that a lower level is already executing it. This way,
- * 'main_running' needs not be protected in a special way.
- *
- * queue_main() is a utility function for putting our main onto the task
- * queue, if main_running is false. It should be called only from a
- * interrupt or bottom half.
- */
-
-#include <linux/gfp.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-
-static inline void queue_main(struct NCR5380_hostdata *hostdata)
-{
- if (!hostdata->main_running) {
- /* If in interrupt and NCR5380_main() not already running,
- queue it on the 'immediate' task queue, to be processed
- immediately after the current interrupt processing has
- finished. */
- schedule_work(&hostdata->main_task);
- }
- /* else: nothing to do: the running NCR5380_main() will pick up
- any newly queued command. */
-}
-
/**
* NCR58380_info - report driver and host information
* @instance: relevant scsi host instance
*
* For use as the host template info() handler.
- *
- * Locks: none
*/
static const char *NCR5380_info(struct Scsi_Host *instance)
@@ -630,13 +575,14 @@ static void prepare_info(struct Scsi_Host *instance)
"base 0x%lx, irq %d, "
"can_queue %d, cmd_per_lun %d, "
"sg_tablesize %d, this_id %d, "
- "flags { %s}, "
+ "flags { %s%s}, "
"options { %s} ",
instance->hostt->name, instance->io_port, instance->n_io_port,
instance->base, instance->irq,
instance->can_queue, instance->cmd_per_lun,
instance->sg_tablesize, instance->this_id,
hostdata->flags & FLAG_TAGGED_QUEUING ? "TAGGED_QUEUING " : "",
+ hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "",
#ifdef DIFFERENTIAL
"DIFFERENTIAL "
#endif
@@ -653,102 +599,6 @@ static void prepare_info(struct Scsi_Host *instance)
}
/**
- * NCR5380_print_status - dump controller info
- * @instance: controller to dump
- *
- * Print commands in the various queues, called from NCR5380_abort
- * to aid debugging.
- */
-
-static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd)
-{
- int i, s;
- unsigned char *command;
- printk("scsi%d: destination target %d, lun %llu\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- printk(KERN_CONT " command = ");
- command = cmd->cmnd;
- printk(KERN_CONT "%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- printk(KERN_CONT " %02x", command[i]);
- printk("\n");
-}
-
-static void NCR5380_print_status(struct Scsi_Host *instance)
-{
- struct NCR5380_hostdata *hostdata;
- struct scsi_cmnd *ptr;
- unsigned long flags;
-
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- local_irq_save(flags);
- printk("NCR5380: coroutine is%s running.\n",
- hostdata->main_running ? "" : "n't");
- if (!hostdata->connected)
- printk("scsi%d: no currently connected command\n", HOSTNO);
- else
- lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected);
- printk("scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
- lprint_Scsi_Cmnd(ptr);
-
- printk("scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr))
- lprint_Scsi_Cmnd(ptr);
-
- local_irq_restore(flags);
- printk("\n");
-}
-
-static void show_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
-{
- int i, s;
- unsigned char *command;
- seq_printf(m, "scsi%d: destination target %d, lun %llu\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- seq_puts(m, " command = ");
- command = cmd->cmnd;
- seq_printf(m, "%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- seq_printf(m, " %02x", command[i]);
- seq_putc(m, '\n');
-}
-
-static int __maybe_unused NCR5380_show_info(struct seq_file *m,
- struct Scsi_Host *instance)
-{
- struct NCR5380_hostdata *hostdata;
- struct scsi_cmnd *ptr;
- unsigned long flags;
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- local_irq_save(flags);
- seq_printf(m, "NCR5380: coroutine is%s running.\n",
- hostdata->main_running ? "" : "n't");
- if (!hostdata->connected)
- seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
- else
- show_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
- seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
- show_Scsi_Cmnd(ptr, m);
-
- seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr))
- show_Scsi_Cmnd(ptr, m);
-
- local_irq_restore(flags);
- return 0;
-}
-
-/**
* NCR5380_init - initialise an NCR5380
* @instance: adapter to configure
* @flags: control flags
@@ -764,11 +614,11 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,
static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int i;
- SETUP_HOSTDATA(instance);
+ unsigned long deadline;
hostdata->host = instance;
- hostdata->aborted = 0;
hostdata->id_mask = 1 << instance->this_id;
hostdata->id_higher_mask = 0;
for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
@@ -782,13 +632,21 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
#if defined (REAL_DMA)
hostdata->dma_len = 0;
#endif
- hostdata->targets_present = 0;
+ spin_lock_init(&hostdata->lock);
hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
+ hostdata->sensing = NULL;
+ INIT_LIST_HEAD(&hostdata->autosense);
+ INIT_LIST_HEAD(&hostdata->unissued);
+ INIT_LIST_HEAD(&hostdata->disconnected);
+
hostdata->flags = flags;
INIT_WORK(&hostdata->main_task, NCR5380_main);
+ hostdata->work_q = alloc_workqueue("ncr5380_%d",
+ WQ_UNBOUND | WQ_MEM_RECLAIM,
+ 1, instance->host_no);
+ if (!hostdata->work_q)
+ return -ENOMEM;
prepare_info(instance);
@@ -797,6 +655,72 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
+ /* Calibrate register polling loop */
+ i = 0;
+ deadline = jiffies + 1;
+ do {
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ deadline += msecs_to_jiffies(256);
+ do {
+ NCR5380_read(STATUS_REG);
+ ++i;
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ hostdata->accesses_per_ms = i / 256;
+
+ return 0;
+}
+
+/**
+ * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
+ * @instance: adapter to check
+ *
+ * If the system crashed, it may have crashed with a connected target and
+ * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
+ * currently established nexus, which we know nothing about. Failing that
+ * do a bus reset.
+ *
+ * Note that a bus reset will cause the chip to assert IRQ.
+ *
+ * Returns 0 if successful, otherwise -ENXIO.
+ */
+
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int pass;
+
+ for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
+ switch (pass) {
+ case 1:
+ case 3:
+ case 5:
+ shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
+ NCR5380_poll_politely(instance,
+ STATUS_REG, SR_BSY, 0, 5 * HZ);
+ break;
+ case 2:
+ shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
+ do_abort(instance);
+ break;
+ case 4:
+ shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
+ do_reset(instance);
+ /* Wait after a reset; the SCSI standard calls for
+ * 250ms, we wait 500ms to be on the safe side.
+ * But some Toshiba CD-ROMs need ten times that.
+ */
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ msleep(2500);
+ else
+ msleep(500);
+ break;
+ case 6:
+ shost_printk(KERN_ERR, instance, "bus locked solid\n");
+ return -ENXIO;
+ }
+ }
return 0;
}
@@ -812,6 +736,38 @@ static void NCR5380_exit(struct Scsi_Host *instance)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
cancel_work_sync(&hostdata->main_task);
+ destroy_workqueue(hostdata->work_q);
+}
+
+/**
+ * complete_cmd - finish processing a command and return it to the SCSI ML
+ * @instance: the host instance
+ * @cmd: command to complete
+ */
+
+static void complete_cmd(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
+
+ if (hostdata->sensing == cmd) {
+ /* Autosense processing ends here */
+ if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ set_host_byte(cmd, DID_ERROR);
+ } else
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->sensing = NULL;
+ }
+
+#ifdef SUPPORT_TAGS
+ cmd_free_tag(cmd);
+#else
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
+#endif
+ cmd->scsi_done(cmd);
}
/**
@@ -819,7 +775,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
* @instance: the relevant SCSI adapter
* @cmd: SCSI command
*
- * cmd is added to the per instance issue_queue, with minor
+ * cmd is added to the per-instance issue queue, with minor
* twiddling done to the host specific fields of cmd. If the
* main coroutine is not running, it is restarted.
*/
@@ -828,44 +784,23 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
struct scsi_cmnd *cmd)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
- struct scsi_cmnd *tmp;
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
unsigned long flags;
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
- printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
- H_NO(cmd));
+ shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
cmd->result = (DID_ERROR << 16);
cmd->scsi_done(cmd);
return 0;
}
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
- /*
- * We use the host_scribble field as a pointer to the next command
- * in a queue
- */
-
- SET_NEXT(cmd, NULL);
cmd->result = 0;
/*
- * Insert the cmd into the issue queue. Note that REQUEST SENSE
- * commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
- * sense data is only guaranteed to be valid while the condition exists.
- */
-
- /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
- * Otherwise a running NCR5380_main may steal the lock.
- * Lock before actually inserting due to fairness reasons explained in
- * atari_scsi.c. If we insert first, then it's impossible for this driver
- * to release the lock.
- * Stop timer for this command while waiting for the lock, or timeouts
- * may happen (and they really do), and it's no good if the command doesn't
- * appear in any of the queues.
* ++roman: Just disabling the NCR interrupt isn't sufficient here,
* because also a timer int can trigger an abort or reset, which would
* alter queues and touch the lock.
@@ -873,7 +808,7 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
if (!NCR5380_acquire_dma_irq(instance))
return SCSI_MLQUEUE_HOST_BUSY;
- local_irq_save(flags);
+ spin_lock_irqsave(&hostdata->lock, flags);
/*
* Insert the cmd into the issue queue. Note that REQUEST SENSE
@@ -882,33 +817,18 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
* sense data is only guaranteed to be valid while the condition exists.
*/
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- SET_NEXT(cmd, hostdata->issue_queue);
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
- NEXT(tmp); tmp = NEXT(tmp))
- ;
- LIST(cmd, tmp);
- SET_NEXT(tmp, cmd);
- }
- local_irq_restore(flags);
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ list_add(&ncmd->list, &hostdata->unissued);
+ else
+ list_add_tail(&ncmd->list, &hostdata->unissued);
- dprintk(NDEBUG_QUEUES, "scsi%d: command added to %s of queue\n", H_NO(cmd),
- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+ spin_unlock_irqrestore(&hostdata->lock, flags);
- /* If queue_command() is called from an interrupt (real one or bottom
- * half), we let queue_main() do the job of taking care about main. If it
- * is already running, this is a no-op, else main will be queued.
- *
- * If we're not in an interrupt, we can call NCR5380_main()
- * unconditionally, because it cannot be already running.
- */
- if (in_interrupt() || irqs_disabled())
- queue_main(hostdata);
- else
- NCR5380_main(&hostdata->main_task);
+ dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
+ cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+ /* Kick off command processing */
+ queue_work(hostdata->work_q, &hostdata->main_task);
return 0;
}
@@ -917,22 +837,85 @@ static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
/* Caller does the locking needed to set & test these data atomically */
- if (!hostdata->disconnected_queue &&
- !hostdata->issue_queue &&
+ if (list_empty(&hostdata->disconnected) &&
+ list_empty(&hostdata->unissued) &&
+ list_empty(&hostdata->autosense) &&
!hostdata->connected &&
- !hostdata->retain_dma_intr)
+ !hostdata->selecting)
NCR5380_release_dma_irq(instance);
}
/**
+ * dequeue_next_cmd - dequeue a command for processing
+ * @instance: the scsi host instance
+ *
+ * Priority is given to commands on the autosense queue. These commands
+ * need autosense because of a CHECK CONDITION result.
+ *
+ * Returns a command pointer if a command is found for a target that is
+ * not already busy. Otherwise returns NULL.
+ */
+
+static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *cmd;
+
+ if (hostdata->sensing || list_empty(&hostdata->autosense)) {
+ list_for_each_entry(ncmd, &hostdata->unissued, list) {
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
+ cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
+
+ if (
+#ifdef SUPPORT_TAGS
+ !is_lun_busy(cmd, 1)
+#else
+ !(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))
+#endif
+ ) {
+ list_del(&ncmd->list);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from issue queue\n", cmd);
+ return cmd;
+ }
+ }
+ } else {
+ /* Autosense processing begins here */
+ ncmd = list_first_entry(&hostdata->autosense,
+ struct NCR5380_cmd, list);
+ list_del(&ncmd->list);
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from autosense queue\n", cmd);
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+ hostdata->sensing = cmd;
+ return cmd;
+ }
+ return NULL;
+}
+
+static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
+ if (hostdata->sensing == cmd) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ list_add(&ncmd->list, &hostdata->autosense);
+ hostdata->sensing = NULL;
+ } else
+ list_add(&ncmd->list, &hostdata->unissued);
+}
+
+/**
* NCR5380_main - NCR state machines
*
* NCR5380_main is a coroutine that runs as long as more work can
* be done on the NCR5380 host adapters in a system. Both
* NCR5380_queue_command() and NCR5380_intr() will try to start it
* in case it is not running.
- *
- * Locks: called as its own thread with no locks held.
*/
static void NCR5380_main(struct work_struct *work)
@@ -940,154 +923,70 @@ static void NCR5380_main(struct work_struct *work)
struct NCR5380_hostdata *hostdata =
container_of(work, struct NCR5380_hostdata, main_task);
struct Scsi_Host *instance = hostdata->host;
- struct scsi_cmnd *tmp, *prev;
int done;
- unsigned long flags;
/*
- * We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set main_running to 0 and exit.
- *
- * Interrupts are enabled before doing various other internal
- * instructions, after we've decided that we need to run through
- * the loop again.
- *
- * this should prevent any race conditions.
- *
* ++roman: Just disabling the NCR interrupt isn't sufficient here,
* because also a timer int can trigger an abort or reset, which can
* alter queues and touch the Falcon lock.
*/
- /* Tell int handlers main() is now already executing. Note that
- no races are possible here. If an int comes in before
- 'main_running' is set here, and queues/executes main via the
- task queue, it doesn't do any harm, just this instance of main
- won't find any work left to do. */
- if (hostdata->main_running)
- return;
- hostdata->main_running = 1;
-
- local_save_flags(flags);
do {
- local_irq_disable(); /* Freeze request queues */
done = 1;
- if (!hostdata->connected) {
- dprintk(NDEBUG_MAIN, "scsi%d: not connected\n", HOSTNO);
- /*
- * Search through the issue_queue for a command destined
- * for a target that's not busy.
- */
-#if (NDEBUG & NDEBUG_LISTS)
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL;
- tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
- ;
- /*printk("%p ", tmp);*/
- if ((tmp == prev) && tmp)
- printk(" LOOP\n");
- /* else printk("\n"); */
-#endif
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
- prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
- u8 lun = tmp->device->lun;
-
- dprintk(NDEBUG_LISTS,
- "MAIN tmp=%p target=%d busy=%d lun=%d\n",
- tmp, scmd_id(tmp), hostdata->busy[scmd_id(tmp)],
- lun);
- /* When we find one, remove it from the issue queue. */
- /* ++guenther: possible race with Falcon locking */
- if (
-#ifdef SUPPORT_TAGS
- !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
-#else
- !(hostdata->busy[tmp->device->id] & (1 << lun))
-#endif
- ) {
- /* ++guenther: just to be sure, this must be atomic */
- local_irq_disable();
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- SET_NEXT(prev, NEXT(tmp));
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
- hostdata->issue_queue = NEXT(tmp);
- }
- SET_NEXT(tmp, NULL);
- hostdata->retain_dma_intr++;
+ spin_lock_irq(&hostdata->lock);
+ while (!hostdata->connected && !hostdata->selecting) {
+ struct scsi_cmnd *cmd = dequeue_next_cmd(instance);
- /* reenable interrupts after finding one */
- local_irq_restore(flags);
+ if (!cmd)
+ break;
- /*
- * Attempt to establish an I_T_L nexus here.
- * On success, instance->hostdata->connected is set.
- * On failure, we must add the command back to the
- * issue queue so we can keep trying.
- */
- dprintk(NDEBUG_MAIN, "scsi%d: main(): command for target %d "
- "lun %d removed from issue_queue\n",
- HOSTNO, tmp->device->id, lun);
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
- /* ++roman: ...and the standard also requires that
- * REQUEST SENSE command are untagged.
- */
+ dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+ /* ++roman: ...and the standard also requires that
+ * REQUEST SENSE command are untagged.
+ */
#ifdef SUPPORT_TAGS
- cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
+ cmd_get_tag(cmd, cmd->cmnd[0] != REQUEST_SENSE);
#endif
- if (!NCR5380_select(instance, tmp)) {
- local_irq_disable();
- hostdata->retain_dma_intr--;
- /* release if target did not response! */
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- break;
- } else {
- local_irq_disable();
- LIST(tmp, hostdata->issue_queue);
- SET_NEXT(tmp, hostdata->issue_queue);
- hostdata->issue_queue = tmp;
+ if (!NCR5380_select(instance, cmd)) {
+ dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
+ maybe_release_dma_irq(instance);
+ } else {
+ dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
+ "main: select failed, returning %p to queue\n", cmd);
+ requeue_cmd(instance, cmd);
#ifdef SUPPORT_TAGS
- cmd_free_tag(tmp);
+ cmd_free_tag(cmd);
#endif
- hostdata->retain_dma_intr--;
- local_irq_restore(flags);
- dprintk(NDEBUG_MAIN, "scsi%d: main(): select() failed, "
- "returned to issue_queue\n", HOSTNO);
- if (hostdata->connected)
- break;
- }
- } /* if target/lun/target queue is not busy */
- } /* for issue_queue */
- } /* if (!hostdata->connected) */
-
+ }
+ }
if (hostdata->connected
#ifdef REAL_DMA
&& !hostdata->dma_len
#endif
) {
- local_irq_restore(flags);
- dprintk(NDEBUG_MAIN, "scsi%d: main: performing information transfer\n",
- HOSTNO);
+ dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n");
NCR5380_information_transfer(instance);
- dprintk(NDEBUG_MAIN, "scsi%d: main: done set false\n", HOSTNO);
done = 0;
}
+ spin_unlock_irq(&hostdata->lock);
+ if (!done)
+ cond_resched();
} while (!done);
-
- /* Better allow ints _after_ 'main_running' has been cleared, else
- an interrupt could believe we'll pick up the work it left for
- us, but we won't see it anymore here... */
- hostdata->main_running = 0;
- local_irq_restore(flags);
}
@@ -1096,27 +995,20 @@ static void NCR5380_main(struct work_struct *work)
* Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
*
* Purpose : Called by interrupt handler when DMA finishes or a phase
- * mismatch occurs (which would finish the DMA transfer).
+ * mismatch occurs (which would finish the DMA transfer).
*
* Inputs : instance - this instance of the NCR5380.
- *
*/
static void NCR5380_dma_complete(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int transferred;
unsigned char **data;
- volatile int *count;
+ int *count;
int saved_data = 0, overrun = 0;
unsigned char p;
- if (!hostdata->connected) {
- printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
- "no connected cmd\n", HOSTNO);
- return;
- }
-
if (hostdata->read_overruns) {
p = hostdata->connected->SCp.phase;
if (p & SR_IO) {
@@ -1126,15 +1018,11 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
(BASR_PHASE_MATCH|BASR_ACK)) {
saved_data = NCR5380_read(INPUT_DATA_REG);
overrun = 1;
- dprintk(NDEBUG_DMA, "scsi%d: read overrun handled\n", HOSTNO);
+ dsprintk(NDEBUG_DMA, instance, "read overrun handled\n");
}
}
}
- dprintk(NDEBUG_DMA, "scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
- HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
-
#if defined(CONFIG_SUN3)
if ((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) {
pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n",
@@ -1153,9 +1041,9 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
}
#endif
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
transferred = hostdata->dma_len - NCR5380_dma_residual(instance);
hostdata->dma_len = 0;
@@ -1194,140 +1082,160 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
* Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
* from the disconnected queue, and restarting NCR5380_main()
* as required.
+ *
+ * The chip can assert IRQ in any of six different conditions. The IRQ flag
+ * is then cleared by reading the Reset Parity/Interrupt Register (RPIR).
+ * Three of these six conditions are latched in the Bus and Status Register:
+ * - End of DMA (cleared by ending DMA Mode)
+ * - Parity error (cleared by reading RPIR)
+ * - Loss of BSY (cleared by reading RPIR)
+ * Two conditions have flag bits that are not latched:
+ * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode)
+ * - Bus reset (non-maskable)
+ * The remaining condition has no flag bit at all:
+ * - Selection/reselection
+ *
+ * Hence, establishing the cause(s) of any interrupt is partly guesswork.
+ * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor
+ * claimed that "the design of the [DP8490] interrupt logic ensures
+ * interrupts will not be lost (they can be on the DP5380)."
+ * The L5380/53C80 datasheet from LOGIC Devices has more details.
+ *
+ * Checking for bus reset by reading RST is futile because of interrupt
+ * latency, but a bus reset will reset chip logic. Checking for parity error
+ * is unnecessary because that interrupt is never enabled. A Loss of BSY
+ * condition will clear DMA Mode. We can tell when this occurs because the
+ * the Busy Monitor interrupt is enabled together with DMA Mode.
*/
static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
struct Scsi_Host *instance = dev_id;
- int done = 1, handled = 0;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int handled = 0;
unsigned char basr;
+ unsigned long flags;
- dprintk(NDEBUG_INTR, "scsi%d: NCR5380 irq triggered\n", HOSTNO);
+ spin_lock_irqsave(&hostdata->lock, flags);
- /* Look for pending interrupts */
basr = NCR5380_read(BUS_AND_STATUS_REG);
- dprintk(NDEBUG_INTR, "scsi%d: BASR=%02x\n", HOSTNO, basr);
- /* dispatch to appropriate routine if found and done=0 */
if (basr & BASR_IRQ) {
- NCR5380_dprint(NDEBUG_INTR, instance);
- if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
- done = 0;
- dprintk(NDEBUG_INTR, "scsi%d: SEL interrupt\n", HOSTNO);
- NCR5380_reselect(instance);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if (basr & BASR_PARITY_ERROR) {
- dprintk(NDEBUG_INTR, "scsi%d: PARITY interrupt\n", HOSTNO);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
- dprintk(NDEBUG_INTR, "scsi%d: RESET interrupt\n", HOSTNO);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else {
- /*
- * The rest of the interrupt conditions can occur only during a
- * DMA transfer
- */
+ unsigned char mr = NCR5380_read(MODE_REG);
+ unsigned char sr = NCR5380_read(STATUS_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
+ irq, basr, sr, mr);
#if defined(REAL_DMA)
- /*
- * We should only get PHASE MISMATCH and EOP interrupts if we have
- * DMA enabled, so do a sanity check based on the current setting
- * of the MODE register.
+ if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
+ /* Probably End of DMA, Phase Mismatch or Loss of BSY.
+ * We ack IRQ after clearing Mode Register. Workarounds
+ * for End of DMA errata need to happen in DMA Mode.
*/
- if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
- ((basr & BASR_END_DMA_TRANSFER) ||
- !(basr & BASR_PHASE_MATCH))) {
+ dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
- dprintk(NDEBUG_INTR, "scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
- NCR5380_dma_complete( instance );
- done = 0;
- } else
+ if (hostdata->connected) {
+ NCR5380_dma_complete(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ } else {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ } else
#endif /* REAL_DMA */
- {
-/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
- if (basr & BASR_PHASE_MATCH)
- dprintk(NDEBUG_INTR, "scsi%d: unknown interrupt, "
- "BASR 0x%x, MR 0x%x, SR 0x%x\n",
- HOSTNO, basr, NCR5380_read(MODE_REG),
- NCR5380_read(STATUS_REG));
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
+ (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
+ /* Probably reselected */
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n");
+
+ if (!hostdata->connected) {
+ NCR5380_reselect(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ }
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ } else {
+ /* Probably Bus Reset */
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
+ dregs->csr |= CSR_DMA_ENABLE;
#endif
- }
- } /* if !(SELECTION || PARITY) */
+ }
handled = 1;
- } /* BASR & IRQ */ else {
- printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
- "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
- NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else {
+ shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n");
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
}
- if (!done) {
- dprintk(NDEBUG_INTR, "scsi%d: in int routine, calling main\n", HOSTNO);
- /* Put a call to NCR5380_main() on the queue... */
- queue_main(shost_priv(instance));
- }
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+
return IRQ_RETVAL(handled);
}
/*
* Function : int NCR5380_select(struct Scsi_Host *instance,
- * struct scsi_cmnd *cmd)
+ * struct scsi_cmnd *cmd)
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
*
* Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute.
+ * target lives, cmd - SCSI command to execute.
*
- * Returns : -1 if selection could not execute for some reason,
- * 0 if selection succeeded or failed because the target
- * did not respond.
+ * Returns cmd if selection failed but should be retried,
+ * NULL if selection failed and should not be retried, or
+ * NULL if selection succeeded (hostdata->connected == cmd).
*
* Side effects :
- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
- * with registers as they should have been on entry - ie
- * SELECT_ENABLE will be set appropriately, the NCR5380
- * will cease to drive any SCSI bus signals.
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
*
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
- * SELECT interrupt will be disabled.
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
*
- * If failed (no target) : cmd->scsi_done() will be called, and the
- * cmd->result host byte set to DID_BAD_TARGET.
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
*/
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char tmp[3], phase;
unsigned char *data;
int len;
- unsigned long timeout;
- unsigned long flags;
+ int err;
- hostdata->restart_select = 0;
NCR5380_dprint(NDEBUG_ARBITRATION, instance);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: starting arbitration, id = %d\n", HOSTNO,
- instance->this_id);
+ dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
+ instance->this_id);
+
+ /*
+ * Arbitration and selection phases are slow and involve dropping the
+ * lock, so we have to watch out for EH. An exception handler may
+ * change 'selecting' to NULL. This function will then return NULL
+ * so that the caller will forget about 'cmd'. (During information
+ * transfer phases, EH may change 'connected' to NULL.)
+ */
+ hostdata->selecting = cmd;
/*
* Set the phase bits to 0, otherwise the NCR5380 won't drive the
* data bus during SELECTION.
*/
- local_irq_save(flags);
- if (hostdata->connected) {
- local_irq_restore(flags);
- return -1;
- }
NCR5380_write(TARGET_COMMAND_REG, 0);
/*
@@ -1337,96 +1245,82 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(MODE_REG, MR_ARBITRATE);
- local_irq_restore(flags);
-
- /* Wait for arbitration logic to complete */
-#if defined(NCR_TIMEOUT)
- {
- unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+ /* The chip now waits for BUS FREE phase. Then after the 800 ns
+ * Bus Free Delay, arbitration will begin.
+ */
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
- time_before(jiffies, timeout) && !hostdata->connected)
- ;
- if (time_after_eq(jiffies, timeout)) {
- printk("scsi : arbitration timeout at %d\n", __LINE__);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
+ spin_unlock_irq(&hostdata->lock);
+ err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0,
+ INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
+ ICR_ARBITRATION_PROGRESS, HZ);
+ spin_lock_irq(&hostdata->lock);
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
+ /* Reselection interrupt */
+ goto out;
}
-#else /* NCR_TIMEOUT */
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
- !hostdata->connected)
- ;
-#endif
-
- dprintk(NDEBUG_ARBITRATION, "scsi%d: arbitration complete\n", HOSTNO);
-
- if (hostdata->connected) {
+ if (!hostdata->selecting) {
+ /* Command was aborted */
NCR5380_write(MODE_REG, MR_BASE);
- return -1;
+ goto out;
}
- /*
- * The arbitration delay is 2.2us, but this is a minimum and there is
- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
- * the integral nature of udelay().
- *
- */
+ if (err < 0) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ shost_printk(KERN_ERR, instance,
+ "select: arbitration timeout\n");
+ goto out;
+ }
+ spin_unlock_irq(&hostdata->lock);
+ /* The SCSI-2 arbitration delay is 2.4 us */
udelay(3);
/* Check for lost arbitration */
if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
NCR5380_write(MODE_REG, MR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
- HOSTNO);
- return -1;
+ dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n");
+ spin_lock_irq(&hostdata->lock);
+ goto out;
}
- /* after/during arbitration, BSY should be asserted.
- IBM DPES-31080 Version S31Q works now */
- /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+ /* After/during arbitration, BSY should be asserted.
+ * IBM DPES-31080 Version S31Q works now
+ * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman)
+ */
NCR5380_write(INITIATOR_COMMAND_REG,
ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
- HOSTNO);
- return -1;
- }
-
/*
* Again, bus clear + bus settle time is 1.2us, however, this is
* a minimum so we'll udelay ceil(1.2)
*/
-#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
- /* ++roman: But some targets (see above :-) seem to need a bit more... */
- udelay(15);
-#else
- udelay(2);
-#endif
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ udelay(15);
+ else
+ udelay(2);
- if (hostdata->connected) {
+ spin_lock_irq(&hostdata->lock);
+
+ /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
+ goto out;
+
+ if (!hostdata->selecting) {
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
+ goto out;
}
- dprintk(NDEBUG_ARBITRATION, "scsi%d: won arbitration\n", HOSTNO);
+ dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
/*
* Now that we have won arbitration, start Selection process, asserting
* the host and target ID's on the SCSI bus.
*/
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd)));
/*
* Raise ATN while SEL is true before BSY goes false from arbitration,
@@ -1434,22 +1328,18 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
* phase immediately after selection.
*/
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL);
NCR5380_write(MODE_REG, MR_BASE);
/*
* Reselect interrupts must be turned off prior to the dropping of BSY,
* otherwise we will trigger an interrupt.
*/
-
- if (hostdata->connected) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
-
NCR5380_write(SELECT_ENABLE_REG, 0);
+ spin_unlock_irq(&hostdata->lock);
+
/*
* The initiator shall then wait at least two deskew delays and release
* the BSY signal.
@@ -1457,8 +1347,8 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
/* Reset BSY */
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
- ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL);
/*
* Something weird happens when we cease to drive BSY - looks
@@ -1479,45 +1369,39 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
udelay(1);
- dprintk(NDEBUG_SELECTION, "scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
+ dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd));
/*
* The SCSI specification calls for a 250 ms timeout for the actual
* selection.
*/
- timeout = jiffies + msecs_to_jiffies(250);
-
- /*
- * XXX very interesting - we're seeing a bounce where the BSY we
- * asserted is being reflected / still asserted (propagation delay?)
- * and it's detecting as true. Sigh.
- */
-
-#if 0
- /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
- * IO while SEL is true. But again, there are some disks out the in the
- * world that do that nevertheless. (Somebody claimed that this announces
- * reselection capability of the target.) So we better skip that test and
- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
- */
-
- while (time_before(jiffies, timeout) &&
- !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO)))
- ;
+ err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY,
+ msecs_to_jiffies(250));
if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+ spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_reselect(instance);
- printk(KERN_ERR "scsi%d: reselection after won arbitration?\n",
- HOSTNO);
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
+ goto out;
+ }
+
+ if (err < 0) {
+ spin_lock_irq(&hostdata->lock);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
+ /* Can't touch cmd if it has been reclaimed by the scsi ML */
+ if (hostdata->selecting) {
+ cmd->result = DID_BAD_TARGET << 16;
+ complete_cmd(instance, cmd);
+ dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
+ cmd = NULL;
+ }
+ goto out;
}
-#else
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY))
- ;
-#endif
/*
* No less than two deskew delays after the initiator detects the
@@ -1529,29 +1413,6 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << cmd->device->id)) {
- printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
- if (hostdata->restart_select)
- printk(KERN_NOTICE "\trestart select\n");
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- cmd->result = DID_BAD_TARGET << 16;
-#ifdef SUPPORT_TAGS
- cmd_free_tag(cmd);
-#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- dprintk(NDEBUG_SELECTION, "scsi%d: target did not respond within 250ms\n", HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return 0;
- }
-
- hostdata->targets_present |= (1 << cmd->device->id);
-
/*
* Since we followed the SCSI spec, and raised ATN while SEL
* was true but before BSY was false during selection, the information
@@ -1563,16 +1424,27 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
* until it wraps back to 0.
*
* XXX - it turns out that there are some broken SCSI-II devices,
- * which claim to support tagged queuing but fail when more than
- * some number of commands are issued at once.
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
*/
/* Wait for start of REQ/ACK handshake */
- while (!(NCR5380_read(STATUS_REG) & SR_REQ))
- ;
- dprintk(NDEBUG_SELECTION, "scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
- HOSTNO, cmd->device->id);
+ err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+ spin_lock_irq(&hostdata->lock);
+ if (err < 0) {
+ shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ goto out;
+ }
+ if (!hostdata->selecting) {
+ do_abort(instance);
+ goto out;
+ }
+
+ dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
+ scmd_id(cmd));
tmp[0] = IDENTIFY(1, cmd->device->lun);
#ifdef SUPPORT_TAGS
@@ -1591,11 +1463,12 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
data = tmp;
phase = PHASE_MSGOUT;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_SELECTION, "scsi%d: nexus established.\n", HOSTNO);
+ dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
/* XXX need to handle errors here */
+
hostdata->connected = cmd;
#ifndef SUPPORT_TAGS
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
#endif
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
@@ -1603,24 +1476,30 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
initialize_SCp(cmd);
- return 0;
+ cmd = NULL;
+
+out:
+ if (!hostdata->selecting)
+ return NULL;
+ hostdata->selecting = NULL;
+ return cmd;
}
/*
* Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using polled I/O
*
* Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
*
* Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes are transferred or exit
- * is in same phase.
+ * maximum number of bytes, 0 if all bytes are transferred or exit
+ * is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
* XXX Note : handling for bus free may be useful.
*/
@@ -1635,9 +1514,9 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
unsigned char *phase, int *count,
unsigned char **data)
{
- register unsigned char p = *phase, tmp;
- register int c = *count;
- register unsigned char *d = *data;
+ unsigned char p = *phase, tmp;
+ int c = *count;
+ unsigned char *d = *data;
/*
* The NCR5380 chip will only drive the SCSI bus when the
@@ -1652,14 +1531,15 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
* Wait for assertion of REQ, after which the phase bits will be
* valid
*/
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
- ;
- dprintk(NDEBUG_HANDSHAKE, "scsi%d: REQ detected\n", HOSTNO);
+ if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
+ break;
+
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
/* Check for phase mismatch */
- if ((tmp & PHASE_MASK) != p) {
- dprintk(NDEBUG_PIO, "scsi%d: phase mismatch\n", HOSTNO);
+ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
+ dsprintk(NDEBUG_PIO, instance, "phase mismatch\n");
NCR5380_dprint_phase(NDEBUG_PIO, instance);
break;
}
@@ -1684,35 +1564,36 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
} else {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
}
} else {
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
}
- while (NCR5380_read(STATUS_REG) & SR_REQ)
- ;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
+ break;
- dprintk(NDEBUG_HANDSHAKE, "scsi%d: req false, handshake complete\n", HOSTNO);
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
- /*
- * We have several special cases to consider during REQ/ACK handshaking :
- * 1. We were in MSGOUT phase, and we are on the last byte of the
- * message. ATN must be dropped as ACK is dropped.
- *
- * 2. We are in a MSGIN phase, and we are on the last byte of the
- * message. We must exit with ACK asserted, so that the calling
- * code may raise ATN before dropping ACK to reject the message.
- *
- * 3. ACK and ATN are clear and the target may proceed as normal.
- */
+/*
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
+ *
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3. ACK and ATN are clear and the target may proceed as normal.
+ */
if (!(p == PHASE_MSGIN && c == 1)) {
if (p == PHASE_MSGOUT && c > 1)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -1721,16 +1602,16 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
}
} while (--c);
- dprintk(NDEBUG_PIO, "scsi%d: residual %d\n", HOSTNO, c);
+ dsprintk(NDEBUG_PIO, instance, "residual %d\n", c);
*count = c;
*data = d;
tmp = NCR5380_read(STATUS_REG);
/* The phase read from the bus is valid if either REQ is (already)
- * asserted or if ACK hasn't been released yet. The latter is the case if
- * we're in MSGIN and all wanted bytes have been received.
+ * asserted or if ACK hasn't been released yet. The latter applies if
+ * we're in MSG IN, DATA IN or STATUS and all bytes have been received.
*/
- if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+ if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
*phase = tmp & PHASE_MASK;
else
*phase = PHASE_UNKNOWN;
@@ -1741,19 +1622,45 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
return -1;
}
-/*
- * Function : do_abort (Scsi_Host *host)
+/**
+ * do_reset - issue a reset command
+ * @instance: adapter to reset
+ *
+ * Issue a reset sequence to the NCR5380 and try and get the bus
+ * back into sane shape.
*
- * Purpose : abort the currently established nexus. Should only be
- * called from a routine which can drop into a
+ * This clears the reset interrupt flag because there may be no handler for
+ * it. When the driver is initialized, the NCR5380_intr() handler has not yet
+ * been installed. And when in EH we may have released the ST DMA interrupt.
+ */
+
+static void do_reset(struct Scsi_Host *instance)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+ udelay(50);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ local_irq_restore(flags);
+}
+
+/**
+ * do_abort - abort the currently established nexus by going to
+ * MESSAGE OUT phase and sending an ABORT message.
+ * @instance: relevant scsi host instance
*
- * Returns : 0 on success, -1 on failure.
+ * Returns 0 on success, -1 on failure.
*/
static int do_abort(struct Scsi_Host *instance)
{
- unsigned char tmp, *msgptr, phase;
+ unsigned char *msgptr, phase, tmp;
int len;
+ int rc;
/* Request message out phase */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -1768,16 +1675,20 @@ static int do_abort(struct Scsi_Host *instance)
* the target sees, so we just handshake.
*/
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
- ;
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
+ if (rc < 0)
+ goto timeout;
+
+ tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ)
- ;
+ if (tmp != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ);
+ if (rc < 0)
+ goto timeout;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
}
@@ -1793,26 +1704,29 @@ static int do_abort(struct Scsi_Host *instance)
*/
return len ? -1 : 0;
+
+timeout:
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
}
#if defined(REAL_DMA)
/*
* Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using either real
- * or pseudo DMA.
+ * or pseudo DMA.
*
* Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
*
* Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes or transferred or exit
- * is in same phase.
- *
- * Also, *phase, *count, *data are modified in place.
+ * maximum number of bytes, 0 if all bytes or transferred or exit
+ * is in same phase.
*
+ * Also, *phase, *count, *data are modified in place.
*/
@@ -1820,10 +1734,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
unsigned char *phase, int *count,
unsigned char **data)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
register int c = *count;
register unsigned char p = *phase;
- unsigned long flags;
#if defined(CONFIG_SUN3)
/* sanity check */
@@ -1834,29 +1747,22 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
}
hostdata->dma_len = c;
- dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
- instance->host_no, (p & SR_IO) ? "reading" : "writing",
- c, (p & SR_IO) ? "to" : "from", *data);
+ dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+ (p & SR_IO) ? "receive" : "send", c, *data);
/* netbsd turns off ints here, why not be safe and do it too */
- local_irq_save(flags);
/* send start chain */
sun3scsi_dma_start(c, *data);
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
if (p & SR_IO) {
- NCR5380_write(TARGET_COMMAND_REG, 1);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(INITIATOR_COMMAND_REG, 0);
- NCR5380_write(MODE_REG,
- (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
} else {
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
- NCR5380_write(MODE_REG,
- (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
NCR5380_write(START_DMA_SEND_REG, 0);
}
@@ -1864,8 +1770,6 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
dregs->csr |= CSR_DMA_ENABLE;
#endif
- local_irq_restore(flags);
-
sun3_dma_active = 1;
#else /* !defined(CONFIG_SUN3) */
@@ -1880,25 +1784,20 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
if (hostdata->read_overruns && (p & SR_IO))
c -= hostdata->read_overruns;
- dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
- HOSTNO, (p & SR_IO) ? "reading" : "writing",
- c, (p & SR_IO) ? "to" : "from", d);
+ dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+ (p & SR_IO) ? "receive" : "send", c, d);
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
-#ifdef REAL_DMA
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
-#endif /* def REAL_DMA */
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) {
/* On the Medusa, it is a must to initialize the DMA before
* starting the NCR. This is also the cleaner way for the TT.
*/
- local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
}
if (p & SR_IO)
@@ -1912,11 +1811,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
/* On the Falcon, the DMA setup must be done after the last */
/* NCR access, else the DMA setup gets trashed!
*/
- local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
}
#endif /* !defined(CONFIG_SUN3) */
@@ -1928,38 +1825,37 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
* Function : NCR5380_information_transfer (struct Scsi_Host *instance)
*
* Purpose : run through the various SCSI phases and do as the target
- * directs us to. Operates on the currently connected command,
- * instance->connected.
+ * directs us to. Operates on the currently connected command,
+ * instance->connected.
*
* Inputs : instance, instance for which we are doing commands
*
* Side effects : SCSI things happen, the disconnected queue will be
- * modified if a command disconnects, *instance->connected will
- * change.
+ * modified if a command disconnects, *instance->connected will
+ * change.
*
* XXX Note : we need to watch for bus free or a reset condition here
- * to recover from an unexpected bus free condition.
+ * to recover from an unexpected bus free condition.
*/
static void NCR5380_information_transfer(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- unsigned long flags;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char msgout = NOP;
int sink = 0;
int len;
-#if defined(REAL_DMA)
int transfersize;
-#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
- struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
+ struct scsi_cmnd *cmd;
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
#endif
- while (1) {
+ while ((cmd = hostdata->connected)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
tmp = NCR5380_read(STATUS_REG);
/* We only have a valid SCSI phase when REQ is asserted */
if (tmp & SR_REQ) {
@@ -1984,7 +1880,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/* this command setup for dma yet? */
if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != cmd)) {
if (cmd->request->cmd_type == REQ_TYPE_FS) {
- sun3scsi_dma_setup(d, count,
+ sun3scsi_dma_setup(instance, d, count,
rq_data_dir(cmd->request));
sun3_dma_setup_done = cmd;
}
@@ -2000,11 +1896,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
+ ICR_ASSERT_ACK);
while (NCR5380_read(STATUS_REG) & SR_REQ)
;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
+ ICR_ASSERT_ATN);
sink = 0;
continue;
}
@@ -2012,12 +1908,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
switch (phase) {
case PHASE_DATAOUT:
#if (NDEBUG & NDEBUG_NO_DATAOUT)
- printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
- "aborted\n", HOSTNO);
+ shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
+ hostdata->connected = NULL;
return;
#endif
case PHASE_DATAIN:
@@ -2031,13 +1927,10 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- /* ++roman: Try to merge some scatter-buffers if
- * they are at contiguous physical addresses.
- */
merge_contiguous_buffers(cmd);
- dprintk(NDEBUG_INFORMATION, "scsi%d: %d bytes and %d buffers left\n",
- HOSTNO, cmd->SCp.this_residual,
- cmd->SCp.buffers_residual);
+ dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
+ cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
}
/*
@@ -2051,16 +1944,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
/* ++roman: I suggest, this should be
- * #if def(REAL_DMA)
+ * #if def(REAL_DMA)
* instead of leaving REAL_DMA out.
*/
#if defined(REAL_DMA)
- if (
#if !defined(CONFIG_SUN3)
- !cmd->device->borken &&
+ transfersize = 0;
+ if (!cmd->device->borken)
#endif
- (transfersize = NCR5380_dma_xfer_len(instance, cmd, phase)) >= DMA_MIN_SIZE) {
+ transfersize = NCR5380_dma_xfer_len(instance, cmd, phase);
+
+ if (transfersize >= DMA_MIN_SIZE) {
len = transfersize;
cmd->SCp.phase = phase;
if (NCR5380_transfer_dma(instance, &phase,
@@ -2068,16 +1963,14 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/*
* If the watchdog timer fires, all future
* accesses to this device will use the
- * polled-IO. */
+ * polled-IO.
+ */
scmd_printk(KERN_INFO, cmd,
"switching to slow handshake\n");
cmd->device->borken = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
#ifdef REAL_DMA
@@ -2093,174 +1986,84 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
}
} else
#endif /* defined(REAL_DMA) */
- NCR5380_transfer_pio(instance, &phase,
- (int *)&cmd->SCp.this_residual,
- (unsigned char **)&cmd->SCp.ptr);
+ {
+ /* Break up transfer into 3 ms chunks,
+ * presuming 6 accesses per handshake.
+ */
+ transfersize = min((unsigned long)cmd->SCp.this_residual,
+ hostdata->accesses_per_ms / 2);
+ len = transfersize;
+ NCR5380_transfer_pio(instance, &phase, &len,
+ (unsigned char **)&cmd->SCp.ptr);
+ cmd->SCp.this_residual -= transfersize - len;
+ }
#if defined(CONFIG_SUN3) && defined(REAL_DMA)
/* if we had intended to dma that command clear it */
if (sun3_dma_setup_done == cmd)
sun3_dma_setup_done = NULL;
#endif
- break;
+ return;
case PHASE_MSGIN:
len = 1;
data = &tmp;
- NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
NCR5380_transfer_pio(instance, &phase, &len, &data);
cmd->SCp.Message = tmp;
switch (tmp) {
- /*
- * Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- *
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands.
- */
-#ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked command "
- "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Sanity check : A linked command should only terminate
- * with one of these messages if there are more linked
- * commands available.
- */
-
- if (!cmd->next_link) {
- printk(KERN_NOTICE "scsi%d: target %d lun %llu "
- "linked command complete, no next_link\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- sink = 1;
- do_abort(instance);
- return;
- }
-
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process; copy it
- * and don't free it! */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked request "
- "done, calling scsi_done().\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
-#endif /* def LINKED */
case ABORT:
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu "
- "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "COMMAND COMPLETE %p target %d lun %llu\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
- local_irq_save(flags);
- hostdata->retain_dma_intr++;
hostdata->connected = NULL;
#ifdef SUPPORT_TAGS
cmd_free_tag(cmd);
if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
- /* Turn a QUEUE FULL status into BUSY, I think the
- * mid level cannot handle QUEUE FULL :-( (The
- * command is retried after BUSY). Also update our
- * queue size to the number of currently issued
- * commands now.
- */
- /* ++Andreas: the mid level code knows about
- QUEUE_FULL now. */
- struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][cmd->device->lun];
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu returned "
- "QUEUE_FULL after %d commands\n",
- HOSTNO, cmd->device->id, cmd->device->lun,
- ta->nr_allocated);
+ u8 lun = cmd->device->lun;
+ struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
+
+ dsprintk(NDEBUG_TAGS, instance,
+ "QUEUE_FULL %p target %d lun %d nr_allocated %d\n",
+ cmd, scmd_id(cmd), lun, ta->nr_allocated);
if (ta->queue_size > ta->nr_allocated)
- ta->nr_allocated = ta->queue_size;
+ ta->queue_size = ta->nr_allocated;
}
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * I'm not sure what the correct thing to do here is :
- *
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- *
- * If it was a REQUEST SENSE command, we need some way to
- * differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the
- * result code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed
- */
-
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (status_byte(cmd->SCp.Status) != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-
- if ((cmd->cmnd[0] == REQUEST_SENSE) &&
- hostdata->ses.cmd_len) {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- hostdata->ses.cmd_len = 0 ;
+ cmd->result &= ~0xffff;
+ cmd->result |= cmd->SCp.Status;
+ cmd->result |= cmd->SCp.Message << 8;
+
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ complete_cmd(instance, cmd);
+ else {
+ if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION ||
+ cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) {
+ dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
+ cmd);
+ list_add_tail(&ncmd->list,
+ &hostdata->autosense);
+ } else
+ complete_cmd(instance, cmd);
}
- if ((cmd->cmnd[0] != REQUEST_SENSE) &&
- (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
- scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
-
- dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n", HOSTNO);
-
- LIST(cmd,hostdata->issue_queue);
- SET_NEXT(cmd, hostdata->issue_queue);
- hostdata->issue_queue = (struct scsi_cmnd *) cmd;
- dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of "
- "issue queue\n", H_NO(cmd));
- } else {
- cmd->scsi_done(cmd);
- }
-
- local_irq_restore(flags);
-
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- local_irq_save(flags);
- hostdata->retain_dma_intr--;
- /* ++roman: For Falcon SCSI, release the lock on the
- * ST-DMA here if no other commands are waiting on the
- * disconnected queue.
- */
maybe_release_dma_irq(instance);
- local_irq_restore(flags);
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
switch (hostdata->last_message) {
case HEAD_OF_QUEUE_TAG:
case ORDERED_QUEUE_TAG:
@@ -2274,27 +2077,20 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->device->tagged_supported = 0;
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
cmd->tag = TAG_NONE;
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu rejected "
- "QUEUE_TAG message; tagged queuing "
- "disabled\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %llu rejected QUEUE_TAG message; tagged queuing disabled\n",
+ scmd_id(cmd), cmd->device->lun);
break;
}
break;
case DISCONNECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- local_irq_save(flags);
- cmd->device->disconnect = 1;
- LIST(cmd,hostdata->disconnected_queue);
- SET_NEXT(cmd, hostdata->disconnected_queue);
hostdata->connected = NULL;
- hostdata->disconnected_queue = cmd;
- local_irq_restore(flags);
- dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d lun %llu was "
- "moved from connected to the "
- "disconnected_queue\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
+ list_add(&ncmd->list, &hostdata->disconnected);
+ dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
+ instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
+
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
@@ -2303,9 +2099,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /* Wait for bus free to avoid nasty timeouts */
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
@@ -2324,37 +2117,30 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
case RESTORE_POINTERS:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
break;
case EXTENDED_MESSAGE:
/*
- * Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't
- * include first two bytes)
- * 2 code
- * 3..length+1 arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
+ * Start the message buffer with the EXTENDED_MESSAGE
* byte, since spi_print_msg() wants the whole thing.
*/
extended_msg[0] = EXTENDED_MESSAGE;
/* Accept first byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_EXTENDED, "scsi%d: receiving extended message\n", HOSTNO);
+ spin_unlock_irq(&hostdata->lock);
+
+ dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n");
len = 2;
data = extended_msg + 1;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d: length=%d, code=0x%02x\n", HOSTNO,
- (int)extended_msg[1], (int)extended_msg[2]);
+ dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
+ (int)extended_msg[1],
+ (int)extended_msg[2]);
- if (!len && extended_msg[1] <=
- (sizeof(extended_msg) - 1)) {
+ if (!len && extended_msg[1] > 0 &&
+ extended_msg[1] <= sizeof(extended_msg) - 2) {
/* Accept third byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
len = extended_msg[1] - 1;
@@ -2362,8 +2148,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d: message received, residual %d\n",
- HOSTNO, len);
+ dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
+ len);
switch (extended_msg[2]) {
case EXTENDED_SDTR:
@@ -2373,15 +2159,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
tmp = 0;
}
} else if (len) {
- printk(KERN_NOTICE "scsi%d: error receiving "
- "extended message\n", HOSTNO);
+ shost_printk(KERN_ERR, instance, "error receiving extended message\n");
tmp = 0;
} else {
- printk(KERN_NOTICE "scsi%d: extended message "
- "code %02x length %d is too long\n",
- HOSTNO, extended_msg[2], extended_msg[1]);
+ shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n",
+ extended_msg[2], extended_msg[1]);
tmp = 0;
}
+
+ spin_lock_irq(&hostdata->lock);
+ if (!hostdata->connected)
+ return;
+
/* Fall through to reject message */
/*
@@ -2390,8 +2179,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
default:
if (!tmp) {
- printk(KERN_INFO "scsi%d: rejecting message ",
- instance->host_no);
+ shost_printk(KERN_ERR, instance, "rejecting message ");
spi_print_msg(extended_msg);
printk("\n");
} else if (tmp != EXTENDED_MESSAGE)
@@ -2414,18 +2202,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
hostdata->last_message = msgout;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
- local_irq_save(flags);
-#ifdef SUPPORT_TAGS
- cmd_free_tag(cmd);
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ complete_cmd(instance, cmd);
maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
}
msgout = NOP;
@@ -2447,22 +2228,25 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->SCp.Status = tmp;
break;
default:
- printk("scsi%d: unknown phase\n", HOSTNO);
+ shost_printk(KERN_ERR, instance, "unknown phase\n");
NCR5380_dprint(NDEBUG_ANY, instance);
} /* switch(phase) */
- } /* if (tmp * SR_REQ) */
- } /* while (1) */
+ } else {
+ spin_unlock_irq(&hostdata->lock);
+ NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+ spin_lock_irq(&hostdata->lock);
+ }
+ }
}
/*
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : does reselection, initializing the instance->connected
- * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
- * nexus has been reestablished,
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
*
* Inputs : instance - this instance of the NCR5380.
- *
*/
@@ -2471,7 +2255,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
static void NCR5380_reselect(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char target_mask;
unsigned char lun;
#ifdef SUPPORT_TAGS
@@ -2480,7 +2264,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
unsigned char msg[3];
int __maybe_unused len;
unsigned char __maybe_unused *data, __maybe_unused phase;
- struct scsi_cmnd *tmp = NULL, *prev;
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *tmp;
/*
* Disable arbitration, etc. since the host adapter obviously
@@ -2488,11 +2273,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
*/
NCR5380_write(MODE_REG, MR_BASE);
- hostdata->restart_select = 1;
target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
- dprintk(NDEBUG_RESELECTION, "scsi%d: reselect\n", HOSTNO);
+ dsprintk(NDEBUG_RESELECTION, instance, "reselect\n");
/*
* At this point, we have detected that our SCSI ID is on the bus,
@@ -2504,17 +2288,22 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
*/
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
- while (NCR5380_read(STATUS_REG) & SR_SEL)
- ;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return;
+ }
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/*
* Wait for target to go into MSGIN.
*/
- while (!(NCR5380_read(STATUS_REG) & SR_REQ))
- ;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+ do_abort(instance);
+ return;
+ }
#if defined(CONFIG_SUN3) && defined(REAL_DMA)
/* acknowledge toggle to MSGIN */
@@ -2527,15 +2316,21 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
data = msg;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+ if (len) {
+ do_abort(instance);
+ return;
+ }
#endif
if (!(msg[0] & 0x80)) {
- printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+ shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
spi_print_msg(msg);
+ printk("\n");
do_abort(instance);
return;
}
- lun = (msg[0] & 0x07);
+ lun = msg[0] & 0x07;
#if defined(SUPPORT_TAGS) && !defined(CONFIG_SUN3)
/* If the phase is still MSGIN, the target wants to send some more
@@ -2551,8 +2346,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
msg[1] == SIMPLE_QUEUE_TAG)
tag = msg[2];
- dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at "
- "reselection\n", HOSTNO, target_mask, lun, tag);
+ dsprintk(NDEBUG_TAGS, instance, "reselect: target mask %02x, lun %d sent tag %d\n",
+ target_mask, lun, tag);
}
#endif
@@ -2561,36 +2356,34 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
* just reestablished, and remove it from the disconnected queue.
*/
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
- tmp; prev = tmp, tmp = NEXT(tmp)) {
- if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+ tmp = NULL;
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ if (target_mask == (1 << scmd_id(cmd)) &&
+ lun == (u8)cmd->device->lun
#ifdef SUPPORT_TAGS
- && (tag == tmp->tag)
+ && (tag == cmd->tag)
#endif
) {
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- SET_NEXT(prev, NEXT(tmp));
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
- hostdata->disconnected_queue = NEXT(tmp);
- }
- SET_NEXT(tmp, NULL);
+ list_del(&ncmd->list);
+ tmp = cmd;
break;
}
}
- if (!tmp) {
- printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
-#ifdef SUPPORT_TAGS
- "tag %d "
-#endif
- "not in disconnected_queue.\n",
- HOSTNO, target_mask, lun
+ if (tmp) {
+ dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
+ "reselect: removed %p from disconnected queue\n", tmp);
+ } else {
+
#ifdef SUPPORT_TAGS
- , tag
+ shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d tag %d not in disconnected queue.\n",
+ target_mask, lun, tag);
+#else
+ shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
+ target_mask, lun);
#endif
- );
/*
* Since we have an established nexus that we can't do anything
* with, we must abort it.
@@ -2614,7 +2407,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
}
/* setup this command for dma if not already */
if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != tmp)) {
- sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request));
+ sun3scsi_dma_setup(instance, d, count,
+ rq_data_dir(tmp->request));
sun3_dma_setup_done = tmp;
}
}
@@ -2639,235 +2433,168 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
msg[1] == SIMPLE_QUEUE_TAG)
tag = msg[2];
- dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at reselection\n"
- HOSTNO, target_mask, lun, tag);
+ dsprintk(NDEBUG_TAGS, instance, "reselect: target mask %02x, lun %d sent tag %d\n"
+ target_mask, lun, tag);
}
#endif
hostdata->connected = tmp;
- dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
- HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+ dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n",
+ scmd_id(tmp), tmp->device->lun, tmp->tag);
}
-/*
- * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
- *
- * Purpose : abort a command
- *
- * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
- * used.
- *
- * Returns : SUCCESS - success, FAILED on failure.
- *
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
- * a problem, we could implement longjmp() / setjmp(), setjmp()
- * called where the loop started in NCR5380_main().
+/**
+ * list_find_cmd - test for presence of a command in a linked list
+ * @haystack: list of commands
+ * @needle: command to search for
*/
-static
-int NCR5380_abort(struct scsi_cmnd *cmd)
+static bool list_find_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
{
- struct Scsi_Host *instance = cmd->device->host;
- SETUP_HOSTDATA(instance);
- struct scsi_cmnd *tmp, **prev;
- unsigned long flags;
-
- scmd_printk(KERN_NOTICE, cmd, "aborting command\n");
-
- NCR5380_print_status(instance);
+ struct NCR5380_cmd *ncmd;
- local_irq_save(flags);
+ list_for_each_entry(ncmd, haystack, list)
+ if (NCR5380_to_scmd(ncmd) == needle)
+ return true;
+ return false;
+}
- dprintk(NDEBUG_ABORT, "scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
- NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
+/**
+ * list_remove_cmd - remove a command from linked list
+ * @haystack: list of commands
+ * @needle: command to remove
+ */
-#if 1
- /*
- * Case 1 : If the command is the currently executing command,
- * we'll set the aborted flag and return control so that
- * information transfer routine can exit cleanly.
- */
+static bool list_del_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
+{
+ if (list_find_cmd(haystack, needle)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle);
- if (hostdata->connected == cmd) {
+ list_del(&ncmd->list);
+ return true;
+ }
+ return false;
+}
- dprintk(NDEBUG_ABORT, "scsi%d: aborting connected command\n", HOSTNO);
- /*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
+/**
+ * NCR5380_abort - scsi host eh_abort_handler() method
+ * @cmd: the command to be aborted
+ *
+ * Try to abort a given command by removing it from queues and/or sending
+ * the target an abort message. This may not succeed in causing a target
+ * to abort the command. Nonetheless, the low-level driver must forget about
+ * the command because the mid-layer reclaims it and it may be re-issued.
+ *
+ * The normal path taken by a command is as follows. For EH we trace this
+ * same path to locate and abort the command.
+ *
+ * unissued -> selecting -> [unissued -> selecting ->]... connected ->
+ * [disconnected -> connected ->]...
+ * [autosense -> connected ->] done
+ *
+ * If cmd was not found at all then presumably it has already been completed,
+ * in which case return SUCCESS to try to avoid further EH measures.
+ *
+ * If the command has not completed yet, we must not fail to find it.
+ * We have no option but to forget the aborted command (even if it still
+ * lacks sense data). The mid-layer may re-issue a command that is in error
+ * recovery (see scsi_send_eh_cmnd), but the logic and data structures in
+ * this driver are such that a command can appear on one queue only.
+ *
+ * The lock protects driver data structures, but EH handlers also use it
+ * to serialize their own execution and prevent their own re-entry.
+ */
- /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
- /*
- * Since we can't change phases until we've completed the current
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
+static int NCR5380_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long flags;
+ int result = SUCCESS;
- /*
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
+ spin_lock_irqsave(&hostdata->lock, flags);
- if (do_abort(instance) == 0) {
- hostdata->aborted = 1;
- hostdata->connected = NULL;
- cmd->result = DID_ABORT << 16;
-#ifdef SUPPORT_TAGS
- cmd_free_tag(cmd);
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
- return SUCCESS;
- } else {
- local_irq_restore(flags);
- printk("scsi%d: abort of connected command failed!\n", HOSTNO);
- return FAILED;
- }
- }
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
- /*
- * Case 2 : If the command hasn't been issued yet, we simply remove it
- * from the issue queue.
- */
- for (prev = (struct scsi_cmnd **)&(hostdata->issue_queue),
- tmp = (struct scsi_cmnd *)hostdata->issue_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- (*prev) = NEXT(tmp);
- SET_NEXT(tmp, NULL);
- tmp->result = DID_ABORT << 16;
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n",
- HOSTNO);
- /* Tagged queuing note: no tag to free here, hasn't been assigned
- * yet... */
- tmp->scsi_done(tmp);
- return SUCCESS;
- }
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from issue queue\n", cmd);
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
+ goto out;
}
- /*
- * Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
-
- if (hostdata->connected) {
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: abort failed, command connected.\n", HOSTNO);
- return FAILED;
+ if (hostdata->selecting == cmd) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: cmd %p == selecting\n", cmd);
+ hostdata->selecting = NULL;
+ cmd->result = DID_ABORT << 16;
+ complete_cmd(instance, cmd);
+ goto out;
}
- /*
- * Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select(). The easiest way to implement this
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that
- * device reselected.
- *
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
-
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp;
- tmp = NEXT(tmp)) {
- if (cmd == tmp) {
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: aborting disconnected command.\n", HOSTNO);
-
- if (NCR5380_select(instance, cmd))
- return FAILED;
-
- dprintk(NDEBUG_ABORT, "scsi%d: nexus reestablished.\n", HOSTNO);
-
- do_abort(instance);
+ if (list_del_cmd(&hostdata->disconnected, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from disconnected list\n", cmd);
+ /* Can't call NCR5380_select() and send ABORT because that
+ * means releasing the lock. Need a bus reset.
+ */
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
+ }
- local_irq_save(flags);
- for (prev = (struct scsi_cmnd **)&(hostdata->disconnected_queue),
- tmp = (struct scsi_cmnd *)hostdata->disconnected_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- *prev = NEXT(tmp);
- SET_NEXT(tmp, NULL);
- tmp->result = DID_ABORT << 16;
- /* We must unlock the tag/LUN immediately here, since the
- * target goes to BUS FREE and doesn't send us another
- * message (COMMAND_COMPLETE or the like)
- */
-#ifdef SUPPORT_TAGS
- cmd_free_tag(tmp);
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ if (hostdata->connected == cmd) {
+ dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+ hostdata->connected = NULL;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
#endif
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- tmp->scsi_done(tmp);
- return SUCCESS;
- }
- }
+ if (do_abort(instance)) {
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
}
+ set_host_byte(cmd, DID_ABORT);
+ complete_cmd(instance, cmd);
+ goto out;
}
- /* Maybe it is sufficient just to release the ST-DMA lock... (if
- * possible at all) At least, we should check if the lock could be
- * released after the abort, in case it is kept due to some bug.
- */
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
+ if (list_del_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from sense queue\n", cmd);
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ }
- /*
- * Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
+out:
+ if (result == FAILED)
+ dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
+ else
+ dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
- printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ maybe_release_dma_irq(instance);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
- return FAILED;
+ return result;
}
-/*
- * Function : int NCR5380_reset (struct scsi_cmnd *cmd)
- *
- * Purpose : reset the SCSI bus.
- *
- * Returns : SUCCESS or FAILURE
+/**
+ * NCR5380_bus_reset - reset the SCSI bus
+ * @cmd: SCSI command undergoing EH
*
+ * Returns SUCCESS
*/
static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
@@ -2876,23 +2603,22 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
int i;
unsigned long flags;
+ struct NCR5380_cmd *ncmd;
- NCR5380_print_status(instance);
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
+
+ do_reset(instance);
- /* get in phase */
- NCR5380_write(TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
- /* assert RST */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
- udelay(40);
/* reset NCR registers */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
- /* ++roman: reset interrupt condition! otherwise no interrupts don't get
- * through anymore ... */
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
/* After the reset, there are no more connected or disconnected commands
* and no busy units; so clear the low-level status here to avoid
@@ -2900,17 +2626,39 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
* commands!
*/
- if (hostdata->issue_queue)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
- if (hostdata->connected)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted a connected command\n", H_NO(cmd));
- if (hostdata->disconnected_queue)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ }
+
+ if (hostdata->selecting) {
+ hostdata->selecting->result = DID_RESET << 16;
+ complete_cmd(instance, hostdata->selecting);
+ hostdata->selecting = NULL;
+ }
+
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+ INIT_LIST_HEAD(&hostdata->disconnected);
+
+ list_for_each_entry(ncmd, &hostdata->autosense, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+ INIT_LIST_HEAD(&hostdata->autosense);
+
+ if (hostdata->connected) {
+ set_host_byte(hostdata->connected, DID_RESET);
+ complete_cmd(instance, hostdata->connected);
+ hostdata->connected = NULL;
+ }
- local_irq_save(flags);
- hostdata->issue_queue = NULL;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
free_all_tags(hostdata);
#endif
@@ -2920,8 +2668,9 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
hostdata->dma_len = 0;
#endif
+ queue_work(hostdata->work_q, &hostdata->main_task);
maybe_release_dma_irq(instance);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
return SUCCESS;
}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 5ede3da..78d1b29 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -66,7 +66,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -98,7 +97,6 @@
#define NCR5380_queue_command atari_scsi_queue_command
#define NCR5380_abort atari_scsi_abort
-#define NCR5380_show_info atari_scsi_show_info
#define NCR5380_info atari_scsi_info
#define NCR5380_dma_read_setup(instance, data, count) \
@@ -161,23 +159,10 @@ static inline unsigned long SCSI_DMA_GETADR(void)
return adr;
}
-#define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \
- (atari_scsi_host->hostdata))->dma_len)
-
-/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
- * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
- * need ten times the standard value... */
-#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-#define AFTER_RESET_DELAY (HZ/2)
-#else
-#define AFTER_RESET_DELAY (5*HZ/2)
-#endif
-
#ifdef REAL_DMA
static void atari_scsi_fetch_restbytes(void);
#endif
-static struct Scsi_Host *atari_scsi_host;
static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value);
@@ -208,12 +193,12 @@ static int setup_cmd_per_lun = -1;
module_param(setup_cmd_per_lun, int, 0);
static int setup_sg_tablesize = -1;
module_param(setup_sg_tablesize, int, 0);
-#ifdef SUPPORT_TAGS
static int setup_use_tagged_queuing = -1;
module_param(setup_use_tagged_queuing, int, 0);
-#endif
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
+static int setup_toshiba_delay = -1;
+module_param(setup_toshiba_delay, int, 0);
#if defined(REAL_DMA)
@@ -273,15 +258,17 @@ static void scsi_dma_buserr(int irq, void *dummy)
#endif
-static irqreturn_t scsi_tt_intr(int irq, void *dummy)
+static irqreturn_t scsi_tt_intr(int irq, void *dev)
{
#ifdef REAL_DMA
+ struct Scsi_Host *instance = dev;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int dma_stat;
dma_stat = tt_scsi_dma.dma_ctrl;
- dprintk(NDEBUG_INTR, "scsi%d: NCR5380 interrupt, DMA status = %02x\n",
- atari_scsi_host->host_no, dma_stat & 0xff);
+ dsprintk(NDEBUG_INTR, instance, "NCR5380 interrupt, DMA status = %02x\n",
+ dma_stat & 0xff);
/* Look if it was the DMA that has interrupted: First possibility
* is that a bus error occurred...
@@ -304,7 +291,8 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
* data reg!
*/
if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
- atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
+ atari_dma_residual = hostdata->dma_len -
+ (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
dprintk(NDEBUG_DMA, "SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
@@ -356,15 +344,17 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
#endif /* REAL_DMA */
- NCR5380_intr(irq, dummy);
+ NCR5380_intr(irq, dev);
return IRQ_HANDLED;
}
-static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
+static irqreturn_t scsi_falcon_intr(int irq, void *dev)
{
#ifdef REAL_DMA
+ struct Scsi_Host *instance = dev;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int dma_stat;
/* Turn off DMA and select sector counter register before
@@ -399,7 +389,7 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
printk(KERN_ERR "SCSI DMA error: %ld bytes lost in "
"ST-DMA fifo\n", transferred & 15);
- atari_dma_residual = HOSTDATA_DMALEN - transferred;
+ atari_dma_residual = hostdata->dma_len - transferred;
dprintk(NDEBUG_DMA, "SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
} else
@@ -411,13 +401,14 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
* data to the original destination address.
*/
memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr),
- HOSTDATA_DMALEN - atari_dma_residual);
+ hostdata->dma_len - atari_dma_residual);
atari_dma_orig_addr = NULL;
}
#endif /* REAL_DMA */
- NCR5380_intr(irq, dummy);
+ NCR5380_intr(irq, dev);
+
return IRQ_HANDLED;
}
@@ -488,7 +479,7 @@ static int __init atari_scsi_setup(char *str)
* Defaults depend on TT or Falcon, determined at run time.
* Negative values mean don't change.
*/
- int ints[6];
+ int ints[8];
get_options(str, ARRAY_SIZE(ints), ints);
@@ -504,10 +495,11 @@ static int __init atari_scsi_setup(char *str)
setup_sg_tablesize = ints[3];
if (ints[0] >= 4)
setup_hostid = ints[4];
-#ifdef SUPPORT_TAGS
if (ints[0] >= 5)
setup_use_tagged_queuing = ints[5];
-#endif
+ /* ints[6] (use_pdma) is ignored */
+ if (ints[0] >= 7)
+ setup_toshiba_delay = ints[7];
return 1;
}
@@ -516,38 +508,6 @@ __setup("atascsi=", atari_scsi_setup);
#endif /* !MODULE */
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-static void __init atari_scsi_reset_boot(void)
-{
- unsigned long end;
-
- /*
- * Do a SCSI reset to clean up the bus during initialization. No messing
- * with the queues, interrupts, or locks necessary here.
- */
-
- printk("Atari SCSI: resetting the SCSI bus...");
-
- /* get in phase */
- NCR5380_write(TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
-
- /* assert RST */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
- /* The min. reset hold time is 25us, so 40us should be enough */
- udelay(50);
- /* reset RST and interrupt */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-
- end = jiffies + AFTER_RESET_DELAY;
- while (time_before(jiffies, end))
- barrier();
-
- printk(" done\n");
-}
-#endif
-
#if defined(REAL_DMA)
static unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance,
@@ -815,14 +775,14 @@ static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
static struct scsi_host_template atari_scsi_template = {
.module = THIS_MODULE,
.proc_name = DRV_MODULE_NAME,
- .show_info = atari_scsi_show_info,
.name = "Atari native SCSI",
.info = atari_scsi_info,
.queuecommand = atari_scsi_queue_command,
.eh_abort_handler = atari_scsi_abort,
.eh_bus_reset_handler = atari_scsi_bus_reset,
.this_id = 7,
- .use_clustering = DISABLE_CLUSTERING
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
};
static int __init atari_scsi_probe(struct platform_device *pdev)
@@ -880,7 +840,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
} else {
/* Test if a host id is set in the NVRam */
if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
- unsigned char b = nvram_read_byte(14);
+ unsigned char b = nvram_read_byte(16);
/* Arbitration enabled? (for TOS)
* If yes, use configured host ID
@@ -915,21 +875,18 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
error = -ENOMEM;
goto fail_alloc;
}
- atari_scsi_host = instance;
-
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
- atari_scsi_reset_boot();
-#endif
instance->irq = irq->start;
host_flags |= IS_A_TT() ? 0 : FLAG_LATE_DMA_SETUP;
-
#ifdef SUPPORT_TAGS
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
#endif
+ host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
- NCR5380_init(instance, host_flags);
+ error = NCR5380_init(instance, host_flags);
+ if (error)
+ goto fail_init;
if (IS_A_TT()) {
error = request_irq(instance->irq, scsi_tt_intr, 0,
@@ -975,6 +932,8 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
#endif
}
+ NCR5380_maybe_reset_bus(instance);
+
error = scsi_add_host(instance, NULL);
if (error)
goto fail_host;
@@ -989,6 +948,7 @@ fail_host:
free_irq(instance->irq, instance);
fail_irq:
NCR5380_exit(instance);
+fail_init:
scsi_host_put(instance);
fail_alloc:
if (atari_dma_buffer)
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 05301bc..8b52a9d 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -41,77 +41,128 @@
static struct scsi_host_template atp870u_template;
static void send_s870(struct atp_unit *dev,unsigned char c);
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
-static void tscam_885(void);
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode);
+
+static inline void atp_writeb_base(struct atp_unit *atp, u8 reg, u8 val)
+{
+ outb(val, atp->baseport + reg);
+}
+
+static inline void atp_writew_base(struct atp_unit *atp, u8 reg, u16 val)
+{
+ outw(val, atp->baseport + reg);
+}
+
+static inline void atp_writeb_io(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+ outb(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writew_io(struct atp_unit *atp, u8 channel, u8 reg, u16 val)
+{
+ outw(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writeb_pci(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+ outb(val, atp->pciport[channel] + reg);
+}
+
+static inline void atp_writel_pci(struct atp_unit *atp, u8 channel, u8 reg, u32 val)
+{
+ outl(val, atp->pciport[channel] + reg);
+}
+
+static inline u8 atp_readb_base(struct atp_unit *atp, u8 reg)
+{
+ return inb(atp->baseport + reg);
+}
+
+static inline u16 atp_readw_base(struct atp_unit *atp, u8 reg)
+{
+ return inw(atp->baseport + reg);
+}
+
+static inline u32 atp_readl_base(struct atp_unit *atp, u8 reg)
+{
+ return inl(atp->baseport + reg);
+}
+
+static inline u8 atp_readb_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inb(atp->ioport[channel] + reg);
+}
+
+static inline u16 atp_readw_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inw(atp->ioport[channel] + reg);
+}
+
+static inline u8 atp_readb_pci(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inb(atp->pciport[channel] + reg);
+}
+
+static inline bool is880(struct atp_unit *atp)
+{
+ return atp->pdev->device == ATP880_DEVID1 ||
+ atp->pdev->device == ATP880_DEVID2;
+}
+
+static inline bool is885(struct atp_unit *atp)
+{
+ return atp->pdev->device == ATP885_DEVID;
+}
static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
{
unsigned long flags;
- unsigned short int tmpcip, id;
+ unsigned short int id;
unsigned char i, j, c, target_id, lun,cmdp;
unsigned char *prd;
struct scsi_cmnd *workreq;
- unsigned int workport, tmport, tmport1;
unsigned long adrcnt, k;
#ifdef ED_DBGP
unsigned long l;
#endif
- int errstus;
struct Scsi_Host *host = dev_id;
struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
for (c = 0; c < 2; c++) {
- tmport = dev->ioport[c] + 0x1f;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x80) != 0)
- {
- goto ch_sel;
- }
+ break;
dev->in_int[c] = 0;
}
- return IRQ_NONE;
-ch_sel:
+ if ((j & 0x80) == 0)
+ return IRQ_NONE;
#ifdef ED_DBGP
printk("atp870u_intr_handle enter\n");
#endif
dev->in_int[c] = 1;
- cmdp = inb(dev->ioport[c] + 0x10);
- workport = dev->ioport[c];
+ cmdp = atp_readb_io(dev, c, 0x10);
if (dev->working[c] != 0) {
- if (dev->dev_id == ATP885_DEVID) {
- tmport1 = workport + 0x16;
- if ((inb(tmport1) & 0x80) == 0)
- outb((inb(tmport1) | 0x80), tmport1);
+ if (is885(dev)) {
+ if ((atp_readb_io(dev, c, 0x16) & 0x80) == 0)
+ atp_writeb_io(dev, c, 0x16, (atp_readb_io(dev, c, 0x16) | 0x80));
}
- tmpcip = dev->pciport[c];
- if ((inb(tmpcip) & 0x08) != 0)
+ if ((atp_readb_pci(dev, c, 0x00) & 0x08) != 0)
{
- tmpcip += 0x2;
for (k=0; k < 1000; k++) {
- if ((inb(tmpcip) & 0x08) == 0) {
- goto stop_dma;
- }
- if ((inb(tmpcip) & 0x01) == 0) {
- goto stop_dma;
- }
+ if ((atp_readb_pci(dev, c, 2) & 0x08) == 0)
+ break;
+ if ((atp_readb_pci(dev, c, 2) & 0x01) == 0)
+ break;
}
}
-stop_dma:
- tmpcip = dev->pciport[c];
- outb(0x00, tmpcip);
- tmport -= 0x08;
+ atp_writeb_pci(dev, c, 0, 0x00);
- i = inb(tmport);
+ i = atp_readb_io(dev, c, 0x17);
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip += 2;
- outb(0x06, tmpcip);
- tmpcip -= 2;
- }
+ if (is885(dev))
+ atp_writeb_pci(dev, c, 2, 0x06);
- tmport -= 0x02;
- target_id = inb(tmport);
- tmport += 0x02;
+ target_id = atp_readb_io(dev, c, 0x15);
/*
* Remap wide devices onto id numbers
@@ -129,7 +180,7 @@ stop_dma:
}
dev->last_cmd[c] |= 0x40;
}
- if (dev->dev_id == ATP885_DEVID)
+ if (is885(dev))
dev->r1f[c][target_id] |= j;
#ifdef ED_DBGP
printk("atp870u_intr_handle status = %x\n",i);
@@ -138,12 +189,11 @@ stop_dma:
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- if (dev->dev_id == ATP885_DEVID) {
- tmport -= 0x05;
+ if (is885(dev)) {
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
if (dev->id[c][target_id].last_len != adrcnt)
{
k = dev->id[c][target_id].last_len;
@@ -152,7 +202,7 @@ stop_dma:
dev->id[c][target_id].last_len = adrcnt;
}
#ifdef ED_DBGP
- printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
+ printk("dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
#endif
}
@@ -160,11 +210,9 @@ stop_dma:
* Flip wide
*/
if (dev->wide_id[c] != 0) {
- tmport = workport + 0x1b;
- outb(0x01, tmport);
- while ((inb(tmport) & 0x01) != 0x01) {
- outb(0x01, tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
}
/*
* Issue more commands
@@ -185,37 +233,34 @@ stop_dma:
#ifdef ED_DBGP
printk("Status 0x85 return\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x40) {
dev->last_cmd[c] |= 0x40;
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x21) {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- tmport -= 0x05;
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
k = dev->id[c][target_id].last_len;
k -= adrcnt;
dev->id[c][target_id].tran_len = k;
dev->id[c][target_id].last_len = adrcnt;
- tmport -= 0x04;
- outb(0x41, tmport);
- tmport += 0x08;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
- if (dev->dev_id == ATP885_DEVID) {
+ if (is885(dev)) {
if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) {
if ((i == 0x4c) || (i == 0x8c))
i=0x48;
@@ -229,11 +274,9 @@ stop_dma:
printk(KERN_DEBUG "Device reselect\n");
#endif
lun = 0;
- tmport -= 0x07;
- if (cmdp == 0x44 || i==0x80) {
- tmport += 0x0d;
- lun = inb(tmport) & 0x07;
- } else {
+ if (cmdp == 0x44 || i == 0x80)
+ lun = atp_readb_io(dev, c, 0x1d) & 0x07;
+ else {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
@@ -241,49 +284,41 @@ stop_dma:
#ifdef ED_DBGP
printk("cmdp = 0x41\n");
#endif
- tmport += 0x02;
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
k = dev->id[c][target_id].last_len;
k -= adrcnt;
dev->id[c][target_id].tran_len = k;
dev->id[c][target_id].last_len = adrcnt;
- tmport += 0x04;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
} else {
#ifdef ED_DBGP
printk("cmdp != 0x41\n");
#endif
- outb(0x46, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x46);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x02;
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x12, 0x00);
+ atp_writeb_io(dev, c, 0x13, 0x00);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
}
if (dev->last_cmd[c] != 0xff) {
dev->last_cmd[c] |= 0x40;
}
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) & 0xfe;
- outb(j, dev->baseport + 0x29);
- tmport = workport + 0x16;
- } else {
- tmport = workport + 0x10;
- outb(0x45, tmport);
- tmport += 0x06;
- }
-
- target_id = inb(tmport);
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) & 0xfe;
+ atp_writeb_base(dev, 0x29, j);
+ } else
+ atp_writeb_io(dev, c, 0x10, 0x45);
+
+ target_id = atp_readb_io(dev, c, 0x16);
/*
* Remap wide identifiers
*/
@@ -292,10 +327,8 @@ stop_dma:
} else {
target_id &= 0x07;
}
- if (dev->dev_id == ATP885_DEVID) {
- tmport = workport + 0x10;
- outb(0x45, tmport);
- }
+ if (is885(dev))
+ atp_writeb_io(dev, c, 0x10, 0x45);
workreq = dev->id[c][target_id].curr_req;
#ifdef ED_DBGP
scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -304,18 +337,16 @@ stop_dma:
printk("\n");
#endif
- tmport = workport + 0x0f;
- outb(lun, tmport);
- tmport += 0x02;
- outb(dev->id[c][target_id].devsp, tmport++);
+ atp_writeb_io(dev, c, 0x0f, lun);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
adrcnt = dev->id[c][target_id].tran_len;
k = dev->id[c][target_id].last_len;
- outb(((unsigned char *) &k)[2], tmport++);
- outb(((unsigned char *) &k)[1], tmport++);
- outb(((unsigned char *) &k)[0], tmport++);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) &k)[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) &k)[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) &k)[0]);
#ifdef ED_DBGP
- printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3));
+ printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, atp_readb_io(dev, c, 0x14), atp_readb_io(dev, c, 0x13), atp_readb_io(dev, c, 0x12));
#endif
/* Remap wide */
j = target_id;
@@ -324,35 +355,28 @@ stop_dma:
}
/* Add direction */
j |= dev->id[c][target_id].dirct;
- outb(j, tmport++);
- outb(0x80,tmport);
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x16, 0x80);
/* enable 32 bit fifo transfer */
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip = dev->pciport[c] + 1;
- i=inb(tmpcip) & 0xf3;
+ if (is885(dev)) {
+ i = atp_readb_pci(dev, c, 1) & 0xf3;
//j=workreq->cmnd[0];
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
i |= 0x0c;
}
- outb(i,tmpcip);
- } else if ((dev->dev_id == ATP880_DEVID1) ||
- (dev->dev_id == ATP880_DEVID2) ) {
- tmport = workport - 0x05;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0x3f), tmport);
- }
+ atp_writeb_pci(dev, c, 1, i);
+ } else if (is880(dev)) {
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+ else
+ atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
} else {
- tmport = workport + 0x3a;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0xf3), tmport);
- }
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+ else
+ atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
}
- tmport = workport + 0x1b;
j = 0;
id = 1;
id = id << target_id;
@@ -362,18 +386,16 @@ stop_dma:
if ((id & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- while ((inb(tmport) & 0x01) != j) {
- outb(j,tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, j);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j)
+ atp_writeb_io(dev, c, 0x1b, j);
if (dev->id[c][target_id].last_len == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("dev->id[c][target_id].last_len = 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
#ifdef ED_DBGP
printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);
@@ -401,39 +423,33 @@ stop_dma:
}
}
}
- tmpcip = dev->pciport[c] + 0x04;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
+ atp_writel_pci(dev, c, 0x04, dev->id[c][target_id].prdaddr);
#ifdef ED_DBGP
printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);
#endif
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip -= 0x04;
- } else {
- tmpcip -= 0x02;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip -= 0x02;
+ if (!is885(dev)) {
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
}
- tmport = workport + 0x18;
/*
* Check transfer direction
*/
if (dev->id[c][target_id].dirct != 0) {
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("status 0x80 return dirct != 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("status 0x80 return dirct = 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
/*
@@ -442,31 +458,22 @@ stop_dma:
workreq = dev->id[c][target_id].curr_req;
- if (i == 0x42) {
- if ((dev->last_cmd[c] & 0xf0) != 0x40)
- {
- dev->last_cmd[c] = 0xff;
- }
- errstus = 0x02;
- workreq->result = errstus;
- goto go_42;
- }
- if (i == 0x16) {
+ if (i == 0x42 || i == 0x16) {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- errstus = 0;
- tmport -= 0x08;
- errstus = inb(tmport);
- if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) {
- printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
- errstus = 0x02;
- }
- workreq->result = errstus;
-go_42:
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) | 0x01;
- outb(j, dev->baseport + 0x29);
+ if (i == 0x16) {
+ workreq->result = atp_readb_io(dev, c, 0x0f);
+ if (((dev->r1f[c][target_id] & 0x10) != 0) && is885(dev)) {
+ printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
+ workreq->result = 0x02;
+ }
+ } else
+ workreq->result = 0x02;
+
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) | 0x01;
+ atp_writeb_base(dev, 0x29, j);
}
/*
* Complete the command
@@ -488,11 +495,9 @@ go_42:
* Take it back wide
*/
if (dev->wide_id[c] != 0) {
- tmport = workport + 0x1b;
- outb(0x01, tmport);
- while ((inb(tmport) & 0x01) != 0x01) {
- outb(0x01, tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
}
/*
* If there is stuff to send and nothing going then send it
@@ -507,7 +512,7 @@ go_42:
}
spin_unlock_irqrestore(dev->host->host_lock, flags);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
@@ -517,84 +522,54 @@ go_42:
}
i &= 0x0f;
if (i == 0x09) {
- tmpcip += 4;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip = tmpcip - 2;
- tmport = workport + 0x10;
- outb(0x41, tmport);
- if (dev->dev_id == ATP885_DEVID) {
- tmport += 2;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ if (is885(dev)) {
k = dev->id[c][target_id].last_len;
- outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[0]), tmport);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x04;
} else {
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x08;
}
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x08) {
- tmpcip += 4;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip = tmpcip - 2;
- tmport = workport + 0x10;
- outb(0x41, tmport);
- if (dev->dev_id == ATP885_DEVID) {
- tmport += 2;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ if (is885(dev)) {
k = dev->id[c][target_id].last_len;
- outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++);
- } else {
- tmport += 5;
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
}
- outb((unsigned char) (inb(tmport) | 0x20), tmport);
+ atp_writeb_io(dev, c, 0x15, atp_readb_io(dev, c, 0x15) | 0x20);
dev->id[c][target_id].dirct = 0x20;
- tmport += 0x03;
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
dev->in_int[c] = 0;
- goto handled;
- }
- tmport -= 0x07;
- if (i == 0x0a) {
- outb(0x30, tmport);
- } else {
- outb(0x46, tmport);
+ return IRQ_HANDLED;
}
+ if (i == 0x0a)
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ else
+ atp_writeb_io(dev, c, 0x10, 0x46);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x02;
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- dev->in_int[c] = 0;
- goto handled;
- } else {
-// tmport = workport + 0x17;
-// inb(tmport);
-// dev->working[c] = 0;
- dev->in_int[c] = 0;
- goto handled;
+ atp_writeb_io(dev, c, 0x12, 0x00);
+ atp_writeb_io(dev, c, 0x13, 0x00);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
}
-
-handled:
-#ifdef ED_DBGP
- printk("atp870u_intr_handle exit\n");
-#endif
+ dev->in_int[c] = 0;
+
return IRQ_HANDLED;
}
/**
@@ -608,7 +583,7 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
void (*done) (struct scsi_cmnd *))
{
unsigned char c;
- unsigned int tmport,m;
+ unsigned int m;
struct atp_unit *dev;
struct Scsi_Host *host;
@@ -677,11 +652,10 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
return 0;
}
dev->quereq[c][dev->quend[c]] = req_p;
- tmport = dev->ioport[c] + 0x1c;
#ifdef ED_DBGP
- printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]);
+ printk("dev->ioport[c] = %x atp_readb_io(dev, c, 0x1c) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],atp_readb_io(dev, c, 0x1c),c,dev->in_int[c],c,dev->in_snd[c]);
#endif
- if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
+ if ((atp_readb_io(dev, c, 0x1c) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
#ifdef ED_DBGP
printk("Call sent_s870(atp870u_queuecommand)\n");
#endif
@@ -706,14 +680,12 @@ static DEF_SCSI_QCMD(atp870u_queuecommand)
*/
static void send_s870(struct atp_unit *dev,unsigned char c)
{
- unsigned int tmport;
- struct scsi_cmnd *workreq;
+ struct scsi_cmnd *workreq = NULL;
unsigned int i;//,k;
unsigned char j, target_id;
unsigned char *prd;
- unsigned short int tmpcip, w;
+ unsigned short int w;
unsigned long l, bttl = 0;
- unsigned int workport;
unsigned long sg_count;
if (dev->in_snd[c] != 0) {
@@ -729,53 +701,42 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) {
dev->last_cmd[c] &= 0x0f;
workreq = dev->id[c][dev->last_cmd[c]].curr_req;
- if (workreq != NULL) { /* check NULL pointer */
- goto cmd_subp;
- }
- dev->last_cmd[c] = 0xff;
- if (dev->quhd[c] == dev->quend[c]) {
- dev->in_snd[c] = 0;
- return ;
+ if (!workreq) {
+ dev->last_cmd[c] = 0xff;
+ if (dev->quhd[c] == dev->quend[c]) {
+ dev->in_snd[c] = 0;
+ return;
+ }
}
}
- if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
- dev->in_snd[c] = 0;
- return ;
- }
- dev->working[c]++;
- j = dev->quhd[c];
- dev->quhd[c]++;
- if (dev->quhd[c] >= qcnt) {
- dev->quhd[c] = 0;
- }
- workreq = dev->quereq[c][dev->quhd[c]];
- if (dev->id[c][scmd_id(workreq)].curr_req == NULL) {
+ if (!workreq) {
+ if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
+ dev->in_snd[c] = 0;
+ return;
+ }
+ dev->working[c]++;
+ j = dev->quhd[c];
+ dev->quhd[c]++;
+ if (dev->quhd[c] >= qcnt)
+ dev->quhd[c] = 0;
+ workreq = dev->quereq[c][dev->quhd[c]];
+ if (dev->id[c][scmd_id(workreq)].curr_req != NULL) {
+ dev->quhd[c] = j;
+ dev->working[c]--;
+ dev->in_snd[c] = 0;
+ return;
+ }
dev->id[c][scmd_id(workreq)].curr_req = workreq;
dev->last_cmd[c] = scmd_id(workreq);
- goto cmd_subp;
- }
- dev->quhd[c] = j;
- dev->working[c]--;
- dev->in_snd[c] = 0;
- return;
-cmd_subp:
- workport = dev->ioport[c];
- tmport = workport + 0x1f;
- if ((inb(tmport) & 0xb0) != 0) {
- goto abortsnd;
- }
- tmport = workport + 0x1c;
- if (inb(tmport) == 0) {
- goto oktosend;
}
-abortsnd:
+ if ((atp_readb_io(dev, c, 0x1f) & 0xb0) != 0 || atp_readb_io(dev, c, 0x1c) != 0) {
#ifdef ED_DBGP
- printk("Abort to Send\n");
+ printk("Abort to Send\n");
#endif
- dev->last_cmd[c] |= 0x40;
- dev->in_snd[c] = 0;
- return;
-oktosend:
+ dev->last_cmd[c] |= 0x40;
+ dev->in_snd[c] = 0;
+ return;
+ }
#ifdef ED_DBGP
printk("OK to Send\n");
scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -786,9 +747,9 @@ oktosend:
#endif
l = scsi_bufflen(workreq);
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) & 0xfe;
- outb(j, dev->baseport + 0x29);
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) & 0xfe;
+ atp_writeb_base(dev, 0x29, j);
dev->r1f[c][scmd_id(workreq)] = 0;
}
@@ -800,7 +761,6 @@ oktosend:
l = 0;
}
- tmport = workport + 0x1b;
j = 0;
target_id = scmd_id(workreq);
@@ -812,9 +772,9 @@ oktosend:
if ((w & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- while ((inb(tmport) & 0x01) != j) {
- outb(j,tmport);
+ atp_writeb_io(dev, c, 0x1b, j);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j) {
+ atp_writeb_pci(dev, c, 0x1b, j);
#ifdef ED_DBGP
printk("send_s870 while loop 1\n");
#endif
@@ -823,24 +783,19 @@ oktosend:
* Write the command
*/
- tmport = workport;
- outb(workreq->cmd_len, tmport++);
- outb(0x2c, tmport++);
- if (dev->dev_id == ATP885_DEVID) {
- outb(0x7f, tmport++);
- } else {
- outb(0xcf, tmport++);
- }
- for (i = 0; i < workreq->cmd_len; i++) {
- outb(workreq->cmnd[i], tmport++);
- }
- tmport = workport + 0x0f;
- outb(workreq->device->lun, tmport);
- tmport += 0x02;
+ atp_writeb_io(dev, c, 0x00, workreq->cmd_len);
+ atp_writeb_io(dev, c, 0x01, 0x2c);
+ if (is885(dev))
+ atp_writeb_io(dev, c, 0x02, 0x7f);
+ else
+ atp_writeb_io(dev, c, 0x02, 0xcf);
+ for (i = 0; i < workreq->cmd_len; i++)
+ atp_writeb_io(dev, c, 0x03 + i, workreq->cmnd[i]);
+ atp_writeb_io(dev, c, 0x0f, workreq->device->lun);
/*
* Write the target
*/
- outb(dev->id[c][target_id].devsp, tmport++);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
#ifdef ED_DBGP
printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
#endif
@@ -849,9 +804,9 @@ oktosend:
/*
* Write transfer size
*/
- outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&l))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&l))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&l))[0]);
j = target_id;
dev->id[c][j].last_len = l;
dev->id[c][j].tran_len = 0;
@@ -867,29 +822,24 @@ oktosend:
/*
* Check transfer direction
*/
- if (workreq->sc_data_direction == DMA_TO_DEVICE) {
- outb((unsigned char) (j | 0x20), tmport++);
- } else {
- outb(j, tmport++);
- }
- outb((unsigned char) (inb(tmport) | 0x80), tmport);
- outb(0x80, tmport);
- tmport = workport + 0x1c;
+ if (workreq->sc_data_direction == DMA_TO_DEVICE)
+ atp_writeb_io(dev, c, 0x15, j | 0x20);
+ else
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x16, atp_readb_io(dev, c, 0x16) | 0x80);
+ atp_writeb_io(dev, c, 0x16, 0x80);
dev->id[c][target_id].dirct = 0;
if (l == 0) {
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
#ifdef ED_DBGP
printk("change SCSI_CMD_REG 0x08\n");
#endif
- outb(0x08, tmport);
- } else {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ } else
dev->last_cmd[c] |= 0x40;
- }
dev->in_snd[c] = 0;
return;
}
- tmpcip = dev->pciport[c];
prd = dev->id[c][target_id].prd_table;
dev->id[c][target_id].prd_pos = prd;
@@ -926,50 +876,37 @@ oktosend:
printk("2. bttl %x, l %x\n",bttl, l);
#endif
}
- tmpcip += 4;
#ifdef ED_DBGP
- printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);
+ printk("send_s870: prdaddr_2 0x%8x target_id %d\n", dev->id[c][target_id].prdaddr,target_id);
#endif
dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip--;
- j=inb(tmpcip) & 0xf3;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ if (is885(dev)) {
+ j = atp_readb_pci(dev, c, 1) & 0xf3;
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) ||
(workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
j |= 0x0c;
}
- outb(j,tmpcip);
- tmpcip--;
- } else if ((dev->dev_id == ATP880_DEVID1) ||
- (dev->dev_id == ATP880_DEVID2)) {
- tmpcip =tmpcip -2;
- tmport = workport - 0x05;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0x3f), tmport);
- }
+ atp_writeb_pci(dev, c, 1, j);
+ } else if (is880(dev)) {
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+ else
+ atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
} else {
- tmpcip =tmpcip -2;
- tmport = workport + 0x3a;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((inb(tmport) & 0xf3) | 0x08, tmport);
- } else {
- outb(inb(tmport) & 0xf3, tmport);
- }
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+ else
+ atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
}
- tmport = workport + 0x1c;
if(workreq->sc_data_direction == DMA_TO_DEVICE) {
dev->id[c][target_id].dirct = 0x20;
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
#ifdef ED_DBGP
printk( "start DMA(to target)\n");
#endif
@@ -979,10 +916,9 @@ oktosend:
dev->in_snd[c] = 0;
return;
}
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
#ifdef ED_DBGP
printk( "start DMA(to host)\n");
#endif
@@ -996,49 +932,40 @@ oktosend:
static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
{
- unsigned int tmport;
unsigned short int i, k;
unsigned char j;
- tmport = dev->ioport[0] + 0x1c;
- outw(*val, tmport);
-FUN_D7:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- k = inw(tmport);
+ k = atp_readw_io(dev, 0, 0x1c);
j = (unsigned char) (k >> 8);
- if ((k & 0x8000) != 0) { /* DB7 all release? */
- goto FUN_D7;
- }
+ if ((k & 0x8000) != 0) /* DB7 all release? */
+ i = 0;
}
*val |= 0x4000; /* assert DB6 */
- outw(*val, tmport);
+ atp_writew_io(dev, 0, 0x1c, *val);
*val &= 0xdfff; /* assert DB5 */
- outw(*val, tmport);
-FUN_D5:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */
- goto FUN_D5;
- }
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) != 0) /* DB5 all release? */
+ i = 0;
}
*val |= 0x8000; /* no DB4-0, assert DB7 */
*val &= 0xe0ff;
- outw(*val, tmport);
+ atp_writew_io(dev, 0, 0x1c, *val);
*val &= 0xbfff; /* release DB6 */
- outw(*val, tmport);
-FUN_D6:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */
- goto FUN_D6;
- }
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x4000) != 0) /* DB6 all release? */
+ i = 0;
}
return j;
}
-static void tscam(struct Scsi_Host *host)
+static void tscam(struct Scsi_Host *host, bool wide_chip, u8 scam_on)
{
- unsigned int tmport;
unsigned char i, j, k;
unsigned long n;
unsigned short int m, assignid_map, val;
@@ -1055,31 +982,28 @@ static void tscam(struct Scsi_Host *host)
}
*/
- tmport = dev->ioport[0] + 1;
- outb(0x08, tmport++);
- outb(0x7f, tmport);
- tmport = dev->ioport[0] + 0x11;
- outb(0x20, tmport);
+ atp_writeb_io(dev, 0, 1, 0x08);
+ atp_writeb_io(dev, 0, 2, 0x7f);
+ atp_writeb_io(dev, 0, 0x11, 0x20);
- if ((dev->scam_on & 0x40) == 0) {
+ if ((scam_on & 0x40) == 0) {
return;
}
m = 1;
m <<= dev->host_id[0];
j = 16;
- if (dev->chip_ver < 4) {
+ if (!wide_chip) {
m |= 0xff00;
j = 8;
}
assignid_map = m;
- tmport = dev->ioport[0] + 0x02;
- outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
+ atp_writeb_io(dev, 0, 0x02, 0x02); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+ atp_writeb_io(dev, 0, 0x03, 0);
+ atp_writeb_io(dev, 0, 0x04, 0);
+ atp_writeb_io(dev, 0, 0x05, 0);
+ atp_writeb_io(dev, 0, 0x06, 0);
+ atp_writeb_io(dev, 0, 0x07, 0);
+ atp_writeb_io(dev, 0, 0x08, 0);
for (i = 0; i < j; i++) {
m = 1;
@@ -1087,92 +1011,73 @@ static void tscam(struct Scsi_Host *host)
if ((m & assignid_map) != 0) {
continue;
}
- tmport = dev->ioport[0] + 0x0f;
- outb(0, tmport++);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
+ atp_writeb_io(dev, 0, 0x0f, 0);
+ atp_writeb_io(dev, 0, 0x12, 0);
+ atp_writeb_io(dev, 0, 0x13, 0);
+ atp_writeb_io(dev, 0, 0x14, 0);
if (i > 7) {
k = (i & 0x07) | 0x40;
} else {
k = i;
}
- outb(k, tmport++);
- tmport = dev->ioport[0] + 0x1b;
- if (dev->chip_ver == 4) {
- outb(0x01, tmport);
- } else {
- outb(0x00, tmport);
- }
-wait_rdyok:
- tmport = dev->ioport[0] + 0x18;
- outb(0x09, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
- tmport -= 0x08;
- k = inb(tmport);
- if (k != 0x16) {
- if ((k == 0x85) || (k == 0x42)) {
- continue;
- }
- tmport = dev->ioport[0] + 0x10;
- outb(0x41, tmport);
- goto wait_rdyok;
- }
+ atp_writeb_io(dev, 0, 0x15, k);
+ if (wide_chip)
+ atp_writeb_io(dev, 0, 0x1b, 0x01);
+ else
+ atp_writeb_io(dev, 0, 0x1b, 0x00);
+ do {
+ atp_writeb_io(dev, 0, 0x18, 0x09);
+
+ while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0x00)
+ cpu_relax();
+ k = atp_readb_io(dev, 0, 0x17);
+ if ((k == 0x85) || (k == 0x42))
+ break;
+ if (k != 0x16)
+ atp_writeb_io(dev, 0, 0x10, 0x41);
+ } while (k != 0x16);
+ if ((k == 0x85) || (k == 0x42))
+ continue;
assignid_map |= m;
}
- tmport = dev->ioport[0] + 0x02;
- outb(0x7f, tmport);
- tmport = dev->ioport[0] + 0x1b;
- outb(0x02, tmport);
+ atp_writeb_io(dev, 0, 0x02, 0x7f);
+ atp_writeb_io(dev, 0, 0x1b, 0x02);
- outb(0, 0x80);
+ udelay(2);
val = 0x0080; /* bsy */
- tmport = dev->ioport[0] + 0x1c;
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
val |= 0x0040; /* sel */
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
val |= 0x0004; /* msg */
- outw(val, tmport);
- inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2); /* 2 deskew delay(45ns*2=90ns) */
val &= 0x007f; /* no bsy */
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
mdelay(128);
val &= 0x00fb; /* after 1ms no msg */
- outw(val, tmport);
-wait_nomsg:
- if ((inb(tmport) & 0x04) != 0) {
- goto wait_nomsg;
- }
- outb(1, 0x80);
+ atp_writew_io(dev, 0, 0x1c, val);
+ while ((atp_readb_io(dev, 0, 0x1c) & 0x04) != 0)
+ ;
+ udelay(2);
udelay(100);
- for (n = 0; n < 0x30000; n++) {
- if ((inb(tmport) & 0x80) != 0) { /* bsy ? */
- goto wait_io;
- }
- }
- goto TCM_SYNC;
-wait_io:
- for (n = 0; n < 0x30000; n++) {
- if ((inb(tmport) & 0x81) == 0x0081) {
- goto wait_io1;
- }
- }
- goto TCM_SYNC;
-wait_io1:
- inb(0x80);
- val |= 0x8003; /* io,cd,db7 */
- outw(val, tmport);
- inb(0x80);
- val &= 0x00bf; /* no sel */
- outw(val, tmport);
- outb(2, 0x80);
-TCM_SYNC:
+ for (n = 0; n < 0x30000; n++)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x80) != 0) /* bsy ? */
+ break;
+ if (n < 0x30000)
+ for (n = 0; n < 0x30000; n++)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x81) == 0x0081) {
+ udelay(2);
+ val |= 0x8003; /* io,cd,db7 */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2);
+ val &= 0x00bf; /* no sel */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2);
+ break;
+ }
+ while (1) {
/*
* The funny division into multiple delays is to accomodate
* arches like ARM where udelay() multiplies its argument by
@@ -1183,55 +1088,48 @@ TCM_SYNC:
*/
mdelay(2);
udelay(48);
- if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */
- outw(0, tmport--);
- outb(0, tmport);
- tmport = dev->ioport[0] + 0x15;
- outb(0, tmport);
- tmport += 0x03;
- outb(0x09, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x80) == 0x00) { /* bsy ? */
+ atp_writew_io(dev, 0, 0x1c, 0);
+ atp_writeb_io(dev, 0, 0x1b, 0);
+ atp_writeb_io(dev, 0, 0x15, 0);
+ atp_writeb_io(dev, 0, 0x18, 0x09);
+ while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0)
cpu_relax();
- tmport -= 0x08;
- inb(tmport);
+ atp_readb_io(dev, 0, 0x17);
return;
}
val &= 0x00ff; /* synchronization */
val |= 0x3f00;
fun_scam(dev, &val);
- outb(3, 0x80);
+ udelay(2);
val &= 0x00ff; /* isolation */
val |= 0x2000;
fun_scam(dev, &val);
- outb(4, 0x80);
+ udelay(2);
i = 8;
j = 0;
-TCM_ID:
- if ((inw(tmport) & 0x2000) == 0) {
- goto TCM_ID;
- }
- outb(5, 0x80);
- val &= 0x00ff; /* get ID_STRING */
- val |= 0x2000;
- k = fun_scam(dev, &val);
- if ((k & 0x03) == 0) {
- goto TCM_5;
- }
- mbuf[j] <<= 0x01;
- mbuf[j] &= 0xfe;
- if ((k & 0x02) != 0) {
- mbuf[j] |= 0x01;
- }
- i--;
- if (i > 0) {
- goto TCM_ID;
+
+ while (1) {
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) == 0)
+ continue;
+ udelay(2);
+ val &= 0x00ff; /* get ID_STRING */
+ val |= 0x2000;
+ k = fun_scam(dev, &val);
+ if ((k & 0x03) == 0)
+ break;
+ mbuf[j] <<= 0x01;
+ mbuf[j] &= 0xfe;
+ if ((k & 0x02) != 0)
+ mbuf[j] |= 0x01;
+ i--;
+ if (i > 0)
+ continue;
+ j++;
+ i = 8;
}
- j++;
- i = 8;
- goto TCM_ID;
-TCM_5: /* isolation complete.. */
+ /* isolation complete.. */
/* mbuf[32]=0;
printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
i = 15;
@@ -1239,33 +1137,33 @@ TCM_5: /* isolation complete.. */
if ((j & 0x20) != 0) { /* bit5=1:ID up to 7 */
i = 7;
}
- if ((j & 0x06) == 0) { /* IDvalid? */
- goto G2Q5;
- }
- k = mbuf[1];
-small_id:
- m = 1;
- m <<= k;
- if ((m & assignid_map) == 0) {
- goto G2Q_QUIN;
- }
- if (k > 0) {
- k--;
- goto small_id;
- }
-G2Q5: /* srch from max acceptable ID# */
- k = i; /* max acceptable ID# */
-G2Q_LP:
- m = 1;
- m <<= k;
- if ((m & assignid_map) == 0) {
- goto G2Q_QUIN;
+ if ((j & 0x06) != 0) { /* IDvalid? */
+ k = mbuf[1];
+ while (1) {
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ break;
+ if (k > 0)
+ k--;
+ else
+ break;
+ }
}
- if (k > 0) {
- k--;
- goto G2Q_LP;
+ if ((m & assignid_map) != 0) { /* srch from max acceptable ID# */
+ k = i; /* max acceptable ID# */
+ while (1) {
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ break;
+ if (k > 0)
+ k--;
+ else
+ break;
+ }
}
-G2Q_QUIN: /* k=binID#, */
+ /* k=binID#, */
assignid_map |= m;
if (k < 8) {
quintet[0] = 0x38; /* 1st dft ID<8 */
@@ -1284,1227 +1182,6 @@ G2Q_QUIN: /* k=binID#, */
val |= m;
fun_scam(dev, &val);
- goto TCM_SYNC;
-
-}
-
-static void is870(struct atp_unit *dev, unsigned int wkport)
-{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n;
- unsigned short int m;
- static unsigned char mbuf[512];
- static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
- static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
- static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e };
- static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
- static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
-
- tmport = wkport + 0x3a;
- outb((unsigned char) (inb(tmport) | 0x10), tmport);
-
- for (i = 0; i < 16; i++) {
- if ((dev->chip_ver != 4) && (i > 7)) {
- break;
- }
- m = 1;
- m = m << i;
- if ((m & dev->active_id[0]) != 0) {
- continue;
- }
- if (i == dev->host_id[0]) {
- printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
- continue;
- }
- tmport = wkport + 0x1b;
- if (dev->chip_ver == 4) {
- outb(0x01, tmport);
- } else {
- outb(0x00, tmport);
- }
- tmport = wkport + 1;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- j = i;
- if ((j & 0x08) != 0) {
- j = (j & 0x07) | 0x40;
- }
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- dev->active_id[0] |= m;
-
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x04;
- outb(0x00, tmport);
-
-phase_cmd:
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- tmport = wkport + 0x10;
- outb(0x41, tmport);
- goto phase_cmd;
- }
-sel_ok:
- tmport = wkport + 3;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- tmport = wkport + 0x1b;
- if (dev->chip_ver == 4)
- outb(0x00, tmport);
-
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- j = 0;
-rd_inq_data:
- k = inb(tmport);
- if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
- goto rd_inq_data;
- }
- if ((k & 0x80) == 0) {
- goto rd_inq_data;
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x16) {
- goto inq_ok;
- }
- tmport = wkport + 0x10;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x16) {
- goto sel_ok;
- }
-inq_ok:
- mbuf[36] = 0;
- printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
- dev->id[0][i].devtype = mbuf[0];
- rmb = mbuf[1];
- n = mbuf[7];
- if (dev->chip_ver != 4) {
- goto not_wide;
- }
- if ((mbuf[7] & 0x60) == 0) {
- goto not_wide;
- }
- if ((dev->global_map[0] & 0x20) == 0) {
- goto not_wide;
- }
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 3;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_wide:
- j = 0;
- tmport = wkport + 0x14;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto try_wide;
- }
- continue;
-widep_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_in:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-widep_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto widep_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto widep_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto widep_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto not_wide;
- }
- if (mbuf[1] != 0x02) {
- goto not_wide;
- }
- if (mbuf[2] != 0x03) {
- goto not_wide;
- }
- if (mbuf[3] != 0x01) {
- goto not_wide;
- }
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
-not_wide:
- if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
- goto set_sync;
- }
- continue;
-set_sync:
- tmport = wkport + 0x1b;
- j = 0;
- if ((m & dev->wide_id[0]) != 0) {
- j |= 0x01;
- }
- outb(j, tmport);
- tmport = wkport + 3;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_sync:
- j = 0;
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- if ((m & dev->wide_id[0]) != 0) {
- outb(synw[j++], tmport);
- } else {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synu[j++], tmport);
- } else {
- outb(synn[j++], tmport);
- }
- }
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto try_sync;
- }
- continue;
-phase_outs:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_ins:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-phase_ins1:
- j = inb(tmport);
- if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto phase_ins1;
- }
- if ((j & 0x80) == 0x00) {
- goto phase_ins1;
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_cmds:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
-tar_dcons:
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- continue;
- }
- if (mbuf[0] != 0x01) {
- continue;
- }
- if (mbuf[1] != 0x03) {
- continue;
- }
- if (mbuf[4] == 0x00) {
- continue;
- }
- if (mbuf[3] > 0x64) {
- continue;
- }
- if (mbuf[4] > 0x0c) {
- mbuf[4] = 0x0c;
- }
- dev->id[0][i].devsp = mbuf[4];
- if ((mbuf[3] < 0x0d) && (rmb == 0)) {
- j = 0xa0;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x1a) {
- j = 0x20;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x33) {
- j = 0x40;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x4c) {
- j = 0x50;
- goto set_syn_ok;
- }
- j = 0x60;
-set_syn_ok:
- dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
- }
- tmport = wkport + 0x3a;
- outb((unsigned char) (inb(tmport) & 0xef), tmport);
-}
-
-static void is880(struct atp_unit *dev, unsigned int wkport)
-{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n, lvdmode;
- unsigned short int m;
- static unsigned char mbuf[512];
- static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
- static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
- static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
- static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
- static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
- static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
-
- lvdmode = inb(wkport + 0x3f) & 0x40;
-
- for (i = 0; i < 16; i++) {
- m = 1;
- m = m << i;
- if ((m & dev->active_id[0]) != 0) {
- continue;
- }
- if (i == dev->host_id[0]) {
- printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
- continue;
- }
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x41;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- j = i;
- if ((j & 0x08) != 0) {
- j = (j & 0x07) | 0x40;
- }
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- dev->active_id[0] |= m;
-
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
-
-phase_cmd:
- tmport = wkport + 0x58;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- tmport = wkport + 0x50;
- outb(0x41, tmport);
- goto phase_cmd;
- }
-sel_ok:
- tmport = wkport + 0x43;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- tmport = wkport + 0x5b;
- outb(0x00, tmport);
- tmport = wkport + 0x58;
- outb(0x08, tmport);
- tmport += 0x07;
- j = 0;
-rd_inq_data:
- k = inb(tmport);
- if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
- goto rd_inq_data;
- }
- if ((k & 0x80) == 0) {
- goto rd_inq_data;
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x16) {
- goto inq_ok;
- }
- tmport = wkport + 0x50;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x16)
- goto sel_ok;
-
-inq_ok:
- mbuf[36] = 0;
- printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
- dev->id[0][i].devtype = mbuf[0];
- rmb = mbuf[1];
- n = mbuf[7];
- if ((mbuf[7] & 0x60) == 0) {
- goto not_wide;
- }
- if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) {
- goto not_wide;
- }
- if (lvdmode == 0) {
- goto chg_wide;
- }
- if (dev->sp[0][i] != 0x04) // force u2
- {
- goto chg_wide;
- }
-
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
-
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_u3:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(u3[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto try_u3;
- }
- continue;
-u3p_out:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto u3p_out;
- }
- continue;
-u3p_in:
- tmport = wkport + 0x54;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-u3p_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto u3p_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto u3p_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto u3p_out;
- }
- continue;
-u3p_cmd:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto u3p_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto chg_wide;
- }
- if (mbuf[1] != 0x06) {
- goto chg_wide;
- }
- if (mbuf[2] != 0x04) {
- goto chg_wide;
- }
- if (mbuf[3] == 0x09) {
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
- dev->id[0][i].devsp = 0xce;
- continue;
- }
-chg_wide:
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_wide:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto try_wide;
- }
- continue;
-widep_out:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_in:
- tmport = wkport + 0x54;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-widep_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto widep_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto widep_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_cmd:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto widep_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto not_wide;
- }
- if (mbuf[1] != 0x02) {
- goto not_wide;
- }
- if (mbuf[2] != 0x03) {
- goto not_wide;
- }
- if (mbuf[3] != 0x01) {
- goto not_wide;
- }
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
-not_wide:
- if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
- m = 1;
- m = m << i;
- if ((dev->async[0] & m) != 0) {
- goto set_sync;
- }
- }
- continue;
-set_sync:
- if (dev->sp[0][i] == 0x02) {
- synu[4] = 0x0c;
- synuw[4] = 0x0c;
- } else {
- if (dev->sp[0][i] >= 0x03) {
- synu[4] = 0x0a;
- synuw[4] = 0x0a;
- }
- }
- tmport = wkport + 0x5b;
- j = 0;
- if ((m & dev->wide_id[0]) != 0) {
- j |= 0x01;
- }
- outb(j, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
- continue;
- }
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_sync:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- if ((m & dev->wide_id[0]) != 0) {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synuw[j++], tmport);
- } else {
- outb(synw[j++], tmport);
- }
- } else {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synu[j++], tmport);
- } else {
- outb(synn[j++], tmport);
- }
- }
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto try_sync;
- }
- continue;
-phase_outs:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_ins:
- tmport = wkport + 0x54;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-phase_ins1:
- j = inb(tmport);
- if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto phase_ins1;
- }
- if ((j & 0x80) == 0x00) {
- goto phase_ins1;
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_cmds:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
-tar_dcons:
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- continue;
- }
- if (mbuf[0] != 0x01) {
- continue;
- }
- if (mbuf[1] != 0x03) {
- continue;
- }
- if (mbuf[4] == 0x00) {
- continue;
- }
- if (mbuf[3] > 0x64) {
- continue;
- }
- if (mbuf[4] > 0x0e) {
- mbuf[4] = 0x0e;
- }
- dev->id[0][i].devsp = mbuf[4];
- if (mbuf[3] < 0x0c) {
- j = 0xb0;
- goto set_syn_ok;
- }
- if ((mbuf[3] < 0x0d) && (rmb == 0)) {
- j = 0xa0;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x1a) {
- j = 0x20;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x33) {
- j = 0x40;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x4c) {
- j = 0x50;
- goto set_syn_ok;
- }
- j = 0x60;
-set_syn_ok:
- dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
}
}
@@ -2560,491 +1237,345 @@ static int atp870u_init_tables(struct Scsi_Host *host)
return 0;
}
-/* return non-zero on detection */
-static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void atp_set_host_id(struct atp_unit *atp, u8 c, u8 host_id)
{
- unsigned char k, m, c;
- unsigned long flags;
- unsigned int base_io, tmport, error,n;
- unsigned char host_id;
- struct Scsi_Host *shpnt = NULL;
- struct atp_unit *atpdev, *p;
- unsigned char setupdata[2][16];
- int count = 0;
+ atp_writeb_io(atp, c, 0, host_id | 0x08);
+ atp_writeb_io(atp, c, 0x18, 0);
+ while ((atp_readb_io(atp, c, 0x1f) & 0x80) == 0)
+ mdelay(1);
+ atp_readb_io(atp, c, 0x17);
+ atp_writeb_io(atp, c, 1, 8);
+ atp_writeb_io(atp, c, 2, 0x7f);
+ atp_writeb_io(atp, c, 0x11, 0x20);
+}
- atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL);
- if (!atpdev)
- return -ENOMEM;
+static void atp870_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, host_id;
+ u8 scam_on;
+ bool wide_chip =
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7610 &&
+ pdev->revision == 4) ||
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612UW) ||
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612SUW);
+
+ pci_read_config_byte(pdev, 0x49, &host_id);
+
+ dev_info(&pdev->dev, "ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+
+ atpdev->ioport[0] = shpnt->io_port;
+ atpdev->pciport[0] = shpnt->io_port + 0x20;
+ host_id &= 0x07;
+ atpdev->host_id[0] = host_id;
+ scam_on = atp_readb_pci(atpdev, 0, 2);
+ atpdev->global_map[0] = atp_readb_base(atpdev, 0x2d);
+ atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x2e);
+
+ if (atpdev->ultra_map[0] == 0) {
+ scam_on = 0x00;
+ atpdev->global_map[0] = 0x20;
+ atpdev->ultra_map[0] = 0xffff;
+ }
- if (pci_enable_device(pdev))
- goto err_eio;
+ if (pdev->revision > 0x07) /* check if atp876 chip */
+ atp_writeb_base(atpdev, 0x3e, 0x00); /* enable terminator */
+
+ k = (atp_readb_base(atpdev, 0x3a) & 0xf3) | 0x10;
+ atp_writeb_base(atpdev, 0x3a, k);
+ atp_writeb_base(atpdev, 0x3a, k & 0xdf);
+ mdelay(32);
+ atp_writeb_base(atpdev, 0x3a, k);
+ mdelay(32);
+ atp_set_host_id(atpdev, 0, host_id);
+
+ tscam(shpnt, wide_chip, scam_on);
+ atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) | 0x10);
+ atp_is(atpdev, 0, wide_chip, 0);
+ atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) & 0xef);
+ atp_writeb_base(atpdev, 0x3b, atp_readb_base(atpdev, 0x3b) | 0x20);
+ shpnt->max_id = wide_chip ? 16 : 8;
+ shpnt->this_id = host_id;
+}
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
- } else {
- printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
- goto err_eio;
- }
+static void atp880_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, m, host_id;
+ unsigned int n;
- /*
- * It's probably easier to weed out some revisions like
- * this than via the PCI device table
- */
- if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
- atpdev->chip_ver = pdev->revision;
- if (atpdev->chip_ver < 2)
- goto err_eio;
- }
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
- switch (ent->device) {
- case PCI_DEVICE_ID_ARTOP_AEC7612UW:
- case PCI_DEVICE_ID_ARTOP_AEC7612SUW:
- case ATP880_DEVID1:
- case ATP880_DEVID2:
- case ATP885_DEVID:
- atpdev->chip_ver = 0x04;
- default:
- break;
- }
- base_io = pci_resource_start(pdev, 0);
- base_io &= 0xfffffff8;
-
- if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
- atpdev->chip_ver = pdev->revision;
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
-
- host_id = inb(base_io + 0x39);
- host_id >>= 0x04;
-
- printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
- " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
- atpdev->ioport[0] = base_io + 0x40;
- atpdev->pciport[0] = base_io + 0x28;
- atpdev->dev_id = ent->device;
- atpdev->host_id[0] = host_id;
-
- tmport = base_io + 0x22;
- atpdev->scam_on = inb(tmport);
- tmport += 0x13;
- atpdev->global_map[0] = inb(tmport);
- tmport += 0x07;
- atpdev->ultra_map[0] = inw(tmport);
-
- n = 0x3f09;
-next_fblk_880:
- if (n >= 0x4000)
- goto flash_ok_880;
+ atpdev->ioport[0] = shpnt->io_port + 0x40;
+ atpdev->pciport[0] = shpnt->io_port + 0x28;
+
+ host_id = atp_readb_base(atpdev, 0x39) >> 4;
+ dev_info(&pdev->dev, "ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+ atpdev->host_id[0] = host_id;
+
+ atpdev->global_map[0] = atp_readb_base(atpdev, 0x35);
+ atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x3c);
+
+ n = 0x3f09;
+ while (n < 0x4000) {
m = 0;
- outw(n, base_io + 0x34);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- if (inb(base_io + 0x30) == 0xff)
- goto flash_ok_880;
-
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ if (atp_readb_base(atpdev, 0x30) == 0xff)
+ break;
+
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
n += 0x0018;
- goto next_fblk_880;
-flash_ok_880:
- outw(0, base_io + 0x34);
- atpdev->ultra_map[0] = 0;
- atpdev->async[0] = 0;
+ }
+ atp_writew_base(atpdev, 0x34, 0);
+ atpdev->ultra_map[0] = 0;
+ atpdev->async[0] = 0;
+ for (k = 0; k < 16; k++) {
+ n = 1 << k;
+ if (atpdev->sp[0][k] > 1)
+ atpdev->ultra_map[0] |= n;
+ else
+ if (atpdev->sp[0][k] == 0)
+ atpdev->async[0] |= n;
+ }
+ atpdev->async[0] = ~(atpdev->async[0]);
+ atp_writeb_base(atpdev, 0x35, atpdev->global_map[0]);
+
+ k = atp_readb_base(atpdev, 0x38) & 0x80;
+ atp_writeb_base(atpdev, 0x38, k);
+ atp_writeb_base(atpdev, 0x3b, 0x20);
+ mdelay(32);
+ atp_writeb_base(atpdev, 0x3b, 0);
+ mdelay(32);
+ atp_readb_io(atpdev, 0, 0x1b);
+ atp_readb_io(atpdev, 0, 0x17);
+
+ atp_set_host_id(atpdev, 0, host_id);
+
+ tscam(shpnt, true, atp_readb_base(atpdev, 0x22));
+ atp_is(atpdev, 0, true, atp_readb_base(atpdev, 0x3f) & 0x40);
+ atp_writeb_base(atpdev, 0x38, 0xb0);
+ shpnt->max_id = 16;
+ shpnt->this_id = host_id;
+}
+
+static void atp885_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, m, c;
+ unsigned int n;
+ unsigned char setupdata[2][16];
+
+ dev_info(&pdev->dev, "ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+
+ atpdev->ioport[0] = shpnt->io_port + 0x80;
+ atpdev->ioport[1] = shpnt->io_port + 0xc0;
+ atpdev->pciport[0] = shpnt->io_port + 0x40;
+ atpdev->pciport[1] = shpnt->io_port + 0x50;
+
+ c = atp_readb_base(atpdev, 0x29);
+ atp_writeb_base(atpdev, 0x29, c | 0x04);
+
+ n = 0x1f80;
+ while (n < 0x2000) {
+ atp_writew_base(atpdev, 0x3c, n);
+ if (atp_readl_base(atpdev, 0x38) == 0xffffffff)
+ break;
+ for (m = 0; m < 2; m++) {
+ atpdev->global_map[m] = 0;
+ for (k = 0; k < 4; k++) {
+ atp_writew_base(atpdev, 0x3c, n++);
+ ((unsigned long *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38);
+ }
+ for (k = 0; k < 4; k++) {
+ atp_writew_base(atpdev, 0x3c, n++);
+ ((unsigned long *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38);
+ }
+ n += 8;
+ }
+ }
+ c = atp_readb_base(atpdev, 0x29);
+ atp_writeb_base(atpdev, 0x29, c & 0xfb);
+ for (c = 0; c < 2; c++) {
+ atpdev->ultra_map[c] = 0;
+ atpdev->async[c] = 0;
for (k = 0; k < 16; k++) {
- n = 1;
- n = n << k;
- if (atpdev->sp[0][k] > 1) {
- atpdev->ultra_map[0] |= n;
- } else {
- if (atpdev->sp[0][k] == 0)
- atpdev->async[0] |= n;
- }
- }
- atpdev->async[0] = ~(atpdev->async[0]);
- outb(atpdev->global_map[0], base_io + 0x35);
-
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
-
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(*atpdev));
- if (atp870u_init_tables(shpnt) < 0) {
- printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
- goto unregister;
- }
-
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
- goto free_tables;
- }
-
- spin_lock_irqsave(shpnt->host_lock, flags);
- tmport = base_io + 0x38;
- k = inb(tmport) & 0x80;
- outb(k, tmport);
- tmport += 0x03;
- outb(0x20, tmport);
- mdelay(32);
- outb(0, tmport);
- mdelay(32);
- tmport = base_io + 0x5b;
- inb(tmport);
- tmport -= 0x04;
- inb(tmport);
- tmport = base_io + 0x40;
- outb((host_id | 0x08), tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
- mdelay(1);
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0x41;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x51;
- outb(0x20, tmport);
-
- tscam(shpnt);
- is880(p, base_io);
- tmport = base_io + 0x38;
- outb(0xb0, tmport);
- shpnt->max_id = 16;
- shpnt->this_id = host_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
- } else if (ent->device == ATP885_DEVID) {
- printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n"
- , base_io, pdev->irq);
-
- atpdev->pdev = pdev;
- atpdev->dev_id = ent->device;
- atpdev->baseport = base_io;
- atpdev->ioport[0] = base_io + 0x80;
- atpdev->ioport[1] = base_io + 0xc0;
- atpdev->pciport[0] = base_io + 0x40;
- atpdev->pciport[1] = base_io + 0x50;
-
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
-
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(struct atp_unit));
- if (atp870u_init_tables(shpnt) < 0)
- goto unregister;
-
-#ifdef ED_DBGP
- printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
-#endif
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
- goto free_tables;
+ n = 1 << k;
+ if (atpdev->sp[c][k] > 1)
+ atpdev->ultra_map[c] |= n;
+ else
+ if (atpdev->sp[c][k] == 0)
+ atpdev->async[c] |= n;
+ }
+ atpdev->async[c] = ~(atpdev->async[c]);
+
+ if (atpdev->global_map[c] == 0) {
+ k = setupdata[c][1];
+ if ((k & 0x40) != 0)
+ atpdev->global_map[c] |= 0x20;
+ k &= 0x07;
+ atpdev->global_map[c] |= k;
+ if ((setupdata[c][2] & 0x04) != 0)
+ atpdev->global_map[c] |= 0x08;
+ atpdev->host_id[c] = setupdata[c][0] & 0x07;
}
-
- spin_lock_irqsave(shpnt->host_lock, flags);
-
- c=inb(base_io + 0x29);
- outb((c | 0x04),base_io + 0x29);
-
- n=0x1f80;
-next_fblk_885:
- if (n >= 0x2000) {
- goto flash_ok_885;
- }
- outw(n,base_io + 0x3c);
- if (inl(base_io + 0x38) == 0xffffffff) {
- goto flash_ok_885;
- }
- for (m=0; m < 2; m++) {
- p->global_map[m]= 0;
- for (k=0; k < 4; k++) {
- outw(n++,base_io + 0x3c);
- ((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38);
- }
- for (k=0; k < 4; k++) {
- outw(n++,base_io + 0x3c);
- ((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38);
- }
- n += 8;
- }
- goto next_fblk_885;
-flash_ok_885:
-#ifdef ED_DBGP
- printk( "Flash Read OK\n");
-#endif
- c=inb(base_io + 0x29);
- outb((c & 0xfb),base_io + 0x29);
- for (c=0;c < 2;c++) {
- p->ultra_map[c]=0;
- p->async[c] = 0;
- for (k=0; k < 16; k++) {
- n=1;
- n = n << k;
- if (p->sp[c][k] > 1) {
- p->ultra_map[c] |= n;
- } else {
- if (p->sp[c][k] == 0) {
- p->async[c] |= n;
- }
- }
- }
- p->async[c] = ~(p->async[c]);
-
- if (p->global_map[c] == 0) {
- k=setupdata[c][1];
- if ((k & 0x40) != 0)
- p->global_map[c] |= 0x20;
- k &= 0x07;
- p->global_map[c] |= k;
- if ((setupdata[c][2] & 0x04) != 0)
- p->global_map[c] |= 0x08;
- p->host_id[c] = setupdata[c][0] & 0x07;
- }
- }
-
- k = inb(base_io + 0x28) & 0x8f;
- k |= 0x10;
- outb(k, base_io + 0x28);
- outb(0x80, base_io + 0x41);
- outb(0x80, base_io + 0x51);
- mdelay(100);
- outb(0, base_io + 0x41);
- outb(0, base_io + 0x51);
- mdelay(1000);
- inb(base_io + 0x9b);
- inb(base_io + 0x97);
- inb(base_io + 0xdb);
- inb(base_io + 0xd7);
- tmport = base_io + 0x80;
- k=p->host_id[0];
- if (k > 7)
- k = (k & 0x07) | 0x40;
- k |= 0x08;
- outb(k, tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0)
- cpu_relax();
-
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0x81;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x91;
- outb(0x20, tmport);
-
- tmport = base_io + 0xc0;
- k=p->host_id[1];
- if (k > 7)
- k = (k & 0x07) | 0x40;
- k |= 0x08;
- outb(k, tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0)
- cpu_relax();
+ }
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0xc1;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0xd1;
- outb(0x20, tmport);
-
- tscam_885();
- printk(KERN_INFO " Scanning Channel A SCSI Device ...\n");
- is885(p, base_io + 0x80, 0);
- printk(KERN_INFO " Scanning Channel B SCSI Device ...\n");
- is885(p, base_io + 0xc0, 1);
-
- k = inb(base_io + 0x28) & 0xcf;
- k |= 0xc0;
- outb(k, base_io + 0x28);
- k = inb(base_io + 0x1f) | 0x80;
- outb(k, base_io + 0x1f);
- k = inb(base_io + 0x29) | 0x01;
- outb(k, base_io + 0x29);
-#ifdef ED_DBGP
- //printk("atp885: atp_host[0] 0x%p\n", atp_host[0]);
-#endif
- shpnt->max_id = 16;
- shpnt->max_lun = (p->global_map[0] & 0x07) + 1;
- shpnt->max_channel = 1;
- shpnt->this_id = p->host_id[0];
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0xff; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
-
- } else {
- error = pci_read_config_byte(pdev, 0x49, &host_id);
+ k = atp_readb_base(atpdev, 0x28) & 0x8f;
+ k |= 0x10;
+ atp_writeb_base(atpdev, 0x28, k);
+ atp_writeb_pci(atpdev, 0, 1, 0x80);
+ atp_writeb_pci(atpdev, 1, 1, 0x80);
+ mdelay(100);
+ atp_writeb_pci(atpdev, 0, 1, 0);
+ atp_writeb_pci(atpdev, 1, 1, 0);
+ mdelay(1000);
+ atp_readb_io(atpdev, 0, 0x1b);
+ atp_readb_io(atpdev, 0, 0x17);
+ atp_readb_io(atpdev, 1, 0x1b);
+ atp_readb_io(atpdev, 1, 0x17);
+
+ k = atpdev->host_id[0];
+ if (k > 7)
+ k = (k & 0x07) | 0x40;
+ atp_set_host_id(atpdev, 0, k);
+
+ k = atpdev->host_id[1];
+ if (k > 7)
+ k = (k & 0x07) | 0x40;
+ atp_set_host_id(atpdev, 1, k);
+
+ mdelay(600); /* this delay used to be called tscam_885() */
+ dev_info(&pdev->dev, "Scanning Channel A SCSI Device ...\n");
+ atp_is(atpdev, 0, true, atp_readb_io(atpdev, 0, 0x1b) >> 7);
+ atp_writeb_io(atpdev, 0, 0x16, 0x80);
+ dev_info(&pdev->dev, "Scanning Channel B SCSI Device ...\n");
+ atp_is(atpdev, 1, true, atp_readb_io(atpdev, 1, 0x1b) >> 7);
+ atp_writeb_io(atpdev, 1, 0x16, 0x80);
+ k = atp_readb_base(atpdev, 0x28) & 0xcf;
+ k |= 0xc0;
+ atp_writeb_base(atpdev, 0x28, k);
+ k = atp_readb_base(atpdev, 0x1f) | 0x80;
+ atp_writeb_base(atpdev, 0x1f, k);
+ k = atp_readb_base(atpdev, 0x29) | 0x01;
+ atp_writeb_base(atpdev, 0x29, k);
+ shpnt->max_id = 16;
+ shpnt->max_lun = (atpdev->global_map[0] & 0x07) + 1;
+ shpnt->max_channel = 1;
+ shpnt->this_id = atpdev->host_id[0];
+}
- printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
- "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
+/* return non-zero on detection */
+static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct Scsi_Host *shpnt = NULL;
+ struct atp_unit *atpdev;
+ int err;
- atpdev->ioport[0] = base_io;
- atpdev->pciport[0] = base_io + 0x20;
- atpdev->dev_id = ent->device;
- host_id &= 0x07;
- atpdev->host_id[0] = host_id;
- tmport = base_io + 0x22;
- atpdev->scam_on = inb(tmport);
- tmport += 0x0b;
- atpdev->global_map[0] = inb(tmport++);
- atpdev->ultra_map[0] = inw(tmport);
+ if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610 && pdev->revision < 2) {
+ dev_err(&pdev->dev, "ATP850S chips (AEC6710L/F cards) are not supported.\n");
+ return -ENODEV;
+ }
- if (atpdev->ultra_map[0] == 0) {
- atpdev->scam_on = 0x00;
- atpdev->global_map[0] = 0x20;
- atpdev->ultra_map[0] = 0xffff;
- }
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
+ err = -EIO;
+ goto disable_device;
+ }
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(*atpdev));
- if (atp870u_init_tables(shpnt) < 0)
- goto unregister;
-
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
- goto free_tables;
- }
-
- spin_lock_irqsave(shpnt->host_lock, flags);
- if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
- tmport = base_io + 0x3e;
- outb(0x00, tmport);
- }
-
- tmport = base_io + 0x3a;
- k = (inb(tmport) & 0xf3) | 0x10;
- outb(k, tmport);
- outb((k & 0xdf), tmport);
- mdelay(32);
- outb(k, tmport);
- mdelay(32);
- tmport = base_io;
- outb((host_id | 0x08), tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
- mdelay(1);
-
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 1;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x11;
- outb(0x20, tmport);
-
- tscam(shpnt);
- is870(p, base_io);
- tmport = base_io + 0x3a;
- outb((inb(tmport) & 0xef), tmport);
- tmport++;
- outb((inb(tmport) | 0x20), tmport);
- if (atpdev->chip_ver == 4)
- shpnt->max_id = 16;
- else
- shpnt->max_id = 8;
- shpnt->this_id = host_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
- }
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- if(ent->device==ATP885_DEVID) {
- if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
- if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- } else {
- if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- }
- count++;
- if (scsi_add_host(shpnt, &pdev->dev))
- goto scsi_add_fail;
- scsi_scan_host(shpnt);
-#ifdef ED_DBGP
- printk("atp870u_prob : exit\n");
-#endif
- return 0;
+ err = pci_request_regions(pdev, "atp870u");
+ if (err)
+ goto disable_device;
+ pci_set_master(pdev);
+
+ err = -ENOMEM;
+ shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+ if (!shpnt)
+ goto release_region;
+
+ atpdev = shost_priv(shpnt);
+
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
+ pci_set_drvdata(pdev, atpdev);
+
+ shpnt->io_port = pci_resource_start(pdev, 0);
+ shpnt->io_port &= 0xfffffff8;
+ shpnt->n_io_port = pci_resource_len(pdev, 0);
+ atpdev->baseport = shpnt->io_port;
+ shpnt->unique_id = shpnt->io_port;
+ shpnt->irq = pdev->irq;
+
+ err = atp870u_init_tables(shpnt);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate tables for Acard controller\n");
+ goto unregister;
+ }
-scsi_add_fail:
- printk("atp870u_prob:scsi_add_fail\n");
- if(ent->device==ATP885_DEVID) {
- release_region(base_io, 0xff);
- } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
- release_region(base_io, 0x60);
- } else {
- release_region(base_io, 0x40);
+ if (is880(atpdev))
+ atp880_init(shpnt);
+ else if (is885(atpdev))
+ atp885_init(shpnt);
+ else
+ atp870_init(shpnt);
+
+ err = request_irq(shpnt->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate IRQ %d.\n", shpnt->irq);
+ goto free_tables;
}
-request_io_fail:
- printk("atp870u_prob:request_io_fail\n");
- free_irq(pdev->irq, shpnt);
+
+ err = scsi_add_host(shpnt, &pdev->dev);
+ if (err)
+ goto scsi_add_fail;
+ scsi_scan_host(shpnt);
+
+ return 0;
+
+scsi_add_fail:
+ free_irq(shpnt->irq, shpnt);
free_tables:
- printk("atp870u_prob:free_table\n");
atp870u_free_tables(shpnt);
unregister:
- printk("atp870u_prob:unregister\n");
scsi_host_put(shpnt);
- return -1;
-err_eio:
- kfree(atpdev);
- return -EIO;
-err_nomem:
- kfree(atpdev);
- return -ENOMEM;
+release_region:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+fail:
+ return err;
}
/* The abort command does not leave the device in a clean state where
@@ -3055,7 +1586,6 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
{
unsigned char j, k, c;
struct scsi_cmnd *workrequ;
- unsigned int tmport;
struct atp_unit *dev;
struct Scsi_Host *host;
host = SCpnt->device->host;
@@ -3065,18 +1595,13 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
printk(" atp870u: abort Channel = %x \n", c);
printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]);
printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]);
- tmport = dev->ioport[c];
for (j = 0; j < 0x18; j++) {
- printk(" r%2x=%2x", j, inb(tmport++));
+ printk(" r%2x=%2x", j, atp_readb_io(dev, c, j));
}
- tmport += 0x04;
- printk(" r1c=%2x", inb(tmport));
- tmport += 0x03;
- printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]);
- tmport= dev->pciport[c];
- printk(" d00=%2x", inb(tmport));
- tmport += 0x02;
- printk(" d02=%2x", inb(tmport));
+ printk(" r1c=%2x", atp_readb_io(dev, c, 0x1c));
+ printk(" r1f=%2x in_snd=%2x ", atp_readb_io(dev, c, 0x1f), dev->in_snd[c]);
+ printk(" d00=%2x", atp_readb_pci(dev, c, 0x00));
+ printk(" d02=%2x", atp_readb_pci(dev, c, 0x02));
for(j=0;j<16;j++) {
if (dev->id[c][j].curr_req != NULL) {
workrequ = dev->id[c][j].curr_req;
@@ -3136,12 +1661,10 @@ static void atp870u_remove (struct pci_dev *pdev)
scsi_remove_host(pshost);
- printk(KERN_INFO "free_irq : %d\n",pshost->irq);
free_irq(pshost->irq, pshost);
- release_region(pshost->io_port, pshost->n_io_port);
- printk(KERN_INFO "atp870u_free_tables : %p\n",pshost);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
atp870u_free_tables(pshost);
- printk(KERN_INFO "scsi_host_put : %p\n",pshost);
scsi_host_put(pshost);
}
MODULE_LICENSE("GPL");
@@ -3185,52 +1708,26 @@ static struct pci_driver atp870u_driver = {
.remove = atp870u_remove,
};
-static int __init atp870u_init(void)
-{
-#ifdef ED_DBGP
- printk("atp870u_init: Entry\n");
-#endif
- return pci_register_driver(&atp870u_driver);
-}
-
-static void __exit atp870u_exit(void)
-{
-#ifdef ED_DBGP
- printk("atp870u_exit: Entry\n");
-#endif
- pci_unregister_driver(&atp870u_driver);
-}
-
-static void tscam_885(void)
-{
- unsigned char i;
-
- for (i = 0; i < 0x2; i++) {
- mdelay(300);
- }
- return;
-}
-
-
+module_pci_driver(atp870u_driver);
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode)
{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n, lvdmode;
+ unsigned char i, j, k, rmb, n;
unsigned short int m;
static unsigned char mbuf[512];
- static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6};
- static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
- static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
- unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
- static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
- unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
- static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0};
- static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
-
- lvdmode=inb(wkport + 0x1b) >> 7;
+ static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
+ static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
+ static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+ unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+ static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+ static unsigned char synw_870[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
+ unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+ static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
+ static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
for (i = 0; i < 16; i++) {
+ if (!wide_chip && (i > 7))
+ break;
m = 1;
m = m << i;
if ((m & dev->active_id[c]) != 0) {
@@ -3240,192 +1737,172 @@ static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[c]);
continue;
}
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x01;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
-
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
+ atp_writeb_io(dev, c, 0x1b, wide_chip ? 0x01 : 0x00);
+ atp_writeb_io(dev, c, 1, 0x08);
+ atp_writeb_io(dev, c, 2, 0x7f);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
j = i;
if ((j & 0x08) != 0) {
j = (j & 0x07) | 0x40;
}
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
- while ((inb(tmport) & 0x80) == 0x00)
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
dev->active_id[c] |= m;
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ if (is885(dev) || is880(dev))
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ else /* result of is870() merge - is this a bug? */
+ atp_writeb_io(dev, c, 0x04, 0x00);
phase_cmd:
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
- tmport = wkport + 0x10;
- outb(0x41, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x41);
goto phase_cmd;
}
sel_ok:
- tmport = wkport + 0x03;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 3, inqd[0]);
+ atp_writeb_io(dev, c, 4, inqd[1]);
+ atp_writeb_io(dev, c, 5, inqd[2]);
+ atp_writeb_io(dev, c, 6, inqd[3]);
+ atp_writeb_io(dev, c, 7, inqd[4]);
+ atp_writeb_io(dev, c, 8, inqd[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, inqd[6]);
+ atp_writeb_io(dev, c, 0x14, inqd[7]);
+ atp_writeb_io(dev, c, 0x18, inqd[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
- tmport = wkport + 0x1b;
- outb(0x00, tmport);
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
+
+ if (wide_chip)
+ atp_writeb_io(dev, c, 0x1b, 0x00);
+
+ atp_writeb_io(dev, c, 0x18, 0x08);
j = 0;
rd_inq_data:
- k = inb(tmport);
+ k = atp_readb_io(dev, c, 0x1f);
if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
+ mbuf[j++] = atp_readb_io(dev, c, 0x19);
goto rd_inq_data;
}
if ((k & 0x80) == 0) {
goto rd_inq_data;
}
- tmport -= 0x08;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x16) {
goto inq_ok;
}
- tmport = wkport + 0x10;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x10, 0x46);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, 0);
+ atp_writeb_io(dev, c, 0x14, 0);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if (inb(tmport) != 0x16) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x16)
goto sel_ok;
- }
+
inq_ok:
mbuf[36] = 0;
- printk( KERN_INFO" ID: %2d %s\n", i, &mbuf[8]);
+ printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
dev->id[c][i].devtype = mbuf[0];
rmb = mbuf[1];
n = mbuf[7];
+ if (!wide_chip)
+ goto not_wide;
if ((mbuf[7] & 0x60) == 0) {
goto not_wide;
}
- if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) {
- goto not_wide;
+ if (is885(dev) || is880(dev)) {
+ if ((i < 8) && ((dev->global_map[c] & 0x20) == 0))
+ goto not_wide;
+ } else { /* result of is870() merge - is this a bug? */
+ if ((dev->global_map[c] & 0x20) == 0)
+ goto not_wide;
}
if (lvdmode == 0) {
- goto chg_wide;
- }
- if (dev->sp[c][i] != 0x04) { // force u2
- goto chg_wide;
- }
-
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ goto chg_wide;
+ }
+ if (dev->sp[c][i] != 0x04) // force u2
+ {
+ goto chg_wide;
+ }
+
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_u3:
j = 0;
- tmport = wkport + 0x14;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(u3[j++], tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x14, 0x09);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, u3[j++]);
cpu_relax();
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3437,19 +1914,13 @@ try_u3:
}
continue;
u3p_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, 0);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3461,25 +1932,19 @@ u3p_out:
}
continue;
u3p_in:
- tmport = wkport + 0x14;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x14, 0x09);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
u3p_in1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto u3p_in1;
}
if ((j & 0x80) == 0x00) {
goto u3p_in1;
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3491,16 +1956,13 @@ u3p_in1:
}
continue;
u3p_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport -= 0x08;
- j = inb(tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
if (j == 0x4e) {
goto u3p_out;
@@ -3527,54 +1989,44 @@ u3p_cmd:
continue;
}
chg_wide:
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_wide:
j = 0;
- tmport = wkport + 0x14;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x14, 0x05);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, wide[j++]);
cpu_relax();
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3586,19 +2038,13 @@ try_wide:
}
continue;
widep_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, 0);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3610,25 +2056,19 @@ widep_out:
}
continue;
widep_in:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x14, 0xff);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
widep_in1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto widep_in1;
}
if ((j & 0x80) == 0x00) {
goto widep_in1;
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3640,17 +2080,14 @@ widep_in1:
}
continue;
widep_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
if (j == 0x4e) {
goto widep_out;
@@ -3673,88 +2110,81 @@ widep_cmd:
m = m << i;
dev->wide_id[c] |= m;
not_wide:
- if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) ||
- ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+ if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) || ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
m = 1;
m = m << i;
if ((dev->async[c] & m) != 0) {
- goto set_sync;
+ goto set_sync;
}
}
continue;
set_sync:
- if (dev->sp[c][i] == 0x02) {
- synu[4]=0x0c;
- synuw[4]=0x0c;
+ if ((!is885(dev) && !is880(dev)) || (dev->sp[c][i] == 0x02)) {
+ synu[4] = 0x0c;
+ synuw[4] = 0x0c;
} else {
- if (dev->sp[c][i] >= 0x03) {
- synu[4]=0x0a;
- synuw[4]=0x0a;
- }
+ if (dev->sp[c][i] >= 0x03) {
+ synu[4] = 0x0a;
+ synuw[4] = 0x0a;
+ }
}
- tmport = wkport + 0x1b;
j = 0;
if ((m & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x1b, j);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_sync:
j = 0;
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
+ atp_writeb_io(dev, c, 0x14, 0x06);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0) {
if ((m & dev->wide_id[c]) != 0) {
- if ((m & dev->ultra_map[c]) != 0) {
- outb(synuw[j++], tmport);
- } else {
- outb(synw[j++], tmport);
- }
+ if (is885(dev) || is880(dev)) {
+ if ((m & dev->ultra_map[c]) != 0) {
+ atp_writeb_io(dev, c, 0x19, synuw[j++]);
+ } else {
+ atp_writeb_io(dev, c, 0x19, synw[j++]);
+ }
+ } else
+ atp_writeb_io(dev, c, 0x19, synw_870[j++]);
} else {
if ((m & dev->ultra_map[c]) != 0) {
- outb(synu[j++], tmport);
+ atp_writeb_io(dev, c, 0x19, synu[j++]);
} else {
- outb(synn[j++], tmport);
+ atp_writeb_io(dev, c, 0x19, synn[j++]);
}
}
- tmport += 0x06;
}
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto phase_ins;
}
@@ -3766,19 +2196,13 @@ try_sync:
}
continue;
phase_outs:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0x00)
+ atp_writeb_io(dev, c, 0x19, 0x00);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x85) {
goto tar_dcons;
}
@@ -3794,26 +2218,25 @@ phase_outs:
}
continue;
phase_ins:
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ if (is885(dev) || is880(dev))
+ atp_writeb_io(dev, c, 0x14, 0x06);
+ else
+ atp_writeb_io(dev, c, 0x14, 0xff);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
phase_ins1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto phase_ins1;
}
if ((j & 0x80) == 0x00) {
goto phase_ins1;
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00);
- j = inb(tmport);
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x85) {
goto tar_dcons;
}
@@ -3829,18 +2252,15 @@ phase_ins1:
}
continue;
phase_cmds:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
tar_dcons:
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
continue;
}
@@ -3856,14 +2276,21 @@ tar_dcons:
if (mbuf[3] > 0x64) {
continue;
}
- if (mbuf[4] > 0x0e) {
- mbuf[4] = 0x0e;
+ if (is885(dev) || is880(dev)) {
+ if (mbuf[4] > 0x0e) {
+ mbuf[4] = 0x0e;
+ }
+ } else {
+ if (mbuf[4] > 0x0c) {
+ mbuf[4] = 0x0c;
+ }
}
dev->id[c][i].devsp = mbuf[4];
- if (mbuf[3] < 0x0c){
- j = 0xb0;
- goto set_syn_ok;
- }
+ if (is885(dev) || is880(dev))
+ if (mbuf[3] < 0x0c) {
+ j = 0xb0;
+ goto set_syn_ok;
+ }
if ((mbuf[3] < 0x0d) && (rmb == 0)) {
j = 0xa0;
goto set_syn_ok;
@@ -3881,16 +2308,10 @@ tar_dcons:
goto set_syn_ok;
}
j = 0x60;
- set_syn_ok:
+set_syn_ok:
dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j;
-#ifdef ED_DBGP
+#ifdef ED_DBGP
printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
#endif
}
- tmport = wkport + 0x16;
- outb(0x80, tmport);
}
-
-module_init(atp870u_init);
-module_exit(atp870u_exit);
-
diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
index 5cf6256..9b839b1 100644
--- a/drivers/scsi/atp870u.h
+++ b/drivers/scsi/atp870u.h
@@ -26,22 +26,18 @@ struct atp_unit
unsigned long baseport;
unsigned long ioport[2];
unsigned long pciport[2];
- unsigned long irq;
unsigned char last_cmd[2];
unsigned char in_snd[2];
unsigned char in_int[2];
unsigned char quhd[2];
unsigned char quend[2];
unsigned char global_map[2];
- unsigned char chip_ver;
- unsigned char scam_on;
unsigned char host_id[2];
unsigned int working[2];
unsigned short wide_id[2];
unsigned short active_id[2];
unsigned short ultra_map[2];
unsigned short async[2];
- unsigned short dev_id;
unsigned char sp[2][16];
unsigned char r1f[2][16];
struct scsi_cmnd *quereq[2][qcnt];
diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig
index 4e7cad2..bad5f32 100644
--- a/drivers/scsi/be2iscsi/Kconfig
+++ b/drivers/scsi/be2iscsi/Kconfig
@@ -3,6 +3,7 @@ config BE2ISCSI
depends on PCI && SCSI && NET
select SCSI_ISCSI_ATTRS
select ISCSI_BOOT_SYSFS
+ select IRQ_POLL
help
This driver implements the iSCSI functionality for Emulex
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 77f992e..ee5ace8 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -20,7 +20,7 @@
#include <linux/pci.h>
#include <linux/if_vlan.h>
-#include <linux/blk-iopoll.h>
+#include <linux/irq_poll.h>
#define FW_VER_LEN 32
#define MCC_Q_LEN 128
#define MCC_CQ_LEN 256
@@ -42,7 +42,7 @@ struct be_queue_info {
u16 id;
u16 tail, head;
bool created;
- atomic_t used; /* Number of valid elements in the queue */
+ u16 used; /* Number of valid elements in the queue */
};
static inline u32 MODULO(u16 val, u16 limit)
@@ -101,7 +101,7 @@ struct be_eq_obj {
struct beiscsi_hba *phba;
struct be_queue_info *cq;
struct work_struct work_cqs; /* Work Item */
- struct blk_iopoll iopoll;
+ struct irq_poll iopoll;
};
struct be_mcc_obj {
@@ -110,10 +110,9 @@ struct be_mcc_obj {
};
struct beiscsi_mcc_tag_state {
-#define MCC_TAG_STATE_COMPLETED 0x00
-#define MCC_TAG_STATE_RUNNING 0x01
-#define MCC_TAG_STATE_TIMEOUT 0x02
- uint8_t tag_state;
+ unsigned long tag_state;
+#define MCC_TAG_STATE_RUNNING 1
+#define MCC_TAG_STATE_TIMEOUT 2
struct be_dma_mem tag_mem_state;
};
@@ -124,7 +123,7 @@ struct be_ctrl_info {
struct pci_dev *pdev;
/* Mbox used for cmd request/response */
- spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */
+ struct mutex 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 */
@@ -133,11 +132,10 @@ struct be_ctrl_info {
/* MCC Rings */
struct be_mcc_obj mcc_obj;
spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
- spinlock_t mcc_cq_lock;
wait_queue_head_t mcc_wait[MAX_MCC_CMD + 1];
unsigned int mcc_tag[MAX_MCC_CMD];
- unsigned int mcc_numtag[MAX_MCC_CMD + 1];
+ unsigned int mcc_tag_status[MAX_MCC_CMD + 1];
unsigned short mcc_alloc_index;
unsigned short mcc_free_index;
unsigned int mcc_tag_available;
@@ -147,6 +145,12 @@ struct be_ctrl_info {
#include "be_cmds.h"
+/* WRB index mask for MCC_Q_LEN queue entries */
+#define MCC_Q_WRB_IDX_MASK CQE_STATUS_WRB_MASK
+#define MCC_Q_WRB_IDX_SHIFT CQE_STATUS_WRB_SHIFT
+/* TAG is from 1...MAX_MCC_CMD, MASK includes MAX_MCC_CMD */
+#define MCC_Q_CMD_TAG_MASK ((MAX_MCC_CMD << 1) - 1)
+
#define PAGE_SHIFT_4K 12
#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
#define mcc_timeout 120000 /* 12s timeout */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index 2778089..a55eaee 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -104,24 +104,16 @@ int be_chk_reset_complete(struct beiscsi_hba *phba)
return 0;
}
-void be_mcc_notify(struct beiscsi_hba *phba)
-{
- struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
- u32 val = 0;
-
- val |= mccq->id & DB_MCCQ_RING_ID_MASK;
- val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
- iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
-}
-
unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
{
unsigned int tag = 0;
+ spin_lock(&phba->ctrl.mcc_lock);
if (phba->ctrl.mcc_tag_available) {
tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
- phba->ctrl.mcc_numtag[tag] = 0;
+ phba->ctrl.mcc_tag_status[tag] = 0;
+ phba->ctrl.ptag_state[tag].tag_state = 0;
}
if (tag) {
phba->ctrl.mcc_tag_available--;
@@ -130,11 +122,89 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
else
phba->ctrl.mcc_alloc_index++;
}
+ spin_unlock(&phba->ctrl.mcc_lock);
return tag;
}
+struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
+ unsigned int *ref_tag)
+{
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ struct be_mcc_wrb *wrb = NULL;
+ unsigned int tag;
+
+ spin_lock_bh(&phba->ctrl.mcc_lock);
+ if (mccq->used == mccq->len) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : MCC queue full: WRB used %u tag avail %u\n",
+ mccq->used, phba->ctrl.mcc_tag_available);
+ goto alloc_failed;
+ }
+
+ if (!phba->ctrl.mcc_tag_available)
+ goto alloc_failed;
+
+ tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index];
+ if (!tag) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : MCC tag 0 allocated: tag avail %u alloc index %u\n",
+ phba->ctrl.mcc_tag_available,
+ phba->ctrl.mcc_alloc_index);
+ goto alloc_failed;
+ }
+
+ /* return this tag for further reference */
+ *ref_tag = tag;
+ phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0;
+ phba->ctrl.mcc_tag_status[tag] = 0;
+ phba->ctrl.ptag_state[tag].tag_state = 0;
+ phba->ctrl.mcc_tag_available--;
+ if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1))
+ phba->ctrl.mcc_alloc_index = 0;
+ else
+ phba->ctrl.mcc_alloc_index++;
+
+ wrb = queue_head_node(mccq);
+ memset(wrb, 0, sizeof(*wrb));
+ wrb->tag0 = tag;
+ wrb->tag0 |= (mccq->head << MCC_Q_WRB_IDX_SHIFT) & MCC_Q_WRB_IDX_MASK;
+ queue_head_inc(mccq);
+ mccq->used++;
+
+alloc_failed:
+ spin_unlock_bh(&phba->ctrl.mcc_lock);
+ return wrb;
+}
+
+void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag)
+{
+ struct be_queue_info *mccq = &ctrl->mcc_obj.q;
+
+ spin_lock_bh(&ctrl->mcc_lock);
+ tag = tag & MCC_Q_CMD_TAG_MASK;
+ ctrl->mcc_tag[ctrl->mcc_free_index] = tag;
+ if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1))
+ ctrl->mcc_free_index = 0;
+ else
+ ctrl->mcc_free_index++;
+ ctrl->mcc_tag_available++;
+ mccq->used--;
+ spin_unlock_bh(&ctrl->mcc_lock);
+}
+
+/**
+ * beiscsi_fail_session(): Closing session with appropriate error
+ * @cls_session: ptr to session
+ **/
+void beiscsi_fail_session(struct iscsi_cls_session *cls_session)
+{
+ iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+}
+
/*
- * beiscsi_mccq_compl()- Wait for completion of MBX
+ * beiscsi_mccq_compl_wait()- Process completion in MCC CQ
* @phba: Driver private structure
* @tag: Tag for the MBX Command
* @wrb: the WRB used for the MBX Command
@@ -146,43 +216,40 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
* Success: 0
* Failure: Non-Zero
**/
-int beiscsi_mccq_compl(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb,
- struct be_dma_mem *mbx_cmd_mem)
+int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
+ uint32_t tag, struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem)
{
int rc = 0;
- uint32_t mcc_tag_response;
+ uint32_t mcc_tag_status;
uint16_t status = 0, addl_status = 0, wrb_num = 0;
struct be_mcc_wrb *temp_wrb;
struct be_cmd_req_hdr *mbx_hdr;
struct be_cmd_resp_hdr *mbx_resp_hdr;
struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
- if (beiscsi_error(phba)) {
- free_mcc_tag(&phba->ctrl, tag);
+ if (beiscsi_error(phba))
return -EPERM;
- }
-
- /* Set MBX Tag state to Active */
- spin_lock(&phba->ctrl.mbox_lock);
- phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_RUNNING;
- spin_unlock(&phba->ctrl.mbox_lock);
/* wait for the mccq completion */
rc = wait_event_interruptible_timeout(
phba->ctrl.mcc_wait[tag],
- phba->ctrl.mcc_numtag[tag],
+ phba->ctrl.mcc_tag_status[tag],
msecs_to_jiffies(
BEISCSI_HOST_MBX_TIMEOUT));
-
+ /**
+ * If MBOX cmd timeout expired, tag and resource allocated
+ * for cmd is not freed until FW returns completion.
+ */
if (rc <= 0) {
struct be_dma_mem *tag_mem;
- /* Set MBX Tag state to timeout */
- spin_lock(&phba->ctrl.mbox_lock);
- phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_TIMEOUT;
- spin_unlock(&phba->ctrl.mbox_lock);
- /* Store resource addr to be freed later */
+ /**
+ * PCI/DMA memory allocated and posted in non-embedded mode
+ * will have mbx_cmd_mem != NULL.
+ * Save virtual and bus addresses for the command so that it
+ * can be freed later.
+ **/
tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
if (mbx_cmd_mem) {
tag_mem->size = mbx_cmd_mem->size;
@@ -191,28 +258,28 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
} else
tag_mem->size = 0;
+ /* first make tag_mem_state visible to all */
+ wmb();
+ set_bit(MCC_TAG_STATE_TIMEOUT,
+ &phba->ctrl.ptag_state[tag].tag_state);
+
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
BEISCSI_LOG_CONFIG,
"BC_%d : MBX Cmd Completion timed out\n");
return -EBUSY;
- } else {
- rc = 0;
- /* Set MBX Tag state to completed */
- spin_lock(&phba->ctrl.mbox_lock);
- phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
- spin_unlock(&phba->ctrl.mbox_lock);
}
- mcc_tag_response = phba->ctrl.mcc_numtag[tag];
- status = (mcc_tag_response & CQE_STATUS_MASK);
- addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >>
+ rc = 0;
+ mcc_tag_status = phba->ctrl.mcc_tag_status[tag];
+ status = (mcc_tag_status & CQE_STATUS_MASK);
+ addl_status = ((mcc_tag_status & CQE_STATUS_ADDL_MASK) >>
CQE_STATUS_ADDL_SHIFT);
if (mbx_cmd_mem) {
mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va;
} else {
- wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >>
+ wrb_num = (mcc_tag_status & CQE_STATUS_WRB_MASK) >>
CQE_STATUS_WRB_SHIFT;
temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
mbx_hdr = embedded_payload(temp_wrb);
@@ -231,7 +298,7 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
mbx_hdr->subsystem,
mbx_hdr->opcode,
status, addl_status);
-
+ rc = -EIO;
if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr;
beiscsi_log(phba, KERN_WARNING,
@@ -241,70 +308,16 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
"Resp_Len : %d Actual_Resp_Len : %d\n",
mbx_resp_hdr->response_length,
mbx_resp_hdr->actual_resp_len);
-
rc = -EAGAIN;
- goto release_mcc_tag;
}
- rc = -EIO;
}
-release_mcc_tag:
- /* Release the MCC entry */
- free_mcc_tag(&phba->ctrl, tag);
-
+ free_mcc_wrb(&phba->ctrl, tag);
return rc;
}
-void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag)
-{
- spin_lock(&ctrl->mbox_lock);
- tag = tag & 0x000000FF;
- ctrl->mcc_tag[ctrl->mcc_free_index] = tag;
- if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1))
- ctrl->mcc_free_index = 0;
- else
- ctrl->mcc_free_index++;
- ctrl->mcc_tag_available++;
- spin_unlock(&ctrl->mbox_lock);
-}
-
-bool is_link_state_evt(u32 trailer)
-{
- return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
- ASYNC_TRAILER_EVENT_CODE_MASK) ==
- ASYNC_EVENT_CODE_LINK_STATE);
-}
-
-static bool is_iscsi_evt(u32 trailer)
-{
- return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
- ASYNC_TRAILER_EVENT_CODE_MASK) ==
- ASYNC_EVENT_CODE_ISCSI;
-}
-
-static int iscsi_evt_type(u32 trailer)
-{
- return (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) &
- ASYNC_TRAILER_EVENT_TYPE_MASK;
-}
-
-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;
-}
-
/*
- * be_mcc_compl_process()- Check the MBX comapletion status
+ * beiscsi_process_mbox_compl()- Check the MBX completion status
* @ctrl: Function specific MBX data structure
* @compl: Completion status of MBX Command
*
@@ -314,8 +327,8 @@ static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
* Success: Zero
* Failure: Non-Zero
**/
-static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
- struct be_mcc_compl *compl)
+static int beiscsi_process_mbox_compl(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl)
{
u16 compl_status, extd_status;
struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
@@ -323,206 +336,228 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
struct be_cmd_req_hdr *hdr = embedded_payload(wrb);
struct be_cmd_resp_hdr *resp_hdr;
- 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;
-
+ /**
+ * To check if valid bit is set, check the entire word as we don't know
+ * the endianness of the data (old entry is host endian while a new
+ * entry is little endian)
+ */
+ if (!compl->flags) {
beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : error in cmd completion: "
- "Subsystem : %d Opcode : %d "
- "status(compl/extd)=%d/%d\n",
- hdr->subsystem, hdr->opcode,
- compl_status, extd_status);
-
- if (compl_status == MCC_STATUS_INSUFFICIENT_BUFFER) {
- resp_hdr = (struct be_cmd_resp_hdr *) hdr;
- if (resp_hdr->response_length)
- return 0;
- }
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : BMBX busy, no completion\n");
return -EBUSY;
}
- return 0;
-}
-
-int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
- struct be_mcc_compl *compl)
-{
- struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
- u16 compl_status, extd_status;
- unsigned short tag;
+ compl->flags = le32_to_cpu(compl->flags);
+ WARN_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0);
+ /**
+ * Just swap the status to host endian;
+ * mcc tag is opaquely copied from mcc_wrb.
+ */
be_dws_le_to_cpu(compl, 4);
-
compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
- CQE_STATUS_COMPL_MASK;
- /* The ctrl.mcc_numtag[tag] is filled with
- * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status,
- * [7:0] = compl_status
- */
- tag = (compl->tag0 & 0x000000FF);
+ CQE_STATUS_COMPL_MASK;
extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
- CQE_STATUS_EXTD_MASK;
+ CQE_STATUS_EXTD_MASK;
+ /* Need to reset the entire word that houses the valid bit */
+ compl->flags = 0;
- ctrl->mcc_numtag[tag] = 0x80000000;
- ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000);
- ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8;
- ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF);
+ if (compl_status == MCC_STATUS_SUCCESS)
+ return 0;
- if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_RUNNING) {
- wake_up_interruptible(&ctrl->mcc_wait[tag]);
- } else if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_TIMEOUT) {
- struct be_dma_mem *tag_mem;
- tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : error in cmd completion: Subsystem : %d Opcode : %d status(compl/extd)=%d/%d\n",
+ hdr->subsystem, hdr->opcode, compl_status, extd_status);
- beiscsi_log(phba, KERN_WARNING,
- BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
- BEISCSI_LOG_CONFIG,
- "BC_%d : MBX Completion for timeout Command "
- "from FW\n");
- /* Check if memory needs to be freed */
- if (tag_mem->size)
- pci_free_consistent(ctrl->pdev, tag_mem->size,
- tag_mem->va, tag_mem->dma);
-
- /* Change tag state */
- spin_lock(&phba->ctrl.mbox_lock);
- ctrl->ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
- spin_unlock(&phba->ctrl.mbox_lock);
-
- /* Free MCC Tag */
- free_mcc_tag(ctrl, tag);
+ if (compl_status == MCC_STATUS_INSUFFICIENT_BUFFER) {
+ /* if status is insufficient buffer, check the length */
+ resp_hdr = (struct be_cmd_resp_hdr *) hdr;
+ if (resp_hdr->response_length)
+ return 0;
}
-
- return 0;
+ return -EINVAL;
}
-static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba)
+static void beiscsi_process_async_link(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl)
{
- struct be_queue_info *mcc_cq = &phba->ctrl.mcc_obj.cq;
- struct be_mcc_compl *compl = queue_tail_node(mcc_cq);
+ struct be_async_event_link_state *evt;
+
+ evt = (struct be_async_event_link_state *)compl;
- if (be_mcc_compl_is_new(compl)) {
- queue_tail_inc(mcc_cq);
- return compl;
+ phba->port_speed = evt->port_speed;
+ /**
+ * Check logical link status in ASYNC event.
+ * This has been newly introduced in SKH-R Firmware 10.0.338.45.
+ **/
+ if (evt->port_link_status & BE_ASYNC_LINK_UP_MASK) {
+ phba->state = BE_ADAPTER_LINK_UP | BE_ADAPTER_CHECK_BOOT;
+ phba->get_boot = BE_GET_BOOT_RETRIES;
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : Link Up on Port %d tag 0x%x\n",
+ evt->physical_port, evt->event_tag);
+ } else {
+ phba->state = BE_ADAPTER_LINK_DOWN;
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : Link Down on Port %d tag 0x%x\n",
+ evt->physical_port, evt->event_tag);
+ iscsi_host_for_each_session(phba->shost,
+ beiscsi_fail_session);
}
- return NULL;
}
-/**
- * be2iscsi_fail_session(): Closing session with appropriate error
- * @cls_session: ptr to session
- *
- * Depending on adapter state appropriate error flag is passed.
- **/
-void be2iscsi_fail_session(struct iscsi_cls_session *cls_session)
+static char *beiscsi_port_misconf_event_msg[] = {
+ "Physical Link is functional.",
+ "Optics faulted/incorrectly installed/not installed - Reseat optics, if issue not resolved, replace.",
+ "Optics of two types installed - Remove one optic or install matching pair of optics.",
+ "Incompatible optics - Replace with compatible optics for card to function.",
+ "Unqualified optics - Replace with Avago optics for Warranty and Technical Support.",
+ "Uncertified optics - Replace with Avago Certified optics to enable link operation."
+};
+
+static void beiscsi_process_async_sli(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl)
{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct beiscsi_hba *phba = iscsi_host_priv(shost);
- uint32_t iscsi_err_flag;
+ struct be_async_event_sli *async_sli;
+ u8 evt_type, state, old_state, le;
+ char *sev = KERN_WARNING;
+ char *msg = NULL;
+
+ evt_type = compl->flags >> ASYNC_TRAILER_EVENT_TYPE_SHIFT;
+ evt_type &= ASYNC_TRAILER_EVENT_TYPE_MASK;
+
+ /* processing only MISCONFIGURED physical port event */
+ if (evt_type != ASYNC_SLI_EVENT_TYPE_MISCONFIGURED)
+ return;
+
+ async_sli = (struct be_async_event_sli *)compl;
+ state = async_sli->event_data1 >>
+ (phba->fw_config.phys_port * 8) & 0xff;
+ le = async_sli->event_data2 >>
+ (phba->fw_config.phys_port * 8) & 0xff;
+
+ old_state = phba->optic_state;
+ phba->optic_state = state;
+
+ if (state >= ARRAY_SIZE(beiscsi_port_misconf_event_msg)) {
+ /* fw is reporting a state we don't know, log and return */
+ __beiscsi_log(phba, KERN_ERR,
+ "BC_%d : Port %c: Unrecognized optic state 0x%x\n",
+ phba->port_name, async_sli->event_data1);
+ return;
+ }
- if (phba->state & BE_ADAPTER_STATE_SHUTDOWN)
- iscsi_err_flag = ISCSI_ERR_INVALID_HOST;
- else
- iscsi_err_flag = ISCSI_ERR_CONN_FAILED;
+ if (ASYNC_SLI_LINK_EFFECT_VALID(le)) {
+ /* log link effect for unqualified-4, uncertified-5 optics */
+ if (state > 3)
+ msg = (ASYNC_SLI_LINK_EFFECT_STATE(le)) ?
+ " Link is non-operational." :
+ " Link is operational.";
+ /* 1 - info */
+ if (ASYNC_SLI_LINK_EFFECT_SEV(le) == 1)
+ sev = KERN_INFO;
+ /* 2 - error */
+ if (ASYNC_SLI_LINK_EFFECT_SEV(le) == 2)
+ sev = KERN_ERR;
+ }
- iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
+ if (old_state != phba->optic_state)
+ __beiscsi_log(phba, sev, "BC_%d : Port %c: %s%s\n",
+ phba->port_name,
+ beiscsi_port_misconf_event_msg[state],
+ !msg ? "" : msg);
}
-void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
- struct be_async_event_link_state *evt)
+void beiscsi_process_async_event(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl)
{
- if ((evt->port_link_status == ASYNC_EVENT_LINK_DOWN) ||
- ((evt->port_link_status & ASYNC_EVENT_LOGICAL) &&
- (evt->port_fault != BEISCSI_PHY_LINK_FAULT_NONE))) {
- phba->state = BE_ADAPTER_LINK_DOWN;
-
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
- "BC_%d : Link Down on Port %d\n",
- evt->physical_port);
-
- iscsi_host_for_each_session(phba->shost,
- be2iscsi_fail_session);
- } else if ((evt->port_link_status & ASYNC_EVENT_LINK_UP) ||
- ((evt->port_link_status & ASYNC_EVENT_LOGICAL) &&
- (evt->port_fault == BEISCSI_PHY_LINK_FAULT_NONE))) {
- phba->state = BE_ADAPTER_LINK_UP | BE_ADAPTER_CHECK_BOOT;
+ char *sev = KERN_INFO;
+ u8 evt_code;
+
+ /* interpret flags as an async trailer */
+ evt_code = compl->flags >> ASYNC_TRAILER_EVENT_CODE_SHIFT;
+ evt_code &= ASYNC_TRAILER_EVENT_CODE_MASK;
+ switch (evt_code) {
+ case ASYNC_EVENT_CODE_LINK_STATE:
+ beiscsi_process_async_link(phba, compl);
+ break;
+ case ASYNC_EVENT_CODE_ISCSI:
+ phba->state |= BE_ADAPTER_CHECK_BOOT;
phba->get_boot = BE_GET_BOOT_RETRIES;
-
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
- "BC_%d : Link UP on Port %d\n",
- evt->physical_port);
+ sev = KERN_ERR;
+ break;
+ case ASYNC_EVENT_CODE_SLI:
+ beiscsi_process_async_sli(phba, compl);
+ break;
+ default:
+ /* event not registered */
+ sev = KERN_ERR;
}
+
+ beiscsi_log(phba, sev, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : ASYNC Event %x: status 0x%08x flags 0x%08x\n",
+ evt_code, compl->status, compl->flags);
}
-int beiscsi_process_mcc(struct beiscsi_hba *phba)
+int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl)
{
- struct be_mcc_compl *compl;
- int num = 0, status = 0;
- struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
+ u16 compl_status, extd_status;
+ struct be_dma_mem *tag_mem;
+ unsigned int tag, wrb_idx;
- spin_lock_bh(&phba->ctrl.mcc_cq_lock);
- while ((compl = be_mcc_compl_get(phba))) {
- if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
- /* Interpret flags as an async trailer */
- if (is_link_state_evt(compl->flags))
- /* Interpret compl as a async link evt */
- beiscsi_async_link_state_process(phba,
- (struct be_async_event_link_state *) compl);
- else if (is_iscsi_evt(compl->flags)) {
- switch (iscsi_evt_type(compl->flags)) {
- case ASYNC_EVENT_NEW_ISCSI_TGT_DISC:
- case ASYNC_EVENT_NEW_ISCSI_CONN:
- case ASYNC_EVENT_NEW_TCP_CONN:
- phba->state |= BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG |
- BEISCSI_LOG_MBOX,
- "BC_%d : Async iscsi Event,"
- " flags handled = 0x%08x\n",
- compl->flags);
- break;
- default:
- phba->state |= BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG |
- BEISCSI_LOG_MBOX,
- "BC_%d : Unsupported Async"
- " Event, flags = 0x%08x\n",
- compl->flags);
- }
- } else
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG |
- BEISCSI_LOG_MBOX,
- "BC_%d : Unsupported Async Event, flags"
- " = 0x%08x\n", compl->flags);
-
- } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
- status = be_mcc_compl_process(ctrl, compl);
- atomic_dec(&phba->ctrl.mcc_obj.q.used);
- }
- be_mcc_compl_use(compl);
- num++;
+ be_dws_le_to_cpu(compl, 4);
+ tag = (compl->tag0 & MCC_Q_CMD_TAG_MASK);
+ wrb_idx = (compl->tag0 & CQE_STATUS_WRB_MASK) >> CQE_STATUS_WRB_SHIFT;
+
+ if (!test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state)) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_MBOX |
+ BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
+ "BC_%d : MBX cmd completed but not posted\n");
+ return 0;
}
- if (num)
- hwi_ring_cq_db(phba, phba->ctrl.mcc_obj.cq.id, num, 1, 0);
+ if (test_bit(MCC_TAG_STATE_TIMEOUT, &ctrl->ptag_state[tag].tag_state)) {
+ beiscsi_log(phba, KERN_WARNING,
+ BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
+ BEISCSI_LOG_CONFIG,
+ "BC_%d : MBX Completion for timeout Command from FW\n");
+ /**
+ * Check for the size before freeing resource.
+ * Only for non-embedded cmd, PCI resource is allocated.
+ **/
+ tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+ if (tag_mem->size)
+ pci_free_consistent(ctrl->pdev, tag_mem->size,
+ tag_mem->va, tag_mem->dma);
+ free_mcc_wrb(ctrl, tag);
+ return 0;
+ }
- spin_unlock_bh(&phba->ctrl.mcc_cq_lock);
- return status;
+ compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
+ CQE_STATUS_COMPL_MASK;
+ extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
+ CQE_STATUS_EXTD_MASK;
+ /* The ctrl.mcc_tag_status[tag] is filled with
+ * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status,
+ * [7:0] = compl_status
+ */
+ ctrl->mcc_tag_status[tag] = CQE_VALID_MASK;
+ ctrl->mcc_tag_status[tag] |= (wrb_idx << CQE_STATUS_WRB_SHIFT);
+ ctrl->mcc_tag_status[tag] |= (extd_status << CQE_STATUS_ADDL_SHIFT) &
+ CQE_STATUS_ADDL_MASK;
+ ctrl->mcc_tag_status[tag] |= (compl_status & CQE_STATUS_MASK);
+
+ /* write ordering forced in wake_up_interruptible */
+ clear_bit(MCC_TAG_STATE_RUNNING, &ctrl->ptag_state[tag].tag_state);
+ wake_up_interruptible(&ctrl->mcc_wait[tag]);
+ return 0;
}
/*
- * be_mcc_wait_compl()- Wait for MBX completion
+ * be_mcc_compl_poll()- Wait for MBX completion
* @phba: driver private structure
*
* Wait till no more pending mcc requests are present
@@ -532,50 +567,57 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
* Failure: Non-Zero
*
**/
-static int be_mcc_wait_compl(struct beiscsi_hba *phba)
+int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag)
{
- int i, status;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ int i;
+
+ if (!test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state)) {
+ beiscsi_log(phba, KERN_ERR,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d: tag %u state not running\n", tag);
+ return 0;
+ }
for (i = 0; i < mcc_timeout; i++) {
if (beiscsi_error(phba))
return -EIO;
- status = beiscsi_process_mcc(phba);
- if (status)
- return status;
-
- if (atomic_read(&phba->ctrl.mcc_obj.q.used) == 0)
+ beiscsi_process_mcc_cq(phba);
+ /* after polling, wrb and tag need to be released */
+ if (!test_bit(MCC_TAG_STATE_RUNNING,
+ &ctrl->ptag_state[tag].tag_state)) {
+ free_mcc_wrb(ctrl, tag);
break;
+ }
udelay(100);
}
- if (i == mcc_timeout) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : FW Timed Out\n");
- phba->fw_timeout = true;
- beiscsi_ue_detect(phba);
- return -EBUSY;
- }
- return 0;
+
+ if (i < mcc_timeout)
+ return 0;
+
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : FW Timed Out\n");
+ phba->fw_timeout = true;
+ beiscsi_ue_detect(phba);
+ return -EBUSY;
}
-/*
- * be_mcc_notify_wait()- Notify and wait for Compl
- * @phba: driver private structure
- *
- * Notify MCC requests and wait for completion
- *
- * return
- * Success: 0
- * Failure: Non-Zero
- **/
-int be_mcc_notify_wait(struct beiscsi_hba *phba)
+void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag)
{
- be_mcc_notify(phba);
- return be_mcc_wait_compl(phba);
+ struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+ u32 val = 0;
+
+ set_bit(MCC_TAG_STATE_RUNNING, &phba->ctrl.ptag_state[tag].tag_state);
+ val |= mccq->id & DB_MCCQ_RING_ID_MASK;
+ val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
+ /* make request available for DMA */
+ wmb();
+ iowrite32(val, phba->db_va + DB_MCCQ_OFFSET);
}
/*
- * be_mbox_db_ready_wait()- Check ready status
+ * be_mbox_db_ready_poll()- Check ready status
* @ctrl: Function specific MBX data structure
*
* Check for the ready status of FW to send BMBX
@@ -585,49 +627,45 @@ int be_mcc_notify_wait(struct beiscsi_hba *phba)
* Success: 0
* Failure: Non-Zero
**/
-static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
+static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
{
-#define BEISCSI_MBX_RDY_BIT_TIMEOUT 4000 /* 4sec */
+ /* wait 30s for generic non-flash MBOX operation */
+#define BEISCSI_MBX_RDY_BIT_TIMEOUT 30000
void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
unsigned long timeout;
- bool read_flag = false;
- int ret = 0, i;
u32 ready;
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(rdybit_check_q);
- if (beiscsi_error(phba))
- return -EIO;
+ /*
+ * This BMBX busy wait path is used during init only.
+ * For the commands executed during init, 5s should suffice.
+ */
+ timeout = jiffies + msecs_to_jiffies(BEISCSI_MBX_RDY_BIT_TIMEOUT);
+ do {
+ if (beiscsi_error(phba))
+ return -EIO;
- timeout = jiffies + (HZ * 110);
+ ready = ioread32(db);
+ if (ready == 0xffffffff)
+ return -EIO;
- do {
- for (i = 0; i < BEISCSI_MBX_RDY_BIT_TIMEOUT; i++) {
- ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
- if (ready) {
- read_flag = true;
- break;
- }
- mdelay(1);
- }
+ ready &= MPU_MAILBOX_DB_RDY_MASK;
+ if (ready)
+ return 0;
- if (!read_flag) {
- wait_event_timeout(rdybit_check_q,
- (read_flag != true),
- HZ * 5);
- }
- } while ((time_before(jiffies, timeout)) && !read_flag);
+ if (time_after(jiffies, timeout))
+ break;
+ msleep(20);
+ } while (!ready);
- if (!read_flag) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : FW Timed Out\n");
- phba->fw_timeout = true;
- beiscsi_ue_detect(phba);
- ret = -EBUSY;
- }
+ beiscsi_log(phba, KERN_ERR,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+ "BC_%d : FW Timed Out\n");
+
+ phba->fw_timeout = true;
+ beiscsi_ue_detect(phba);
- return ret;
+ return -EBUSY;
}
/*
@@ -648,10 +686,8 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
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;
- struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
- status = be_mbox_db_ready_wait(ctrl);
+ status = be_mbox_db_ready_poll(ctrl);
if (status)
return status;
@@ -660,7 +696,7 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
iowrite32(val, db);
- status = be_mbox_db_ready_wait(ctrl);
+ status = be_mbox_db_ready_poll(ctrl);
if (status)
return status;
@@ -670,81 +706,15 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
val |= (u32) (mbox_mem->dma >> 4) << 2;
iowrite32(val, db);
- status = be_mbox_db_ready_wait(ctrl);
+ status = be_mbox_db_ready_poll(ctrl);
if (status)
return status;
- if (be_mcc_compl_is_new(compl)) {
- status = be_mcc_compl_process(ctrl, &mbox->compl);
- be_mcc_compl_use(compl);
- if (status) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : After be_mcc_compl_process\n");
-
- return status;
- }
- } else {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : Invalid Mailbox Completion\n");
-
- return -EBUSY;
- }
- return 0;
-}
-
-/*
- * Insert the mailbox address into the doorbell in two steps
- * Polls on the mbox doorbell till a command completion (or a timeout) occurs
- */
-static int be_mbox_notify_wait(struct beiscsi_hba *phba)
-{
- int status;
- u32 val = 0;
- void __iomem *db = phba->ctrl.db + MPU_MAILBOX_DB_OFFSET;
- struct be_dma_mem *mbox_mem = &phba->ctrl.mbox_mem;
- struct be_mcc_mailbox *mbox = mbox_mem->va;
- struct be_mcc_compl *compl = &mbox->compl;
- struct be_ctrl_info *ctrl = &phba->ctrl;
-
- status = be_mbox_db_ready_wait(ctrl);
- if (status)
- return status;
-
- val |= MPU_MAILBOX_DB_HI_MASK;
- /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
- val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
- iowrite32(val, db);
-
- /* wait for ready to be set */
- status = be_mbox_db_ready_wait(ctrl);
- if (status != 0)
- return status;
-
- val = 0;
- /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
- val |= (u32)(mbox_mem->dma >> 4) << 2;
- iowrite32(val, db);
+ /* RDY is set; small delay before CQE read. */
+ udelay(1);
- status = be_mbox_db_ready_wait(ctrl);
- if (status != 0)
- return status;
-
- /* A cq entry has been made now */
- if (be_mcc_compl_is_new(compl)) {
- status = be_mcc_compl_process(ctrl, &mbox->compl);
- be_mcc_compl_use(compl);
- if (status)
- return status;
- } else {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BC_%d : invalid mailbox completion\n");
-
- return -EBUSY;
- }
- return 0;
+ status = beiscsi_process_mbox_compl(ctrl, &mbox->compl);
+ return status;
}
void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
@@ -809,21 +779,6 @@ struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem)
return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;
}
-struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba)
-{
- struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
- struct be_mcc_wrb *wrb;
-
- WARN_ON(atomic_read(&mccq->used) >= mccq->len);
- wrb = queue_head_node(mccq);
- memset(wrb, 0, sizeof(*wrb));
- wrb->tag0 = (mccq->head & 0x000000FF) << 16;
- queue_head_inc(mccq);
- atomic_inc(&mccq->used);
- return wrb;
-}
-
-
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay)
{
@@ -833,7 +788,7 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_dma_mem *q_mem = &eq->dma_mem;
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -860,7 +815,7 @@ int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
eq->id = le16_to_cpu(resp->eq_id);
eq->created = true;
}
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -881,7 +836,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
int status;
u8 *endian_check;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
endian_check = (u8 *) wrb;
@@ -900,7 +855,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BC_%d : be_cmd_fw_initialize Failed\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -921,7 +876,7 @@ int be_cmd_fw_uninit(struct be_ctrl_info *ctrl)
int status;
u8 *endian_check;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
endian_check = (u8 *) wrb;
@@ -941,7 +896,7 @@ int be_cmd_fw_uninit(struct be_ctrl_info *ctrl)
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BC_%d : be_cmd_fw_uninit Failed\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -957,7 +912,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
void *ctxt = &req->context;
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1007,7 +962,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
"BC_%d : In be_cmd_cq_create, status=ox%08x\n",
status);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1025,13 +980,13 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
struct be_queue_info *cq)
{
struct be_mcc_wrb *wrb;
- struct be_cmd_req_mcc_create *req;
+ struct be_cmd_req_mcc_create_ext *req;
struct be_dma_mem *q_mem = &mccq->dma_mem;
struct be_ctrl_info *ctrl;
void *ctxt;
int status;
- spin_lock(&phba->ctrl.mbox_lock);
+ mutex_lock(&phba->ctrl.mbox_lock);
ctrl = &phba->ctrl;
wrb = wrb_from_mbox(&ctrl->mbox_mem);
memset(wrb, 0, sizeof(*wrb));
@@ -1041,9 +996,12 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+ OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req));
req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+ req->async_evt_bitmap = 1 << ASYNC_EVENT_CODE_LINK_STATE;
+ req->async_evt_bitmap |= 1 << ASYNC_EVENT_CODE_ISCSI;
+ req->async_evt_bitmap |= 1 << ASYNC_EVENT_CODE_SLI;
AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt,
PCI_FUNC(phba->pcidev->devfn));
@@ -1056,13 +1014,13 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
- status = be_mbox_notify_wait(phba);
+ status = be_mbox_notify(ctrl);
if (!status) {
struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);
mccq->id = le16_to_cpu(resp->id);
mccq->created = true;
}
- spin_unlock(&phba->ctrl.mbox_lock);
+ mutex_unlock(&phba->ctrl.mbox_lock);
return status;
}
@@ -1080,7 +1038,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
"BC_%d : In beiscsi_cmd_q_destroy "
"queue_type : %d\n", queue_type);
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1110,7 +1068,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
opcode = OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES;
break;
default:
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
BUG();
return -ENXIO;
}
@@ -1120,7 +1078,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1155,7 +1113,7 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
void *ctxt = &req->context;
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1227,7 +1185,7 @@ int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
defq_ring->doorbell_offset = resp->doorbell_offset;
}
}
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1255,7 +1213,7 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1286,7 +1244,7 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl,
pwrb_context->doorbell_offset = resp->doorbell_offset;
}
}
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1297,7 +1255,7 @@ int be_cmd_iscsi_post_template_hdr(struct be_ctrl_info *ctrl,
struct be_post_template_pages_req *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1310,7 +1268,7 @@ int be_cmd_iscsi_post_template_hdr(struct be_ctrl_info *ctrl,
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1320,7 +1278,7 @@ int be_cmd_iscsi_remove_template_hdr(struct be_ctrl_info *ctrl)
struct be_remove_template_pages_req *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1331,7 +1289,7 @@ int be_cmd_iscsi_remove_template_hdr(struct be_ctrl_info *ctrl)
req->type = BEISCSI_TEMPLATE_HDR_TYPE_ISCSI;
status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1350,7 +1308,7 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
if (num_pages == 0xff)
num_pages = 1;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
do {
memset(wrb, 0, sizeof(*wrb));
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
@@ -1379,7 +1337,7 @@ int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
}
} while (num_pages > 0);
error:
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
if (status != 0)
beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
return status;
@@ -1392,15 +1350,15 @@ int beiscsi_cmd_reset_function(struct beiscsi_hba *phba)
struct be_post_sgl_pages_req *req = embedded_payload(wrb);
int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_FUNCTION_RESET, sizeof(*req));
- status = be_mbox_notify_wait(phba);
+ status = be_mbox_notify(ctrl);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -1417,21 +1375,20 @@ int beiscsi_cmd_reset_function(struct beiscsi_hba *phba)
int be_cmd_set_vlan(struct beiscsi_hba *phba,
uint16_t vlan_tag)
{
- unsigned int tag = 0;
+ unsigned int tag;
struct be_mcc_wrb *wrb;
struct be_cmd_set_vlan_req *req;
struct be_ctrl_info *ctrl = &phba->ctrl;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*wrb), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
OPCODE_COMMON_ISCSI_NTWK_SET_VLAN,
@@ -1440,8 +1397,8 @@ int be_cmd_set_vlan(struct beiscsi_hba *phba,
req->interface_hndl = phba->interface_handle;
req->vlan_priority = vlan_tag;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 4bfca35..deeb951 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -58,15 +58,16 @@ struct be_mcc_wrb {
#define MCC_STATUS_ILLEGAL_FIELD 0x3
#define MCC_STATUS_INSUFFICIENT_BUFFER 0x4
-#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 16 /* bits 0 - 15 */
+#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 16 /* bits 31 - 16 */
#define CQE_STATUS_ADDL_MASK 0xFF00
-#define CQE_STATUS_MASK 0xFF
-#define CQE_STATUS_ADDL_SHIFT 0x08
+#define CQE_STATUS_ADDL_SHIFT 8
+#define CQE_STATUS_MASK 0xFF
#define CQE_STATUS_WRB_MASK 0xFF0000
#define CQE_STATUS_WRB_SHIFT 16
+
#define BEISCSI_HOST_MBX_TIMEOUT (110 * 1000)
#define BEISCSI_FW_MBX_TIMEOUT 100
@@ -119,13 +120,22 @@ struct be_mcc_compl {
#define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF
#define ASYNC_EVENT_CODE_LINK_STATE 0x1
#define ASYNC_EVENT_CODE_ISCSI 0x4
+#define ASYNC_EVENT_CODE_SLI 0x11
#define ASYNC_TRAILER_EVENT_TYPE_SHIFT 16 /* bits 16 - 23 */
-#define ASYNC_TRAILER_EVENT_TYPE_MASK 0xF
+#define ASYNC_TRAILER_EVENT_TYPE_MASK 0xFF
+
+/* iSCSI events */
#define ASYNC_EVENT_NEW_ISCSI_TGT_DISC 0x4
#define ASYNC_EVENT_NEW_ISCSI_CONN 0x5
#define ASYNC_EVENT_NEW_TCP_CONN 0x7
+/* SLI events */
+#define ASYNC_SLI_EVENT_TYPE_MISCONFIGURED 0x9
+#define ASYNC_SLI_LINK_EFFECT_VALID(le) (le & 0x80)
+#define ASYNC_SLI_LINK_EFFECT_SEV(le) ((le >> 1) & 0x03)
+#define ASYNC_SLI_LINK_EFFECT_STATE(le) (le & 0x01)
+
struct be_async_event_trailer {
u32 code;
};
@@ -133,7 +143,6 @@ struct be_async_event_trailer {
enum {
ASYNC_EVENT_LINK_DOWN = 0x0,
ASYNC_EVENT_LINK_UP = 0x1,
- ASYNC_EVENT_LOGICAL = 0x2
};
/**
@@ -143,16 +152,39 @@ enum {
struct be_async_event_link_state {
u8 physical_port;
u8 port_link_status;
+/**
+ * ASYNC_EVENT_LINK_DOWN 0x0
+ * ASYNC_EVENT_LINK_UP 0x1
+ * ASYNC_EVENT_LINK_LOGICAL_DOWN 0x2
+ * ASYNC_EVENT_LINK_LOGICAL_UP 0x3
+ */
+#define BE_ASYNC_LINK_UP_MASK 0x01
u8 port_duplex;
u8 port_speed;
-#define BEISCSI_PHY_LINK_FAULT_NONE 0x00
-#define BEISCSI_PHY_LINK_FAULT_LOCAL 0x01
-#define BEISCSI_PHY_LINK_FAULT_REMOTE 0x02
+/* BE2ISCSI_LINK_SPEED_ZERO 0x00 - no link */
+#define BE2ISCSI_LINK_SPEED_10MBPS 0x01
+#define BE2ISCSI_LINK_SPEED_100MBPS 0x02
+#define BE2ISCSI_LINK_SPEED_1GBPS 0x03
+#define BE2ISCSI_LINK_SPEED_10GBPS 0x04
+#define BE2ISCSI_LINK_SPEED_25GBPS 0x06
+#define BE2ISCSI_LINK_SPEED_40GBPS 0x07
u8 port_fault;
- u8 rsvd0[7];
+ u8 event_reason;
+ u16 qos_link_speed;
+ u32 event_tag;
struct be_async_event_trailer trailer;
} __packed;
+/**
+ * When async-trailer is SLI event, mcc_compl is interpreted as
+ */
+struct be_async_event_sli {
+ u32 event_data1;
+ u32 event_data2;
+ u32 reserved;
+ u32 trailer;
+} __packed;
+
struct be_mcc_mailbox {
struct be_mcc_wrb wrb;
struct be_mcc_compl compl;
@@ -172,6 +204,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_CQ_CREATE 12
#define OPCODE_COMMON_EQ_CREATE 13
#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_MCC_CREATE_EXT 90
#define OPCODE_COMMON_ADD_TEMPLATE_HEADER_BUFFERS 24
#define OPCODE_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS 25
#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32
@@ -183,6 +216,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_EQ_DESTROY 55
#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58
#define OPCODE_COMMON_FUNCTION_RESET 61
+#define OPCODE_COMMON_GET_PORT_NAME 77
/**
* LIST of opcodes that are common between Initiator and Target
@@ -587,10 +621,11 @@ struct amap_mcc_context {
u8 rsvd2[32];
} __packed;
-struct be_cmd_req_mcc_create {
+struct be_cmd_req_mcc_create_ext {
struct be_cmd_req_hdr hdr;
u16 num_pages;
u16 rsvd0;
+ u32 async_evt_bitmap;
u8 context[sizeof(struct amap_mcc_context) / 8];
struct phys_addr pages[8];
} __packed;
@@ -653,20 +688,6 @@ struct be_cmd_req_modify_eq_delay {
/******************** Get MAC ADDR *******************/
-#define ETH_ALEN 6
-
-struct be_cmd_get_nic_conf_req {
- 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_get_nic_conf_resp {
struct be_cmd_resp_hdr hdr;
u32 nic_port_count;
@@ -675,9 +696,8 @@ struct be_cmd_get_nic_conf_resp {
u32 link_state;
u32 max_frame_size;
u16 size_of_structure;
- u8 mac_address[6];
- u32 rsvd[23];
-};
+ u8 mac_address[ETH_ALEN];
+} __packed;
#define BEISCSI_ALIAS_LEN 32
@@ -689,29 +709,6 @@ struct be_cmd_hba_name {
u8 initiator_alias[BEISCSI_ALIAS_LEN];
} __packed;
-struct be_cmd_ntwk_link_status_req {
- struct be_cmd_req_hdr hdr;
- u32 rsvd0;
-} __packed;
-
-/*** Port Speed Values ***/
-#define BE2ISCSI_LINK_SPEED_ZERO 0x00
-#define BE2ISCSI_LINK_SPEED_10MBPS 0x01
-#define BE2ISCSI_LINK_SPEED_100MBPS 0x02
-#define BE2ISCSI_LINK_SPEED_1GBPS 0x03
-#define BE2ISCSI_LINK_SPEED_10GBPS 0x04
-struct be_cmd_ntwk_link_status_resp {
- struct be_cmd_resp_hdr hdr;
- u8 phys_port;
- u8 mac_duplex;
- u8 mac_speed;
- u8 mac_fault;
- u8 mgmt_mac_duplex;
- u8 mgmt_mac_speed;
- u16 qos_link_speed;
- u32 logical_link_speed;
-} __packed;
-
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay);
@@ -730,28 +727,28 @@ int be_poll_mcc(struct be_ctrl_info *ctrl);
int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
unsigned int be_cmd_get_initname(struct beiscsi_hba *phba);
-unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
-void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
+void free_mcc_wrb(struct be_ctrl_info *ctrl, unsigned int tag);
int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *,
int num);
-int beiscsi_mccq_compl(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb,
- struct be_dma_mem *mbx_cmd_mem);
+int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
+ uint32_t tag, struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem);
/*ISCSI Functuions */
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
int be_cmd_fw_uninit(struct be_ctrl_info *ctrl);
struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
-struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba);
-int be_mcc_notify_wait(struct beiscsi_hba *phba);
-void be_mcc_notify(struct beiscsi_hba *phba);
-unsigned int alloc_mcc_tag(struct beiscsi_hba *phba);
-void beiscsi_async_link_state_process(struct beiscsi_hba *phba,
- struct be_async_event_link_state *evt);
-int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
- struct be_mcc_compl *compl);
+int be_mcc_compl_poll(struct beiscsi_hba *phba, unsigned int tag);
+void be_mcc_notify(struct beiscsi_hba *phba, unsigned int tag);
+struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
+ unsigned int *ref_tag);
+void beiscsi_process_async_event(struct beiscsi_hba *phba,
+ struct be_mcc_compl *compl);
+int beiscsi_process_mcc_compl(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl);
+
int be_mbox_notify(struct be_ctrl_info *ctrl);
@@ -777,8 +774,6 @@ int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
struct hwi_wrb_context *pwrb_context,
uint8_t ulp_num);
-bool is_link_state_evt(u32 trailer);
-
/* Configuration Functions */
int be_cmd_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag);
@@ -1137,6 +1132,21 @@ struct be_cmd_get_all_if_id_req {
u32 if_hndl_list[1];
} __packed;
+struct be_cmd_get_port_name {
+ union {
+ struct be_cmd_req_hdr req_hdr;
+ struct be_cmd_resp_hdr resp_hdr;
+ } h;
+ union {
+ struct {
+ u32 reserved;
+ } req;
+ struct {
+ u32 port_names;
+ } resp;
+ } p;
+} __packed;
+
#define ISCSI_OPCODE_SCSI_DATA_OUT 5
#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5
#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
@@ -1367,5 +1377,5 @@ void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
u8 subsystem, u8 opcode, int cmd_len);
-void be2iscsi_fail_session(struct iscsi_cls_session *cls_session);
+void beiscsi_fail_session(struct iscsi_cls_session *cls_session);
#endif /* !BEISCSI_CMDS_H */
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index b7087ba..09f89a3 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -367,13 +367,14 @@ beiscsi_set_vlan_tag(struct Scsi_Host *shost,
struct iscsi_iface_param_info *iface_param)
{
struct beiscsi_hba *phba = iscsi_host_priv(shost);
- int ret = 0;
+ int ret;
/* Get the Interface Handle */
- if (mgmt_get_all_if_id(phba)) {
+ ret = mgmt_get_all_if_id(phba);
+ if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BS_%d : Getting Interface Handle Failed\n");
- return -EIO;
+ return ret;
}
switch (iface_param->param) {
@@ -465,6 +466,10 @@ beiscsi_set_ipv6(struct Scsi_Host *shost,
ret = mgmt_set_ip(phba, iface_param, NULL,
ISCSI_BOOTPROTO_STATIC);
break;
+ case ISCSI_NET_PARAM_VLAN_ENABLED:
+ case ISCSI_NET_PARAM_VLAN_TAG:
+ ret = beiscsi_set_vlan_tag(shost, iface_param);
+ break;
default:
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
"BS_%d : Param %d not supported\n",
@@ -730,7 +735,7 @@ static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba)
return -EBUSY;
}
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
@@ -753,7 +758,7 @@ static void beiscsi_get_port_state(struct Scsi_Host *shost)
struct beiscsi_hba *phba = iscsi_host_priv(shost);
struct iscsi_cls_host *ihost = shost->shost_data;
- ihost->port_state = (phba->state == BE_ADAPTER_LINK_UP) ?
+ ihost->port_state = (phba->state & BE_ADAPTER_LINK_UP) ?
ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN;
}
@@ -761,34 +766,13 @@ static void beiscsi_get_port_state(struct Scsi_Host *shost)
* beiscsi_get_port_speed - Get the Port Speed from Adapter
* @shost : pointer to scsi_host structure
*
- * returns Success/Failure
*/
-static int beiscsi_get_port_speed(struct Scsi_Host *shost)
+static void beiscsi_get_port_speed(struct Scsi_Host *shost)
{
- int rc;
- unsigned int tag;
- struct be_mcc_wrb *wrb;
- struct be_cmd_ntwk_link_status_resp *resp;
struct beiscsi_hba *phba = iscsi_host_priv(shost);
struct iscsi_cls_host *ihost = shost->shost_data;
- tag = be_cmd_get_port_speed(phba);
- if (!tag) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Getting Port Speed Failed\n");
-
- return -EBUSY;
- }
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
- if (rc) {
- beiscsi_log(phba, KERN_ERR,
- BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
- "BS_%d : Port Speed MBX Failed\n");
- return rc;
- }
- resp = embedded_payload(wrb);
-
- switch (resp->mac_speed) {
+ switch (phba->port_speed) {
case BE2ISCSI_LINK_SPEED_10MBPS:
ihost->port_speed = ISCSI_PORT_SPEED_10MBPS;
break;
@@ -801,10 +785,15 @@ static int beiscsi_get_port_speed(struct Scsi_Host *shost)
case BE2ISCSI_LINK_SPEED_10GBPS:
ihost->port_speed = ISCSI_PORT_SPEED_10GBPS;
break;
+ case BE2ISCSI_LINK_SPEED_25GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_25GBPS;
+ break;
+ case BE2ISCSI_LINK_SPEED_40GBPS:
+ ihost->port_speed = ISCSI_PORT_SPEED_40GBPS;
+ break;
default:
ihost->port_speed = ISCSI_PORT_SPEED_UNKNOWN;
}
- return 0;
}
/**
@@ -854,12 +843,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
status = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
break;
case ISCSI_HOST_PARAM_PORT_SPEED:
- status = beiscsi_get_port_speed(shost);
- if (status) {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BS_%d : Retreiving Port Speed Failed\n");
- return status;
- }
+ beiscsi_get_port_speed(shost);
status = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
break;
default:
@@ -1159,7 +1143,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
return -EAGAIN;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
@@ -1292,9 +1276,9 @@ static void beiscsi_flush_cq(struct beiscsi_hba *phba)
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
- beiscsi_process_cq(pbe_eq);
- blk_iopoll_enable(&pbe_eq->iopoll);
+ irq_poll_disable(&pbe_eq->iopoll);
+ beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC);
+ irq_poll_enable(&pbe_eq->iopoll);
}
}
@@ -1318,7 +1302,7 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag)
ret = -EAGAIN;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ ret = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
/* Flush the CQ entries */
beiscsi_flush_cq(phba);
@@ -1393,7 +1377,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
beiscsi_ep->ep_cid);
}
- beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
beiscsi_close_conn(beiscsi_ep, tcp_upload_flag);
free_ep:
msleep(BEISCSI_LOGOUT_SYNC_DELAY);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 2e6abe7..f05e773 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -29,6 +29,7 @@
#include <linux/iscsi_boot_sysfs.h>
#include <linux/module.h>
#include <linux/bsg-lib.h>
+#include <linux/irq_poll.h>
#include <scsi/libiscsi.h>
#include <scsi/scsi_bsg_iscsi.h>
@@ -285,7 +286,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
return FAILED;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (rc != -EBUSY)
pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
@@ -366,7 +367,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
return FAILED;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (rc != -EBUSY)
pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
@@ -727,9 +728,8 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
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);
+ mutex_init(&ctrl->mbox_lock);
spin_lock_init(&phba->ctrl.mcc_lock);
- spin_lock_init(&phba->ctrl.mcc_cq_lock);
return status;
}
@@ -895,32 +895,17 @@ static irqreturn_t be_isr_mcc(int irq, void *dev_id)
static irqreturn_t be_isr_msix(int irq, void *dev_id)
{
struct beiscsi_hba *phba;
- struct be_eq_entry *eqe = NULL;
struct be_queue_info *eq;
- struct be_queue_info *cq;
- unsigned int num_eq_processed;
struct be_eq_obj *pbe_eq;
pbe_eq = dev_id;
eq = &pbe_eq->q;
- cq = pbe_eq->cq;
- eqe = queue_tail_node(eq);
phba = pbe_eq->phba;
- num_eq_processed = 0;
- while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
- & EQE_VALID_MASK) {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
- AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
- queue_tail_inc(eq);
- eqe = queue_tail_node(eq);
- num_eq_processed++;
- }
-
- if (num_eq_processed)
- hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
+ /* disable interrupt till iopoll completes */
+ hwi_ring_eq_db(phba, eq->id, 1, 0, 0, 1);
+ irq_poll_sched(&pbe_eq->iopoll);
return IRQ_HANDLED;
}
@@ -972,8 +957,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
spin_unlock_irqrestore(&phba->isr_lock, flags);
num_mcceq_processed++;
} else {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
+ irq_poll_sched(&pbe_eq->iopoll);
num_ioeq_processed++;
}
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
@@ -998,6 +982,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
return IRQ_NONE;
}
+
static int beiscsi_init_irqs(struct beiscsi_hba *phba)
{
struct pci_dev *pcidev = phba->pcidev;
@@ -1072,7 +1057,7 @@ free_msix_irqs:
void hwi_ring_cq_db(struct beiscsi_hba *phba,
unsigned int id, unsigned int num_processed,
- unsigned char rearm, unsigned char event)
+ unsigned char rearm)
{
u32 val = 0;
@@ -1147,6 +1132,7 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
{
struct sgl_handle *psgl_handle;
+ spin_lock_bh(&phba->io_sgl_lock);
if (phba->io_sgl_hndl_avbl) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO,
"BM_%d : In alloc_io_sgl_handle,"
@@ -1164,12 +1150,14 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
phba->io_sgl_alloc_index++;
} else
psgl_handle = NULL;
+ spin_unlock_bh(&phba->io_sgl_lock);
return psgl_handle;
}
static void
free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
{
+ spin_lock_bh(&phba->io_sgl_lock);
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_IO,
"BM_%d : In free_,io_sgl_free_index=%d\n",
phba->io_sgl_free_index);
@@ -1184,6 +1172,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
"value there=%p\n", phba->io_sgl_free_index,
phba->io_sgl_hndl_base
[phba->io_sgl_free_index]);
+ spin_unlock_bh(&phba->io_sgl_lock);
return;
}
phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle;
@@ -1192,39 +1181,62 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
phba->io_sgl_free_index = 0;
else
phba->io_sgl_free_index++;
+ spin_unlock_bh(&phba->io_sgl_lock);
+}
+
+static inline struct wrb_handle *
+beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context,
+ unsigned int wrbs_per_cxn)
+{
+ struct wrb_handle *pwrb_handle;
+
+ spin_lock_bh(&pwrb_context->wrb_lock);
+ pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index];
+ pwrb_context->wrb_handles_available--;
+ if (pwrb_context->alloc_index == (wrbs_per_cxn - 1))
+ pwrb_context->alloc_index = 0;
+ else
+ pwrb_context->alloc_index++;
+ spin_unlock_bh(&pwrb_context->wrb_lock);
+
+ return pwrb_handle;
}
/**
* alloc_wrb_handle - To allocate a wrb handle
* @phba: The hba pointer
* @cid: The cid to use for allocation
+ * @pwrb_context: ptr to ptr to wrb context
*
* This happens under session_lock until submission to chip
*/
-struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid)
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ struct hwi_wrb_context **pcontext)
{
struct hwi_wrb_context *pwrb_context;
struct hwi_controller *phwi_ctrlr;
- struct wrb_handle *pwrb_handle, *pwrb_handle_tmp;
uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
phwi_ctrlr = phba->phwi_ctrlr;
pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
- if (pwrb_context->wrb_handles_available >= 2) {
- pwrb_handle = pwrb_context->pwrb_handle_base[
- pwrb_context->alloc_index];
- pwrb_context->wrb_handles_available--;
- if (pwrb_context->alloc_index ==
- (phba->params.wrbs_per_cxn - 1))
- pwrb_context->alloc_index = 0;
- else
- pwrb_context->alloc_index++;
- pwrb_handle_tmp = pwrb_context->pwrb_handle_base[
- pwrb_context->alloc_index];
- pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index;
- } else
- pwrb_handle = NULL;
- return pwrb_handle;
+ /* return the context address */
+ *pcontext = pwrb_context;
+ return beiscsi_get_wrb_handle(pwrb_context, phba->params.wrbs_per_cxn);
+}
+
+static inline void
+beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context,
+ struct wrb_handle *pwrb_handle,
+ unsigned int wrbs_per_cxn)
+{
+ spin_lock_bh(&pwrb_context->wrb_lock);
+ pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
+ pwrb_context->wrb_handles_available++;
+ if (pwrb_context->free_index == (wrbs_per_cxn - 1))
+ pwrb_context->free_index = 0;
+ else
+ pwrb_context->free_index++;
+ spin_unlock_bh(&pwrb_context->wrb_lock);
}
/**
@@ -1239,13 +1251,9 @@ static void
free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
struct wrb_handle *pwrb_handle)
{
- pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle;
- pwrb_context->wrb_handles_available++;
- if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1))
- pwrb_context->free_index = 0;
- else
- pwrb_context->free_index++;
-
+ beiscsi_put_wrb_handle(pwrb_context,
+ pwrb_handle,
+ phba->params.wrbs_per_cxn);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
"BM_%d : FREE WRB: pwrb_handle=%p free_index=0x%x"
@@ -1258,6 +1266,7 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
{
struct sgl_handle *psgl_handle;
+ spin_lock_bh(&phba->mgmt_sgl_lock);
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;
@@ -1275,13 +1284,14 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
phba->eh_sgl_alloc_index++;
} else
psgl_handle = NULL;
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
return psgl_handle;
}
void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
{
-
+ spin_lock_bh(&phba->mgmt_sgl_lock);
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BM_%d : In free_mgmt_sgl_handle,"
"eh_sgl_free_index=%d\n",
@@ -1296,6 +1306,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
"BM_%d : Double Free in eh SGL ,"
"eh_sgl_free_index=%d\n",
phba->eh_sgl_free_index);
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
return;
}
phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle;
@@ -1305,6 +1316,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
phba->eh_sgl_free_index = 0;
else
phba->eh_sgl_free_index++;
+ spin_unlock_bh(&phba->mgmt_sgl_lock);
}
static void
@@ -2029,7 +2041,7 @@ static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn,
phwi_ctrlr, cri_index));
}
-static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
+void beiscsi_process_mcc_cq(struct beiscsi_hba *phba)
{
struct be_queue_info *mcc_cq;
struct be_mcc_compl *mcc_compl;
@@ -2039,31 +2051,15 @@ static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
mcc_compl = queue_tail_node(mcc_cq);
mcc_compl->flags = le32_to_cpu(mcc_compl->flags);
while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) {
-
if (num_processed >= 32) {
hwi_ring_cq_db(phba, mcc_cq->id,
- num_processed, 0, 0);
+ num_processed, 0);
num_processed = 0;
}
if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) {
- /* Interpret flags as an async trailer */
- if (is_link_state_evt(mcc_compl->flags))
- /* Interpret compl as a async link evt */
- beiscsi_async_link_state_process(phba,
- (struct be_async_event_link_state *) mcc_compl);
- else {
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_MBOX,
- "BM_%d : Unsupported Async Event, flags"
- " = 0x%08x\n",
- mcc_compl->flags);
- if (phba->state & BE_ADAPTER_LINK_UP) {
- phba->state |= BE_ADAPTER_CHECK_BOOT;
- phba->get_boot = BE_GET_BOOT_RETRIES;
- }
- }
+ beiscsi_process_async_event(phba, mcc_compl);
} else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) {
- be_mcc_compl_process_isr(&phba->ctrl, mcc_compl);
- atomic_dec(&phba->ctrl.mcc_obj.q.used);
+ beiscsi_process_mcc_compl(&phba->ctrl, mcc_compl);
}
mcc_compl->flags = 0;
@@ -2074,24 +2070,24 @@ static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
}
if (num_processed > 0)
- hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1, 0);
-
+ hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1);
}
/**
* beiscsi_process_cq()- Process the Completion Queue
* @pbe_eq: Event Q on which the Completion has come
+ * @budget: Max number of events to processed
*
* return
* Number of Completion Entries processed.
**/
-unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
+unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
{
struct be_queue_info *cq;
struct sol_cqe *sol;
struct dmsg_cqe *dmsg;
+ unsigned int total = 0;
unsigned int num_processed = 0;
- unsigned int tot_nump = 0;
unsigned short code = 0, cid = 0;
uint16_t cri_index = 0;
struct beiscsi_conn *beiscsi_conn;
@@ -2142,12 +2138,12 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
beiscsi_ep = ep->dd_data;
beiscsi_conn = beiscsi_ep->conn;
- if (num_processed >= 32) {
- hwi_ring_cq_db(phba, cq->id,
- num_processed, 0, 0);
- tot_nump += num_processed;
+ /* replenish cq */
+ if (num_processed == 32) {
+ hwi_ring_cq_db(phba, cq->id, 32, 0);
num_processed = 0;
}
+ total++;
switch (code) {
case SOL_CMD_COMPLETE:
@@ -2192,7 +2188,13 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
"BM_%d : Ignoring %s[%d] on CID : %d\n",
cqe_desc[code], code, cid);
break;
+ case CXN_KILLED_HDR_DIGEST_ERR:
case SOL_CMD_KILLED_DATA_DIGEST_ERR:
+ beiscsi_log(phba, KERN_ERR,
+ BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
+ "BM_%d : Cmd Notification %s[%d] on CID : %d\n",
+ cqe_desc[code], code, cid);
+ break;
case CMD_KILLED_INVALID_STATSN_RCVD:
case CMD_KILLED_INVALID_R2T_RCVD:
case CMD_CXN_KILLED_LUN_INVALID:
@@ -2218,7 +2220,6 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
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:
@@ -2253,13 +2254,12 @@ proc_next_cqe:
queue_tail_inc(cq);
sol = queue_tail_node(cq);
num_processed++;
+ if (total == budget)
+ break;
}
- if (num_processed > 0) {
- tot_nump += num_processed;
- hwi_ring_cq_db(phba, cq->id, num_processed, 1, 0);
- }
- return tot_nump;
+ hwi_ring_cq_db(phba, cq->id, num_processed, 1);
+ return total;
}
void beiscsi_process_all_cqs(struct work_struct *work)
@@ -2279,36 +2279,52 @@ void beiscsi_process_all_cqs(struct work_struct *work)
spin_lock_irqsave(&phba->isr_lock, flags);
pbe_eq->todo_mcc_cq = false;
spin_unlock_irqrestore(&phba->isr_lock, flags);
- beiscsi_process_mcc_isr(phba);
+ beiscsi_process_mcc_cq(phba);
}
if (pbe_eq->todo_cq) {
spin_lock_irqsave(&phba->isr_lock, flags);
pbe_eq->todo_cq = false;
spin_unlock_irqrestore(&phba->isr_lock, flags);
- beiscsi_process_cq(pbe_eq);
+ beiscsi_process_cq(pbe_eq, BE2_MAX_NUM_CQ_PROC);
}
/* rearm EQ for further interrupts */
hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
-static int be_iopoll(struct blk_iopoll *iop, int budget)
+static int be_iopoll(struct irq_poll *iop, int budget)
{
- unsigned int ret;
+ unsigned int ret, num_eq_processed;
struct beiscsi_hba *phba;
struct be_eq_obj *pbe_eq;
+ struct be_eq_entry *eqe = NULL;
+ struct be_queue_info *eq;
+ num_eq_processed = 0;
pbe_eq = container_of(iop, struct be_eq_obj, iopoll);
- ret = beiscsi_process_cq(pbe_eq);
+ phba = pbe_eq->phba;
+ eq = &pbe_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);
+ num_eq_processed++;
+ }
+
+ hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
+
+ ret = beiscsi_process_cq(pbe_eq, budget);
pbe_eq->cq_count += ret;
if (ret < budget) {
- phba = pbe_eq->phba;
- blk_iopoll_complete(iop);
+ irq_poll_complete(iop);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
- "BM_%d : rearm pbe_eq->q.id =%d\n",
- pbe_eq->q.id);
+ "BM_%d : rearm pbe_eq->q.id =%d ret %d\n",
+ pbe_eq->q.id, ret);
hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
return ret;
@@ -2502,7 +2518,7 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
* @pwrb: ptr to the WRB entry
* @task: iscsi task which is to be executed
**/
-static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
+static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
{
struct iscsi_sge *psgl;
struct beiscsi_io_task *io_task = task->dd_data;
@@ -2534,6 +2550,9 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
task->data,
task->data_count,
PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(phba->pcidev,
+ io_task->mtask_addr))
+ return -ENOMEM;
io_task->mtask_data_count = task->data_count;
} else
io_task->mtask_addr = 0;
@@ -2578,6 +2597,7 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106);
}
AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
+ return 0;
}
/**
@@ -2706,8 +2726,10 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba)
phwi_ctrlr->wrb_context = kzalloc(sizeof(struct hwi_wrb_context) *
phba->params.cxns_per_ctrl,
GFP_KERNEL);
- if (!phwi_ctrlr->wrb_context)
+ if (!phwi_ctrlr->wrb_context) {
+ kfree(phba->phwi_ctrlr);
return -ENOMEM;
+ }
phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr),
GFP_KERNEL);
@@ -2904,6 +2926,7 @@ static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
}
num_cxn_wrbh--;
}
+ spin_lock_init(&pwrb_context->wrb_lock);
}
idx = 0;
for (index = 0; index < phba->params.cxns_per_ctrl; index++) {
@@ -3184,7 +3207,7 @@ be_sgl_create_contiguous(void *virtual_address,
{
WARN_ON(!virtual_address);
WARN_ON(!physical_address);
- WARN_ON(!length > 0);
+ WARN_ON(!length);
WARN_ON(!sgl);
sgl->va = virtual_address;
@@ -3866,6 +3889,8 @@ static int hwi_init_port(struct beiscsi_hba *phba)
phwi_context->min_eqd = 0;
phwi_context->cur_eqd = 0;
be_cmd_fw_initialize(&phba->ctrl);
+ /* set optic state to unknown */
+ phba->optic_state = 0xff;
status = beiscsi_create_eqs(phba, phwi_context);
if (status != 0) {
@@ -4384,7 +4409,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
goto boot_freemem;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ ret = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
@@ -4468,6 +4493,7 @@ put_shost:
scsi_host_put(phba->shost);
free_kset:
iscsi_boot_destroy_kset(phba->boot_kset);
+ phba->boot_kset = NULL;
return -ENOMEM;
}
@@ -4607,11 +4633,9 @@ beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
}
if (io_task->psgl_handle) {
- spin_lock_bh(&phba->mgmt_sgl_lock);
free_mgmt_sgl_handle(phba,
io_task->psgl_handle);
io_task->psgl_handle = NULL;
- spin_unlock_bh(&phba->mgmt_sgl_lock);
}
if (io_task->mtask_addr) {
@@ -4657,9 +4681,7 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
}
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;
}
@@ -4678,6 +4700,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_offload_params *params)
{
struct wrb_handle *pwrb_handle;
+ struct hwi_wrb_context *pwrb_context = NULL;
struct beiscsi_hba *phba = beiscsi_conn->phba;
struct iscsi_task *task = beiscsi_conn->task;
struct iscsi_session *session = task->conn->session;
@@ -4692,14 +4715,17 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
beiscsi_cleanup_task(task);
spin_unlock_bh(&session->back_lock);
- pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid);
+ pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid,
+ &pwrb_context);
/* Check for the adapter family */
if (is_chip_be2_be3r(phba))
beiscsi_offload_cxn_v0(params, pwrb_handle,
- phba->init_mem);
+ phba->init_mem,
+ pwrb_context);
else
- beiscsi_offload_cxn_v2(params, pwrb_handle);
+ beiscsi_offload_cxn_v2(params, pwrb_handle,
+ pwrb_context);
be_dws_le_to_cpu(pwrb_handle->pwrb,
sizeof(struct iscsi_target_context_update_wrb));
@@ -4710,6 +4736,20 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
iowrite32(doorbell, phba->db_va +
beiscsi_conn->doorbell_offset);
+
+ /*
+ * There is no completion for CONTEXT_UPDATE. The completion of next
+ * WRB posted guarantees FW's processing and DMA'ing of it.
+ * Use beiscsi_put_wrb_handle to put it back in the pool which makes
+ * sure zero'ing or reuse of the WRB only after wrbs_per_cxn.
+ */
+ beiscsi_put_wrb_handle(pwrb_context, pwrb_handle,
+ phba->params.wrbs_per_cxn);
+ beiscsi_log(phba, KERN_INFO,
+ BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
+ "BM_%d : put CONTEXT_UPDATE pwrb_handle=%p free_index=0x%x wrb_handles_available=%d\n",
+ pwrb_handle, pwrb_context->free_index,
+ pwrb_context->wrb_handles_available);
}
static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt,
@@ -4757,9 +4797,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->pwrb_handle = NULL;
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) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
@@ -4769,7 +4807,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
goto free_hndls;
}
io_task->pwrb_handle = alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid,
+ &io_task->pwrb_context);
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
@@ -4783,10 +4822,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
beiscsi_conn->task = task;
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) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
@@ -4803,7 +4840,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->psgl_handle;
io_task->pwrb_handle =
alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid,
+ &io_task->pwrb_context);
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
@@ -4824,9 +4862,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
beiscsi_conn->plogin_wrb_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) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
@@ -4839,7 +4875,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
}
io_task->pwrb_handle =
alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid,
+ &io_task->pwrb_context);
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
@@ -4860,15 +4897,11 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
return 0;
free_io_hndls:
- spin_lock(&phba->io_sgl_lock);
free_io_sgl_handle(phba, io_task->psgl_handle);
- spin_unlock(&phba->io_sgl_lock);
goto free_hndls;
free_mgmt_hndls:
- spin_lock(&phba->mgmt_sgl_lock);
free_mgmt_sgl_handle(phba, io_task->psgl_handle);
io_task->psgl_handle = NULL;
- spin_unlock(&phba->mgmt_sgl_lock);
free_hndls:
phwi_ctrlr = phba->phwi_ctrlr;
cri_index = BE_GET_CRI_FROM_CID(
@@ -4896,7 +4929,6 @@ int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg,
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) {
@@ -4925,7 +4957,12 @@ int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg,
hwi_write_sgl_v2(pwrb, sg, num_sg, io_task);
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb,
- io_task->pwrb_handle->nxt_wrb_index);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
@@ -4952,7 +4989,6 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
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) {
@@ -4982,7 +5018,13 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
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);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
+
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
@@ -5005,6 +5047,7 @@ static int beiscsi_mtask(struct iscsi_task *task)
unsigned int doorbell = 0;
unsigned int cid;
unsigned int pwrb_typeoffset = 0;
+ int ret = 0;
cid = beiscsi_conn->beiscsi_conn_cid;
pwrb = io_task->pwrb_handle->pwrb;
@@ -5020,7 +5063,13 @@ static int beiscsi_mtask(struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb,
task->data_count);
AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
- io_task->pwrb_handle->nxt_wrb_index);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
+
pwrb_typeoffset = BE_WRB_TYPE_OFFSET;
} else {
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb,
@@ -5032,7 +5081,13 @@ static int beiscsi_mtask(struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb,
task->data_count);
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb,
- io_task->pwrb_handle->nxt_wrb_index);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
+
pwrb_typeoffset = SKH_WRB_TYPE_OFFSET;
}
@@ -5041,7 +5096,7 @@ static int beiscsi_mtask(struct iscsi_task *task)
case ISCSI_OP_LOGIN:
AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1);
ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_NOOP_OUT:
if (task->hdr->ttt != ISCSI_RESERVED_TAG) {
@@ -5061,19 +5116,19 @@ static int beiscsi_mtask(struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
dmsg, pwrb, 0);
}
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_TEXT:
ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_SCSI_TMFUNC:
ADAPTER_SET_WRB_TYPE(pwrb, INI_TMF_CMD, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_LOGOUT:
ADAPTER_SET_WRB_TYPE(pwrb, HWH_TYPE_LOGOUT, pwrb_typeoffset);
- hwi_write_buffer(pwrb, task);
+ ret = hwi_write_buffer(pwrb, task);
break;
default:
@@ -5084,6 +5139,9 @@ static int beiscsi_mtask(struct iscsi_task *task)
return -EINVAL;
}
+ if (ret)
+ return ret;
+
/* Set the task type */
io_task->wrb_type = (is_chip_be2_be3r(phba)) ?
AMAP_GET_BITS(struct amap_iscsi_wrb, type, pwrb) :
@@ -5102,23 +5160,21 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
{
struct beiscsi_io_task *io_task = task->dd_data;
struct scsi_cmnd *sc = task->sc;
- struct beiscsi_hba *phba = NULL;
+ struct beiscsi_hba *phba;
struct scatterlist *sg;
int num_sg;
unsigned int writedir = 0, xferlen = 0;
- phba = ((struct beiscsi_conn *)task->conn->dd_data)->phba;
+ if (!io_task->conn->login_in_progress)
+ task->hdr->exp_statsn = 0;
if (!sc)
return beiscsi_mtask(task);
io_task->scsi_cmnd = sc;
num_sg = scsi_dma_map(sc);
+ phba = io_task->conn->phba;
if (num_sg < 0) {
- struct iscsi_conn *conn = task->conn;
- struct beiscsi_hba *phba = NULL;
-
- phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_ISCSI,
"BM_%d : scsi_dma_map Failed "
@@ -5181,12 +5237,13 @@ static int beiscsi_bsg_request(struct bsg_job *job)
rc = wait_event_interruptible_timeout(
phba->ctrl.mcc_wait[tag],
- phba->ctrl.mcc_numtag[tag],
+ phba->ctrl.mcc_tag_status[tag],
msecs_to_jiffies(
BEISCSI_HOST_MBX_TIMEOUT));
- extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
- status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
- free_mcc_tag(&phba->ctrl, tag);
+ extd_status = (phba->ctrl.mcc_tag_status[tag] &
+ CQE_STATUS_ADDL_MASK) >> CQE_STATUS_ADDL_SHIFT;
+ status = phba->ctrl.mcc_tag_status[tag] & CQE_STATUS_MASK;
+ free_mcc_wrb(&phba->ctrl, tag);
resp = (struct be_cmd_resp_hdr *)nonemb_cmd.va;
sg_copy_from_buffer(job->reply_payload.sg_list,
job->reply_payload.sg_cnt,
@@ -5247,21 +5304,18 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
if (phba->msix_enabled) {
for (i = 0; i <= phba->num_cpus; i++) {
msix_vec = phba->msix_entries[i].vector;
- synchronize_irq(msix_vec);
free_irq(msix_vec, &phwi_context->be_eq[i]);
kfree(phba->msi_name[i]);
}
} else
- if (phba->pcidev->irq) {
- synchronize_irq(phba->pcidev->irq);
+ if (phba->pcidev->irq)
free_irq(phba->pcidev->irq, phba);
- }
pci_disable_msix(phba->pcidev);
cancel_delayed_work_sync(&phba->beiscsi_hw_check_task);
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
+ irq_poll_disable(&pbe_eq->iopoll);
}
if (unload_state == BEISCSI_CLEAN_UNLOAD) {
@@ -5283,7 +5337,6 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
static void beiscsi_remove(struct pci_dev *pcidev)
{
-
struct beiscsi_hba *phba = NULL;
phba = pci_get_drvdata(pcidev);
@@ -5293,9 +5346,9 @@ static void beiscsi_remove(struct pci_dev *pcidev)
}
beiscsi_destroy_def_ifaces(phba);
- beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
iscsi_boot_destroy_kset(phba->boot_kset);
iscsi_host_remove(phba->shost);
+ beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
pci_dev_put(phba->pcidev);
iscsi_host_free(phba->shost);
pci_disable_pcie_error_reporting(pcidev);
@@ -5304,23 +5357,6 @@ static void beiscsi_remove(struct pci_dev *pcidev)
pci_disable_device(pcidev);
}
-static void beiscsi_shutdown(struct pci_dev *pcidev)
-{
-
- struct beiscsi_hba *phba = NULL;
-
- phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev);
- if (!phba) {
- dev_err(&pcidev->dev, "beiscsi_shutdown called with no phba\n");
- return;
- }
-
- phba->state = BE_ADAPTER_STATE_SHUTDOWN;
- iscsi_host_for_each_session(phba->shost, be2iscsi_fail_session);
- beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
- pci_disable_device(pcidev);
-}
-
static void beiscsi_msix_enable(struct beiscsi_hba *phba)
{
int i, status;
@@ -5383,7 +5419,7 @@ static void be_eqd_update(struct beiscsi_hba *phba)
if (num) {
tag = be_cmd_modify_eq_delay(phba, set_eqd, num);
if (tag)
- beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
}
}
@@ -5534,11 +5570,17 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
phba->shost->max_id = phba->params.cxns_per_ctrl;
phba->shost->can_queue = phba->params.ios_per_ctrl;
ret = hwi_init_controller(phba);
+ if (ret) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BM_%d : beiscsi_eeh_resume -"
+ "Failed to initialize beiscsi_hba.\n");
+ goto ret_err;
+ }
for (i = 0; i < MAX_MCC_CMD; i++) {
init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
phba->ctrl.mcc_tag[i] = i + 1;
- phba->ctrl.mcc_numtag[i + 1] = 0;
+ phba->ctrl.mcc_tag_status[i + 1] = 0;
phba->ctrl.mcc_tag_available++;
}
@@ -5547,9 +5589,8 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
}
i = (phba->msix_enabled) ? i : 0;
@@ -5641,6 +5682,9 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
goto hba_free;
}
+ /*
+ * FUNCTION_RESET should clean up any stale info in FW for this fn
+ */
ret = beiscsi_cmd_reset_function(phba);
if (ret) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -5664,6 +5708,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
"BM_%d : Error getting fw config\n");
goto free_port;
}
+ mgmt_get_port_name(&phba->ctrl, phba);
+ beiscsi_get_params(phba);
if (enable_msix)
find_num_cpus(phba);
@@ -5681,7 +5727,6 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
}
phba->shost->max_id = phba->params.cxns_per_ctrl;
- beiscsi_get_params(phba);
phba->shost->can_queue = phba->params.ios_per_ctrl;
ret = beiscsi_init_port(phba);
if (ret < 0) {
@@ -5694,7 +5739,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
for (i = 0; i < MAX_MCC_CMD; i++) {
init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
phba->ctrl.mcc_tag[i] = i + 1;
- phba->ctrl.mcc_numtag[i + 1] = 0;
+ phba->ctrl.mcc_tag_status[i + 1] = 0;
phba->ctrl.mcc_tag_available++;
memset(&phba->ctrl.ptag_state[i].tag_mem_state, 0,
sizeof(struct be_dma_mem));
@@ -5720,9 +5765,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
}
i = (phba->msix_enabled) ? i : 0;
@@ -5763,7 +5807,7 @@ free_blkenbld:
destroy_workqueue(phba->wq);
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
+ irq_poll_disable(&pbe_eq->iopoll);
}
free_twq:
beiscsi_clean_port(phba);
@@ -5829,7 +5873,6 @@ static struct pci_driver beiscsi_pci_driver = {
.name = DRV_NAME,
.probe = beiscsi_dev_probe,
.remove = beiscsi_remove,
- .shutdown = beiscsi_shutdown,
.id_table = beiscsi_pci_id_table,
.err_handler = &beiscsi_eeh_handlers
};
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 51366de..30a4606 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -36,7 +36,7 @@
#include <scsi/scsi_transport_iscsi.h>
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "10.6.0.0"
+#define BUILD_STR "11.0.0.0"
#define BE_NAME "Emulex OneConnect" \
"Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
@@ -63,6 +63,7 @@
#define BE2_SGE 32
#define BE2_DEFPDU_HDR_SZ 64
#define BE2_DEFPDU_DATA_SZ 8192
+#define BE2_MAX_NUM_CQ_PROC 512
#define MAX_CPUS 64
#define BEISCSI_MAX_NUM_CPUS 7
@@ -103,8 +104,7 @@
#define BE_ADAPTER_LINK_UP 0x001
#define BE_ADAPTER_LINK_DOWN 0x002
#define BE_ADAPTER_PCI_ERR 0x004
-#define BE_ADAPTER_STATE_SHUTDOWN 0x008
-#define BE_ADAPTER_CHECK_BOOT 0x010
+#define BE_ADAPTER_CHECK_BOOT 0x008
#define BEISCSI_CLEAN_UNLOAD 0x01
@@ -304,6 +304,7 @@ struct invalidate_command_table {
#define BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cri) \
(phwi_ctrlr->wrb_context[cri].ulp_num)
struct hwi_wrb_context {
+ spinlock_t wrb_lock;
struct list_head wrb_handle_list;
struct list_head wrb_handle_drvr_list;
struct wrb_handle **pwrb_handle_base;
@@ -398,7 +399,9 @@ struct beiscsi_hba {
* group together since they are used most frequently
* for cid to cri conversion
*/
+#define BEISCSI_PHYS_PORT_MAX 4
unsigned int phys_port;
+ /* valid values of phys_port id are 0, 1, 2, 3 */
unsigned int eqid_count;
unsigned int cqid_count;
unsigned int iscsi_cid_start[BEISCSI_ULP_COUNT];
@@ -416,6 +419,7 @@ struct beiscsi_hba {
} fw_config;
unsigned int state;
+ u8 optic_state;
int get_boot;
bool fw_timeout;
bool ue_detected;
@@ -423,6 +427,8 @@ struct beiscsi_hba {
bool mac_addr_set;
u8 mac_address[ETH_ALEN];
+ u8 port_name;
+ u8 port_speed;
char fw_ver_str[BEISCSI_VER_STRLEN];
char wq_name[20];
struct workqueue_struct *wq; /* The actuak work queue */
@@ -502,6 +508,7 @@ struct beiscsi_io_task {
struct sgl_handle *psgl_handle;
struct beiscsi_conn *conn;
struct scsi_cmnd *scsi_cmnd;
+ struct hwi_wrb_context *pwrb_context;
unsigned int cmd_sn;
unsigned int flags;
unsigned short cid;
@@ -833,7 +840,8 @@ struct amap_iscsi_wrb_v2 {
} __packed;
-struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid);
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ struct hwi_wrb_context **pcontext);
void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
@@ -843,9 +851,10 @@ void beiscsi_free_mgmt_task_handles(struct beiscsi_conn *beiscsi_conn,
void hwi_ring_cq_db(struct beiscsi_hba *phba,
unsigned int id, unsigned int num_processed,
- unsigned char rearm, unsigned char event);
+ unsigned char rearm);
-unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq);
+unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget);
+void beiscsi_process_mcc_cq(struct beiscsi_hba *phba);
static inline bool beiscsi_error(struct beiscsi_hba *phba)
{
@@ -1044,7 +1053,6 @@ enum hwh_type_enum {
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;
@@ -1073,12 +1081,14 @@ struct hwi_context_memory {
#define BEISCSI_LOG_CONFIG 0x0020 /* CONFIG Code Path */
#define BEISCSI_LOG_ISCSI 0x0040 /* SCSI/iSCSI Protocol related Logs */
+#define __beiscsi_log(phba, level, fmt, arg...) \
+ shost_printk(level, phba->shost, fmt, __LINE__, ##arg)
+
#define beiscsi_log(phba, level, mask, fmt, arg...) \
do { \
uint32_t log_value = phba->attr_log_enable; \
if (((mask) & log_value) || (level[1] <= '3')) \
- shost_printk(level, phba->shost, \
- fmt, __LINE__, ##arg); \
-} while (0)
+ __beiscsi_log(phba, level, fmt, ##arg); \
+} while (0);
#endif
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 1b2bd04..83926e2 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -161,20 +161,17 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct be_cmd_req_modify_eq_delay *req;
- unsigned int tag = 0;
+ unsigned int tag;
int i;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
-
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
@@ -187,8 +184,8 @@ int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
cpu_to_le32(set_eqd[i].delay_multiplier);
}
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -209,22 +206,20 @@ unsigned int mgmt_reopen_session(struct beiscsi_hba *phba,
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct be_cmd_reopen_session_req *req;
- unsigned int tag = 0;
+ unsigned int tag;
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In bescsi_get_boot_target\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_DRIVER_REOPEN_ALL_SESSIONS,
@@ -234,8 +229,8 @@ unsigned int mgmt_reopen_session(struct beiscsi_hba *phba,
req->reopen_type = reopen_type;
req->session_handle = sess_handle;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -244,29 +239,27 @@ unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba)
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct be_cmd_get_boot_target_req *req;
- unsigned int tag = 0;
+ unsigned int tag;
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In bescsi_get_boot_target\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET,
sizeof(struct be_cmd_get_boot_target_resp));
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -276,7 +269,7 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
{
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
- unsigned int tag = 0;
+ unsigned int tag;
struct be_cmd_get_session_req *req;
struct be_cmd_get_session_resp *resp;
struct be_sge *sge;
@@ -285,22 +278,17 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In beiscsi_get_session_info\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
nonemb_cmd->size = sizeof(*resp);
req = nonemb_cmd->va;
memset(req, 0, sizeof(*req));
- wrb = wrb_from_mccq(phba);
sge = nonembedded_sgl(wrb);
- wrb->tag0 |= tag;
-
-
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_SESSION_GET_A_SESSION,
@@ -310,12 +298,54 @@ unsigned int mgmt_get_session_info(struct beiscsi_hba *phba,
sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd->size);
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
/**
+ * mgmt_get_port_name()- Get port name for the function
+ * @ctrl: ptr to Ctrl Info
+ * @phba: ptr to the dev priv structure
+ *
+ * Get the alphanumeric character for port
+ *
+ **/
+int mgmt_get_port_name(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba)
+{
+ int ret = 0;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_get_port_name *ioctl;
+
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ memset(wrb, 0, sizeof(*wrb));
+ ioctl = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*ioctl), true, 0);
+ be_cmd_hdr_prepare(&ioctl->h.req_hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_PORT_NAME,
+ EMBED_MBX_MAX_PAYLOAD_SIZE);
+ ret = be_mbox_notify(ctrl);
+ phba->port_name = 0;
+ if (!ret) {
+ phba->port_name = ioctl->p.resp.port_names >>
+ (phba->fw_config.phys_port * 8) & 0xff;
+ } else {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : GET_PORT_NAME ret 0x%x status 0x%x\n",
+ ret, ioctl->h.resp_hdr.status);
+ }
+
+ if (phba->port_name == 0)
+ phba->port_name = '?';
+
+ mutex_unlock(&ctrl->mbox_lock);
+ return ret;
+}
+
+/**
* mgmt_get_fw_config()- Get the FW config for the function
* @ctrl: ptr to Ctrl Info
* @phba: ptr to the dev priv structure
@@ -331,91 +361,147 @@ int 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;
+ struct be_fw_cfg *pfw_cfg = embedded_payload(wrb);
+ uint32_t cid_count, icd_count;
+ int status = -EINVAL;
+ uint8_t ulp_num = 0;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*pfw_cfg), true, 0);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
-
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ be_cmd_hdr_prepare(&pfw_cfg->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
EMBED_MBX_MAX_PAYLOAD_SIZE);
- status = be_mbox_notify(ctrl);
- if (!status) {
- uint8_t ulp_num = 0;
- struct be_fw_cfg *pfw_cfg;
- pfw_cfg = req;
- if (!is_chip_be2_be3r(phba)) {
- phba->fw_config.eqid_count = pfw_cfg->eqid_count;
- phba->fw_config.cqid_count = pfw_cfg->cqid_count;
+ if (be_mbox_notify(ctrl)) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : Failed in mgmt_get_fw_config\n");
+ goto fail_init;
+ }
- beiscsi_log(phba, KERN_INFO,
- BEISCSI_LOG_INIT,
- "BG_%d : EQ_Count : %d CQ_Count : %d\n",
- phba->fw_config.eqid_count,
+ /* FW response formats depend on port id */
+ phba->fw_config.phys_port = pfw_cfg->phys_port;
+ if (phba->fw_config.phys_port >= BEISCSI_PHYS_PORT_MAX) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid physical port id %d\n",
+ phba->fw_config.phys_port);
+ goto fail_init;
+ }
+
+ /* populate and check FW config against min and max values */
+ if (!is_chip_be2_be3r(phba)) {
+ phba->fw_config.eqid_count = pfw_cfg->eqid_count;
+ phba->fw_config.cqid_count = pfw_cfg->cqid_count;
+ if (phba->fw_config.eqid_count == 0 ||
+ phba->fw_config.eqid_count > 2048) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid EQ count %d\n",
+ phba->fw_config.eqid_count);
+ goto fail_init;
+ }
+ if (phba->fw_config.cqid_count == 0 ||
+ phba->fw_config.cqid_count > 4096) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : invalid CQ count %d\n",
phba->fw_config.cqid_count);
+ goto fail_init;
}
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : EQ_Count : %d CQ_Count : %d\n",
+ phba->fw_config.eqid_count,
+ phba->fw_config.cqid_count);
+ }
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
- if (pfw_cfg->ulp[ulp_num].ulp_mode &
- BEISCSI_ULP_ISCSI_INI_MODE)
- set_bit(ulp_num,
- &phba->fw_config.ulp_supported);
-
- phba->fw_config.phys_port = pfw_cfg->phys_port;
- for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
- if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-
- phba->fw_config.iscsi_cid_start[ulp_num] =
- pfw_cfg->ulp[ulp_num].sq_base;
- phba->fw_config.iscsi_cid_count[ulp_num] =
- pfw_cfg->ulp[ulp_num].sq_count;
-
- phba->fw_config.iscsi_icd_start[ulp_num] =
- pfw_cfg->ulp[ulp_num].icd_base;
- phba->fw_config.iscsi_icd_count[ulp_num] =
- pfw_cfg->ulp[ulp_num].icd_count;
-
- phba->fw_config.iscsi_chain_start[ulp_num] =
- pfw_cfg->chain_icd[ulp_num].chain_base;
- phba->fw_config.iscsi_chain_count[ulp_num] =
- pfw_cfg->chain_icd[ulp_num].chain_count;
-
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : Function loaded on ULP : %d\n"
- "\tiscsi_cid_count : %d\n"
- "\tiscsi_cid_start : %d\n"
- "\t iscsi_icd_count : %d\n"
- "\t iscsi_icd_start : %d\n",
- ulp_num,
- phba->fw_config.
- iscsi_cid_count[ulp_num],
- phba->fw_config.
- iscsi_cid_start[ulp_num],
- phba->fw_config.
- iscsi_icd_count[ulp_num],
- phba->fw_config.
- iscsi_icd_start[ulp_num]);
- }
+ /**
+ * Check on which all ULP iSCSI Protocol is loaded.
+ * Set the Bit for those ULP. This set flag is used
+ * at all places in the code to check on which ULP
+ * iSCSi Protocol is loaded
+ **/
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
+ if (pfw_cfg->ulp[ulp_num].ulp_mode &
+ BEISCSI_ULP_ISCSI_INI_MODE) {
+ set_bit(ulp_num, &phba->fw_config.ulp_supported);
+
+ /* Get the CID, ICD and Chain count for each ULP */
+ phba->fw_config.iscsi_cid_start[ulp_num] =
+ pfw_cfg->ulp[ulp_num].sq_base;
+ phba->fw_config.iscsi_cid_count[ulp_num] =
+ pfw_cfg->ulp[ulp_num].sq_count;
+
+ phba->fw_config.iscsi_icd_start[ulp_num] =
+ pfw_cfg->ulp[ulp_num].icd_base;
+ phba->fw_config.iscsi_icd_count[ulp_num] =
+ pfw_cfg->ulp[ulp_num].icd_count;
+
+ phba->fw_config.iscsi_chain_start[ulp_num] =
+ pfw_cfg->chain_icd[ulp_num].chain_base;
+ phba->fw_config.iscsi_chain_count[ulp_num] =
+ pfw_cfg->chain_icd[ulp_num].chain_count;
+
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : Function loaded on ULP : %d\n"
+ "\tiscsi_cid_count : %d\n"
+ "\tiscsi_cid_start : %d\n"
+ "\t iscsi_icd_count : %d\n"
+ "\t iscsi_icd_start : %d\n",
+ ulp_num,
+ phba->fw_config.
+ iscsi_cid_count[ulp_num],
+ phba->fw_config.
+ iscsi_cid_start[ulp_num],
+ phba->fw_config.
+ iscsi_icd_count[ulp_num],
+ phba->fw_config.
+ iscsi_icd_start[ulp_num]);
}
+ }
- phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
- BEISCSI_FUNC_DUA_MODE);
+ if (phba->fw_config.ulp_supported == 0) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d : iSCSI initiator mode not set: ULP0 %x ULP1 %x\n",
+ pfw_cfg->ulp[BEISCSI_ULP0].ulp_mode,
+ pfw_cfg->ulp[BEISCSI_ULP1].ulp_mode);
+ goto fail_init;
+ }
- beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
- "BG_%d : DUA Mode : 0x%x\n",
- phba->fw_config.dual_ulp_aware);
+ /**
+ * ICD is shared among ULPs. Use icd_count of any one loaded ULP
+ **/
+ for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
+ if (test_bit(ulp_num, &phba->fw_config.ulp_supported))
+ break;
+ icd_count = phba->fw_config.iscsi_icd_count[ulp_num];
+ if (icd_count == 0 || icd_count > 65536) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+ "BG_%d: invalid ICD count %d\n", icd_count);
+ goto fail_init;
+ }
- } else {
+ cid_count = BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP0) +
+ BEISCSI_GET_CID_COUNT(phba, BEISCSI_ULP1);
+ if (cid_count == 0 || cid_count > 4096) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
- "BG_%d : Failed in mgmt_get_fw_config\n");
- status = -EINVAL;
+ "BG_%d: invalid CID count %d\n", cid_count);
+ goto fail_init;
}
- spin_unlock(&ctrl->mbox_lock);
+ /**
+ * Check FW is dual ULP aware i.e. can handle either
+ * of the protocols.
+ */
+ phba->fw_config.dual_ulp_aware = (pfw_cfg->function_mode &
+ BEISCSI_FUNC_DUA_MODE);
+
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
+ "BG_%d : DUA Mode : 0x%x\n",
+ phba->fw_config.dual_ulp_aware);
+
+ /* all set, continue using this FW config */
+ status = 0;
+fail_init:
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -440,7 +526,7 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
req = nonemb_cmd.va;
memset(req, 0, sizeof(*req));
- spin_lock(&ctrl->mbox_lock);
+ mutex_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,
@@ -470,7 +556,7 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
} else
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BG_%d : Failed in mgmt_check_supported_fw\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
if (nonemb_cmd.va)
pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
nonemb_cmd.va, nonemb_cmd.dma);
@@ -501,8 +587,9 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
req->region = region;
req->sector = sector;
req->offset = offset;
- spin_lock(&ctrl->mbox_lock);
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
case BEISCSI_WRITE_FLASH:
offset = sector * sector_size + offset;
@@ -521,28 +608,26 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
"BG_%d : Unsupported cmd = 0x%x\n\n",
bsg_req->rqst_data.h_vendor.vendor_cmd[0]);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return -ENOSYS;
}
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
mcc_sge = nonembedded_sgl(wrb);
be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false,
job->request_payload.sg_cnt);
mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
mcc_sge->len = cpu_to_le32(nonemb_cmd->size);
- wrb->tag0 |= tag;
- be_mcc_notify(phba);
+ be_mcc_notify(phba, tag);
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -558,12 +643,19 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
- struct iscsi_cleanup_req *req = embedded_payload(wrb);
- int status = 0;
+ struct be_mcc_wrb *wrb;
+ struct iscsi_cleanup_req *req;
+ unsigned int tag;
+ int status;
- spin_lock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return -EBUSY;
+ }
+ req = embedded_payload(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));
@@ -572,11 +664,12 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num)
req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba, ulp_num));
req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba, ulp_num));
- status = be_mcc_notify_wait(phba);
+ be_mcc_notify(phba, tag);
+ status = be_mcc_compl_poll(phba, tag);
if (status)
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT,
"BG_%d : mgmt_epfw_cleanup , FAILED\n");
- spin_unlock(&ctrl->mbox_lock);
+ mutex_unlock(&ctrl->mbox_lock);
return status;
}
@@ -590,20 +683,18 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
struct be_mcc_wrb *wrb;
struct be_sge *sge;
struct invalidate_commands_params_in *req;
- unsigned int i, tag = 0;
+ unsigned int i, tag;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
req = nonemb_cmd->va;
memset(req, 0, sizeof(*req));
- wrb = wrb_from_mccq(phba);
sge = nonembedded_sgl(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
@@ -621,8 +712,8 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd->size);
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -637,16 +728,14 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
struct iscsi_invalidate_connection_params_in *req;
unsigned int tag = 0;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
- wrb->tag0 |= tag;
- req = embedded_payload(wrb);
+ req = embedded_payload(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,
@@ -658,8 +747,8 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
else
req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE;
req->save_cfg = savecfg_flag;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -669,25 +758,23 @@ unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
struct be_ctrl_info *ctrl = &phba->ctrl;
struct be_mcc_wrb *wrb;
struct tcp_upload_params_in *req;
- unsigned int tag = 0;
+ unsigned int tag;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
- req = embedded_payload(wrb);
- wrb->tag0 |= tag;
+ req = embedded_payload(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;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -722,6 +809,13 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
unsigned short cid = beiscsi_ep->ep_cid;
struct be_sge *sge;
+ if (dst_addr->sa_family != PF_INET && dst_addr->sa_family != PF_INET6) {
+ beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
+ "BG_%d : unknown addr family %d\n",
+ dst_addr->sa_family);
+ return -EINVAL;
+ }
+
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -732,18 +826,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
ptemplate_address = &template_address;
ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address);
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
- sge = nonembedded_sgl(wrb);
+ sge = nonembedded_sgl(wrb);
req = nonemb_cmd->va;
memset(req, 0, sizeof(*req));
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
@@ -760,7 +853,8 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
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) {
+ } else {
+ /* else its PF_INET6 family */
req->ip_address.ip_type = BE2_IPV6;
memcpy(&req->ip_address.addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
@@ -769,14 +863,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
memcpy(&beiscsi_ep->dst6_addr,
&daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
beiscsi_ep->ip_type = BE2_IPV6;
- } else{
- beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
- "BG_%d : unknown addr family %d\n",
- dst_addr->sa_family);
- spin_unlock(&ctrl->mbox_lock);
- free_mcc_tag(&phba->ctrl, tag);
- return -EINVAL;
-
}
req->cid = cid;
i = phba->nxt_cqid++;
@@ -801,35 +887,45 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
req->tcp_window_scale_count = 2;
}
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba)
{
struct be_ctrl_info *ctrl = &phba->ctrl;
- struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
- struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb);
- struct be_cmd_get_all_if_id_req *pbe_allid = req;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_get_all_if_id_req *req;
+ struct be_cmd_get_all_if_id_req *pbe_allid;
+ unsigned int tag;
int status = 0;
- memset(wrb, 0, sizeof(*wrb));
-
- spin_lock(&ctrl->mbox_lock);
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return -EINTR;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return -ENOMEM;
+ }
+ req = embedded_payload(wrb);
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID,
sizeof(*req));
- status = be_mbox_notify(ctrl);
- if (!status)
- phba->interface_handle = pbe_allid->if_hndl_list[0];
- else {
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
+
+ status = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
+ if (status) {
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
"BG_%d : Failed in mgmt_get_all_if_id\n");
+ return -EBUSY;
}
- spin_unlock(&ctrl->mbox_lock);
+
+ pbe_allid = embedded_payload(wrb);
+ phba->interface_handle = pbe_allid->if_hndl_list[0];
return status;
}
@@ -852,27 +948,24 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
unsigned int tag;
int rc = 0;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
rc = -ENOMEM;
goto free_cmd;
}
- wrb = wrb_from_mccq(phba);
- wrb->tag0 |= tag;
sge = nonembedded_sgl(wrb);
-
be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd->dma));
sge->len = cpu_to_le32(nonemb_cmd->size);
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
- rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, nonemb_cmd);
if (resp_buf)
memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
@@ -1003,8 +1096,9 @@ int mgmt_set_ip(struct beiscsi_hba *phba,
uint32_t ip_type;
int rc;
- if (mgmt_get_all_if_id(phba))
- return -EIO;
+ rc = mgmt_get_all_if_id(phba);
+ if (rc)
+ return rc;
ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ?
BE2_IPV6 : BE2_IPV4 ;
@@ -1173,8 +1267,9 @@ int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type,
uint32_t ioctl_size = sizeof(struct be_cmd_get_if_info_resp);
int rc;
- if (mgmt_get_all_if_id(phba))
- return -EIO;
+ rc = mgmt_get_all_if_id(phba);
+ if (rc)
+ return rc;
do {
rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd,
@@ -1245,55 +1340,27 @@ int mgmt_get_nic_conf(struct beiscsi_hba *phba,
unsigned int be_cmd_get_initname(struct beiscsi_hba *phba)
{
- unsigned int tag = 0;
+ unsigned int tag;
struct be_mcc_wrb *wrb;
struct be_cmd_hba_name *req;
struct be_ctrl_info *ctrl = &phba->ctrl;
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
+ if (mutex_lock_interruptible(&ctrl->mbox_lock))
+ return 0;
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
+ return 0;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_CFG_GET_HBA_NAME,
sizeof(*req));
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
- return tag;
-}
-
-unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba)
-{
- unsigned int tag = 0;
- struct be_mcc_wrb *wrb;
- struct be_cmd_ntwk_link_status_req *req;
- struct be_ctrl_info *ctrl = &phba->ctrl;
-
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
- return tag;
- }
-
- wrb = wrb_from_mccq(phba);
- req = embedded_payload(wrb);
- wrb->tag0 |= tag;
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
- OPCODE_COMMON_NTWK_LINK_STATUS_QUERY,
- sizeof(*req));
-
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
return tag;
}
@@ -1330,7 +1397,7 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
return -EAGAIN;
}
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
@@ -1364,7 +1431,7 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
return -EAGAIN;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
@@ -1406,7 +1473,7 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
return -EBUSY;
}
- rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, NULL, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
(BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
@@ -1573,7 +1640,8 @@ beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr,
void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
struct wrb_handle *pwrb_handle,
- struct be_mem_descriptor *mem_descr)
+ struct be_mem_descriptor *mem_descr,
+ struct hwi_wrb_context *pwrb_context)
{
struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
@@ -1617,7 +1685,14 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
max_burst_length) / 32]);
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb,
- pwrb, pwrb_handle->nxt_wrb_index);
+ pwrb, pwrb_handle->wrb_index);
+ if (pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ ptr2nextwrb,
+ pwrb_context->plast_wrb,
+ pwrb_handle->wrb_index);
+ pwrb_context->plast_wrb = pwrb;
+
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,
@@ -1637,7 +1712,8 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
}
void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
- struct wrb_handle *pwrb_handle)
+ struct wrb_handle *pwrb_handle,
+ struct hwi_wrb_context *pwrb_context)
{
struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
@@ -1652,7 +1728,14 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
BE_TGT_CTX_UPDT_CMD);
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
ptr2nextwrb,
- pwrb, pwrb_handle->nxt_wrb_index);
+ pwrb, pwrb_handle->wrb_index);
+ if (pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+ ptr2nextwrb,
+ pwrb_context->plast_wrb,
+ pwrb_handle->wrb_index);
+ pwrb_context->plast_wrb = pwrb;
+
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx,
pwrb, pwrb_handle->wrb_index);
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
@@ -1733,19 +1816,17 @@ int beiscsi_logout_fw_sess(struct beiscsi_hba *phba,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : In bescsi_logout_fwboot_sess\n");
- spin_lock(&ctrl->mbox_lock);
- tag = alloc_mcc_tag(phba);
- if (!tag) {
- spin_unlock(&ctrl->mbox_lock);
+ mutex_lock(&ctrl->mbox_lock);
+ wrb = alloc_mcc_wrb(phba, &tag);
+ if (!wrb) {
+ mutex_unlock(&ctrl->mbox_lock);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : MBX Tag Failure\n");
return -EINVAL;
}
- wrb = wrb_from_mccq(phba);
req = embedded_payload(wrb);
- wrb->tag0 |= tag;
be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
OPCODE_ISCSI_INI_SESSION_LOGOUT_TARGET,
@@ -1753,10 +1834,10 @@ int beiscsi_logout_fw_sess(struct beiscsi_hba *phba,
/* Set the session handle */
req->session_handle = fw_sess_handle;
- be_mcc_notify(phba);
- spin_unlock(&ctrl->mbox_lock);
+ be_mcc_notify(phba, tag);
+ mutex_unlock(&ctrl->mbox_lock);
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl_wait(phba, tag, &wrb, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index afa326d..f3a48a0 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -268,6 +268,8 @@ struct beiscsi_endpoint {
int mgmt_get_fw_config(struct be_ctrl_info *ctrl,
struct beiscsi_hba *phba);
+int mgmt_get_port_name(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba);
unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
struct beiscsi_endpoint *beiscsi_ep,
@@ -330,10 +332,13 @@ ssize_t beiscsi_phys_port_disp(struct device *dev,
void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
struct wrb_handle *pwrb_handle,
- struct be_mem_descriptor *mem_descr);
+ struct be_mem_descriptor *mem_descr,
+ struct hwi_wrb_context *pwrb_context);
void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
- struct wrb_handle *pwrb_handle);
+ struct wrb_handle *pwrb_handle,
+ struct hwi_wrb_context *pwrb_context);
+
void beiscsi_ue_detect(struct beiscsi_hba *phba);
int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
struct be_set_eqd *, int num);
diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h
index 4ad7e36..0e119d8 100644
--- a/drivers/scsi/bfa/bfa.h
+++ b/drivers/scsi/bfa/bfa.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index e3f67b0..7209afa 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -90,6 +91,25 @@ static bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
+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);
+
+ trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+ if (trcm->tail == trcm->head)
+ trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+}
+
static void
bfa_com_port_attach(struct bfa_s *bfa)
{
diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h
index 91a8aa3..df6760c 100644
--- a/drivers/scsi/bfa/bfa_cs.h
+++ b/drivers/scsi/bfa/bfa_cs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -107,44 +108,11 @@ bfa_trc_stop(struct bfa_trc_mod_s *trcm)
trcm->stopped = 1;
}
-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);
-
- trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
- if (trcm->tail == trcm->head)
- trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
-}
-
+void
+__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data);
-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);
-
- trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
- if (trcm->tail == trcm->head)
- trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
-}
+void
+__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data);
#define bfa_sm_fault(__mod, __event) do { \
bfa_trc(__mod, (((u32)0xDEAD << 16) | __event)); \
diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h
index 877b86d..5dc3782 100644
--- a/drivers/scsi/bfa/bfa_defs.h
+++ b/drivers/scsi/bfa/bfa_defs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h
index 06f0a16..5815a90 100644
--- a/drivers/scsi/bfa/bfa_defs_fcs.h
+++ b/drivers/scsi/bfa/bfa_defs_fcs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index 638f441f..e81707f 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h
index 64069a0..18b7304 100644
--- a/drivers/scsi/bfa/bfa_fc.h
+++ b/drivers/scsi/bfa/bfa_fc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c
index dce787f..b8dadc9 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.c
+++ b/drivers/scsi/bfa/bfa_fcbuild.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h
index 03c753d..b109a88 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.h
+++ b/drivers/scsi/bfa/bfa_fcbuild.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index d7385d1..20982e7 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h
index e693af6..e93921d 100644
--- a/drivers/scsi/bfa/bfa_fcpim.h
+++ b/drivers/scsi/bfa/bfa_fcpim.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
index 0f19455..1e7e139 100644
--- a/drivers/scsi/bfa/bfa_fcs.c
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h
index 42bcb97..06dc215 100644
--- a/drivers/scsi/bfa/bfa_fcs.h
+++ b/drivers/scsi/bfa/bfa_fcs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -633,7 +634,7 @@ void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
/*
* HBA Attribute Block : BFA internal representation. Note : Some variable
- * sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based
+ * sizes have been trimmed to suit BFA For Ex : Model will be "QLogic ". Based
* on this the size has been reduced to 16 bytes from the standard's 64 bytes.
*/
struct bfa_fcs_fdmi_hba_attr_s {
diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c
index 6dc7926..4f089d7 100644
--- a/drivers/scsi/bfa/bfa_fcs_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index ff75ef8..7733ad5 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -2653,7 +2654,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
strncpy(hba_attr->node_sym_name.symname,
port->port_cfg.node_sym_name.symname, BFA_SYMNAME_MAXLEN);
- strcpy(hba_attr->vendor_info, "BROCADE");
+ strcpy(hba_attr->vendor_info, "QLogic");
hba_attr->num_ports =
cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c
index 2035b0d..de50349 100644
--- a/drivers/scsi/bfa/bfa_fcs_rport.c
+++ b/drivers/scsi/bfa/bfa_fcs_rport.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
index ea24d4c..c4a0c0e 100644
--- a/drivers/scsi/bfa/bfa_hw_cb.c
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
index 637527f..b0ff378 100644
--- a/drivers/scsi/bfa/bfa_hw_ct.c
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 98f7e8c..a1ada4a 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -2697,7 +2698,7 @@ bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)
bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);
}
-#define BFA_MFG_NAME "Brocade"
+#define BFA_MFG_NAME "QLogic"
void
bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
struct bfa_adapter_attr_s *ad_attr)
@@ -2802,7 +2803,7 @@ void
bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
{
memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
- memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+ strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
}
void
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index a38aafa0..713745d 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index 453c2f5..f1b80da 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index bd53150..651a8fb 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h
index a14c784..53135f2 100644
--- a/drivers/scsi/bfa/bfa_modules.h
+++ b/drivers/scsi/bfa/bfa_modules.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_plog.h b/drivers/scsi/bfa/bfa_plog.h
index 1c9baa6..da570c0 100644
--- a/drivers/scsi/bfa/bfa_plog.h
+++ b/drivers/scsi/bfa/bfa_plog.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index 8ea7697..da1721e 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h
index 2fcab6b..26dc1bf 100644
--- a/drivers/scsi/bfa/bfa_port.h
+++ b/drivers/scsi/bfa/bfa_port.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c
index 625225f..12de292 100644
--- a/drivers/scsi/bfa/bfa_svc.c
+++ b/drivers/scsi/bfa/bfa_svc.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h
index ef07365..ea2278b 100644
--- a/drivers/scsi/bfa/bfa_svc.h
+++ b/drivers/scsi/bfa/bfa_svc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index cc3b9d3..9d253cb 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -130,13 +131,9 @@ MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for "
"boot port. Otherwise 10 secs in RHEL4 & 0 for "
"[RHEL5, SLES10, ESX40] Range[>0]");
module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts "
- "for Brocade-415/425/815/825 cards, default=0, "
- " Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts for QLogic-415/425/815/825 cards, default=0 Range[false:0|true:1]");
module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts "
- "if possible for Brocade-1010/1020/804/1007/902/1741 "
- "cards, default=0, Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts if possible for QLogic-1010/1020/804/1007/902/1741 cards, default=0, Range[false:0|true:1]");
module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1, "
"Range[false:0|true:1]");
@@ -838,8 +835,7 @@ bfad_drv_init(struct bfad_s *bfad)
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, %s",
- "System may need more memory.\n");
+ "Not enough memory to attach all QLogic BR-series HBA ports. System may need more memory.\n");
return BFA_STATUS_FAILED;
}
@@ -1710,7 +1706,7 @@ bfad_init(void)
{
int error = 0;
- printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n",
+ pr_info("QLogic BR-series BFA FC/FCOE SCSI driver - version: %s\n",
BFAD_DRIVER_VERSION);
if (num_sgpgs > 0)
@@ -1817,6 +1813,6 @@ bfad_free_fwimg(void)
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_DESCRIPTION("QLogic BR-series Fibre Channel HBA Driver" BFAD_PROTO_NAME);
+MODULE_AUTHOR("QLogic Corporation");
MODULE_VERSION(BFAD_DRIVER_VERSION);
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 40be670..13db3b7 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -750,65 +751,65 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
bfa_get_adapter_model(&bfad->bfa, model);
nports = bfa_get_nports(&bfad->bfa);
- if (!strcmp(model, "Brocade-425"))
+ if (!strcmp(model, "QLogic-425"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe dual port FC HBA");
- else if (!strcmp(model, "Brocade-825"))
+ "QLogic BR-series 4Gbps PCIe dual port FC HBA");
+ else if (!strcmp(model, "QLogic-825"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe dual port FC HBA");
- else if (!strcmp(model, "Brocade-42B"))
+ "QLogic BR-series 8Gbps PCIe dual port FC HBA");
+ else if (!strcmp(model, "QLogic-42B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe dual port FC HBA for HP");
- else if (!strcmp(model, "Brocade-82B"))
+ "QLogic BR-series 4Gbps PCIe dual port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-82B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe dual port FC HBA for HP");
- else if (!strcmp(model, "Brocade-1010"))
+ "QLogic BR-series 8Gbps PCIe dual port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-1010"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
- else if (!strcmp(model, "Brocade-1020"))
+ "QLogic BR-series 10Gbps single port CNA");
+ else if (!strcmp(model, "QLogic-1020"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
- else if (!strcmp(model, "Brocade-1007"))
+ "QLogic BR-series 10Gbps dual port CNA");
+ else if (!strcmp(model, "QLogic-1007"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps CNA for IBM Blade Center");
- else if (!strcmp(model, "Brocade-415"))
+ "QLogic BR-series 10Gbps CNA for IBM Blade Center");
+ else if (!strcmp(model, "QLogic-415"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe single port FC HBA");
- else if (!strcmp(model, "Brocade-815"))
+ "QLogic BR-series 4Gbps PCIe single port FC HBA");
+ else if (!strcmp(model, "QLogic-815"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe single port FC HBA");
- else if (!strcmp(model, "Brocade-41B"))
+ "QLogic BR-series 8Gbps PCIe single port FC HBA");
+ else if (!strcmp(model, "QLogic-41B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe single port FC HBA for HP");
- else if (!strcmp(model, "Brocade-81B"))
+ "QLogic BR-series 4Gbps PCIe single port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-81B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe single port FC HBA for HP");
- else if (!strcmp(model, "Brocade-804"))
+ "QLogic BR-series 8Gbps PCIe single port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-804"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps FC HBA for HP Bladesystem C-class");
- else if (!strcmp(model, "Brocade-1741"))
+ "QLogic BR-series 8Gbps FC HBA for HP Bladesystem C-class");
+ else if (!strcmp(model, "QLogic-1741"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps CNA for Dell M-Series Blade Servers");
- else if (strstr(model, "Brocade-1860")) {
+ "QLogic BR-series 10Gbps CNA for Dell M-Series Blade Servers");
+ else if (strstr(model, "QLogic-1860")) {
if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
+ "QLogic BR-series 10Gbps single port CNA");
else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA");
+ "QLogic BR-series 16Gbps PCIe single port FC HBA");
else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
+ "QLogic BR-series 10Gbps dual port CNA");
else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA");
- } else if (!strcmp(model, "Brocade-1867")) {
+ "QLogic BR-series 16Gbps PCIe dual port FC HBA");
+ } else if (!strcmp(model, "QLogic-1867")) {
if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA for IBM");
+ "QLogic BR-series 16Gbps PCIe single port FC HBA for IBM");
else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA for IBM");
+ "QLogic BR-series 16Gbps PCIe dual port FC HBA for IBM");
} else
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Invalid Model");
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index 023b9d4..d1ad020 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h
index 90abef6..917e140 100644
--- a/drivers/scsi/bfa/bfad_bsg.h
+++ b/drivers/scsi/bfa/bfad_bsg.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index 74a307c..8dcd8c7 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 8b97877..f9e8620 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -57,7 +58,7 @@
#ifdef BFA_DRIVER_VERSION
#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
#else
-#define BFAD_DRIVER_VERSION "3.2.23.0"
+#define BFAD_DRIVER_VERSION "3.2.25.0"
#endif
#define BFAD_PROTO_NAME FCPI_NAME
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 8367c11..6c805e1 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -185,7 +186,7 @@ bfad_im_info(struct Scsi_Host *shost)
memset(bfa_buf, 0, sizeof(bfa_buf));
snprintf(bfa_buf, sizeof(bfa_buf),
- "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s",
+ "QLogic BR-series FC/FCOE Adapter, hwpath: %s driver: %s",
bfad->pci_name, BFAD_DRIVER_VERSION);
return bfa_buf;
@@ -271,6 +272,19 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
cmnd->host_scribble = NULL;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ /*
+ * bfa_itnim can be NULL if the port gets disconnected and the bfa
+ * and fcs layers have cleaned up their nexus with the targets and
+ * the same has not been cleaned up by the shim
+ */
+ if (bfa_itnim == NULL) {
+ bfa_tskim_free(tskim);
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ "target reset, bfa_itnim is NULL\n");
+ rc = BFA_STATUS_FAILED;
+ goto out;
+ }
+
memset(&scsilun, 0, sizeof(scsilun));
bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
@@ -326,6 +340,19 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
cmnd->SCp.ptr = (char *)&wq;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ /*
+ * bfa_itnim can be NULL if the port gets disconnected and the bfa
+ * and fcs layers have cleaned up their nexus with the targets and
+ * the same has not been cleaned up by the shim
+ */
+ if (bfa_itnim == NULL) {
+ bfa_tskim_free(tskim);
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ "lun reset, bfa_itnim is NULL\n");
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ rc = FAILED;
+ goto out;
+ }
int_to_scsilun(cmnd->device->lun, &scsilun);
bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
@@ -800,7 +827,6 @@ struct scsi_host_template bfad_im_scsi_host_template = {
.shost_attrs = bfad_im_host_attrs,
.max_sectors = BFAD_MAX_SECTORS,
.vendor_id = BFA_PCI_VENDOR_ID_BROCADE,
- .use_blk_tags = 1,
};
struct scsi_host_template bfad_im_vport_template = {
@@ -822,7 +848,6 @@ struct scsi_host_template bfad_im_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = bfad_im_vport_attrs,
.max_sectors = BFAD_MAX_SECTORS,
- .use_blk_tags = 1,
};
bfa_status_t
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
index f6c1023..836fdc2 100644
--- a/drivers/scsi/bfa/bfad_im.h
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h
index 9ef91f9..97600dc 100644
--- a/drivers/scsi/bfa/bfi.h
+++ b/drivers/scsi/bfa/bfi.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h
index 1a3fe5a..ae5bfe0 100644
--- a/drivers/scsi/bfa/bfi_ms.h
+++ b/drivers/scsi/bfa/bfi_ms.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
diff --git a/drivers/scsi/bfa/bfi_reg.h b/drivers/scsi/bfa/bfi_reg.h
index 99133bc..fd5b876 100644
--- a/drivers/scsi/bfa/bfi_reg.h
+++ b/drivers/scsi/bfa/bfi_reg.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series 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
@@ -16,7 +17,7 @@
*/
/*
- * bfi_reg.h ASIC register defines for all Brocade adapter ASICs
+ * bfi_reg.h ASIC register defines for all QLogic BR-series adapter ASICs
*/
#ifndef __BFI_REG_H__
diff --git a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
index fe2106c..ac1c0b6 100644
--- a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
+++ b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
@@ -1,9 +1,9 @@
-/* 57xx_hsi_bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* 57xx_hsi_bnx2fc.h: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig
index 0978828..d401a09 100644
--- a/drivers/scsi/bnx2fc/Kconfig
+++ b/drivers/scsi/bnx2fc/Kconfig
@@ -1,5 +1,5 @@
config SCSI_BNX2X_FCOE
- tristate "QLogic NetXtreme II FCoE support"
+ tristate "QLogic FCoE offload support"
depends on PCI
depends on (IPV6 || IPV6=n)
depends on LIBFC
@@ -9,5 +9,4 @@ config SCSI_BNX2X_FCOE
select NET_VENDOR_BROADCOM
select CNIC
---help---
- This driver supports FCoE offload for the QLogic NetXtreme II
- devices.
+ This driver supports FCoE offload for the QLogic devices.
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 1346e05..499e369 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -1,7 +1,7 @@
-/* bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc.h: QLogic Linux FCoE offload driver.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
@@ -65,7 +65,7 @@
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
-#define BNX2FC_VERSION "2.4.2"
+#define BNX2FC_VERSION "2.9.6"
#define PFX "bnx2fc: "
@@ -303,7 +303,6 @@ struct bnx2fc_rport {
#define BNX2FC_FLAG_OFLD_REQ_CMPL 0x5
#define BNX2FC_FLAG_CTX_ALLOC_FAILURE 0x6
#define BNX2FC_FLAG_UPLD_REQ_COMPL 0x7
-#define BNX2FC_FLAG_EXPL_LOGO 0x8
#define BNX2FC_FLAG_DISABLE_FAILED 0x9
#define BNX2FC_FLAG_ENABLED 0xa
diff --git a/drivers/scsi/bnx2fc/bnx2fc_constants.h b/drivers/scsi/bnx2fc/bnx2fc_constants.h
index e147cc7..5b20efb 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_constants.h
+++ b/drivers/scsi/bnx2fc/bnx2fc_constants.h
@@ -1,9 +1,9 @@
-/* bnx2fc_constants.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_constants.h: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.c b/drivers/scsi/bnx2fc/bnx2fc_debug.c
index d055df0..c9e0bc7 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_debug.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_debug.c
@@ -1,9 +1,9 @@
-/* bnx2fc_debug.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_debug.c: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.h b/drivers/scsi/bnx2fc/bnx2fc_debug.h
index 2b90067..34fda3e 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_debug.h
+++ b/drivers/scsi/bnx2fc/bnx2fc_debug.h
@@ -1,9 +1,9 @@
-/* bnx2fc_debug.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_debug.h: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c
index ef355c1..5beea77 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_els.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_els.c
@@ -1,10 +1,10 @@
/*
- * bnx2fc_els.c: QLogic NetXtreme II Linux FCoE offload driver.
+ * bnx2fc_els.c: QLogic Linux FCoE offload driver.
* This file contains helper routines that handle ELS requests
* and responses.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
@@ -689,8 +689,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
rc = -EINVAL;
goto els_err;
}
- if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) ||
- (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) {
+ if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) {
printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op);
rc = -EINVAL;
goto els_err;
@@ -707,6 +706,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
els_req->cb_func = cb_func;
cb_arg->io_req = els_req;
els_req->cb_arg = cb_arg;
+ els_req->data_xfer_len = data_len;
mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req);
rc = bnx2fc_init_mp_req(els_req);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index b0bc5ff..d7029ea 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -1,10 +1,10 @@
-/* bnx2fc_fcoe.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_fcoe.c: QLogic Linux FCoE offload driver.
* This file contains the code that interacts with libfc, libfcoe,
* cnic modules to create FCoE instances, send/receive non-offloaded
* FIP/FCoE packets, listen to link events etc.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
@@ -23,16 +23,16 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
#define DRV_MODULE_NAME "bnx2fc"
#define DRV_MODULE_VERSION BNX2FC_VERSION
-#define DRV_MODULE_RELDATE "Dec 11, 2013"
+#define DRV_MODULE_RELDATE "October 15, 2015"
static char version[] =
- "QLogic NetXtreme II FCoE Driver " DRV_MODULE_NAME \
+ "QLogic FCoE Driver " DRV_MODULE_NAME \
" v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Bhanu Prakash Gollapudi <bprakash@broadcom.com>");
-MODULE_DESCRIPTION("QLogic NetXtreme II BCM57710 FCoE Driver");
+MODULE_DESCRIPTION("QLogic FCoE Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
@@ -97,6 +97,15 @@ static void __exit bnx2fc_mod_exit(void);
unsigned int bnx2fc_debug_level;
module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging,
+ "Option to enable extended logging,\n"
+ "\t\tDefault is 0 - no logging.\n"
+ "\t\t0x01 - SCSI cmd error, cleanup.\n"
+ "\t\t0x02 - Session setup, cleanup, etc.\n"
+ "\t\t0x04 - lport events, link, mtu, etc.\n"
+ "\t\t0x08 - ELS logs.\n"
+ "\t\t0x10 - fcoe L2 fame related logs.\n"
+ "\t\t0xff - LOG all messages.");
static int bnx2fc_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu);
@@ -2091,7 +2100,7 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr)
{
struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr);
struct bnx2fc_hba *hba;
- struct cnic_fc_npiv_tbl npiv_tbl;
+ struct cnic_fc_npiv_tbl *npiv_tbl;
struct fc_lport *lport;
if (interface->enabled == false) {
@@ -2123,11 +2132,16 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr)
if (!hba->cnic->get_fc_npiv_tbl)
goto done;
- memset(&npiv_tbl, 0, sizeof(npiv_tbl));
- if (hba->cnic->get_fc_npiv_tbl(hba->cnic, &npiv_tbl))
+ npiv_tbl = kzalloc(sizeof(struct cnic_fc_npiv_tbl), GFP_KERNEL);
+ if (!npiv_tbl)
goto done;
- bnx2fc_npiv_create_vports(lport, &npiv_tbl);
+ if (hba->cnic->get_fc_npiv_tbl(hba->cnic, npiv_tbl))
+ goto done_free;
+
+ bnx2fc_npiv_create_vports(lport, npiv_tbl);
+done_free:
+ kfree(npiv_tbl);
done:
return 0;
}
@@ -2862,7 +2876,6 @@ static struct scsi_host_template bnx2fc_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
.max_sectors = 1024,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index c6688d7..28c671b 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -1,9 +1,9 @@
-/* bnx2fc_hwi.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_hwi.c: QLogic Linux FCoE offload driver.
* This file contains the code that low level functions that interact
* with 57712 FCoE firmware.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 9ecca85..2230dab 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1,8 +1,8 @@
-/* bnx2fc_io.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_io.c: QLogic Linux FCoE offload driver.
* IO manager and SCSI IO processing.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
@@ -40,11 +40,8 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
{
struct bnx2fc_cmd *io_req = container_of(work, struct bnx2fc_cmd,
timeout_work.work);
- struct fc_lport *lport;
- struct fc_rport_priv *rdata;
u8 cmd_type = io_req->cmd_type;
struct bnx2fc_rport *tgt = io_req->tgt;
- int logo_issued;
int rc;
BNX2FC_IO_DBG(io_req, "cmd_timeout, cmd_type = %d,"
@@ -80,25 +77,14 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
io_req->refcount.refcount.counter);
if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
&io_req->req_flags))) {
-
- lport = io_req->port->lport;
- rdata = io_req->tgt->rdata;
- logo_issued = test_and_set_bit(
- BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
+ /*
+ * Cleanup and return original command to
+ * mid-layer.
+ */
+ bnx2fc_initiate_cleanup(io_req);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
- /* Explicitly logo the target */
- if (!logo_issued) {
- BNX2FC_IO_DBG(io_req, "Explicit "
- "logo - tgt flags = 0x%lx\n",
- tgt->flags);
-
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
return;
}
} else {
@@ -116,28 +102,10 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
rc = bnx2fc_initiate_abts(io_req);
if (rc == SUCCESS)
goto done;
- /*
- * Explicitly logo the target if
- * abts initiation fails
- */
- lport = io_req->port->lport;
- rdata = io_req->tgt->rdata;
- logo_issued = test_and_set_bit(
- BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
+
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
- if (!logo_issued) {
- BNX2FC_IO_DBG(io_req, "Explicit "
- "logo - tgt flags = 0x%lx\n",
- tgt->flags);
-
-
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
return;
} else {
BNX2FC_IO_DBG(io_req, "IO already in "
@@ -152,22 +120,9 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
if (!test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
&io_req->req_flags)) {
- lport = io_req->port->lport;
- rdata = io_req->tgt->rdata;
- logo_issued = test_and_set_bit(
- BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
- /* Explicitly logo the target */
- if (!logo_issued) {
- BNX2FC_IO_DBG(io_req, "Explicitly logo"
- "(els)\n");
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
return;
}
} else {
@@ -623,8 +578,12 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
mp_req = (struct bnx2fc_mp_req *)&(io_req->mp_req);
memset(mp_req, 0, sizeof(struct bnx2fc_mp_req));
- mp_req->req_len = sizeof(struct fcp_cmnd);
- io_req->data_xfer_len = mp_req->req_len;
+ if (io_req->cmd_type != BNX2FC_ELS) {
+ mp_req->req_len = sizeof(struct fcp_cmnd);
+ io_req->data_xfer_len = mp_req->req_len;
+ } else
+ mp_req->req_len = io_req->data_xfer_len;
+
mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&mp_req->req_buf_dma,
GFP_ATOMIC);
@@ -1108,18 +1067,11 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
}
-int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req)
+int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
{
struct bnx2fc_rport *tgt = io_req->tgt;
- struct fc_rport_priv *rdata = tgt->rdata;
- int logo_issued;
int rc = SUCCESS;
- int wait_cnt = 0;
- BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n",
- tgt->flags);
- logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
io_req->wait_for_comp = 1;
bnx2fc_initiate_cleanup(io_req);
@@ -1132,21 +1084,8 @@ int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req)
* release the reference taken in eh_abort to allow the
* target to re-login after flushing IOs
*/
- kref_put(&io_req->refcount, bnx2fc_cmd_release);
-
- if (!logo_issued) {
- clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- do {
- msleep(BNX2FC_RELOGIN_WAIT_TIME);
- if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) {
- rc = FAILED;
- break;
- }
- } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags));
- }
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+
spin_lock_bh(&tgt->tgt_lock);
return rc;
}
@@ -1165,8 +1104,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
struct bnx2fc_cmd *io_req;
struct fc_lport *lport;
struct bnx2fc_rport *tgt;
- int rc = FAILED;
-
+ int rc;
rc = fc_block_scsi_eh(sc_cmd);
if (rc)
@@ -1175,7 +1113,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
lport = shost_priv(sc_cmd->device->host);
if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
printk(KERN_ERR PFX "eh_abort: link not ready\n");
- return rc;
+ return FAILED;
}
tgt = (struct bnx2fc_rport *)&rp[1];
@@ -1248,7 +1186,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
- rc = bnx2fc_expl_logo(lport, io_req);
+ rc = bnx2fc_abts_cleanup(io_req);
/* This only occurs when an task abort was requested while ABTS
is in progress. Setting the IO_CLEANUP flag will skip the
RRQ process in the case when the fw generated SCSI_CMD cmpl
@@ -1287,7 +1225,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
/* Let the scsi-ml try to recover this command */
printk(KERN_ERR PFX "abort failed, xid = 0x%x\n",
io_req->xid);
- rc = bnx2fc_expl_logo(lport, io_req);
+ rc = bnx2fc_abts_cleanup(io_req);
goto out;
} else {
/*
@@ -1755,7 +1693,10 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
int fcp_rsp_len = 0;
io_req->fcp_status = FC_GOOD;
- io_req->fcp_resid = fcp_rsp->fcp_resid;
+ io_req->fcp_resid = 0;
+ if (rsp_flags & (FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER |
+ FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER))
+ io_req->fcp_resid = fcp_rsp->fcp_resid;
io_req->scsi_comp_flags = rsp_flags;
CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status =
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index c66c708..08ec318 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -1,9 +1,9 @@
-/* bnx2fc_tgt.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_tgt.c: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* 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
@@ -560,12 +560,6 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
(hba->num_ofld_sess == 0)) {
wake_up_interruptible(&hba->shutdown_wait);
}
- if (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags)) {
- printk(KERN_ERR PFX "Relogin to the tgt\n");
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_login(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
mutex_unlock(&hba->hba_mutex);
break;
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
index 2c4562d..c2a6f9f 100644
--- a/drivers/scsi/csiostor/csio_scsi.c
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -2283,7 +2283,6 @@ struct scsi_host_template csio_fcoe_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = csio_fcoe_lport_attrs,
.max_sectors = CSIO_MAX_SECTOR_SIZE,
- .use_blk_tags = 1,
};
struct scsi_host_template csio_fcoe_shost_vport_template = {
@@ -2303,7 +2302,6 @@ struct scsi_host_template csio_fcoe_shost_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = csio_fcoe_vport_attrs,
.max_sectors = CSIO_MAX_SECTOR_SIZE,
- .use_blk_tags = 1,
};
/*
diff --git a/drivers/scsi/cxgbi/cxgb3i/Kbuild b/drivers/scsi/cxgbi/cxgb3i/Kbuild
index 6f095e2..961a12f 100644
--- a/drivers/scsi/cxgbi/cxgb3i/Kbuild
+++ b/drivers/scsi/cxgbi/cxgb3i/Kbuild
@@ -1,3 +1,3 @@
-EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3
+ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index 0e2bee9..e22a268 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(cxgb3i_snd_win, "TCP send window in bytes (default=128KB)");
static int cxgb3i_rx_credit_thres = 10 * 1024;
module_param(cxgb3i_rx_credit_thres, int, 0644);
-MODULE_PARM_DESC(rx_credit_thres,
+MODULE_PARM_DESC(cxgb3i_rx_credit_thres,
"RX credits return threshold in bytes (default=10KB)");
static unsigned int cxgb3i_max_connect = 8 * 1024;
diff --git a/drivers/scsi/cxgbi/cxgb4i/Kbuild b/drivers/scsi/cxgbi/cxgb4i/Kbuild
index 8290cda..3745864 100644
--- a/drivers/scsi/cxgbi/cxgb4i/Kbuild
+++ b/drivers/scsi/cxgbi/cxgb4i/Kbuild
@@ -1,3 +1,3 @@
-EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
+ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
obj-$(CONFIG_SCSI_CXGB4_ISCSI) += cxgb4i.o
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 804806e..339f6b7 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <scsi/scsi_host.h>
@@ -158,7 +159,6 @@ static struct scsi_transport_template *cxgb4i_stt;
* open/close/abort and data send/receive.
*/
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define RCV_BUFSIZ_MASK 0x3FFU
#define MAX_IMM_TX_PKT_LEN 256
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h
index 22dd8d6..2fd9c76 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h
@@ -25,21 +25,4 @@
#define T5_ISS_VALID (1 << 18)
-struct ulptx_idata {
- __be32 cmd_more;
- __be32 len;
-};
-
-struct cpl_rx_data_ddp {
- union opcode_tid ot;
- __be16 urg;
- __be16 len;
- __be32 seq;
- union {
- __be32 nxt_seq;
- __be32 ddp_report;
- };
- __be32 ulp_crc;
- __be32 ddpvld;
-};
#endif /* __CXGB4I_H__ */
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index c11cd19..6e68155 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -34,7 +34,6 @@ extern const struct file_operations cxlflash_cxl_fops;
sectors
*/
-#define NUM_RRQ_ENTRY 16 /* for master issued cmds */
#define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry))
/* AFU command retry limit */
@@ -48,9 +47,12 @@ extern const struct file_operations cxlflash_cxl_fops;
index derivation
*/
-#define CXLFLASH_MAX_CMDS 16
+#define CXLFLASH_MAX_CMDS 256
#define CXLFLASH_MAX_CMDS_PER_LUN CXLFLASH_MAX_CMDS
+/* RRQ for master issued cmds */
+#define NUM_RRQ_ENTRY CXLFLASH_MAX_CMDS
+
static inline void check_sizes(void)
{
@@ -106,7 +108,6 @@ struct cxlflash_cfg {
atomic_t scan_host_needed;
struct cxl_afu *cxl_afu;
- struct pci_dev *parent_dev;
atomic_t recovery_threads;
struct mutex ctx_recovery_mutex;
@@ -149,7 +150,7 @@ struct afu_cmd {
struct afu {
/* Stuff requiring alignment go first. */
- u64 rrq_entry[NUM_RRQ_ENTRY]; /* 128B RRQ */
+ u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */
/*
* Command & data for AFU commands.
*/
@@ -165,6 +166,8 @@ struct afu {
struct sisl_host_map __iomem *host_map; /* MC host map */
struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */
+ struct kref mapcount;
+
ctx_hndl_t ctx_hndl; /* master's context handle */
u64 *hrrq_start;
u64 *hrrq_end;
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 1e5bf0c..8fb9643 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -289,7 +289,7 @@ static void context_reset(struct afu_cmd *cmd)
atomic64_set(&afu->room, room);
if (room)
goto write_rrin;
- udelay(nretry);
+ udelay(1 << nretry);
} while (nretry++ < MC_ROOM_RETRY_CNT);
pr_err("%s: no cmd_room to send reset\n", __func__);
@@ -303,7 +303,7 @@ write_rrin:
if (rrin != 0x1)
break;
/* Double delay each time */
- udelay(2 << nretry);
+ udelay(1 << nretry);
} while (nretry++ < MC_ROOM_RETRY_CNT);
}
@@ -338,7 +338,7 @@ retry:
atomic64_set(&afu->room, room);
if (room)
goto write_ioarrin;
- udelay(nretry);
+ udelay(1 << nretry);
} while (nretry++ < MC_ROOM_RETRY_CNT);
dev_err(dev, "%s: no cmd_room to send 0x%X\n",
@@ -352,7 +352,7 @@ retry:
* afu->room.
*/
if (nretry++ < MC_ROOM_RETRY_CNT) {
- udelay(nretry);
+ udelay(1 << nretry);
goto retry;
}
@@ -368,6 +368,7 @@ out:
no_room:
afu->read_room = true;
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
rc = SCSI_MLQUEUE_HOST_BUSY;
goto out;
@@ -473,6 +474,16 @@ out:
return rc;
}
+static void afu_unmap(struct kref *ref)
+{
+ struct afu *afu = container_of(ref, struct afu, mapcount);
+
+ if (likely(afu->afu_map)) {
+ cxl_psa_unmap((void __iomem *)afu->afu_map);
+ afu->afu_map = NULL;
+ }
+}
+
/**
* cxlflash_driver_info() - information handler for this host driver
* @host: SCSI host associated with device.
@@ -503,6 +514,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
ulong lock_flags;
short lflag = 0;
int rc = 0;
+ int kref_got = 0;
dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
"cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
goto out;
}
+ kref_get(&cfg->afu->mapcount);
+ kref_got = 1;
+
cmd->rcb.ctx_id = afu->ctx_hndl;
cmd->rcb.port_sel = port_sel;
cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
@@ -587,6 +602,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
}
out:
+ if (kref_got)
+ kref_put(&afu->mapcount, afu_unmap);
pr_devel("%s: returning rc=%d\n", __func__, rc);
return rc;
}
@@ -632,46 +649,57 @@ static void free_mem(struct cxlflash_cfg *cfg)
* @cfg: Internal structure associated with the host.
*
* Safe to call with AFU in a partially allocated/initialized state.
+ *
+ * Cleans up all state associated with the command queue, and unmaps
+ * the MMIO space.
+ *
+ * - complete() will take care of commands we initiated (they'll be checked
+ * in as part of the cleanup that occurs after the completion)
+ *
+ * - cmd_checkin() will take care of entries that we did not initiate and that
+ * have not (and will not) complete because they are sitting on a [now stale]
+ * hardware queue
*/
static void stop_afu(struct cxlflash_cfg *cfg)
{
int i;
struct afu *afu = cfg->afu;
+ struct afu_cmd *cmd;
if (likely(afu)) {
- for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
- complete(&afu->cmd[i].cevent);
+ for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+ cmd = &afu->cmd[i];
+ complete(&cmd->cevent);
+ if (!atomic_read(&cmd->free))
+ cmd_checkin(cmd);
+ }
if (likely(afu->afu_map)) {
cxl_psa_unmap((void __iomem *)afu->afu_map);
afu->afu_map = NULL;
}
+ kref_put(&afu->mapcount, afu_unmap);
}
}
/**
- * term_mc() - terminates the master context
+ * term_intr() - disables all AFU interrupts
* @cfg: Internal structure associated with the host.
* @level: Depth of allocation, where to begin waterfall tear down.
*
* Safe to call with AFU/MC in partially allocated/initialized state.
*/
-static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level)
+static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level)
{
- int rc = 0;
struct afu *afu = cfg->afu;
struct device *dev = &cfg->dev->dev;
if (!afu || !cfg->mcctx) {
- dev_err(dev, "%s: returning from term_mc with NULL afu or MC\n",
- __func__);
+ dev_err(dev, "%s: returning with NULL afu or MC\n", __func__);
return;
}
switch (level) {
- case UNDO_START:
- rc = cxl_stop_context(cfg->mcctx);
- BUG_ON(rc);
case UNMAP_THREE:
cxl_unmap_afu_irq(cfg->mcctx, 3, afu);
case UNMAP_TWO:
@@ -680,9 +708,34 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level)
cxl_unmap_afu_irq(cfg->mcctx, 1, afu);
case FREE_IRQ:
cxl_free_afu_irqs(cfg->mcctx);
- case RELEASE_CONTEXT:
- cfg->mcctx = NULL;
+ /* fall through */
+ case UNDO_NOOP:
+ /* No action required */
+ break;
+ }
+}
+
+/**
+ * term_mc() - terminates the master context
+ * @cfg: Internal structure associated with the host.
+ * @level: Depth of allocation, where to begin waterfall tear down.
+ *
+ * Safe to call with AFU/MC in partially allocated/initialized state.
+ */
+static void term_mc(struct cxlflash_cfg *cfg)
+{
+ int rc = 0;
+ struct afu *afu = cfg->afu;
+ struct device *dev = &cfg->dev->dev;
+
+ if (!afu || !cfg->mcctx) {
+ dev_err(dev, "%s: returning with NULL afu or MC\n", __func__);
+ return;
}
+
+ rc = cxl_stop_context(cfg->mcctx);
+ WARN_ON(rc);
+ cfg->mcctx = NULL;
}
/**
@@ -693,11 +746,21 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level)
*/
static void term_afu(struct cxlflash_cfg *cfg)
{
- term_mc(cfg, UNDO_START);
-
+ /*
+ * Tear down is carefully orchestrated to ensure
+ * no interrupts can come in when the problem state
+ * area is unmapped.
+ *
+ * 1) Disable all AFU interrupts
+ * 2) Unmap the problem state area
+ * 3) Stop the master context
+ */
+ term_intr(cfg, UNMAP_THREE);
if (cfg->afu)
stop_afu(cfg);
+ term_mc(cfg);
+
pr_debug("%s: returning\n", __func__);
}
@@ -731,10 +794,9 @@ static void cxlflash_remove(struct pci_dev *pdev)
scsi_remove_host(cfg->host);
/* fall through */
case INIT_STATE_AFU:
- term_afu(cfg);
cancel_work_sync(&cfg->work_q);
+ term_afu(cfg);
case INIT_STATE_PCI:
- pci_release_regions(cfg->dev);
pci_disable_device(pdev);
case INIT_STATE_NONE:
free_mem(cfg);
@@ -807,15 +869,6 @@ static int init_pci(struct cxlflash_cfg *cfg)
struct pci_dev *pdev = cfg->dev;
int rc = 0;
- cfg->cxlflash_regs_pci = pci_resource_start(pdev, 0);
- rc = pci_request_regions(pdev, CXLFLASH_NAME);
- if (rc < 0) {
- dev_err(&pdev->dev,
- "%s: Couldn't register memory range of registers\n",
- __func__);
- goto out;
- }
-
rc = pci_enable_device(pdev);
if (rc || pci_channel_offline(pdev)) {
if (pci_channel_offline(pdev)) {
@@ -827,55 +880,13 @@ static int init_pci(struct cxlflash_cfg *cfg)
dev_err(&pdev->dev, "%s: Cannot enable adapter\n",
__func__);
cxlflash_wait_for_pci_err_recovery(cfg);
- goto out_release_regions;
- }
- }
-
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (rc < 0) {
- dev_dbg(&pdev->dev, "%s: Failed to set 64 bit PCI DMA mask\n",
- __func__);
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- }
-
- if (rc < 0) {
- dev_err(&pdev->dev, "%s: Failed to set PCI DMA mask\n",
- __func__);
- goto out_disable;
- }
-
- pci_set_master(pdev);
-
- if (pci_channel_offline(pdev)) {
- cxlflash_wait_for_pci_err_recovery(cfg);
- if (pci_channel_offline(pdev)) {
- rc = -EIO;
- goto out_msi_disable;
+ goto out;
}
}
- rc = pci_save_state(pdev);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- dev_err(&pdev->dev, "%s: Failed to save PCI config space\n",
- __func__);
- rc = -EIO;
- goto cleanup_nolog;
- }
-
out:
pr_debug("%s: returning rc=%d\n", __func__, rc);
return rc;
-
-cleanup_nolog:
-out_msi_disable:
- cxlflash_wait_for_pci_err_recovery(cfg);
-out_disable:
- pci_disable_device(pdev);
-out_release_regions:
- pci_release_regions(pdev);
- goto out;
-
}
/**
@@ -1108,7 +1119,7 @@ static const struct asyc_intr_info ainfo[] = {
{SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
{SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
{SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
- {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0},
+ {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET},
{SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
{SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
{SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
@@ -1316,6 +1327,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
__func__, port);
cfg->lr_state = LINK_RESET_REQUIRED;
cfg->lr_port = port;
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
@@ -1336,6 +1348,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
if (info->action & SCAN_HOST) {
atomic_inc(&cfg->scan_host_needed);
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
}
@@ -1372,7 +1385,7 @@ static int start_context(struct cxlflash_cfg *cfg)
*/
static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
{
- struct pci_dev *dev = cfg->parent_dev;
+ struct pci_dev *dev = cfg->dev;
int rc = 0;
int ro_start, ro_size, i, j, k;
ssize_t vpd_size;
@@ -1381,7 +1394,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" };
/* Get the VPD data from the device */
- vpd_size = pci_read_vpd(dev, 0, sizeof(vpd_data), vpd_data);
+ vpd_size = cxl_read_adapter_vpd(dev, vpd_data, sizeof(vpd_data));
if (unlikely(vpd_size <= 0)) {
dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n",
__func__, vpd_size);
@@ -1614,41 +1627,24 @@ static int start_afu(struct cxlflash_cfg *cfg)
}
/**
- * init_mc() - create and register as the master context
+ * init_intr() - setup interrupt handlers for the master context
* @cfg: Internal structure associated with the host.
*
* Return: 0 on success, -errno on failure
*/
-static int init_mc(struct cxlflash_cfg *cfg)
+static enum undo_level init_intr(struct cxlflash_cfg *cfg,
+ struct cxl_context *ctx)
{
- struct cxl_context *ctx;
- struct device *dev = &cfg->dev->dev;
struct afu *afu = cfg->afu;
+ struct device *dev = &cfg->dev->dev;
int rc = 0;
- enum undo_level level;
-
- ctx = cxl_get_context(cfg->dev);
- if (unlikely(!ctx))
- return -ENOMEM;
- cfg->mcctx = ctx;
-
- /* Set it up as a master with the CXL */
- cxl_set_master(ctx);
-
- /* During initialization reset the AFU to start from a clean slate */
- rc = cxl_afu_reset(cfg->mcctx);
- if (unlikely(rc)) {
- dev_err(dev, "%s: initial AFU reset failed rc=%d\n",
- __func__, rc);
- level = RELEASE_CONTEXT;
- goto out;
- }
+ enum undo_level level = UNDO_NOOP;
rc = cxl_allocate_afu_irqs(ctx, 3);
if (unlikely(rc)) {
dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n",
__func__, rc);
- level = RELEASE_CONTEXT;
+ level = UNDO_NOOP;
goto out;
}
@@ -1678,8 +1674,47 @@ static int init_mc(struct cxlflash_cfg *cfg)
level = UNMAP_TWO;
goto out;
}
+out:
+ return level;
+}
- rc = 0;
+/**
+ * init_mc() - create and register as the master context
+ * @cfg: Internal structure associated with the host.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static int init_mc(struct cxlflash_cfg *cfg)
+{
+ struct cxl_context *ctx;
+ struct device *dev = &cfg->dev->dev;
+ int rc = 0;
+ enum undo_level level;
+
+ ctx = cxl_get_context(cfg->dev);
+ if (unlikely(!ctx)) {
+ rc = -ENOMEM;
+ goto ret;
+ }
+ cfg->mcctx = ctx;
+
+ /* Set it up as a master with the CXL */
+ cxl_set_master(ctx);
+
+ /* During initialization reset the AFU to start from a clean slate */
+ rc = cxl_afu_reset(cfg->mcctx);
+ if (unlikely(rc)) {
+ dev_err(dev, "%s: initial AFU reset failed rc=%d\n",
+ __func__, rc);
+ goto ret;
+ }
+
+ level = init_intr(cfg, ctx);
+ if (unlikely(level)) {
+ dev_err(dev, "%s: setting up interrupts failed rc=%d\n",
+ __func__, rc);
+ goto out;
+ }
/* This performs the equivalent of the CXL_IOCTL_START_WORK.
* The CXL_IOCTL_GET_PROCESS_ELEMENT is implicit in the process
@@ -1695,7 +1730,7 @@ ret:
pr_debug("%s: returning rc=%d\n", __func__, rc);
return rc;
out:
- term_mc(cfg, level);
+ term_intr(cfg, level);
goto ret;
}
@@ -1731,6 +1766,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
rc = -ENOMEM;
goto err1;
}
+ kref_init(&afu->mapcount);
/* No byte reverse on reading afu_version or string will be backwards */
reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1765,10 +1801,10 @@ out:
return rc;
err2:
- cxl_psa_unmap((void __iomem *)afu->afu_map);
- afu->afu_map = NULL;
+ kref_put(&afu->mapcount, afu_unmap);
err1:
- term_mc(cfg, UNDO_START);
+ term_intr(cfg, UNMAP_THREE);
+ term_mc(cfg);
goto out;
}
@@ -2114,6 +2150,16 @@ static ssize_t lun_mode_store(struct device *dev,
rc = kstrtouint(buf, 10, &lun_mode);
if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) {
afu->internal_lun = lun_mode;
+
+ /*
+ * When configured for internal LUN, there is only one channel,
+ * channel number 0, else there will be 2 (default).
+ */
+ if (afu->internal_lun)
+ shost->max_channel = 0;
+ else
+ shost->max_channel = NUM_FC_PORTS - 1;
+
afu_reset(cfg);
scsi_scan_host(cfg->host);
}
@@ -2260,7 +2306,7 @@ static struct scsi_host_template driver_template = {
.eh_device_reset_handler = cxlflash_eh_device_reset_handler,
.eh_host_reset_handler = cxlflash_eh_host_reset_handler,
.change_queue_depth = cxlflash_change_queue_depth,
- .cmd_per_lun = 16,
+ .cmd_per_lun = CXLFLASH_MAX_CMDS_PER_LUN,
.can_queue = CXLFLASH_MAX_CMDS,
.this_id = -1,
.sg_tablesize = SG_NONE, /* No scatter gather support */
@@ -2274,6 +2320,7 @@ static struct scsi_host_template driver_template = {
* Device dependent values
*/
static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
+static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS };
/*
* PCI device binding table
@@ -2281,6 +2328,8 @@ static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
static struct pci_device_id cxlflash_pci_table[] = {
{PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+ {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
{}
};
@@ -2339,6 +2388,7 @@ static void cxlflash_worker_thread(struct work_struct *work)
if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
scsi_scan_host(cfg->host);
+ kref_put(&afu->mapcount, afu_unmap);
}
/**
@@ -2353,7 +2403,6 @@ static int cxlflash_probe(struct pci_dev *pdev,
{
struct Scsi_Host *host;
struct cxlflash_cfg *cfg = NULL;
- struct device *phys_dev;
struct dev_dependent_vals *ddv;
int rc = 0;
@@ -2419,19 +2468,6 @@ static int cxlflash_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, cfg);
- /*
- * Use the special service provided to look up the physical
- * PCI device, since we are called on the probe of the virtual
- * PCI host bus (vphb)
- */
- phys_dev = cxl_get_phys_dev(pdev);
- if (!dev_is_pci(phys_dev)) {
- dev_err(&pdev->dev, "%s: not a pci dev\n", __func__);
- rc = -ENODEV;
- goto out_remove;
- }
- cfg->parent_dev = to_pci_dev(phys_dev);
-
cfg->cxl_afu = cxl_pci_to_afu(pdev);
rc = init_pci(cfg);
@@ -2505,8 +2541,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev,
if (unlikely(rc))
dev_err(dev, "%s: Failed to mark user contexts!(%d)\n",
__func__, rc);
- term_mc(cfg, UNDO_START);
- stop_afu(cfg);
+ term_afu(cfg);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
cfg->state = STATE_FAILTERM;
@@ -2585,8 +2620,7 @@ static struct pci_driver cxlflash_driver = {
*/
static int __init init_cxlflash(void)
{
- pr_info("%s: IBM Power CXL Flash Adapter: %s\n",
- __func__, CXLFLASH_DRIVER_DATE);
+ pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME);
cxlflash_list_init();
diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h
index 6032456..eb9d8f7 100644
--- a/drivers/scsi/cxlflash/main.h
+++ b/drivers/scsi/cxlflash/main.h
@@ -22,10 +22,9 @@
#define CXLFLASH_NAME "cxlflash"
#define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter"
-#define CXLFLASH_DRIVER_DATE "(August 13, 2015)"
-#define PCI_DEVICE_ID_IBM_CORSA 0x04F0
-#define CXLFLASH_SUBS_DEV_ID 0x04F0
+#define PCI_DEVICE_ID_IBM_CORSA 0x04F0
+#define PCI_DEVICE_ID_IBM_FLASH_GT 0x0600
/* Since there is only one target, make it 0 */
#define CXLFLASH_TARGET 0
@@ -80,12 +79,11 @@
#define WWPN_BUF_LEN (WWPN_LEN + 1)
enum undo_level {
- RELEASE_CONTEXT = 0,
+ UNDO_NOOP = 0,
FREE_IRQ,
UNMAP_ONE,
UNMAP_TWO,
- UNMAP_THREE,
- UNDO_START
+ UNMAP_THREE
};
struct dev_dependent_vals {
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index cac2e6a..d8a5cb3 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -709,27 +709,32 @@ int cxlflash_disk_release(struct scsi_device *sdev,
* @cfg: Internal structure associated with the host.
* @ctxi: Context to release.
*
- * Note that the rht_lun member of the context was cut from a single
- * allocation when the context was created and therefore does not need
- * to be explicitly freed. Also note that we conditionally check for the
- * existence of the context control map before clearing the RHT registers
- * and context capabilities because it is possible to destroy a context
- * while the context is in the error state (previous mapping was removed
- * [so we don't have to worry about clearing] and context is waiting for
- * a new mapping).
+ * This routine is safe to be called with a a non-initialized context
+ * and is tolerant of being called with the context's mutex held (it
+ * will be unlocked if necessary before freeing). Also note that the
+ * routine conditionally checks for the existence of the context control
+ * map before clearing the RHT registers and context capabilities because
+ * it is possible to destroy a context while the context is in the error
+ * state (previous mapping was removed [so there is no need to worry about
+ * clearing] and context is waiting for a new mapping).
*/
static void destroy_context(struct cxlflash_cfg *cfg,
struct ctx_info *ctxi)
{
struct afu *afu = cfg->afu;
- WARN_ON(!list_empty(&ctxi->luns));
+ if (ctxi->initialized) {
+ WARN_ON(!list_empty(&ctxi->luns));
- /* Clear RHT registers and drop all capabilities for this context */
- if (afu->afu_map && ctxi->ctrl_map) {
- writeq_be(0, &ctxi->ctrl_map->rht_start);
- writeq_be(0, &ctxi->ctrl_map->rht_cnt_id);
- writeq_be(0, &ctxi->ctrl_map->ctx_cap);
+ /* Clear RHT registers and drop all capabilities for context */
+ if (afu->afu_map && ctxi->ctrl_map) {
+ writeq_be(0, &ctxi->ctrl_map->rht_start);
+ writeq_be(0, &ctxi->ctrl_map->rht_cnt_id);
+ writeq_be(0, &ctxi->ctrl_map->ctx_cap);
+ }
+
+ if (mutex_is_locked(&ctxi->mutex))
+ mutex_unlock(&ctxi->mutex);
}
/* Free memory associated with context */
@@ -742,23 +747,12 @@ static void destroy_context(struct cxlflash_cfg *cfg,
/**
* create_context() - allocates and initializes a context
* @cfg: Internal structure associated with the host.
- * @ctx: Previously obtained CXL context reference.
- * @ctxid: Previously obtained process element associated with CXL context.
- * @adap_fd: Previously obtained adapter fd associated with CXL context.
- * @file: Previously obtained file associated with CXL context.
- * @perms: User-specified permissions.
- *
- * The context's mutex is locked when an allocated context is returned.
*
* Return: Allocated context on success, NULL on failure
*/
-static struct ctx_info *create_context(struct cxlflash_cfg *cfg,
- struct cxl_context *ctx, int ctxid,
- int adap_fd, struct file *file,
- u32 perms)
+static struct ctx_info *create_context(struct cxlflash_cfg *cfg)
{
struct device *dev = &cfg->dev->dev;
- struct afu *afu = cfg->afu;
struct ctx_info *ctxi = NULL;
struct llun_info **lli = NULL;
u8 *ws = NULL;
@@ -781,28 +775,49 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg,
ctxi->rht_lun = lli;
ctxi->rht_needs_ws = ws;
ctxi->rht_start = rhte;
- ctxi->rht_perms = perms;
+out:
+ return ctxi;
+
+err:
+ kfree(ws);
+ kfree(lli);
+ kfree(ctxi);
+ ctxi = NULL;
+ goto out;
+}
+
+/**
+ * init_context() - initializes a previously allocated context
+ * @ctxi: Previously allocated context
+ * @cfg: Internal structure associated with the host.
+ * @ctx: Previously obtained CXL context reference.
+ * @ctxid: Previously obtained process element associated with CXL context.
+ * @adap_fd: Previously obtained adapter fd associated with CXL context.
+ * @file: Previously obtained file associated with CXL context.
+ * @perms: User-specified permissions.
+ *
+ * Upon return, the context is marked as initialized and the context's mutex
+ * is locked.
+ */
+static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg,
+ struct cxl_context *ctx, int ctxid, int adap_fd,
+ struct file *file, u32 perms)
+{
+ struct afu *afu = cfg->afu;
+ ctxi->rht_perms = perms;
ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl;
ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid);
ctxi->lfd = adap_fd;
ctxi->pid = current->tgid; /* tgid = pid */
ctxi->ctx = ctx;
ctxi->file = file;
+ ctxi->initialized = true;
mutex_init(&ctxi->mutex);
INIT_LIST_HEAD(&ctxi->luns);
INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */
mutex_lock(&ctxi->mutex);
-out:
- return ctxi;
-
-err:
- kfree(ws);
- kfree(lli);
- kfree(ctxi);
- ctxi = NULL;
- goto out;
}
/**
@@ -1300,9 +1315,9 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
u32 perms;
int ctxid = -1;
u64 rctxid = 0UL;
- struct file *file;
+ struct file *file = NULL;
- struct cxl_context *ctx;
+ struct cxl_context *ctx = NULL;
int fd = -1;
@@ -1356,7 +1371,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
if (unlikely(!lun_access)) {
dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__);
rc = -ENOMEM;
- goto err0;
+ goto err;
}
lun_access->lli = lli;
@@ -1371,53 +1386,56 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
goto out_attach;
}
+ ctxi = create_context(cfg);
+ if (unlikely(!ctxi)) {
+ dev_err(dev, "%s: Failed to create context! (%d)\n",
+ __func__, ctxid);
+ goto err;
+ }
+
ctx = cxl_dev_context_init(cfg->dev);
- if (unlikely(IS_ERR_OR_NULL(ctx))) {
+ if (IS_ERR_OR_NULL(ctx)) {
dev_err(dev, "%s: Could not initialize context %p\n",
__func__, ctx);
rc = -ENODEV;
- goto err1;
+ goto err;
+ }
+
+ work = &ctxi->work;
+ work->num_interrupts = attach->num_interrupts;
+ work->flags = CXL_START_WORK_NUM_IRQS;
+
+ rc = cxl_start_work(ctx, work);
+ if (unlikely(rc)) {
+ dev_dbg(dev, "%s: Could not start context rc=%d\n",
+ __func__, rc);
+ goto err;
}
ctxid = cxl_process_element(ctx);
- if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+ if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
- goto err2;
+ goto err;
}
file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd);
if (unlikely(fd < 0)) {
rc = -ENODEV;
dev_err(dev, "%s: Could not get file descriptor\n", __func__);
- goto err2;
+ goto err;
}
/* Translate read/write O_* flags from fcntl.h to AFU permission bits */
perms = SISL_RHT_PERM(attach->hdr.flags + 1);
- ctxi = create_context(cfg, ctx, ctxid, fd, file, perms);
- if (unlikely(!ctxi)) {
- dev_err(dev, "%s: Failed to create context! (%d)\n",
- __func__, ctxid);
- goto err3;
- }
-
- work = &ctxi->work;
- work->num_interrupts = attach->num_interrupts;
- work->flags = CXL_START_WORK_NUM_IRQS;
-
- rc = cxl_start_work(ctx, work);
- if (unlikely(rc)) {
- dev_dbg(dev, "%s: Could not start context rc=%d\n",
- __func__, rc);
- goto err4;
- }
+ /* Context mutex is locked upon return */
+ init_context(ctxi, cfg, ctx, ctxid, fd, file, perms);
rc = afu_attach(cfg, ctxi);
if (unlikely(rc)) {
dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc);
- goto err5;
+ goto err;
}
/*
@@ -1453,13 +1471,14 @@ out:
__func__, ctxid, fd, attach->block_size, rc, attach->last_lba);
return rc;
-err5:
- cxl_stop_context(ctx);
-err4:
- put_context(ctxi);
- destroy_context(cfg, ctxi);
- ctxi = NULL;
-err3:
+err:
+ /* Cleanup CXL context; okay to 'stop' even if it was not started */
+ if (!IS_ERR_OR_NULL(ctx)) {
+ cxl_stop_context(ctx);
+ cxl_release_context(ctx);
+ ctx = NULL;
+ }
+
/*
* Here, we're overriding the fops with a dummy all-NULL fops because
* fput() calls the release fop, which will cause us to mistakenly
@@ -1467,15 +1486,21 @@ err3:
* to that routine (cxlflash_cxl_release) we should try to fix the
* issue here.
*/
- file->f_op = &null_fops;
- fput(file);
- put_unused_fd(fd);
- fd = -1;
-err2:
- cxl_release_context(ctx);
-err1:
+ if (fd > 0) {
+ file->f_op = &null_fops;
+ fput(file);
+ put_unused_fd(fd);
+ fd = -1;
+ file = NULL;
+ }
+
+ /* Cleanup our context; safe to call even with mutex locked */
+ if (ctxi) {
+ destroy_context(cfg, ctxi);
+ ctxi = NULL;
+ }
+
kfree(lun_access);
-err0:
scsi_device_put(sdev);
goto out;
}
@@ -1500,31 +1525,31 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
struct afu *afu = cfg->afu;
ctx = cxl_dev_context_init(cfg->dev);
- if (unlikely(IS_ERR_OR_NULL(ctx))) {
+ if (IS_ERR_OR_NULL(ctx)) {
dev_err(dev, "%s: Could not initialize context %p\n",
__func__, ctx);
rc = -ENODEV;
goto out;
}
+ rc = cxl_start_work(ctx, &ctxi->work);
+ if (unlikely(rc)) {
+ dev_dbg(dev, "%s: Could not start context rc=%d\n",
+ __func__, rc);
+ goto err1;
+ }
+
ctxid = cxl_process_element(ctx);
- if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+ if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
- goto err1;
+ goto err2;
}
file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd);
if (unlikely(fd < 0)) {
rc = -ENODEV;
dev_err(dev, "%s: Could not get file descriptor\n", __func__);
- goto err1;
- }
-
- rc = cxl_start_work(ctx, &ctxi->work);
- if (unlikely(rc)) {
- dev_dbg(dev, "%s: Could not start context rc=%d\n",
- __func__, rc);
goto err2;
}
@@ -1569,10 +1594,10 @@ out:
return rc;
err3:
- cxl_stop_context(ctx);
-err2:
fput(file);
put_unused_fd(fd);
+err2:
+ cxl_stop_context(ctx);
err1:
cxl_release_context(ctx);
goto out;
diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h
index bede574..5f9a091 100644
--- a/drivers/scsi/cxlflash/superpipe.h
+++ b/drivers/scsi/cxlflash/superpipe.h
@@ -102,6 +102,7 @@ struct ctx_info {
u64 ctxid;
int lfd;
pid_t pid;
+ bool initialized;
bool unavail;
bool err_recovery_active;
struct mutex mutex; /* Context protection */
diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c
index a53f583..50f8e93 100644
--- a/drivers/scsi/cxlflash/vlun.c
+++ b/drivers/scsi/cxlflash/vlun.c
@@ -1008,6 +1008,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
virt->last_lba = last_lba;
virt->rsrc_handle = rsrc_handle;
+ if (lli->port_sel == BOTH_PORTS)
+ virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE;
out:
if (likely(ctxi))
put_context(ctxi);
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig
index e5647d5..0b331c9 100644
--- a/drivers/scsi/device_handler/Kconfig
+++ b/drivers/scsi/device_handler/Kconfig
@@ -13,13 +13,13 @@ menuconfig SCSI_DH
config SCSI_DH_RDAC
tristate "LSI RDAC Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
If you have a LSI RDAC select y. Otherwise, say N.
config SCSI_DH_HP_SW
tristate "HP/COMPAQ MSA Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
If you have a HP/COMPAQ MSA device that requires START_STOP to
be sent to start it and cannot upgrade the firmware then select y.
@@ -27,13 +27,13 @@ config SCSI_DH_HP_SW
config SCSI_DH_EMC
tristate "EMC CLARiiON Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
If you have a EMC CLARiiON select y. Otherwise, say N.
config SCSI_DH_ALUA
tristate "SPC-3 ALUA Device Handler"
- depends on SCSI_DH
+ depends on SCSI_DH && SCSI
help
SCSI Device handler for generic SPC-3 Asymmetric Logical Unit
Access (ALUA).
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index cc2773b..8eaed05 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -22,20 +22,15 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_proto.h>
+#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
#define ALUA_DH_NAME "alua"
-#define ALUA_DH_VER "1.3"
-
-#define TPGS_STATE_OPTIMIZED 0x0
-#define TPGS_STATE_NONOPTIMIZED 0x1
-#define TPGS_STATE_STANDBY 0x2
-#define TPGS_STATE_UNAVAILABLE 0x3
-#define TPGS_STATE_LBA_DEPENDENT 0x4
-#define TPGS_STATE_OFFLINE 0xe
-#define TPGS_STATE_TRANSITIONING 0xf
+#define ALUA_DH_VER "2.0"
#define TPGS_SUPPORT_NONE 0x00
#define TPGS_SUPPORT_OPTIMIZED 0x01
@@ -54,27 +49,62 @@
#define TPGS_MODE_IMPLICIT 0x1
#define TPGS_MODE_EXPLICIT 0x2
-#define ALUA_INQUIRY_SIZE 36
+#define ALUA_RTPG_SIZE 128
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
+#define ALUA_RTPG_DELAY_MSECS 5
-/* flags passed from user level */
-#define ALUA_OPTIMIZE_STPG 1
+/* device handler flags */
+#define ALUA_OPTIMIZE_STPG 0x01
+#define ALUA_RTPG_EXT_HDR_UNSUPP 0x02
+#define ALUA_SYNC_STPG 0x04
+/* State machine flags */
+#define ALUA_PG_RUN_RTPG 0x10
+#define ALUA_PG_RUN_STPG 0x20
+#define ALUA_PG_RUNNING 0x40
-struct alua_dh_data {
+static uint optimize_stpg;
+module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
+
+static LIST_HEAD(port_group_list);
+static DEFINE_SPINLOCK(port_group_lock);
+static struct workqueue_struct *kaluad_wq;
+static struct workqueue_struct *kaluad_sync_wq;
+
+struct alua_port_group {
+ struct kref kref;
+ struct rcu_head rcu;
+ struct list_head node;
+ struct list_head dh_list;
+ unsigned char device_id_str[256];
+ int device_id_len;
int group_id;
- int rel_port;
int tpgs;
int state;
int pref;
unsigned flags; /* used for optimizing STPG */
- unsigned char inq[ALUA_INQUIRY_SIZE];
- unsigned char *buff;
- int bufflen;
unsigned char transition_tmo;
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
- int senselen;
+ unsigned long expiry;
+ unsigned long interval;
+ struct delayed_work rtpg_work;
+ spinlock_t lock;
+ struct list_head rtpg_list;
+ struct scsi_device *rtpg_sdev;
+};
+
+struct alua_dh_data {
+ struct list_head node;
+ struct alua_port_group *pg;
+ int group_id;
+ spinlock_t pg_lock;
struct scsi_device *sdev;
+ int init_error;
+ struct mutex init_mutex;
+};
+
+struct alua_queue_data {
+ struct list_head entry;
activate_complete callback_fn;
void *callback_data;
};
@@ -82,231 +112,160 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_CURRENT 0
#define ALUA_POLICY_SWITCH_ALL 1
-static char print_alua_state(int);
-static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
-
-static int realloc_buffer(struct alua_dh_data *h, unsigned len)
-{
- if (h->buff && h->buff != h->inq)
- kfree(h->buff);
-
- h->buff = kmalloc(len, GFP_NOIO);
- if (!h->buff) {
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
- return 1;
- }
- h->bufflen = len;
- return 0;
-}
+static void alua_rtpg_work(struct work_struct *work);
+static void alua_rtpg_queue(struct alua_port_group *pg,
+ struct scsi_device *sdev,
+ struct alua_queue_data *qdata, bool force);
+static void alua_check(struct scsi_device *sdev, bool force);
-static struct request *get_alua_req(struct scsi_device *sdev,
- void *buffer, unsigned buflen, int rw)
+static void release_port_group(struct kref *kref)
{
- struct request *rq;
- struct request_queue *q = sdev->request_queue;
-
- rq = blk_get_request(q, rw, GFP_NOIO);
-
- if (IS_ERR(rq)) {
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_get_request failed\n", __func__);
- return NULL;
- }
- blk_rq_set_block_pc(rq);
-
- if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
- blk_put_request(rq);
- sdev_printk(KERN_INFO, sdev,
- "%s: blk_rq_map_kern failed\n", __func__);
- return NULL;
- }
-
- rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
- rq->retries = ALUA_FAILOVER_RETRIES;
- rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
-
- return rq;
+ struct alua_port_group *pg;
+
+ pg = container_of(kref, struct alua_port_group, kref);
+ if (pg->rtpg_sdev)
+ flush_delayed_work(&pg->rtpg_work);
+ spin_lock(&port_group_lock);
+ list_del(&pg->node);
+ spin_unlock(&port_group_lock);
+ kfree_rcu(pg, rcu);
}
/*
- * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
+ * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+ int bufflen, struct scsi_sense_hdr *sshdr, int flags)
{
- struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
- goto done;
+ u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)];
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
/* Prepare the command. */
- rq->cmd[0] = INQUIRY;
- rq->cmd[1] = 1;
- rq->cmd[2] = 0x83;
- rq->cmd[4] = h->bufflen;
- rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
-
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: evpd inquiry failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
- blk_put_request(rq);
-done:
- return err;
+ memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN));
+ cdb[0] = MAINTENANCE_IN;
+ if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
+ cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
+ else
+ cdb[1] = MI_REPORT_TARGET_PGS;
+ put_unaligned_be32(bufflen, &cdb[6]);
+
+ return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE,
+ buff, bufflen, sshdr,
+ ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, NULL, req_flags);
}
/*
- * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
- * @sdev: sdev the command should be sent to
+ * submit_stpg - Issue a SET TARGET PORT GROUP command
+ *
+ * Currently we're only setting the current target port group state
+ * to 'active/optimized' and let the array firmware figure out
+ * the states of the remaining groups.
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
- bool rtpg_ext_hdr_req)
+static int submit_stpg(struct scsi_device *sdev, int group_id,
+ struct scsi_sense_hdr *sshdr)
{
- struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
+ u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)];
+ unsigned char stpg_data[8];
+ int stpg_len = 8;
+ int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
- goto done;
+ /* Prepare the data buffer */
+ memset(stpg_data, 0, stpg_len);
+ stpg_data[4] = SCSI_ACCESS_STATE_OPTIMAL;
+ put_unaligned_be16(group_id, &stpg_data[6]);
/* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_IN;
- if (rtpg_ext_hdr_req)
- rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
- else
- rq->cmd[1] = MI_REPORT_TARGET_PGS;
- rq->cmd[6] = (h->bufflen >> 24) & 0xff;
- rq->cmd[7] = (h->bufflen >> 16) & 0xff;
- rq->cmd[8] = (h->bufflen >> 8) & 0xff;
- rq->cmd[9] = h->bufflen & 0xff;
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
-
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
- blk_put_request(rq);
-done:
- return err;
+ memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_OUT));
+ cdb[0] = MAINTENANCE_OUT;
+ cdb[1] = MO_SET_TARGET_PGS;
+ put_unaligned_be32(stpg_len, &cdb[6]);
+
+ return scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE,
+ stpg_data, stpg_len,
+ sshdr, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, NULL, req_flags);
}
-/*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
- *
- * Send a SET TARGET GROUP STATES command to the device.
- * We only have to test here if we should resubmit the command;
- * any other error is assumed as a failure.
- */
-static void stpg_endio(struct request *req, int error)
+struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
+ int group_id)
{
- struct alua_dh_data *h = req->end_io_data;
- struct scsi_sense_hdr sense_hdr;
- unsigned err = SCSI_DH_OK;
-
- if (host_byte(req->errors) != DID_OK ||
- msg_byte(req->errors) != COMMAND_COMPLETE) {
- err = SCSI_DH_IO;
- goto done;
+ struct alua_port_group *pg;
+
+ list_for_each_entry(pg, &port_group_list, node) {
+ if (pg->group_id != group_id)
+ continue;
+ if (pg->device_id_len != id_size)
+ continue;
+ if (strncmp(pg->device_id_str, id_str, id_size))
+ continue;
+ if (!kref_get_unless_zero(&pg->kref))
+ continue;
+ return pg;
}
- if (req->sense_len > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err) {
- err = SCSI_DH_IO;
- goto done;
- }
- err = alua_check_sense(h->sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE) {
- err = SCSI_DH_RETRY;
- goto done;
- }
- sdev_printk(KERN_INFO, h->sdev,
- "%s: stpg sense code: %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
- err = SCSI_DH_IO;
- } else if (error)
- err = SCSI_DH_IO;
-
- if (err == SCSI_DH_OK) {
- h->state = TPGS_STATE_OPTIMIZED;
- sdev_printk(KERN_INFO, h->sdev,
- "%s: port group %02x switched to state %c\n",
- ALUA_DH_NAME, h->group_id,
- print_alua_state(h->state));
- }
-done:
- req->end_io_data = NULL;
- __blk_put_request(req->q, req);
- if (h->callback_fn) {
- h->callback_fn(h->callback_data, err);
- h->callback_fn = h->callback_data = NULL;
- }
- return;
+ return NULL;
}
/*
- * submit_stpg - Issue a SET TARGET GROUP STATES command
+ * alua_alloc_pg - Allocate a new port_group structure
+ * @sdev: scsi device
+ * @h: alua device_handler data
+ * @group_id: port group id
*
- * Currently we're only setting the current target port group state
- * to 'active/optimized' and let the array firmware figure out
- * the states of the remaining groups.
+ * Allocate a new port_group structure for a given
+ * device.
*/
-static unsigned submit_stpg(struct alua_dh_data *h)
+struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
+ int group_id, int tpgs)
{
- struct request *rq;
- int stpg_len = 8;
- struct scsi_device *sdev = h->sdev;
+ struct alua_port_group *pg, *tmp_pg;
- /* Prepare the data buffer */
- memset(h->buff, 0, stpg_len);
- h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
- h->buff[6] = (h->group_id >> 8) & 0xff;
- h->buff[7] = h->group_id & 0xff;
+ pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
+ if (!pg)
+ return ERR_PTR(-ENOMEM);
- rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
- if (!rq)
- return SCSI_DH_RES_TEMP_UNAVAIL;
+ pg->device_id_len = scsi_vpd_lun_id(sdev, pg->device_id_str,
+ sizeof(pg->device_id_str));
+ if (pg->device_id_len <= 0) {
+ /*
+ * Internal error: TPGS supported but no device
+ * identifcation found. Disable ALUA support.
+ */
+ kfree(pg);
+ sdev_printk(KERN_INFO, sdev,
+ "%s: No device descriptors found\n",
+ ALUA_DH_NAME);
+ return ERR_PTR(-ENXIO);
+ }
+ pg->group_id = group_id;
+ pg->tpgs = tpgs;
+ pg->state = SCSI_ACCESS_STATE_OPTIMAL;
+ if (optimize_stpg)
+ pg->flags |= ALUA_OPTIMIZE_STPG;
+ kref_init(&pg->kref);
+ INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
+ INIT_LIST_HEAD(&pg->rtpg_list);
+ INIT_LIST_HEAD(&pg->node);
+ INIT_LIST_HEAD(&pg->dh_list);
+ spin_lock_init(&pg->lock);
+
+ spin_lock(&port_group_lock);
+ tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+ group_id);
+ if (tmp_pg) {
+ spin_unlock(&port_group_lock);
+ kfree(pg);
+ return tmp_pg;
+ }
- /* Prepare the command. */
- rq->cmd[0] = MAINTENANCE_OUT;
- rq->cmd[1] = MO_SET_TARGET_PGS;
- rq->cmd[6] = (stpg_len >> 24) & 0xff;
- rq->cmd[7] = (stpg_len >> 16) & 0xff;
- rq->cmd[8] = (stpg_len >> 8) & 0xff;
- rq->cmd[9] = stpg_len & 0xff;
- rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
- rq->end_io_data = h;
-
- blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
- return SCSI_DH_OK;
+ list_add(&pg->node, &port_group_list);
+ spin_unlock(&port_group_lock);
+
+ return pg;
}
/*
@@ -316,12 +275,23 @@ static unsigned submit_stpg(struct alua_dh_data *h)
* Examine the TPGS setting of the sdev to find out if ALUA
* is supported.
*/
-static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_tpgs(struct scsi_device *sdev)
{
- int err = SCSI_DH_OK;
+ int tpgs = TPGS_MODE_NONE;
+
+ /*
+ * ALUA support for non-disk devices is fraught with
+ * difficulties, so disable it for now.
+ */
+ if (sdev->type != TYPE_DISK) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: disable for non-disk devices\n",
+ ALUA_DH_NAME);
+ return tpgs;
+ }
- h->tpgs = scsi_device_tpgs(sdev);
- switch (h->tpgs) {
+ tpgs = scsi_device_tpgs(sdev);
+ switch (tpgs) {
case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
sdev_printk(KERN_INFO, sdev,
"%s: supports implicit and explicit TPGS\n",
@@ -335,71 +305,38 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
ALUA_DH_NAME);
break;
- default:
- h->tpgs = TPGS_MODE_NONE;
+ case TPGS_MODE_NONE:
sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
ALUA_DH_NAME);
- err = SCSI_DH_DEV_UNSUPP;
+ break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: unsupported TPGS setting %d\n",
+ ALUA_DH_NAME, tpgs);
+ tpgs = TPGS_MODE_NONE;
break;
}
- return err;
+ return tpgs;
}
/*
- * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * alua_check_vpd - Evaluate INQUIRY vpd page 0x83
* @sdev: device to be checked
*
* Extract the relative target port and the target port group
* descriptor from the list of identificators.
*/
-static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
+ int tpgs)
{
- int len;
- unsigned err;
- unsigned char *d;
+ int rel_port = -1, group_id;
+ struct alua_port_group *pg, *old_pg = NULL;
+ bool pg_updated = false;
+ unsigned long flags;
- retry:
- err = submit_vpd_inquiry(sdev, h);
-
- if (err != SCSI_DH_OK)
- return err;
-
- /* Check if vpd page exceeds initial buffer */
- len = (h->buff[2] << 8) + h->buff[3] + 4;
- if (len > h->bufflen) {
- /* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
- sdev_printk(KERN_WARNING, sdev,
- "%s: kmalloc buffer failed\n",
- ALUA_DH_NAME);
- /* Temporary failure, bypass */
- return SCSI_DH_DEV_TEMP_BUSY;
- }
- goto retry;
- }
-
- /*
- * Now look for the correct descriptor.
- */
- d = h->buff + 4;
- while (d < h->buff + len) {
- switch (d[1] & 0xf) {
- case 0x4:
- /* Relative target port */
- h->rel_port = (d[6] << 8) + d[7];
- break;
- case 0x5:
- /* Target port group */
- h->group_id = (d[6] << 8) + d[7];
- break;
- default:
- break;
- }
- d += d[3] + 4;
- }
-
- if (h->group_id == -1) {
+ group_id = scsi_vpd_tpg_id(sdev, &rel_port);
+ if (group_id < 0) {
/*
* Internal error; TPGS supported but required
* VPD identification descriptors not present.
@@ -408,34 +345,65 @@ static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev,
"%s: No target port descriptors found\n",
ALUA_DH_NAME);
- h->state = TPGS_STATE_OPTIMIZED;
- h->tpgs = TPGS_MODE_NONE;
- err = SCSI_DH_DEV_UNSUPP;
- } else {
- sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->group_id, h->rel_port);
+ return SCSI_DH_DEV_UNSUPP;
}
- return err;
+ pg = alua_alloc_pg(sdev, group_id, tpgs);
+ if (IS_ERR(pg)) {
+ if (PTR_ERR(pg) == -ENOMEM)
+ return SCSI_DH_NOMEM;
+ return SCSI_DH_DEV_UNSUPP;
+ }
+ sdev_printk(KERN_INFO, sdev,
+ "%s: device %s port group %x rel port %x\n",
+ ALUA_DH_NAME, pg->device_id_str, group_id, rel_port);
+
+ /* Check for existing port group references */
+ spin_lock(&h->pg_lock);
+ old_pg = h->pg;
+ if (old_pg != pg) {
+ /* port group has changed. Update to new port group */
+ if (h->pg) {
+ spin_lock_irqsave(&old_pg->lock, flags);
+ list_del_rcu(&h->node);
+ spin_unlock_irqrestore(&old_pg->lock, flags);
+ }
+ rcu_assign_pointer(h->pg, pg);
+ pg_updated = true;
+ }
+
+ spin_lock_irqsave(&pg->lock, flags);
+ if (sdev->synchronous_alua)
+ pg->flags |= ALUA_SYNC_STPG;
+ if (pg_updated)
+ list_add_rcu(&h->node, &pg->dh_list);
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ alua_rtpg_queue(h->pg, sdev, NULL, true);
+ spin_unlock(&h->pg_lock);
+
+ if (old_pg)
+ kref_put(&old_pg->kref, release_port_group);
+
+ return SCSI_DH_OK;
}
-static char print_alua_state(int state)
+static char print_alua_state(unsigned char state)
{
switch (state) {
- case TPGS_STATE_OPTIMIZED:
+ case SCSI_ACCESS_STATE_OPTIMAL:
return 'A';
- case TPGS_STATE_NONOPTIMIZED:
+ case SCSI_ACCESS_STATE_ACTIVE:
return 'N';
- case TPGS_STATE_STANDBY:
+ case SCSI_ACCESS_STATE_STANDBY:
return 'S';
- case TPGS_STATE_UNAVAILABLE:
+ case SCSI_ACCESS_STATE_UNAVAILABLE:
return 'U';
- case TPGS_STATE_LBA_DEPENDENT:
+ case SCSI_ACCESS_STATE_LBA:
return 'L';
- case TPGS_STATE_OFFLINE:
+ case SCSI_ACCESS_STATE_OFFLINE:
return 'O';
- case TPGS_STATE_TRANSITIONING:
+ case SCSI_ACCESS_STATE_TRANSITIONING:
return 'T';
default:
return 'X';
@@ -447,40 +415,24 @@ static int alua_check_sense(struct scsi_device *sdev,
{
switch (sense_hdr->sense_key) {
case NOT_READY:
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
* LUN Not Accessible - ALUA state transition
*/
- return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
- /*
- * LUN Not Accessible -- Target port in standby state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
- /*
- * LUN Not Accessible -- Target port in unavailable state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
- /*
- * LUN Not Ready -- Offline
- */
- return SUCCESS;
- if (sdev->allow_restart &&
- sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02)
- /*
- * if the device is not started, we need to wake
- * the error handler to start the motor
- */
- return FAILED;
+ alua_check(sdev, false);
+ return NEEDS_RETRY;
+ }
break;
case UNIT_ATTENTION:
- if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+ if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
/*
- * Power On, Reset, or Bus Device Reset, just retry.
+ * Power On, Reset, or Bus Device Reset.
+ * Might have obscured a state transition,
+ * so schedule a recheck.
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+ }
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
/*
* Device internal reset
@@ -491,16 +443,20 @@ static int alua_check_sense(struct scsi_device *sdev,
* Mode Parameters Changed
*/
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
/*
* ALUA state changed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07)
+ }
+ if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
/*
* Implicit ALUA state transition failed
*/
+ alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+ }
if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
/*
* Inquiry data has changed
@@ -520,38 +476,74 @@ static int alua_check_sense(struct scsi_device *sdev,
}
/*
+ * alua_tur - Send a TEST UNIT READY
+ * @sdev: device to which the TEST UNIT READY command should be send
+ *
+ * Send a TEST UNIT READY to @sdev to figure out the device state
+ * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
+ * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise.
+ */
+static int alua_tur(struct scsi_device *sdev)
+{
+ struct scsi_sense_hdr sense_hdr;
+ int retval;
+
+ retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, &sense_hdr);
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ return SCSI_DH_RETRY;
+ else if (retval)
+ return SCSI_DH_IO;
+ else
+ return SCSI_DH_OK;
+}
+
+/*
* alua_rtpg - Evaluate REPORT TARGET GROUP STATES
* @sdev: the device to be evaluated.
- * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for device to exit transitioning state
*
* Evaluate the Target Port Group State.
* Returns SCSI_DH_DEV_OFFLINED if the path is
* found to be unusable.
*/
-static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
{
struct scsi_sense_hdr sense_hdr;
- int len, k, off, valid_states = 0;
- unsigned char *ucp;
- unsigned err;
- bool rtpg_ext_hdr_req = 1;
- unsigned long expiry, interval = 0;
+ struct alua_port_group *tmp_pg;
+ int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
+ unsigned char *desc, *buff;
+ unsigned err, retval;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
+ unsigned long flags;
- if (!h->transition_tmo)
- expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
- else
- expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
+ if (!pg->expiry) {
+ unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
- retry:
- err = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
+ if (pg->transition_tmo)
+ transition_tmo = pg->transition_tmo * HZ;
+
+ pg->expiry = round_jiffies_up(jiffies + transition_tmo);
+ }
+
+ buff = kzalloc(bufflen, GFP_KERNEL);
+ if (!buff)
+ return SCSI_DH_DEV_TEMP_BUSY;
- if (err == SCSI_DH_IO && h->senselen > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err)
+ retry:
+ retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, pg->flags);
+
+ if (retval) {
+ if (!scsi_sense_valid(&sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: rtpg failed, result %d\n",
+ ALUA_DH_NAME, retval);
+ kfree(buff);
+ if (driver_byte(retval) == DRIVER_ERROR)
+ return SCSI_DH_DEV_TEMP_BUSY;
return SCSI_DH_IO;
+ }
/*
* submit_rtpg() has failed on existing arrays
@@ -561,73 +553,111 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* The retry without rtpg_ext_hdr_req set
* handles this.
*/
- if (rtpg_ext_hdr_req == 1 &&
+ if (!(pg->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
sense_hdr.sense_key == ILLEGAL_REQUEST &&
sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
- rtpg_ext_hdr_req = 0;
+ pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
-
- err = alua_check_sense(sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
- goto retry;
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg sense code %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
- err = SCSI_DH_IO;
+ /*
+ * Retry on ALUA state transition or if any
+ * UNIT ATTENTION occurred.
+ */
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ err = SCSI_DH_RETRY;
+ else if (sense_hdr.sense_key == UNIT_ATTENTION)
+ err = SCSI_DH_RETRY;
+ if (err == SCSI_DH_RETRY &&
+ pg->expiry != 0 && time_before(jiffies, pg->expiry)) {
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ return err;
+ }
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ kfree(buff);
+ pg->expiry = 0;
+ return SCSI_DH_IO;
}
- if (err != SCSI_DH_OK)
- return err;
- len = (h->buff[0] << 24) + (h->buff[1] << 16) +
- (h->buff[2] << 8) + h->buff[3] + 4;
+ len = get_unaligned_be32(&buff[0]) + 4;
- if (len > h->bufflen) {
+ if (len > bufflen) {
/* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
+ kfree(buff);
+ bufflen = len;
+ buff = kmalloc(bufflen, GFP_KERNEL);
+ if (!buff) {
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
+ pg->expiry = 0;
return SCSI_DH_DEV_TEMP_BUSY;
}
goto retry;
}
- orig_transition_tmo = h->transition_tmo;
- if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && h->buff[5] != 0)
- h->transition_tmo = h->buff[5];
+ orig_transition_tmo = pg->transition_tmo;
+ if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0)
+ pg->transition_tmo = buff[5];
else
- h->transition_tmo = ALUA_FAILOVER_TIMEOUT;
+ pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
- if (wait_for_transition && (orig_transition_tmo != h->transition_tmo)) {
+ if (orig_transition_tmo != pg->transition_tmo) {
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
- ALUA_DH_NAME, h->transition_tmo);
- expiry = jiffies + h->transition_tmo * HZ;
+ ALUA_DH_NAME, pg->transition_tmo);
+ pg->expiry = jiffies + pg->transition_tmo * HZ;
}
- if ((h->buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
+ if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
tpg_desc_tbl_off = 8;
else
tpg_desc_tbl_off = 4;
- for (k = tpg_desc_tbl_off, ucp = h->buff + tpg_desc_tbl_off;
+ for (k = tpg_desc_tbl_off, desc = buff + tpg_desc_tbl_off;
k < len;
- k += off, ucp += off) {
-
- if (h->group_id == (ucp[2] << 8) + ucp[3]) {
- h->state = ucp[0] & 0x0f;
- h->pref = ucp[0] >> 7;
- valid_states = ucp[1];
+ k += off, desc += off) {
+ u16 group_id = get_unaligned_be16(&desc[2]);
+
+ spin_lock_irqsave(&port_group_lock, flags);
+ tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
+ group_id);
+ spin_unlock_irqrestore(&port_group_lock, flags);
+ if (tmp_pg) {
+ if (spin_trylock_irqsave(&tmp_pg->lock, flags)) {
+ if ((tmp_pg == pg) ||
+ !(tmp_pg->flags & ALUA_PG_RUNNING)) {
+ struct alua_dh_data *h;
+
+ tmp_pg->state = desc[0] & 0x0f;
+ tmp_pg->pref = desc[0] >> 7;
+ rcu_read_lock();
+ list_for_each_entry_rcu(h,
+ &tmp_pg->dh_list, node) {
+ /* h->sdev should always be valid */
+ BUG_ON(!h->sdev);
+ h->sdev->access_state = desc[0];
+ }
+ rcu_read_unlock();
+ }
+ if (tmp_pg == pg)
+ valid_states = desc[1];
+ spin_unlock_irqrestore(&tmp_pg->lock, flags);
+ }
+ kref_put(&tmp_pg->kref, release_port_group);
}
- off = 8 + (ucp[7] * 4);
+ off = 8 + (desc[7] * 4);
}
+ spin_lock_irqsave(&pg->lock, flags);
sdev_printk(KERN_INFO, sdev,
"%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
- ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
- h->pref ? "preferred" : "non-preferred",
+ ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state),
+ pg->pref ? "preferred" : "non-preferred",
valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
@@ -636,36 +666,236 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
- switch (h->state) {
- case TPGS_STATE_TRANSITIONING:
- if (wait_for_transition) {
- if (time_before(jiffies, expiry)) {
- /* State transition, retry */
- interval += 2000;
- msleep(interval);
- goto retry;
- }
+ switch (pg->state) {
+ case SCSI_ACCESS_STATE_TRANSITIONING:
+ if (time_before(jiffies, pg->expiry)) {
+ /* State transition, retry */
+ pg->interval = 2;
err = SCSI_DH_RETRY;
} else {
- err = SCSI_DH_OK;
- }
+ struct alua_dh_data *h;
- /* Transitioning time exceeded, set port to standby */
- h->state = TPGS_STATE_STANDBY;
+ /* Transitioning time exceeded, set port to standby */
+ err = SCSI_DH_IO;
+ pg->state = SCSI_ACCESS_STATE_STANDBY;
+ pg->expiry = 0;
+ rcu_read_lock();
+ list_for_each_entry_rcu(h, &pg->dh_list, node) {
+ BUG_ON(!h->sdev);
+ h->sdev->access_state =
+ (pg->state & SCSI_ACCESS_STATE_MASK);
+ if (pg->pref)
+ h->sdev->access_state |=
+ SCSI_ACCESS_STATE_PREFERRED;
+ }
+ rcu_read_unlock();
+ }
break;
- case TPGS_STATE_OFFLINE:
+ case SCSI_ACCESS_STATE_OFFLINE:
/* Path unusable */
err = SCSI_DH_DEV_OFFLINED;
+ pg->expiry = 0;
break;
default:
/* Useable path if active */
err = SCSI_DH_OK;
+ pg->expiry = 0;
break;
}
+ spin_unlock_irqrestore(&pg->lock, flags);
+ kfree(buff);
return err;
}
/*
+ * alua_stpg - Issue a SET TARGET PORT GROUP command
+ *
+ * Issue a SET TARGET PORT GROUP command and evaluate the
+ * response. Returns SCSI_DH_RETRY per default to trigger
+ * a re-evaluation of the target group state or SCSI_DH_OK
+ * if no further action needs to be taken.
+ */
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
+{
+ int retval;
+ struct scsi_sense_hdr sense_hdr;
+
+ if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
+ /* Only implicit ALUA supported, retry */
+ return SCSI_DH_RETRY;
+ }
+ switch (pg->state) {
+ case SCSI_ACCESS_STATE_OPTIMAL:
+ return SCSI_DH_OK;
+ case SCSI_ACCESS_STATE_ACTIVE:
+ if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
+ !pg->pref &&
+ (pg->tpgs & TPGS_MODE_IMPLICIT))
+ return SCSI_DH_OK;
+ break;
+ case SCSI_ACCESS_STATE_STANDBY:
+ case SCSI_ACCESS_STATE_UNAVAILABLE:
+ break;
+ case SCSI_ACCESS_STATE_OFFLINE:
+ return SCSI_DH_IO;
+ case SCSI_ACCESS_STATE_TRANSITIONING:
+ break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, unhandled TPGS state %d",
+ ALUA_DH_NAME, pg->state);
+ return SCSI_DH_NOSYS;
+ }
+ retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
+
+ if (retval) {
+ if (!scsi_sense_valid(&sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, result %d",
+ ALUA_DH_NAME, retval);
+ if (driver_byte(retval) == DRIVER_ERROR)
+ return SCSI_DH_DEV_TEMP_BUSY;
+ } else {
+ sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ }
+ }
+ /* Retry RTPG */
+ return SCSI_DH_RETRY;
+}
+
+static void alua_rtpg_work(struct work_struct *work)
+{
+ struct alua_port_group *pg =
+ container_of(work, struct alua_port_group, rtpg_work.work);
+ struct scsi_device *sdev;
+ LIST_HEAD(qdata_list);
+ int err = SCSI_DH_OK;
+ struct alua_queue_data *qdata, *tmp;
+ unsigned long flags;
+ struct workqueue_struct *alua_wq = kaluad_wq;
+
+ spin_lock_irqsave(&pg->lock, flags);
+ sdev = pg->rtpg_sdev;
+ if (!sdev) {
+ WARN_ON(pg->flags & ALUA_PG_RUN_RTPG);
+ WARN_ON(pg->flags & ALUA_PG_RUN_STPG);
+ spin_unlock_irqrestore(&pg->lock, flags);
+ return;
+ }
+ if (pg->flags & ALUA_SYNC_STPG)
+ alua_wq = kaluad_sync_wq;
+ pg->flags |= ALUA_PG_RUNNING;
+ if (pg->flags & ALUA_PG_RUN_RTPG) {
+ int state = pg->state;
+
+ pg->flags &= ~ALUA_PG_RUN_RTPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ if (state == SCSI_ACCESS_STATE_TRANSITIONING) {
+ if (alua_tur(sdev) == SCSI_DH_RETRY) {
+ spin_lock_irqsave(&pg->lock, flags);
+ pg->flags &= ~ALUA_PG_RUNNING;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ /* Send RTPG on failure or if TUR indicates SUCCESS */
+ }
+ err = alua_rtpg(sdev, pg);
+ spin_lock_irqsave(&pg->lock, flags);
+ if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
+ pg->flags &= ~ALUA_PG_RUNNING;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ if (err != SCSI_DH_OK)
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ }
+ if (pg->flags & ALUA_PG_RUN_STPG) {
+ pg->flags &= ~ALUA_PG_RUN_STPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ err = alua_stpg(sdev, pg);
+ spin_lock_irqsave(&pg->lock, flags);
+ if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ pg->interval = 0;
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ queue_delayed_work(alua_wq, &pg->rtpg_work,
+ pg->interval * HZ);
+ return;
+ }
+ }
+
+ list_splice_init(&pg->rtpg_list, &qdata_list);
+ pg->rtpg_sdev = NULL;
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
+ list_del(&qdata->entry);
+ if (qdata->callback_fn)
+ qdata->callback_fn(qdata->callback_data, err);
+ kfree(qdata);
+ }
+ spin_lock_irqsave(&pg->lock, flags);
+ pg->flags &= ~ALUA_PG_RUNNING;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ scsi_device_put(sdev);
+ kref_put(&pg->kref, release_port_group);
+}
+
+static void alua_rtpg_queue(struct alua_port_group *pg,
+ struct scsi_device *sdev,
+ struct alua_queue_data *qdata, bool force)
+{
+ int start_queue = 0;
+ unsigned long flags;
+ struct workqueue_struct *alua_wq = kaluad_wq;
+
+ if (!pg)
+ return;
+
+ spin_lock_irqsave(&pg->lock, flags);
+ if (qdata) {
+ list_add_tail(&qdata->entry, &pg->rtpg_list);
+ pg->flags |= ALUA_PG_RUN_STPG;
+ force = true;
+ }
+ if (pg->rtpg_sdev == NULL) {
+ pg->interval = 0;
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ kref_get(&pg->kref);
+ pg->rtpg_sdev = sdev;
+ scsi_device_get(sdev);
+ start_queue = 1;
+ } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) {
+ pg->flags |= ALUA_PG_RUN_RTPG;
+ /* Do not queue if the worker is already running */
+ if (!(pg->flags & ALUA_PG_RUNNING)) {
+ kref_get(&pg->kref);
+ start_queue = 1;
+ }
+ }
+
+ if (pg->flags & ALUA_SYNC_STPG)
+ alua_wq = kaluad_sync_wq;
+ spin_unlock_irqrestore(&pg->lock, flags);
+
+ if (start_queue &&
+ !queue_delayed_work(alua_wq, &pg->rtpg_work,
+ msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) {
+ scsi_device_put(sdev);
+ kref_put(&pg->kref, release_port_group);
+ }
+}
+
+/*
* alua_initialize - Initialize ALUA state
* @sdev: the device to be initialized
*
@@ -674,21 +904,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
*/
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int err;
-
- err = alua_check_tpgs(sdev, h);
- if (err != SCSI_DH_OK)
- goto out;
-
- err = alua_vpd_inquiry(sdev, h);
- if (err != SCSI_DH_OK)
- goto out;
-
- err = alua_rtpg(sdev, h, 0);
- if (err != SCSI_DH_OK)
- goto out;
-
-out:
+ int err = SCSI_DH_DEV_UNSUPP, tpgs;
+
+ mutex_lock(&h->init_mutex);
+ tpgs = alua_check_tpgs(sdev);
+ if (tpgs != TPGS_MODE_NONE)
+ err = alua_check_vpd(sdev, h, tpgs);
+ h->init_error = err;
+ mutex_unlock(&h->init_mutex);
return err;
}
/*
@@ -703,9 +926,11 @@ out:
static int alua_set_params(struct scsi_device *sdev, const char *params)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group __rcu *pg = NULL;
unsigned int optimize = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
+ unsigned long flags;
if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
return -EINVAL;
@@ -715,18 +940,23 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
return -EINVAL;
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+ spin_lock_irqsave(&pg->lock, flags);
if (optimize)
- h->flags |= ALUA_OPTIMIZE_STPG;
+ pg->flags |= ALUA_OPTIMIZE_STPG;
else
- h->flags &= ~ALUA_OPTIMIZE_STPG;
+ pg->flags &= ~ALUA_OPTIMIZE_STPG;
+ spin_unlock_irqrestore(&pg->lock, flags);
+ rcu_read_unlock();
return result;
}
-static uint optimize_stpg;
-module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
-
/*
* alua_activate - activate a path
* @sdev: device on the path to be activated
@@ -742,48 +972,33 @@ static int alua_activate(struct scsi_device *sdev,
{
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
- int stpg = 0;
+ struct alua_queue_data *qdata;
+ struct alua_port_group __rcu *pg;
- err = alua_rtpg(sdev, h, 1);
- if (err != SCSI_DH_OK)
+ qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
+ if (!qdata) {
+ err = SCSI_DH_RES_TEMP_UNAVAIL;
goto out;
-
- if (optimize_stpg)
- h->flags |= ALUA_OPTIMIZE_STPG;
-
- if (h->tpgs & TPGS_MODE_EXPLICIT) {
- switch (h->state) {
- case TPGS_STATE_NONOPTIMIZED:
- stpg = 1;
- if ((h->flags & ALUA_OPTIMIZE_STPG) &&
- (!h->pref) &&
- (h->tpgs & TPGS_MODE_IMPLICIT))
- stpg = 0;
- break;
- case TPGS_STATE_STANDBY:
- case TPGS_STATE_UNAVAILABLE:
- stpg = 1;
- break;
- case TPGS_STATE_OFFLINE:
- err = SCSI_DH_IO;
- break;
- case TPGS_STATE_TRANSITIONING:
- err = SCSI_DH_RETRY;
- break;
- default:
- break;
- }
}
-
- if (stpg) {
- h->callback_fn = fn;
- h->callback_data = data;
- err = submit_stpg(h);
- if (err == SCSI_DH_OK)
- return 0;
- h->callback_fn = h->callback_data = NULL;
+ qdata->callback_fn = fn;
+ qdata->callback_data = data;
+
+ mutex_lock(&h->init_mutex);
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg || !kref_get_unless_zero(&pg->kref)) {
+ rcu_read_unlock();
+ kfree(qdata);
+ err = h->init_error;
+ mutex_unlock(&h->init_mutex);
+ goto out;
}
+ fn = NULL;
+ rcu_read_unlock();
+ mutex_unlock(&h->init_mutex);
+ alua_rtpg_queue(pg, sdev, qdata, true);
+ kref_put(&pg->kref, release_port_group);
out:
if (fn)
fn(data, err);
@@ -791,6 +1006,29 @@ out:
}
/*
+ * alua_check - check path status
+ * @sdev: device on the path to be checked
+ *
+ * Check the device status
+ */
+static void alua_check(struct scsi_device *sdev, bool force)
+{
+ struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group *pg;
+
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (!pg || !kref_get_unless_zero(&pg->kref)) {
+ rcu_read_unlock();
+ return;
+ }
+ rcu_read_unlock();
+
+ alua_rtpg_queue(pg, sdev, NULL, force);
+ kref_put(&pg->kref, release_port_group);
+}
+
+/*
* alua_prep_fn - request callback
*
* Fail I/O to all paths not in state
@@ -799,13 +1037,20 @@ out:
static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
{
struct alua_dh_data *h = sdev->handler_data;
+ struct alua_port_group __rcu *pg;
+ unsigned char state = SCSI_ACCESS_STATE_OPTIMAL;
int ret = BLKPREP_OK;
- if (h->state == TPGS_STATE_TRANSITIONING)
+ rcu_read_lock();
+ pg = rcu_dereference(h->pg);
+ if (pg)
+ state = pg->state;
+ rcu_read_unlock();
+ if (state == SCSI_ACCESS_STATE_TRANSITIONING)
ret = BLKPREP_DEFER;
- else if (h->state != TPGS_STATE_OPTIMIZED &&
- h->state != TPGS_STATE_NONOPTIMIZED &&
- h->state != TPGS_STATE_LBA_DEPENDENT) {
+ else if (state != SCSI_ACCESS_STATE_OPTIMAL &&
+ state != SCSI_ACCESS_STATE_ACTIVE &&
+ state != SCSI_ACCESS_STATE_LBA) {
ret = BLKPREP_KILL;
req->cmd_flags |= REQ_QUIET;
}
@@ -813,6 +1058,13 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
}
+static void alua_rescan(struct scsi_device *sdev)
+{
+ struct alua_dh_data *h = sdev->handler_data;
+
+ alua_initialize(sdev, h);
+}
+
/*
* alua_bus_attach - Attach device handler
* @sdev: device to be attached to
@@ -820,20 +1072,21 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
static int alua_bus_attach(struct scsi_device *sdev)
{
struct alua_dh_data *h;
- int err;
+ int err, ret = -EINVAL;
h = kzalloc(sizeof(*h) , GFP_KERNEL);
if (!h)
return -ENOMEM;
- h->tpgs = TPGS_MODE_UNINITIALIZED;
- h->state = TPGS_STATE_OPTIMIZED;
- h->group_id = -1;
- h->rel_port = -1;
- h->buff = h->inq;
- h->bufflen = ALUA_INQUIRY_SIZE;
+ spin_lock_init(&h->pg_lock);
+ rcu_assign_pointer(h->pg, NULL);
+ h->init_error = SCSI_DH_OK;
h->sdev = sdev;
+ INIT_LIST_HEAD(&h->node);
+ mutex_init(&h->init_mutex);
err = alua_initialize(sdev, h);
+ if (err == SCSI_DH_NOMEM)
+ ret = -ENOMEM;
if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
goto failed;
@@ -841,7 +1094,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
return 0;
failed:
kfree(h);
- return -EINVAL;
+ return ret;
}
/*
@@ -851,9 +1104,19 @@ failed:
static void alua_bus_detach(struct scsi_device *sdev)
{
struct alua_dh_data *h = sdev->handler_data;
-
- if (h->buff && h->inq != h->buff)
- kfree(h->buff);
+ struct alua_port_group *pg;
+
+ spin_lock(&h->pg_lock);
+ pg = h->pg;
+ rcu_assign_pointer(h->pg, NULL);
+ h->sdev = NULL;
+ spin_unlock(&h->pg_lock);
+ if (pg) {
+ spin_lock_irq(&pg->lock);
+ list_del_rcu(&h->node);
+ spin_unlock_irq(&pg->lock);
+ kref_put(&pg->kref, release_port_group);
+ }
sdev->handler_data = NULL;
kfree(h);
}
@@ -866,6 +1129,7 @@ static struct scsi_device_handler alua_dh = {
.prep_fn = alua_prep_fn,
.check_sense = alua_check_sense,
.activate = alua_activate,
+ .rescan = alua_rescan,
.set_params = alua_set_params,
};
@@ -873,16 +1137,31 @@ static int __init alua_init(void)
{
int r;
+ kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0);
+ if (!kaluad_wq) {
+ /* Temporary failure, bypass */
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
+ kaluad_sync_wq = create_workqueue("kaluad_sync");
+ if (!kaluad_sync_wq) {
+ destroy_workqueue(kaluad_wq);
+ return SCSI_DH_DEV_TEMP_BUSY;
+ }
r = scsi_register_device_handler(&alua_dh);
- if (r != 0)
+ if (r != 0) {
printk(KERN_ERR "%s: Failed to register scsi device handler",
ALUA_DH_NAME);
+ destroy_workqueue(kaluad_sync_wq);
+ destroy_workqueue(kaluad_wq);
+ }
return r;
}
static void __exit alua_exit(void)
{
scsi_unregister_device_handler(&alua_dh);
+ destroy_workqueue(kaluad_sync_wq);
+ destroy_workqueue(kaluad_wq);
}
module_init(alua_init);
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index e6fb97c..375d818 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -199,7 +199,12 @@ static int parse_sp_info_reply(struct scsi_device *sdev,
csdev->lun_state = csdev->buffer[4];
csdev->current_sp = csdev->buffer[8];
csdev->port = csdev->buffer[7];
-
+ if (csdev->lun_state == CLARIION_LUN_OWNED)
+ sdev->access_state = SCSI_ACCESS_STATE_OPTIMAL;
+ else
+ sdev->access_state = SCSI_ACCESS_STATE_STANDBY;
+ if (csdev->default_sp == csdev->current_sp)
+ sdev->access_state |= SCSI_ACCESS_STATE_PREFERRED;
out:
return err;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 3613581..06fbd0b 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -165,6 +165,7 @@ struct rdac_controller {
struct work_struct ms_work;
struct scsi_device *ms_sdev;
struct list_head ms_head;
+ struct list_head dh_list;
};
struct c2_inquiry {
@@ -181,7 +182,9 @@ struct c2_inquiry {
};
struct rdac_dh_data {
+ struct list_head node;
struct rdac_controller *ctlr;
+ struct scsi_device *sdev;
#define UNINITIALIZED_LUN (1 << 8)
unsigned lun;
@@ -392,6 +395,7 @@ static struct rdac_controller *get_controller(int index, char *array_name,
INIT_WORK(&ctlr->ms_work, send_mode_select);
INIT_LIST_HEAD(&ctlr->ms_head);
list_add(&ctlr->node, &ctlr_list);
+ INIT_LIST_HEAD(&ctlr->dh_list);
return ctlr;
}
@@ -455,7 +459,8 @@ static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
{
- int err;
+ int err, access_state;
+ struct rdac_dh_data *tmp;
struct c9_inquiry *inqp;
h->state = RDAC_STATE_ACTIVE;
@@ -471,19 +476,31 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
h->mode = RDAC_MODE; /* LUN in RDAC mode */
/* Update ownership */
- if (inqp->avte_cvp & 0x1)
+ if (inqp->avte_cvp & 0x1) {
h->lun_state = RDAC_LUN_OWNED;
- else {
+ access_state = SCSI_ACCESS_STATE_OPTIMAL;
+ } else {
h->lun_state = RDAC_LUN_UNOWNED;
- if (h->mode == RDAC_MODE)
+ if (h->mode == RDAC_MODE) {
h->state = RDAC_STATE_PASSIVE;
+ access_state = SCSI_ACCESS_STATE_STANDBY;
+ } else
+ access_state = SCSI_ACCESS_STATE_ACTIVE;
}
/* Update path prio*/
- if (inqp->path_prio & 0x1)
+ if (inqp->path_prio & 0x1) {
h->preferred = RDAC_PREFERRED;
- else
+ access_state |= SCSI_ACCESS_STATE_PREFERRED;
+ } else
h->preferred = RDAC_NON_PREFERRED;
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp, &h->ctlr->dh_list, node) {
+ /* h->sdev should always be valid */
+ BUG_ON(!tmp->sdev);
+ tmp->sdev->access_state = access_state;
+ }
+ rcu_read_unlock();
}
return err;
@@ -508,6 +525,10 @@ static int initialize_controller(struct scsi_device *sdev,
h->ctlr = get_controller(index, array_name, array_id, sdev);
if (!h->ctlr)
err = SCSI_DH_RES_TEMP_UNAVAIL;
+ else {
+ list_add_rcu(&h->node, &h->ctlr->dh_list);
+ h->sdev = sdev;
+ }
spin_unlock(&list_lock);
}
return err;
@@ -562,7 +583,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
/*
* Command Lock contention
*/
- err = SCSI_DH_RETRY;
+ err = SCSI_DH_IMM_RETRY;
break;
default:
break;
@@ -612,6 +633,8 @@ retry:
err = mode_select_handle_sense(sdev, h->sense);
if (err == SCSI_DH_RETRY && retry_cnt--)
goto retry;
+ if (err == SCSI_DH_IMM_RETRY)
+ goto retry;
}
if (err == SCSI_DH_OK) {
h->state = RDAC_STATE_ACTIVE;
@@ -827,8 +850,11 @@ static void rdac_bus_detach( struct scsi_device *sdev )
flush_workqueue(kmpath_rdacd);
spin_lock(&list_lock);
- if (h->ctlr)
+ if (h->ctlr) {
+ list_del_rcu(&h->node);
+ h->sdev = NULL;
kref_put(&h->ctlr->kref, release_controller);
+ }
spin_unlock(&list_lock);
sdev->handler_data = NULL;
kfree(h);
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 3e08812..6c14e68 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -36,17 +36,10 @@
#define DONT_USE_INTR
-#define NCR5380_read(reg) inb(port + reg)
-#define NCR5380_write(reg, value) outb(value, port + reg)
+#define NCR5380_read(reg) inb(instance->io_port + reg)
+#define NCR5380_write(reg, value) outb(value, instance->io_port + reg)
#define NCR5380_implementation_fields /* none */
-#define NCR5380_local_declare() unsigned int port
-#define NCR5380_setup(instance) port = instance->io_port
-
-/*
- * Includes needed for NCR5380.[ch] (XXX: Move them to NCR5380.h)
- */
-#include <linux/delay.h>
#include "NCR5380.h"
#include "NCR5380.c"
@@ -56,6 +49,7 @@
static struct scsi_host_template dmx3191d_driver_template = {
+ .module = THIS_MODULE,
.proc_name = DMX3191D_DRIVER_NAME,
.name = "Domex DMX3191D",
.info = NCR5380_info,
@@ -67,6 +61,8 @@ static struct scsi_host_template dmx3191d_driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int dmx3191d_probe_one(struct pci_dev *pdev,
@@ -97,17 +93,25 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
*/
shost->irq = NO_IRQ;
- NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
+ error = NCR5380_init(shost, FLAG_NO_PSEUDO_DMA);
+ if (error)
+ goto out_host_put;
+
+ NCR5380_maybe_reset_bus(shost);
pci_set_drvdata(pdev, shost);
error = scsi_add_host(shost, &pdev->dev);
if (error)
- goto out_release_region;
+ goto out_exit;
scsi_scan_host(shost);
return 0;
+out_exit:
+ NCR5380_exit(shost);
+out_host_put:
+ scsi_host_put(shost);
out_release_region:
release_region(io, DMX3191D_REGION_LEN);
out_disable_device:
@@ -119,15 +123,14 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
static void dmx3191d_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ unsigned long io = shost->io_port;
scsi_remove_host(shost);
NCR5380_exit(shost);
-
- release_region(shost->io_port, DMX3191D_REGION_LEN);
- pci_disable_device(pdev);
-
scsi_host_put(shost);
+ release_region(io, DMX3191D_REGION_LEN);
+ pci_disable_device(pdev);
}
static struct pci_device_id dmx3191d_pci_tbl[] = {
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index d4cda5e..21c8d21 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -180,11 +180,14 @@ static u8 adpt_read_blink_led(adpt_hba* host)
*============================================================================
*/
+#ifdef MODULE
static struct pci_device_id dptids[] = {
{ PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, }
};
+#endif
+
MODULE_DEVICE_TABLE(pci,dptids);
static int adpt_detect(struct scsi_host_template* sht)
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 4c74c7b..6c736b0 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -1,9 +1,5 @@
-
#define PSEUDO_DMA
#define DONT_USE_INTR
-#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */
-#define DMA_WORKS_RIGHT
-
/*
* DTC 3180/3280 driver, by
@@ -50,15 +46,13 @@
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/stat.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <scsi/scsi_host.h>
+
#include "dtc.h"
#define AUTOPROBE_IRQ
#include "NCR5380.h"
@@ -150,7 +144,7 @@ static const struct signature {
static int __init dtc_setup(char *str)
{
- static int commandline_current = 0;
+ static int commandline_current;
int i;
int ints[10];
@@ -188,7 +182,7 @@ __setup("dtc=", dtc_setup);
static int __init dtc_detect(struct scsi_host_template * tpnt)
{
- static int current_override = 0, current_base = 0;
+ static int current_override, current_base;
struct Scsi_Host *instance;
unsigned int addr;
void __iomem *base;
@@ -205,9 +199,8 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
addr = 0;
} else
for (; !addr && (current_base < NO_BASES); ++current_base) {
-#if (DTCDEBUG & DTCDEBUG_INIT)
- printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
-#endif
+ dprintk(NDEBUG_INIT, "dtc: probing address 0x%08x\n",
+ (unsigned int)bases[current_base].address);
if (bases[current_base].noauto)
continue;
base = ioremap(bases[current_base].address, 0x2000);
@@ -216,18 +209,14 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
for (sig = 0; sig < NO_SIGNATURES; ++sig) {
if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
addr = bases[current_base].address;
-#if (DTCDEBUG & DTCDEBUG_INIT)
- printk(KERN_DEBUG "scsi-dtc : detected board.\n");
-#endif
+ dprintk(NDEBUG_INIT, "dtc: detected board\n");
goto found;
}
}
iounmap(base);
}
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
- printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
-#endif
+ dprintk(NDEBUG_INIT, "dtc: addr = 0x%08x\n", addr);
if (!addr)
break;
@@ -235,12 +224,15 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
found:
instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
if (instance == NULL)
- break;
+ goto out_unmap;
instance->base = addr;
((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
- NCR5380_init(instance, 0);
+ if (NCR5380_init(instance, FLAG_NO_DMA_FIXUP))
+ goto out_unregister;
+
+ NCR5380_maybe_reset_bus(instance);
NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */
if (overrides[current_override].irq != IRQ_AUTO)
@@ -271,14 +263,19 @@ found:
printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
instance->irq = NO_IRQ;
#endif
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+ dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
+ instance->host_no, instance->irq);
++current_override;
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out_unmap:
+ iounmap(base);
+ return count;
}
/*
@@ -331,12 +328,8 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
unsigned char *d = dst;
int i; /* For counting time spent in the poll-loop */
struct NCR5380_hostdata *hostdata = shost_priv(instance);
- NCR5380_local_declare();
- NCR5380_setup(instance);
i = 0;
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
else
@@ -348,7 +341,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
++i;
rtrc(3);
- memcpy_fromio(d, base + DTC_DATA_BUF, 128);
+ memcpy_fromio(d, hostdata->base + DTC_DATA_BUF, 128);
d += 128;
len -= 128;
rtrc(7);
@@ -358,9 +351,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
rtrc(4);
while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
++i;
- NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
rtrc(0);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
if (i > hostdata->spin_max_r)
hostdata->spin_max_r = i;
return (0);
@@ -383,12 +374,7 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
{
int i;
struct NCR5380_hostdata *hostdata = shost_priv(instance);
- NCR5380_local_declare();
- NCR5380_setup(instance);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
- /* set direction (write) */
if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, 0);
else
@@ -400,7 +386,7 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
++i;
rtrc(3);
- memcpy_toio(base + DTC_DATA_BUF, src, 128);
+ memcpy_toio(hostdata->base + DTC_DATA_BUF, src, 128);
src += 128;
len -= 128;
}
@@ -413,47 +399,60 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
++i;
rtrc(7);
/* Check for parity error here. fixme. */
- NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
rtrc(0);
if (i > hostdata->spin_max_w)
hostdata->spin_max_w = i;
return (0);
}
+static int dtc_dma_xfer_len(struct scsi_cmnd *cmd)
+{
+ int transfersize = cmd->transfersize;
+
+ /* Limit transfers to 32K, for xx400 & xx406
+ * pseudoDMA that transfers in 128 bytes blocks.
+ */
+ if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
+ !(cmd->SCp.this_residual % transfersize))
+ transfersize = 32 * 1024;
+
+ return transfersize;
+}
+
MODULE_LICENSE("GPL");
#include "NCR5380.c"
static int dtc_release(struct Scsi_Host *shost)
{
- NCR5380_local_declare();
- NCR5380_setup(shost);
+ struct NCR5380_hostdata *hostdata = shost_priv(shost);
+
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
scsi_unregister(shost);
- iounmap(base);
+ iounmap(hostdata->base);
return 0;
}
static struct scsi_host_template driver_template = {
- .name = "DTC 3180/3280 ",
- .detect = dtc_detect,
- .release = dtc_release,
- .proc_name = "dtc3x80",
- .show_info = dtc_show_info,
- .write_info = dtc_write_info,
- .info = dtc_info,
- .queuecommand = dtc_queue_command,
- .eh_abort_handler = dtc_abort,
- .eh_bus_reset_handler = dtc_bus_reset,
- .bios_param = dtc_biosparam,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .name = "DTC 3180/3280",
+ .detect = dtc_detect,
+ .release = dtc_release,
+ .proc_name = "dtc3x80",
+ .show_info = dtc_show_info,
+ .write_info = dtc_write_info,
+ .info = dtc_info,
+ .queuecommand = dtc_queue_command,
+ .eh_abort_handler = dtc_abort,
+ .eh_bus_reset_handler = dtc_bus_reset,
+ .bios_param = dtc_biosparam,
+ .can_queue = 32,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index 78a2332..56732cb 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -10,54 +10,17 @@
#ifndef DTC3280_H
#define DTC3280_H
-#define DTCDEBUG 0
-#define DTCDEBUG_INIT 0x1
-#define DTCDEBUG_TRANSFER 0x2
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
-#endif
-
#define NCR5380_implementation_fields \
void __iomem *base
-#define NCR5380_local_declare() \
- void __iomem *base
-
-#define NCR5380_setup(instance) \
- base = ((struct NCR5380_hostdata *)(instance)->hostdata)->base
+#define DTC_address(reg) \
+ (((struct NCR5380_hostdata *)shost_priv(instance))->base + DTC_5380_OFFSET + reg)
-#define DTC_address(reg) (base + DTC_5380_OFFSET + reg)
-
-#define dbNCR5380_read(reg) \
- (rval=readb(DTC_address(reg)), \
- (((unsigned char) printk("DTC : read register %d at addr %p is: %02x\n"\
- , (reg), DTC_address(reg), rval)), rval ) )
-
-#define dbNCR5380_write(reg, value) do { \
- printk("DTC : write %02x to register %d at address %p\n", \
- (value), (reg), DTC_address(reg)); \
- writeb(value, DTC_address(reg));} while(0)
-
-
-#if !(DTCDEBUG & DTCDEBUG_TRANSFER)
#define NCR5380_read(reg) (readb(DTC_address(reg)))
#define NCR5380_write(reg, value) (writeb(value, DTC_address(reg)))
-#else
-#define NCR5380_read(reg) (readb(DTC_address(reg)))
-#define xNCR5380_read(reg) \
- (((unsigned char) printk("DTC : read register %d at address %p\n"\
- , (reg), DTC_address(reg))), readb(DTC_address(reg)))
-#define NCR5380_write(reg, value) do { \
- printk("DTC : write %02x to register %d at address %p\n", \
- (value), (reg), DTC_address(reg)); \
- writeb(value, DTC_address(reg));} while(0)
-#endif
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+ dtc_dma_xfer_len(cmd)
#define NCR5380_intr dtc_intr
#define NCR5380_queue_command dtc_queue_command
diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c
index baf9130..3e84834 100644
--- a/drivers/scsi/esas2r/esas2r_ioctl.c
+++ b/drivers/scsi/esas2r/esas2r_ioctl.c
@@ -1360,14 +1360,15 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg)
if (ioctl->header.channel == 0xFF) {
a = (struct esas2r_adapter *)hostdata;
} else {
- a = esas2r_adapters[ioctl->header.channel];
- if (ioctl->header.channel >= MAX_ADAPTERS || (a == NULL)) {
+ if (ioctl->header.channel >= MAX_ADAPTERS ||
+ esas2r_adapters[ioctl->header.channel] == NULL) {
ioctl->header.return_code = IOCTL_BAD_CHANNEL;
esas2r_log(ESAS2R_LOG_WARN, "bad channel value");
kfree(ioctl);
return -ENOTSUPP;
}
+ a = esas2r_adapters[ioctl->header.channel];
}
switch (cmd) {
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
index 31f8966..33581ba 100644
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -256,7 +256,6 @@ static struct scsi_host_template driver_template = {
.proc_name = ESAS2R_DRVR_NAME,
.change_queue_depth = scsi_change_queue_depth,
.max_sectors = 0xFFFF,
- .use_blk_tags = 1,
};
int sgl_page_size = 512;
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 065b25d..71cb05b 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2694,7 +2694,6 @@ struct scsi_host_template scsi_esp_template = {
.use_clustering = ENABLE_CLUSTERING,
.max_sectors = 0xffff,
.skip_settle_delay = 1,
- .use_blk_tags = 1,
};
EXPORT_SYMBOL(scsi_esp_template);
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index d3eb80c..0efe711 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -287,7 +287,6 @@ static struct scsi_host_template fcoe_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xffff,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -1626,7 +1625,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
/* crc offload */
if (likely(lport->crc_offload)) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_headroom(skb);
skb->csum_offset = skb->len;
crc = 0;
@@ -1873,7 +1872,6 @@ static int fcoe_percpu_receive_thread(void *arg)
set_user_nice(current, MIN_NICE);
-retry:
while (!kthread_should_stop()) {
spin_lock_bh(&p->fcoe_rx_list.lock);
@@ -1883,7 +1881,7 @@ retry:
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_bh(&p->fcoe_rx_list.lock);
schedule();
- goto retry;
+ continue;
}
spin_unlock_bh(&p->fcoe_rx_list.lock);
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 34a1b1f..3e83d48 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -1118,7 +1118,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
* If this is the first validated FCF, note the time and
* set a timer to trigger selection.
*/
- if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) {
+ if (mtu_valid && !fip->sel_fcf && !fip->sel_time &&
+ fcoe_ctlr_fcf_usable(fcf)) {
fip->sel_time = jiffies +
msecs_to_jiffies(FCOE_CTLR_START_DELAY);
if (!timer_pending(&fip->timer) ||
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index d7597c0..641c60e 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -93,36 +93,40 @@ static struct notifier_block libfcoe_notifier = {
int fcoe_link_speed_update(struct fc_lport *lport)
{
struct net_device *netdev = fcoe_get_netdev(lport);
- struct ethtool_cmd ecmd;
+ struct ethtool_link_ksettings ecmd;
- if (!__ethtool_get_settings(netdev, &ecmd)) {
+ if (!__ethtool_get_link_ksettings(netdev, &ecmd)) {
lport->link_supported_speeds &= ~(FC_PORTSPEED_1GBIT |
FC_PORTSPEED_10GBIT |
FC_PORTSPEED_20GBIT |
FC_PORTSPEED_40GBIT);
- if (ecmd.supported & (SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full |
- SUPPORTED_1000baseKX_Full))
+ if (ecmd.link_modes.supported[0] & (
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_1000baseKX_Full))
lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
- if (ecmd.supported & (SUPPORTED_10000baseT_Full |
- SUPPORTED_10000baseKX4_Full |
- SUPPORTED_10000baseKR_Full |
- SUPPORTED_10000baseR_FEC))
+ if (ecmd.link_modes.supported[0] & (
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_10000baseKX4_Full |
+ SUPPORTED_10000baseKR_Full |
+ SUPPORTED_10000baseR_FEC))
lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
- if (ecmd.supported & (SUPPORTED_20000baseMLD2_Full |
- SUPPORTED_20000baseKR2_Full))
+ if (ecmd.link_modes.supported[0] & (
+ SUPPORTED_20000baseMLD2_Full |
+ SUPPORTED_20000baseKR2_Full))
lport->link_supported_speeds |= FC_PORTSPEED_20GBIT;
- if (ecmd.supported & (SUPPORTED_40000baseKR4_Full |
- SUPPORTED_40000baseCR4_Full |
- SUPPORTED_40000baseSR4_Full |
- SUPPORTED_40000baseLR4_Full))
+ if (ecmd.link_modes.supported[0] & (
+ SUPPORTED_40000baseKR4_Full |
+ SUPPORTED_40000baseCR4_Full |
+ SUPPORTED_40000baseSR4_Full |
+ SUPPORTED_40000baseLR4_Full))
lport->link_supported_speeds |= FC_PORTSPEED_40GBIT;
- switch (ethtool_cmd_speed(&ecmd)) {
+ switch (ecmd.base.speed) {
case SPEED_1000:
lport->link_speed = FC_PORTSPEED_1GBIT;
break;
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index eefe14d..b87ab38 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -1768,7 +1768,7 @@ struct scsi_host_template fdomain_driver_template = {
};
#ifndef PCMCIA
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && defined(MODULE)
static struct pci_device_id fdomain_pci_tbl[] = {
{ PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 8a0d4d7..58ce902 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -118,7 +118,6 @@ static struct scsi_host_template fnic_host_template = {
.sg_tablesize = FNIC_MAX_SG_DESC_CNT,
.max_sectors = 0xffff,
.shost_attrs = fnic_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -697,13 +696,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
fnic->fnic_max_tag_id = host->can_queue;
- err = scsi_init_shared_tag_map(host, fnic->fnic_max_tag_id);
- if (err) {
- shost_printk(KERN_ERR, fnic->lport->host,
- "Unable to alloc shared tag map\n");
- goto err_out_dev_close;
- }
-
host->max_lun = fnic->config.luns_per_tgt;
host->max_id = FNIC_MAX_FCP_TARGET;
host->max_cmd_len = FCOE_MAX_CMD_LEN;
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 266b909..f3032ca 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -958,23 +958,22 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic,
case FCPIO_INVALID_PARAM: /* some parameter in request invalid */
case FCPIO_REQ_NOT_SUPPORTED:/* request type is not supported */
default:
- shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n",
- fnic_fcpio_status_to_str(hdr_status));
sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status;
break;
}
- if (hdr_status != FCPIO_SUCCESS) {
- atomic64_inc(&fnic_stats->io_stats.io_failures);
- shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n",
- fnic_fcpio_status_to_str(hdr_status));
- }
/* Break link with the SCSI command */
CMD_SP(sc) = NULL;
CMD_FLAGS(sc) |= FNIC_IO_DONE;
spin_unlock_irqrestore(io_lock, flags);
+ if (hdr_status != FCPIO_SUCCESS) {
+ atomic64_inc(&fnic_stats->io_stats.io_failures);
+ shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n",
+ fnic_fcpio_status_to_str(hdr_status));
+ }
+
fnic_release_ioreq_buf(fnic, io_req, sc);
mempool_free(io_req, fnic->io_req_pool);
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index f8d2478..90091e6 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -56,40 +56,31 @@
*
*/
-/* settings for DTC3181E card with only Mustek scanner attached */
-#define USLEEP_POLL msecs_to_jiffies(10)
-#define USLEEP_SLEEP msecs_to_jiffies(200)
-#define USLEEP_WAITLONG msecs_to_jiffies(5000)
-
#define AUTOPROBE_IRQ
#ifdef CONFIG_SCSI_GENERIC_NCR53C400
-#define NCR53C400_PSEUDO_DMA 1
#define PSEUDO_DMA
-#define NCR53C400
#endif
#include <asm/io.h>
-#include <linux/signal.h>
#include <linux/blkdev.h>
+#include <linux/module.h>
#include <scsi/scsi_host.h>
#include "g_NCR5380.h"
#include "NCR5380.h"
-#include <linux/stat.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/isapnp.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#define NCR_NOT_SET 0
-static int ncr_irq = NCR_NOT_SET;
-static int ncr_dma = NCR_NOT_SET;
-static int ncr_addr = NCR_NOT_SET;
-static int ncr_5380 = NCR_NOT_SET;
-static int ncr_53c400 = NCR_NOT_SET;
-static int ncr_53c400a = NCR_NOT_SET;
-static int dtc_3181e = NCR_NOT_SET;
+static int ncr_irq;
+static int ncr_dma;
+static int ncr_addr;
+static int ncr_5380;
+static int ncr_53c400;
+static int ncr_53c400a;
+static int dtc_3181e;
+static int hp_c2502;
static struct override {
NCR5380_map_type NCR5380_map_name;
@@ -121,7 +112,7 @@ static struct override {
static void __init internal_setup(int board, char *str, int *ints)
{
- static int commandline_current = 0;
+ static int commandline_current;
switch (board) {
case BOARD_NCR5380:
if (ints[0] != 2 && ints[0] != 3) {
@@ -235,6 +226,30 @@ static int __init do_DTC3181E_setup(char *str)
#endif
+#ifndef SCSI_G_NCR5380_MEM
+/*
+ * Configure I/O address of 53C400A or DTC436 by writing magic numbers
+ * to ports 0x779 and 0x379.
+ */
+static void magic_configure(int idx, u8 irq, u8 magic[])
+{
+ u8 cfg = 0;
+
+ outb(magic[0], 0x779);
+ outb(magic[1], 0x379);
+ outb(magic[2], 0x379);
+ outb(magic[3], 0x379);
+ outb(magic[4], 0x379);
+
+ /* allowed IRQs for HP C2502 */
+ if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
+ irq = 0;
+ if (idx >= 0 && idx <= 7)
+ cfg = 0x80 | idx | (irq << 4);
+ outb(cfg, 0x379);
+}
+#endif
+
/**
* generic_NCR5380_detect - look for NCR5380 controllers
* @tpnt: the scsi template
@@ -243,19 +258,18 @@ static int __init do_DTC3181E_setup(char *str)
* and DTC436(ISAPnP) controllers. If overrides have been set we use
* them.
*
- * The caller supplied NCR5380_init function is invoked from here, before
- * the interrupt line is taken.
- *
* Locks: none
*/
static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
{
- static int current_override = 0;
+ static int current_override;
int count;
unsigned int *ports;
+ u8 *magic = NULL;
#ifndef SCSI_G_NCR5380_MEM
int i;
+ int port_idx = -1;
unsigned long region_size = 16;
#endif
static unsigned int __initdata ncr_53c400a_ports[] = {
@@ -264,27 +278,36 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
static unsigned int __initdata dtc_3181e_ports[] = {
0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
};
- int flags = 0;
+ static u8 ncr_53c400a_magic[] __initdata = { /* 53C400A & DTC436 */
+ 0x59, 0xb9, 0xc5, 0xae, 0xa6
+ };
+ static u8 hp_c2502_magic[] __initdata = { /* HP C2502 */
+ 0x0f, 0x22, 0xf0, 0x20, 0x80
+ };
+ int flags;
struct Scsi_Host *instance;
+ struct NCR5380_hostdata *hostdata;
#ifdef SCSI_G_NCR5380_MEM
unsigned long base;
void __iomem *iomem;
#endif
- if (ncr_irq != NCR_NOT_SET)
+ if (ncr_irq)
overrides[0].irq = ncr_irq;
- if (ncr_dma != NCR_NOT_SET)
+ if (ncr_dma)
overrides[0].dma = ncr_dma;
- if (ncr_addr != NCR_NOT_SET)
+ if (ncr_addr)
overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr;
- if (ncr_5380 != NCR_NOT_SET)
+ if (ncr_5380)
overrides[0].board = BOARD_NCR5380;
- else if (ncr_53c400 != NCR_NOT_SET)
+ else if (ncr_53c400)
overrides[0].board = BOARD_NCR53C400;
- else if (ncr_53c400a != NCR_NOT_SET)
+ else if (ncr_53c400a)
overrides[0].board = BOARD_NCR53C400A;
- else if (dtc_3181e != NCR_NOT_SET)
+ else if (dtc_3181e)
overrides[0].board = BOARD_DTC3181E;
+ else if (hp_c2502)
+ overrides[0].board = BOARD_HP_C2502;
#ifndef SCSI_G_NCR5380_MEM
if (!current_override && isapnp_present()) {
struct pnp_dev *dev = NULL;
@@ -318,41 +341,45 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
}
}
#endif
- tpnt->proc_name = "g_NCR5380";
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
if (!(overrides[current_override].NCR5380_map_name))
continue;
ports = NULL;
+ flags = 0;
switch (overrides[current_override].board) {
case BOARD_NCR5380:
flags = FLAG_NO_PSEUDO_DMA;
break;
case BOARD_NCR53C400:
- flags = FLAG_NCR53C400;
+#ifdef PSEUDO_DMA
+ flags = FLAG_NO_DMA_FIXUP;
+#endif
break;
case BOARD_NCR53C400A:
- flags = FLAG_NO_PSEUDO_DMA;
+ flags = FLAG_NO_DMA_FIXUP;
+ ports = ncr_53c400a_ports;
+ magic = ncr_53c400a_magic;
+ break;
+ case BOARD_HP_C2502:
+ flags = FLAG_NO_DMA_FIXUP;
ports = ncr_53c400a_ports;
+ magic = hp_c2502_magic;
break;
case BOARD_DTC3181E:
- flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
+ flags = FLAG_NO_DMA_FIXUP;
ports = dtc_3181e_ports;
+ magic = ncr_53c400a_magic;
break;
}
#ifndef SCSI_G_NCR5380_MEM
- if (ports) {
+ if (ports && magic) {
/* wakeup sequence for the NCR53C400A and DTC3181E */
/* Disable the adapter and look for a free io port */
- outb(0x59, 0x779);
- outb(0xb9, 0x379);
- outb(0xc5, 0x379);
- outb(0xae, 0x379);
- outb(0xa6, 0x379);
- outb(0x00, 0x379);
+ magic_configure(-1, 0, magic);
if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
for (i = 0; ports[i]; i++) {
@@ -371,17 +398,12 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
}
if (ports[i]) {
/* At this point we have our region reserved */
- outb(0x59, 0x779);
- outb(0xb9, 0x379);
- outb(0xc5, 0x379);
- outb(0xae, 0x379);
- outb(0xa6, 0x379);
- outb(0x80 | i, 0x379); /* set io port to be used */
+ magic_configure(i, 0, magic); /* no IRQ yet */
outb(0xc0, ports[i] + 9);
if (inb(ports[i] + 9) != 0x80)
continue;
- else
- overrides[current_override].NCR5380_map_name = ports[i];
+ overrides[current_override].NCR5380_map_name = ports[i];
+ port_idx = i;
} else
continue;
}
@@ -403,24 +425,65 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
}
#endif
instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
- if (instance == NULL) {
-#ifndef SCSI_G_NCR5380_MEM
- release_region(overrides[current_override].NCR5380_map_name, region_size);
-#else
- iounmap(iomem);
- release_mem_region(base, NCR5380_region_size);
-#endif
- continue;
- }
+ if (instance == NULL)
+ goto out_release;
+ hostdata = shost_priv(instance);
- instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
#ifndef SCSI_G_NCR5380_MEM
+ instance->io_port = overrides[current_override].NCR5380_map_name;
instance->n_io_port = region_size;
+ hostdata->io_width = 1; /* 8-bit PDMA by default */
+
+ /*
+ * On NCR53C400 boards, NCR5380 registers are mapped 8 past
+ * the base address.
+ */
+ switch (overrides[current_override].board) {
+ case BOARD_NCR53C400:
+ instance->io_port += 8;
+ hostdata->c400_ctl_status = 0;
+ hostdata->c400_blk_cnt = 1;
+ hostdata->c400_host_buf = 4;
+ break;
+ case BOARD_DTC3181E:
+ hostdata->io_width = 2; /* 16-bit PDMA */
+ /* fall through */
+ case BOARD_NCR53C400A:
+ case BOARD_HP_C2502:
+ hostdata->c400_ctl_status = 9;
+ hostdata->c400_blk_cnt = 10;
+ hostdata->c400_host_buf = 8;
+ break;
+ }
#else
- ((struct NCR5380_hostdata *)instance->hostdata)->iomem = iomem;
+ instance->base = overrides[current_override].NCR5380_map_name;
+ hostdata->iomem = iomem;
+ switch (overrides[current_override].board) {
+ case BOARD_NCR53C400:
+ hostdata->c400_ctl_status = 0x100;
+ hostdata->c400_blk_cnt = 0x101;
+ hostdata->c400_host_buf = 0x104;
+ break;
+ case BOARD_DTC3181E:
+ case BOARD_NCR53C400A:
+ case BOARD_HP_C2502:
+ pr_err(DRV_MODULE_NAME ": unknown register offsets\n");
+ goto out_unregister;
+ }
#endif
- NCR5380_init(instance, flags);
+ if (NCR5380_init(instance, flags))
+ goto out_unregister;
+
+ switch (overrides[current_override].board) {
+ case BOARD_NCR53C400:
+ case BOARD_DTC3181E:
+ case BOARD_NCR53C400A:
+ case BOARD_HP_C2502:
+ NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+ }
+
+ NCR5380_maybe_reset_bus(instance);
if (overrides[current_override].irq != IRQ_AUTO)
instance->irq = overrides[current_override].irq;
@@ -431,12 +494,18 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
if (instance->irq == 255)
instance->irq = NO_IRQ;
- if (instance->irq != NO_IRQ)
+ if (instance->irq != NO_IRQ) {
+#ifndef SCSI_G_NCR5380_MEM
+ /* set IRQ for HP C2502 */
+ if (overrides[current_override].board == BOARD_HP_C2502)
+ magic_configure(port_idx, instance->irq, magic);
+#endif
if (request_irq(instance->irq, generic_NCR5380_intr,
0, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = NO_IRQ;
}
+ }
if (instance->irq == NO_IRQ) {
printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
@@ -447,6 +516,17 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out_release:
+#ifndef SCSI_G_NCR5380_MEM
+ release_region(overrides[current_override].NCR5380_map_name, region_size);
+#else
+ iounmap(iomem);
+ release_mem_region(base, NCR5380_region_size);
+#endif
+ return count;
}
/**
@@ -460,21 +540,15 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
{
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
if (instance->irq != NO_IRQ)
free_irq(instance->irq, instance);
NCR5380_exit(instance);
-
#ifndef SCSI_G_NCR5380_MEM
- release_region(instance->NCR5380_instance_name, instance->n_io_port);
+ release_region(instance->io_port, instance->n_io_port);
#else
iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem);
- release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
+ release_mem_region(instance->base, NCR5380_region_size);
#endif
-
-
return 0;
}
@@ -507,7 +581,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
}
#endif
-#ifdef NCR53C400_PSEUDO_DMA
+#ifdef PSEUDO_DMA
/**
* NCR5380_pread - pseudo DMA read
@@ -521,75 +595,68 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int blocks = len / 128;
int start = 0;
- int bl;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
- NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
- NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+ NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
+ NCR5380_write(hostdata->c400_blk_cnt, blocks);
while (1) {
- if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+ if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
break;
- }
- if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+ if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
return -1;
}
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
+ ; /* FIXME - no timeout */
#ifndef SCSI_G_NCR5380_MEM
- {
- int i;
- for (i = 0; i < 128; i++)
- dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
- }
+ if (hostdata->io_width == 2)
+ insw(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 64);
+ else
+ insb(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128);
+ memcpy_fromio(dst + start,
+ hostdata->iomem + NCR53C400_host_buffer, 128);
#endif
start += 128;
blocks--;
}
if (blocks) {
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
- {
- // FIXME - no timeout
- }
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
+ ; /* FIXME - no timeout */
#ifndef SCSI_G_NCR5380_MEM
- {
- int i;
- for (i = 0; i < 128; i++)
- dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
- }
+ if (hostdata->io_width == 2)
+ insw(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 64);
+ else
+ insb(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128);
+ memcpy_fromio(dst + start,
+ hostdata->iomem + NCR53C400_host_buffer, 128);
#endif
start += 128;
blocks--;
}
- if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+ if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
printk("53C400r: no 53C80 gated irq after transfer");
-#if 0
- /*
- * DON'T DO THIS - THEY NEVER ARRIVE!
- */
- printk("53C400r: Waiting for 53C80 registers\n");
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+ /* wait for 53C80 registers to be available */
+ while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
;
-#endif
+
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
printk(KERN_ERR "53C400r: no end dma signal\n");
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
return 0;
}
@@ -605,89 +672,91 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int blocks = len / 128;
int start = 0;
- int bl;
- int i;
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
- NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
- NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+ NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+ NCR5380_write(hostdata->c400_blk_cnt, blocks);
while (1) {
- if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+ if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
return -1;
}
- if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+ if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
break;
- }
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
; // FIXME - timeout
#ifndef SCSI_G_NCR5380_MEM
- {
- for (i = 0; i < 128; i++)
- NCR5380_write(C400_HOST_BUFFER, src[start + i]);
- }
+ if (hostdata->io_width == 2)
+ outsw(instance->io_port + hostdata->c400_host_buf,
+ src + start, 64);
+ else
+ outsb(instance->io_port + hostdata->c400_host_buf,
+ src + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128);
+ memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
+ src + start, 128);
#endif
start += 128;
blocks--;
}
if (blocks) {
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
; // FIXME - no timeout
#ifndef SCSI_G_NCR5380_MEM
- {
- for (i = 0; i < 128; i++)
- NCR5380_write(C400_HOST_BUFFER, src[start + i]);
- }
+ if (hostdata->io_width == 2)
+ outsw(instance->io_port + hostdata->c400_host_buf,
+ src + start, 64);
+ else
+ outsb(instance->io_port + hostdata->c400_host_buf,
+ src + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128);
+ memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
+ src + start, 128);
#endif
start += 128;
blocks--;
}
-#if 0
- printk("53C400w: waiting for registers to be available\n");
- THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG);
- printk("53C400w: Got em\n");
-#endif
-
- /* Let's wait for this instead - could be ugly */
- /* All documentation says to check for this. Maybe my hardware is too
- * fast. Waiting for it seems to work fine! KLL
- */
- while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
- ; // FIXME - no timeout
-
- /*
- * I know. i is certainly != 0 here but the loop is new. See previous
- * comment.
- */
- if (i) {
- if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
- printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i);
- } else
- printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n");
+ /* wait for 53C80 registers to be available */
+ while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
+ udelay(4); /* DTC436 chip hangs without this */
+ /* FIXME - no timeout */
+ }
-#if 0
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
printk(KERN_ERR "53C400w: no end dma signal\n");
}
-#endif
+
while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
; // TIMEOUT
return 0;
}
-#endif /* PSEUDO_DMA */
+
+static int generic_NCR5380_dma_xfer_len(struct scsi_cmnd *cmd)
+{
+ int transfersize = cmd->transfersize;
+
+ /* Limit transfers to 32K, for xx400 & xx406
+ * pseudoDMA that transfers in 128 bytes blocks.
+ */
+ if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
+ !(cmd->SCp.this_residual % transfersize))
+ transfersize = 32 * 1024;
+
+ /* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
+ if (transfersize % 128)
+ transfersize = 0;
+
+ return transfersize;
+}
+
+#endif /* PSEUDO_DMA */
/*
* Include the NCR5380 core code that we build our driver around
@@ -696,22 +765,24 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
#include "NCR5380.c"
static struct scsi_host_template driver_template = {
- .show_info = generic_NCR5380_show_info,
- .name = "Generic NCR5380/NCR53C400 SCSI",
- .detect = generic_NCR5380_detect,
- .release = generic_NCR5380_release_resources,
- .info = generic_NCR5380_info,
- .queuecommand = generic_NCR5380_queue_command,
+ .proc_name = DRV_MODULE_NAME,
+ .name = "Generic NCR5380/NCR53C400 SCSI",
+ .detect = generic_NCR5380_detect,
+ .release = generic_NCR5380_release_resources,
+ .info = generic_NCR5380_info,
+ .queuecommand = generic_NCR5380_queue_command,
.eh_abort_handler = generic_NCR5380_abort,
.eh_bus_reset_handler = generic_NCR5380_bus_reset,
- .bios_param = NCR5380_BIOSPARAM,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .bios_param = NCR5380_BIOSPARAM,
+ .can_queue = 16,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
-#include <linux/module.h>
+
#include "scsi_module.c"
module_param(ncr_irq, int, 0);
@@ -721,6 +792,7 @@ module_param(ncr_5380, int, 0);
module_param(ncr_53c400, int, 0);
module_param(ncr_53c400a, int, 0);
module_param(dtc_3181e, int, 0);
+module_param(hp_c2502, int, 0);
MODULE_LICENSE("GPL");
#if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE)
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index bea1a3b..6f3d2ac 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -14,81 +14,67 @@
#ifndef GENERIC_NCR5380_H
#define GENERIC_NCR5380_H
-#ifdef NCR53C400
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
#define BIOSPARAM
#define NCR5380_BIOSPARAM generic_NCR5380_biosparam
#else
#define NCR5380_BIOSPARAM NULL
#endif
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
#define __STRVAL(x) #x
#define STRVAL(x) __STRVAL(x)
#ifndef SCSI_G_NCR5380_MEM
+#define DRV_MODULE_NAME "g_NCR5380"
-#define NCR5380_map_config port
#define NCR5380_map_type int
#define NCR5380_map_name port
-#define NCR5380_instance_name io_port
-#define NCR53C400_register_offset 0
-#define NCR53C400_address_adjust 8
-#ifdef NCR53C400
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
#define NCR5380_region_size 16
#else
#define NCR5380_region_size 8
#endif
-#define NCR5380_read(reg) (inb(NCR5380_map_name + (reg)))
-#define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg))))
+#define NCR5380_read(reg) \
+ inb(instance->io_port + (reg))
+#define NCR5380_write(reg, value) \
+ outb(value, instance->io_port + (reg))
#define NCR5380_implementation_fields \
- NCR5380_map_type NCR5380_map_name
-
-#define NCR5380_local_declare() \
- register NCR5380_implementation_fields
-
-#define NCR5380_setup(instance) \
- NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name)
+ int c400_ctl_status; \
+ int c400_blk_cnt; \
+ int c400_host_buf; \
+ int io_width;
#else
/* therefore SCSI_G_NCR5380_MEM */
+#define DRV_MODULE_NAME "g_NCR5380_mmio"
-#define NCR5380_map_config memory
#define NCR5380_map_type unsigned long
#define NCR5380_map_name base
-#define NCR5380_instance_name base
-#define NCR53C400_register_offset 0x108
-#define NCR53C400_address_adjust 0
#define NCR53C400_mem_base 0x3880
#define NCR53C400_host_buffer 0x3900
#define NCR5380_region_size 0x3a00
-#define NCR5380_read(reg) readb(iomem + NCR53C400_mem_base + (reg))
-#define NCR5380_write(reg, value) writeb(value, iomem + NCR53C400_mem_base + (reg))
+#define NCR5380_read(reg) \
+ readb(((struct NCR5380_hostdata *)shost_priv(instance))->iomem + \
+ NCR53C400_mem_base + (reg))
+#define NCR5380_write(reg, value) \
+ writeb(value, ((struct NCR5380_hostdata *)shost_priv(instance))->iomem + \
+ NCR53C400_mem_base + (reg))
#define NCR5380_implementation_fields \
- NCR5380_map_type NCR5380_map_name; \
- void __iomem *iomem;
-
-#define NCR5380_local_declare() \
- register void __iomem *iomem
-
-#define NCR5380_setup(instance) \
- iomem = (((struct NCR5380_hostdata *)(instance)->hostdata)->iomem)
+ void __iomem *iomem; \
+ int c400_ctl_status; \
+ int c400_blk_cnt; \
+ int c400_host_buf;
#endif
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+ generic_NCR5380_dma_xfer_len(cmd)
+
#define NCR5380_intr generic_NCR5380_intr
#define NCR5380_queue_command generic_NCR5380_queue_command
#define NCR5380_abort generic_NCR5380_abort
@@ -102,7 +88,7 @@
#define BOARD_NCR53C400 1
#define BOARD_NCR53C400A 2
#define BOARD_DTC3181E 3
+#define BOARD_HP_C2502 4
-#endif /* ndef ASM */
#endif /* GENERIC_NCR5380_H */
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 71e1380..0a76774 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -2838,7 +2838,6 @@ static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
u16 idx, gdth_evt_data *evt)
{
gdth_evt_str *e;
- struct timeval tv;
/* no GDTH_LOCK_HA() ! */
TRACE2(("gdth_store_event() source %d idx %d\n", source, idx));
@@ -2854,8 +2853,7 @@ static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
!strcmp((char *)&ebuffer[elastidx].event_data.event_string,
(char *)&evt->event_string)))) {
e = &ebuffer[elastidx];
- do_gettimeofday(&tv);
- e->last_stamp = tv.tv_sec;
+ e->last_stamp = (u32)ktime_get_real_seconds();
++e->same_count;
} else {
if (ebuffer[elastidx].event_source != 0) { /* entry not free ? */
@@ -2871,8 +2869,7 @@ static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
e = &ebuffer[elastidx];
e->event_source = source;
e->event_idx = idx;
- do_gettimeofday(&tv);
- e->first_stamp = e->last_stamp = tv.tv_sec;
+ e->first_stamp = e->last_stamp = (u32)ktime_get_real_seconds();
e->same_count = 1;
e->event_data = *evt;
e->application = 0;
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index e66e997..be609db 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -148,7 +148,6 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
gdth_cmd_str *gdtcmd;
gdth_evt_str *estr;
char hrec[161];
- struct timeval tv;
char *buf;
gdth_dskstat_str *pds;
@@ -540,8 +539,14 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
if (estr->event_data.eu.driver.ionode == ha->hanum &&
estr->event_source == ES_ASYNC) {
gdth_log_event(&estr->event_data, hrec);
- do_gettimeofday(&tv);
- sec = (int)(tv.tv_sec - estr->first_stamp);
+
+ /*
+ * Elapsed seconds subtraction with unsigned operands is
+ * safe from wrap around in year 2106. Executes as:
+ * operand a + (2's complement operand b) + 1
+ */
+
+ sec = (int)((u32)ktime_get_real_seconds() - estr->first_stamp);
if (sec < 0) sec = 0;
seq_printf(m," date- %02d:%02d:%02d\t%s\n",
sec/3600, sec%3600/60, sec%60, hrec);
diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig
new file mode 100644
index 0000000..d1dd161
--- /dev/null
+++ b/drivers/scsi/hisi_sas/Kconfig
@@ -0,0 +1,8 @@
+config SCSI_HISI_SAS
+ tristate "HiSilicon SAS"
+ depends on HAS_DMA && HAS_IOMEM
+ depends on ARM64 || COMPILE_TEST
+ select SCSI_SAS_LIBSAS
+ select BLK_DEV_INTEGRITY
+ help
+ This driver supports HiSilicon's SAS HBA
diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
new file mode 100644
index 0000000..c6d3a1b
--- /dev/null
+++ b/drivers/scsi/hisi_sas/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_main.o
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o hisi_sas_v2_hw.o
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
new file mode 100644
index 0000000..29e89f3
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef _HISI_SAS_H_
+#define _HISI_SAS_H_
+
+#include <linux/acpi.h>
+#include <linux/dmapool.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <scsi/sas_ata.h>
+#include <scsi/libsas.h>
+
+#define DRV_VERSION "v1.3"
+
+#define HISI_SAS_MAX_PHYS 9
+#define HISI_SAS_MAX_QUEUES 32
+#define HISI_SAS_QUEUE_SLOTS 512
+#define HISI_SAS_MAX_ITCT_ENTRIES 2048
+#define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
+
+#define HISI_SAS_STATUS_BUF_SZ \
+ (sizeof(struct hisi_sas_err_record) + 1024)
+#define HISI_SAS_COMMAND_TABLE_SZ \
+ (((sizeof(union hisi_sas_command_table)+3)/4)*4)
+
+#define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
+#define HISI_SAS_MAX_SMP_RESP_SZ 1028
+#define HISI_SAS_MAX_STP_RESP_SZ 28
+
+#define DEV_IS_EXPANDER(type) \
+ ((type == SAS_EDGE_EXPANDER_DEVICE) || \
+ (type == SAS_FANOUT_EXPANDER_DEVICE))
+
+struct hisi_hba;
+
+enum {
+ PORT_TYPE_SAS = (1U << 1),
+ PORT_TYPE_SATA = (1U << 0),
+};
+
+enum dev_status {
+ HISI_SAS_DEV_NORMAL,
+ HISI_SAS_DEV_EH,
+};
+
+enum hisi_sas_dev_type {
+ HISI_SAS_DEV_TYPE_STP = 0,
+ HISI_SAS_DEV_TYPE_SSP,
+ HISI_SAS_DEV_TYPE_SATA,
+};
+
+struct hisi_sas_phy {
+ struct hisi_hba *hisi_hba;
+ struct hisi_sas_port *port;
+ struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ struct timer_list timer;
+ struct work_struct phyup_ws;
+ u64 port_id; /* from hw */
+ u64 dev_sas_addr;
+ u64 phy_type;
+ u64 frame_rcvd_size;
+ u8 frame_rcvd[32];
+ u8 phy_attached;
+ u8 reserved[3];
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate;
+};
+
+struct hisi_sas_port {
+ struct asd_sas_port sas_port;
+ u8 port_attached;
+ u8 id; /* from hw */
+ struct list_head list;
+};
+
+struct hisi_sas_cq {
+ struct hisi_hba *hisi_hba;
+ int id;
+};
+
+struct hisi_sas_device {
+ enum sas_device_type dev_type;
+ struct hisi_hba *hisi_hba;
+ struct domain_device *sas_device;
+ u64 attached_phy;
+ u64 device_id;
+ u64 running_req;
+ u8 dev_status;
+};
+
+struct hisi_sas_slot {
+ struct list_head entry;
+ struct sas_task *task;
+ struct hisi_sas_port *port;
+ u64 n_elem;
+ int dlvry_queue;
+ int dlvry_queue_slot;
+ int cmplt_queue;
+ int cmplt_queue_slot;
+ int idx;
+ int abort;
+ void *cmd_hdr;
+ dma_addr_t cmd_hdr_dma;
+ void *status_buffer;
+ dma_addr_t status_buffer_dma;
+ void *command_table;
+ dma_addr_t command_table_dma;
+ struct hisi_sas_sge_page *sge_page;
+ dma_addr_t sge_page_dma;
+ struct work_struct abort_slot;
+};
+
+struct hisi_sas_tmf_task {
+ u8 tmf;
+ u16 tag_of_task_to_be_managed;
+};
+
+struct hisi_sas_hw {
+ int (*hw_init)(struct hisi_hba *hisi_hba);
+ void (*setup_itct)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *device);
+ void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
+ int (*get_free_slot)(struct hisi_hba *hisi_hba, int *q, int *s);
+ void (*start_delivery)(struct hisi_hba *hisi_hba);
+ int (*prep_ssp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf);
+ int (*prep_smp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot);
+ int (*prep_stp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot);
+ int (*slot_complete)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int abort);
+ void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*free_device)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *dev);
+ int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
+ int max_command_entries;
+ int complete_hdr_size;
+};
+
+struct hisi_hba {
+ /* This must be the first element, used by SHOST_TO_SAS_HA */
+ struct sas_ha_struct *p;
+
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct regmap *ctrl;
+ u32 ctrl_reset_reg;
+ u32 ctrl_reset_sts_reg;
+ u32 ctrl_clock_ena_reg;
+ u8 sas_addr[SAS_ADDR_SIZE];
+
+ int n_phy;
+ int scan_finished;
+ spinlock_t lock;
+
+ struct timer_list timer;
+ struct workqueue_struct *wq;
+
+ int slot_index_count;
+ unsigned long *slot_index_tags;
+
+ /* SCSI/SAS glue */
+ struct sas_ha_struct sha;
+ struct Scsi_Host *shost;
+
+ struct hisi_sas_cq cq[HISI_SAS_MAX_QUEUES];
+ struct hisi_sas_phy phy[HISI_SAS_MAX_PHYS];
+ struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
+
+ int queue_count;
+ int queue;
+ struct hisi_sas_slot *slot_prep;
+
+ struct dma_pool *sge_page_pool;
+ struct hisi_sas_device devices[HISI_SAS_MAX_DEVICES];
+ struct dma_pool *command_table_pool;
+ struct dma_pool *status_buffer_pool;
+ struct hisi_sas_cmd_hdr *cmd_hdr[HISI_SAS_MAX_QUEUES];
+ dma_addr_t cmd_hdr_dma[HISI_SAS_MAX_QUEUES];
+ void *complete_hdr[HISI_SAS_MAX_QUEUES];
+ dma_addr_t complete_hdr_dma[HISI_SAS_MAX_QUEUES];
+ struct hisi_sas_initial_fis *initial_fis;
+ dma_addr_t initial_fis_dma;
+ struct hisi_sas_itct *itct;
+ dma_addr_t itct_dma;
+ struct hisi_sas_iost *iost;
+ dma_addr_t iost_dma;
+ struct hisi_sas_breakpoint *breakpoint;
+ dma_addr_t breakpoint_dma;
+ struct hisi_sas_breakpoint *sata_breakpoint;
+ dma_addr_t sata_breakpoint_dma;
+ struct hisi_sas_slot *slot_info;
+ const struct hisi_sas_hw *hw; /* Low level hw interface */
+};
+
+/* Generic HW DMA host memory structures */
+/* Delivery queue header */
+struct hisi_sas_cmd_hdr {
+ /* dw0 */
+ __le32 dw0;
+
+ /* dw1 */
+ __le32 dw1;
+
+ /* dw2 */
+ __le32 dw2;
+
+ /* dw3 */
+ __le32 transfer_tags;
+
+ /* dw4 */
+ __le32 data_transfer_len;
+
+ /* dw5 */
+ __le32 first_burst_num;
+
+ /* dw6 */
+ __le32 sg_len;
+
+ /* dw7 */
+ __le32 dw7;
+
+ /* dw8-9 */
+ __le64 cmd_table_addr;
+
+ /* dw10-11 */
+ __le64 sts_buffer_addr;
+
+ /* dw12-13 */
+ __le64 prd_table_addr;
+
+ /* dw14-15 */
+ __le64 dif_prd_table_addr;
+};
+
+struct hisi_sas_itct {
+ __le64 qw0;
+ __le64 sas_addr;
+ __le64 qw2;
+ __le64 qw3;
+ __le64 qw4_15[12];
+};
+
+struct hisi_sas_iost {
+ __le64 qw0;
+ __le64 qw1;
+ __le64 qw2;
+ __le64 qw3;
+};
+
+struct hisi_sas_err_record {
+ u32 data[4];
+};
+
+struct hisi_sas_initial_fis {
+ struct hisi_sas_err_record err_record;
+ struct dev_to_host_fis fis;
+ u32 rsvd[3];
+};
+
+struct hisi_sas_breakpoint {
+ u8 data[128]; /*io128 byte*/
+};
+
+struct hisi_sas_sge {
+ __le64 addr;
+ __le32 page_ctrl_0;
+ __le32 page_ctrl_1;
+ __le32 data_len;
+ __le32 data_off;
+};
+
+struct hisi_sas_command_table_smp {
+ u8 bytes[44];
+};
+
+struct hisi_sas_command_table_stp {
+ struct host_to_dev_fis command_fis;
+ u8 dummy[12];
+ u8 atapi_cdb[ATAPI_CDB_LEN];
+};
+
+#define HISI_SAS_SGE_PAGE_CNT SCSI_MAX_SG_SEGMENTS
+struct hisi_sas_sge_page {
+ struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
+};
+
+struct hisi_sas_command_table_ssp {
+ struct ssp_frame_hdr hdr;
+ union {
+ struct {
+ struct ssp_command_iu task;
+ u32 prot[6];
+ };
+ struct ssp_tmf_iu ssp_task;
+ struct xfer_rdy_iu xfer_rdy;
+ struct ssp_response_iu ssp_res;
+ } u;
+};
+
+union hisi_sas_command_table {
+ struct hisi_sas_command_table_ssp ssp;
+ struct hisi_sas_command_table_smp smp;
+ struct hisi_sas_command_table_stp stp;
+};
+extern int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *ops);
+extern int hisi_sas_remove(struct platform_device *pdev);
+
+extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy);
+extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot);
+#endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
new file mode 100644
index 0000000..097ab4f
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -0,0 +1,1418 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas"
+
+#define DEV_IS_GONE(dev) \
+ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
+
+static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+ u8 *lun, struct hisi_sas_tmf_task *tmf);
+
+static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
+{
+ return device->port->ha->lldd_ha;
+}
+
+static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ clear_bit(slot_idx, bitmap);
+}
+
+static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ hisi_sas_slot_index_clear(hisi_hba, slot_idx);
+}
+
+static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ set_bit(slot_idx, bitmap);
+}
+
+static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, int *slot_idx)
+{
+ unsigned int index;
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ index = find_first_zero_bit(bitmap, hisi_hba->slot_index_count);
+ if (index >= hisi_hba->slot_index_count)
+ return -SAS_QUEUE_FULL;
+ hisi_sas_slot_index_set(hisi_hba, index);
+ *slot_idx = index;
+ return 0;
+}
+
+static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->slot_index_count; ++i)
+ hisi_sas_slot_index_clear(hisi_hba, i);
+}
+
+void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ if (!slot->task)
+ return;
+
+ if (!sas_protocol_ata(task->task_proto))
+ if (slot->n_elem)
+ dma_unmap_sg(dev, task->scatter, slot->n_elem,
+ task->data_dir);
+
+ if (slot->command_table)
+ dma_pool_free(hisi_hba->command_table_pool,
+ slot->command_table, slot->command_table_dma);
+
+ if (slot->status_buffer)
+ dma_pool_free(hisi_hba->status_buffer_pool,
+ slot->status_buffer, slot->status_buffer_dma);
+
+ if (slot->sge_page)
+ dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+ slot->sge_page_dma);
+
+ list_del_init(&slot->entry);
+ task->lldd_task = NULL;
+ slot->task = NULL;
+ slot->port = NULL;
+ hisi_sas_slot_index_free(hisi_hba, slot->idx);
+ memset(slot, 0, sizeof(*slot));
+}
+EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
+
+static int hisi_sas_task_prep_smp(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ return hisi_hba->hw->prep_smp(hisi_hba, slot);
+}
+
+static int hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf);
+}
+
+static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ return hisi_hba->hw->prep_stp(hisi_hba, slot);
+}
+
+/*
+ * This function will issue an abort TMF regardless of whether the
+ * task is in the sdev or not. Then it will do the task complete
+ * cleanup and callbacks.
+ */
+static void hisi_sas_slot_abort(struct work_struct *work)
+{
+ struct hisi_sas_slot *abort_slot =
+ container_of(work, struct hisi_sas_slot, abort_slot);
+ struct sas_task *task = abort_slot->task;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct hisi_sas_tmf_task tmf_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct scsi_lun lun;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int tag = abort_slot->idx;
+
+ if (!(task->task_proto & SAS_PROTOCOL_SSP)) {
+ dev_err(dev, "cannot abort slot for non-ssp task\n");
+ goto out;
+ }
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_ABORT_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task);
+out:
+ /* Do cleanup for this task */
+ hisi_sas_slot_task_free(hisi_hba, task, abort_slot);
+ if (task->task_done)
+ task->task_done(task);
+ if (sas_dev && sas_dev->running_req)
+ sas_dev->running_req--;
+}
+
+static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+ int is_tmf, struct hisi_sas_tmf_task *tmf,
+ int *pass)
+{
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_cmd_hdr *cmd_hdr_base;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+
+ if (!device->port) {
+ struct task_status_struct *ts = &task->task_status;
+
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ /*
+ * libsas will use dev->port, should
+ * not call task_done for sata
+ */
+ if (device->dev_type != SAS_SATA_DEV)
+ task->task_done(task);
+ return 0;
+ }
+
+ if (DEV_IS_GONE(sas_dev)) {
+ if (sas_dev)
+ dev_info(dev, "task prep: device %llu not ready\n",
+ sas_dev->device_id);
+ else
+ dev_info(dev, "task prep: device %016llx not ready\n",
+ SAS_ADDR(device->sas_addr));
+
+ rc = SAS_PHY_DOWN;
+ return rc;
+ }
+ port = device->port->lldd_port;
+ if (port && !port->port_attached && !tmf) {
+ if (sas_protocol_ata(task->task_proto)) {
+ struct task_status_struct *ts = &task->task_status;
+
+ dev_info(dev,
+ "task prep: SATA/STP port%d not attach device\n",
+ device->port->id);
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PHY_DOWN;
+ task->task_done(task);
+ } else {
+ struct task_status_struct *ts = &task->task_status;
+
+ dev_info(dev,
+ "task prep: SAS port%d does not attach device\n",
+ device->port->id);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ task->task_done(task);
+ }
+ return 0;
+ }
+
+ if (!sas_protocol_ata(task->task_proto)) {
+ if (task->num_scatter) {
+ n_elem = dma_map_sg(dev, task->scatter,
+ task->num_scatter, task->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto prep_out;
+ }
+ }
+ } else
+ n_elem = task->num_scatter;
+
+ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
+ if (rc)
+ goto err_out;
+ rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
+ &dlvry_queue_slot);
+ if (rc)
+ goto err_out_tag;
+
+ slot = &hisi_hba->slot_info[slot_idx];
+ memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+ slot->idx = slot_idx;
+ slot->n_elem = n_elem;
+ slot->dlvry_queue = dlvry_queue;
+ slot->dlvry_queue_slot = dlvry_queue_slot;
+ cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
+ slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
+ slot->task = task;
+ slot->port = port;
+ task->lldd_task = slot;
+ INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort);
+
+ slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
+ GFP_ATOMIC,
+ &slot->status_buffer_dma);
+ if (!slot->status_buffer) {
+ rc = -ENOMEM;
+ goto err_out_slot_buf;
+ }
+ memset(slot->status_buffer, 0, HISI_SAS_STATUS_BUF_SZ);
+
+ slot->command_table = dma_pool_alloc(hisi_hba->command_table_pool,
+ GFP_ATOMIC,
+ &slot->command_table_dma);
+ if (!slot->command_table) {
+ rc = -ENOMEM;
+ goto err_out_status_buf;
+ }
+ memset(slot->command_table, 0, HISI_SAS_COMMAND_TABLE_SZ);
+ memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ rc = hisi_sas_task_prep_smp(hisi_hba, slot);
+ break;
+ case SAS_PROTOCOL_SSP:
+ rc = hisi_sas_task_prep_ssp(hisi_hba, slot, is_tmf, tmf);
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ rc = hisi_sas_task_prep_ata(hisi_hba, slot);
+ break;
+ default:
+ dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n",
+ task->task_proto);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc) {
+ dev_err(dev, "task prep: rc = 0x%x\n", rc);
+ if (slot->sge_page)
+ goto err_out_sge;
+ goto err_out_command_table;
+ }
+
+ list_add_tail(&slot->entry, &port->list);
+ spin_lock(&task->task_state_lock);
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&task->task_state_lock);
+
+ hisi_hba->slot_prep = slot;
+
+ sas_dev->running_req++;
+ ++(*pass);
+
+ return 0;
+
+err_out_sge:
+ dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+ slot->sge_page_dma);
+err_out_command_table:
+ dma_pool_free(hisi_hba->command_table_pool, slot->command_table,
+ slot->command_table_dma);
+err_out_status_buf:
+ dma_pool_free(hisi_hba->status_buffer_pool, slot->status_buffer,
+ slot->status_buffer_dma);
+err_out_slot_buf:
+ /* Nothing to be done */
+err_out_tag:
+ hisi_sas_slot_index_free(hisi_hba, slot_idx);
+err_out:
+ dev_err(dev, "task prep: failed[%d]!\n", rc);
+ if (!sas_protocol_ata(task->task_proto))
+ if (n_elem)
+ dma_unmap_sg(dev, task->scatter, n_elem,
+ task->data_dir);
+prep_out:
+ return rc;
+}
+
+static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
+ int is_tmf, struct hisi_sas_tmf_task *tmf)
+{
+ u32 rc;
+ u32 pass = 0;
+ unsigned long flags;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ /* protect task_prep and start_delivery sequence */
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass);
+ if (rc)
+ dev_err(dev, "task exec: failed[%d]!\n", rc);
+
+ if (likely(pass))
+ hisi_hba->hw->start_delivery(hisi_hba);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ return rc;
+}
+
+static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha;
+
+ if (!phy->phy_attached)
+ return;
+
+ sas_ha = &hisi_hba->sha;
+ sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
+
+ if (sas_phy->phy) {
+ struct sas_phy *sphy = sas_phy->phy;
+
+ sphy->negotiated_linkrate = sas_phy->linkrate;
+ sphy->minimum_linkrate = phy->minimum_linkrate;
+ sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+ sphy->maximum_linkrate = phy->maximum_linkrate;
+ }
+
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ struct sas_identify_frame *id;
+
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ /*Nothing*/
+ }
+
+ sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
+ sas_ha->notify_port_event(sas_phy, PORTE_BYTES_DMAED);
+}
+
+static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
+{
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct hisi_sas_device *sas_dev = NULL;
+ int i;
+
+ spin_lock(&hisi_hba->lock);
+ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+ if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
+ hisi_hba->devices[i].device_id = i;
+ sas_dev = &hisi_hba->devices[i];
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+ sas_dev->dev_type = device->dev_type;
+ sas_dev->hisi_hba = hisi_hba;
+ sas_dev->sas_device = device;
+ break;
+ }
+ }
+ spin_unlock(&hisi_hba->lock);
+
+ return sas_dev;
+}
+
+static int hisi_sas_dev_found(struct domain_device *device)
+{
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ sas_dev = hisi_sas_alloc_dev(device);
+ if (!sas_dev) {
+ dev_err(dev, "fail alloc dev: max support %d devices\n",
+ HISI_SAS_MAX_DEVICES);
+ return -EINVAL;
+ }
+
+ device->lldd_dev = sas_dev;
+ hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ int phy_no;
+ u8 phy_num = parent_dev->ex_dev.num_phys;
+ struct ex_phy *phy;
+
+ for (phy_no = 0; phy_no < phy_num; phy_no++) {
+ phy = &parent_dev->ex_dev.ex_phy[phy_no];
+ if (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(device->sas_addr)) {
+ sas_dev->attached_phy = phy_no;
+ break;
+ }
+ }
+
+ if (phy_no == phy_num) {
+ dev_info(dev, "dev found: no attached "
+ "dev:%016llx at ex:%016llx\n",
+ SAS_ADDR(device->sas_addr),
+ SAS_ADDR(parent_dev->sas_addr));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int hisi_sas_slave_configure(struct scsi_device *sdev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(sdev);
+ int ret = sas_slave_configure(sdev);
+
+ if (ret)
+ return ret;
+ if (!dev_is_sata(dev))
+ sas_change_queue_depth(sdev, 64);
+
+ return 0;
+}
+
+static void hisi_sas_scan_start(struct Scsi_Host *shost)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; ++i)
+ hisi_sas_bytes_dmaed(hisi_hba, i);
+
+ hisi_hba->scan_finished = 1;
+}
+
+static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ struct sas_ha_struct *sha = &hisi_hba->sha;
+
+ if (hisi_hba->scan_finished == 0)
+ return 0;
+
+ sas_drain_work(sha);
+ return 1;
+}
+
+static void hisi_sas_phyup_work(struct work_struct *work)
+{
+ struct hisi_sas_phy *phy =
+ container_of(work, struct hisi_sas_phy, phyup_ws);
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ int phy_no = sas_phy->id;
+
+ hisi_hba->hw->sl_notify(hisi_hba, phy_no); /* This requires a sleep */
+ hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+}
+
+static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ phy->hisi_hba = hisi_hba;
+ phy->port = NULL;
+ init_timer(&phy->timer);
+ sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
+ sas_phy->class = SAS;
+ sas_phy->iproto = SAS_PROTOCOL_ALL;
+ sas_phy->tproto = 0;
+ sas_phy->type = PHY_TYPE_PHYSICAL;
+ sas_phy->role = PHY_ROLE_INITIATOR;
+ sas_phy->oob_mode = OOB_NOT_CONNECTED;
+ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+ sas_phy->id = phy_no;
+ sas_phy->sas_addr = &hisi_hba->sas_addr[0];
+ sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+ sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata;
+ sas_phy->lldd_phy = phy;
+
+ INIT_WORK(&phy->phyup_ws, hisi_sas_phyup_work);
+}
+
+static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+ struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+ struct asd_sas_port *sas_port = sas_phy->port;
+ struct hisi_sas_port *port = &hisi_hba->port[sas_phy->id];
+ unsigned long flags;
+
+ if (!sas_port)
+ return;
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ port->port_attached = 1;
+ port->id = phy->port_id;
+ phy->port = port;
+ sas_port->lldd_port = port;
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+}
+
+static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, int phy_no,
+ struct domain_device *device)
+{
+ struct hisi_sas_phy *phy;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot, *slot2;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ phy = &hisi_hba->phy[phy_no];
+ port = phy->port;
+ if (!port)
+ return;
+
+ list_for_each_entry_safe(slot, slot2, &port->list, entry) {
+ struct sas_task *task;
+
+ task = slot->task;
+ if (device && task->dev != device)
+ continue;
+
+ dev_info(dev, "Release slot [%d:%d], task [%p]:\n",
+ slot->dlvry_queue, slot->dlvry_queue_slot, task);
+ hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+ }
+}
+
+static void hisi_sas_port_notify_deformed(struct asd_sas_phy *sas_phy)
+{
+ struct domain_device *device;
+ struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+ struct asd_sas_port *sas_port = sas_phy->port;
+
+ list_for_each_entry(device, &sas_port->dev_list, dev_list_node)
+ hisi_sas_do_release_task(phy->hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
+ struct domain_device *device)
+{
+ struct asd_sas_port *port = device->port;
+ struct asd_sas_phy *sas_phy;
+
+ list_for_each_entry(sas_phy, &port->phy_list, port_phy_el)
+ hisi_sas_do_release_task(hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_dev_gone(struct domain_device *device)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 dev_id = sas_dev->device_id;
+
+ dev_info(dev, "found dev[%lld:%x] is gone\n",
+ sas_dev->device_id, sas_dev->dev_type);
+
+ hisi_hba->hw->free_device(hisi_hba, sas_dev);
+ device->lldd_dev = NULL;
+ memset(sas_dev, 0, sizeof(*sas_dev));
+ sas_dev->device_id = dev_id;
+ sas_dev->dev_type = SAS_PHY_UNUSED;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+}
+
+static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
+{
+ return hisi_sas_task_exec(task, gfp_flags, 0, NULL);
+}
+
+static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+ int phy_no = sas_phy->id;
+
+ switch (func) {
+ case PHY_FUNC_HARD_RESET:
+ hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_LINK_RESET:
+ hisi_hba->hw->phy_enable(hisi_hba, phy_no);
+ hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_DISABLE:
+ hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_SET_LINK_RATE:
+ case PHY_FUNC_RELEASE_SPINUP_HOLD:
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static void hisi_sas_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->slow_task->timer))
+ return;
+ complete(&task->slow_task->completion);
+}
+
+static void hisi_sas_tmf_timedout(unsigned long data)
+{
+ struct sas_task *task = (struct sas_task *)data;
+
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ complete(&task->slow_task->completion);
+}
+
+#define TASK_TIMEOUT 20
+#define TASK_RETRY 3
+static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
+ void *parameter, u32 para_len,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct sas_task *task;
+ int res, retry;
+
+ for (retry = 0; retry < TASK_RETRY; retry++) {
+ task = sas_alloc_slow_task(GFP_KERNEL);
+ if (!task)
+ return -ENOMEM;
+
+ task->dev = device;
+ task->task_proto = device->tproto;
+
+ memcpy(&task->ssp_task, parameter, para_len);
+ task->task_done = hisi_sas_task_done;
+
+ task->slow_task->timer.data = (unsigned long) task;
+ task->slow_task->timer.function = hisi_sas_tmf_timedout;
+ task->slow_task->timer.expires = jiffies + TASK_TIMEOUT*HZ;
+ add_timer(&task->slow_task->timer);
+
+ res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf);
+
+ if (res) {
+ del_timer(&task->slow_task->timer);
+ dev_err(dev, "abort tmf: executing internal task failed: %d\n",
+ res);
+ goto ex_err;
+ }
+
+ wait_for_completion(&task->slow_task->completion);
+ res = TMF_RESP_FUNC_FAILED;
+ /* Even TMF timed out, return direct. */
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ dev_err(dev, "abort tmf: TMF task[%d] timeout\n",
+ tmf->tag_of_task_to_be_managed);
+ if (task->lldd_task) {
+ struct hisi_sas_slot *slot =
+ task->lldd_task;
+
+ hisi_sas_slot_task_free(hisi_hba,
+ task, slot);
+ }
+
+ goto ex_err;
+ }
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_UNDERRUN) {
+ /* no error, but return the number of bytes of
+ * underrun
+ */
+ dev_warn(dev, "abort tmf: task to dev %016llx "
+ "resp: 0x%x sts 0x%x underrun\n",
+ SAS_ADDR(device->sas_addr),
+ task->task_status.resp,
+ task->task_status.stat);
+ res = task->task_status.residual;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_OVERRUN) {
+ dev_warn(dev, "abort tmf: blocked task error\n");
+ res = -EMSGSIZE;
+ break;
+ }
+
+ dev_warn(dev, "abort tmf: task to dev "
+ "%016llx resp: 0x%x status 0x%x\n",
+ SAS_ADDR(device->sas_addr), task->task_status.resp,
+ task->task_status.stat);
+ sas_free_task(task);
+ task = NULL;
+ }
+ex_err:
+ WARN_ON(retry == TASK_RETRY);
+ sas_free_task(task);
+ return res;
+}
+
+static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+ u8 *lun, struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_ssp_task ssp_task;
+
+ if (!(device->tproto & SAS_PROTOCOL_SSP))
+ return TMF_RESP_FUNC_ESUPP;
+
+ memcpy(ssp_task.LUN, lun, 8);
+
+ return hisi_sas_exec_internal_tmf_task(device, &ssp_task,
+ sizeof(ssp_task), tmf);
+}
+
+static int hisi_sas_abort_task(struct sas_task *task)
+{
+ struct scsi_lun lun;
+ struct hisi_sas_tmf_task tmf_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc = TMF_RESP_FUNC_FAILED;
+ unsigned long flags;
+
+ if (!sas_dev) {
+ dev_warn(dev, "Device has been removed\n");
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ sas_dev->dev_status = HISI_SAS_DEV_EH;
+ if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_ABORT_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun,
+ &tmf_task);
+
+ /* if successful, clear the task and callback forwards.*/
+ if (rc == TMF_RESP_FUNC_COMPLETE) {
+ if (task->lldd_task) {
+ struct hisi_sas_slot *slot;
+
+ slot = &hisi_hba->slot_info
+ [tmf_task.tag_of_task_to_be_managed];
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ }
+ }
+
+ } else if (task->task_proto & SAS_PROTOCOL_SATA ||
+ task->task_proto & SAS_PROTOCOL_STP) {
+ if (task->dev->dev_type == SAS_SATA_DEV) {
+ struct hisi_slot_info *slot = task->lldd_task;
+
+ dev_notice(dev, "abort task: hba=%p task=%p slot=%p\n",
+ hisi_hba, task, slot);
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ }
+
+ }
+
+out:
+ if (rc != TMF_RESP_FUNC_COMPLETE)
+ dev_notice(dev, "abort task: rc=%d\n", rc);
+ return rc;
+}
+
+static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
+{
+ struct hisi_sas_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ tmf_task.tmf = TMF_ABORT_TASK_SET;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+ return rc;
+}
+
+static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct hisi_sas_tmf_task tmf_task;
+
+ tmf_task.tmf = TMF_CLEAR_ACA;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+ return rc;
+}
+
+static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
+{
+ struct sas_phy *phy = sas_get_local_phy(device);
+ int rc, reset_type = (device->dev_type == SAS_SATA_DEV ||
+ (device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
+ rc = sas_phy_reset(phy, reset_type);
+ sas_put_local_phy(phy);
+ msleep(2000);
+ return rc;
+}
+
+static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ unsigned long flags;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ if (sas_dev->dev_status != HISI_SAS_DEV_EH)
+ return TMF_RESP_FUNC_FAILED;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+
+ rc = hisi_sas_debug_I_T_nexus_reset(device);
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_release_task(hisi_hba, device);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ return 0;
+}
+
+static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
+{
+ struct hisi_sas_tmf_task tmf_task;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = &hisi_hba->pdev->dev;
+ unsigned long flags;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ tmf_task.tmf = TMF_LU_RESET;
+ sas_dev->dev_status = HISI_SAS_DEV_EH;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+ if (rc == TMF_RESP_FUNC_COMPLETE) {
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_release_task(hisi_hba, device);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ }
+
+ /* If failed, fall-through I_T_Nexus reset */
+ dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
+ sas_dev->device_id, rc);
+ return rc;
+}
+
+static int hisi_sas_query_task(struct sas_task *task)
+{
+ struct scsi_lun lun;
+ struct hisi_sas_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_QUERY_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ rc = hisi_sas_debug_issue_ssp_tmf(device,
+ lun.scsi_lun,
+ &tmf_task);
+ switch (rc) {
+ /* The task is still in Lun, release it then */
+ case TMF_RESP_FUNC_SUCC:
+ /* The task is not in Lun or failed, reset the phy */
+ case TMF_RESP_FUNC_FAILED:
+ case TMF_RESP_FUNC_COMPLETE:
+ break;
+ }
+ }
+ return rc;
+}
+
+static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
+{
+ hisi_sas_port_notify_formed(sas_phy);
+}
+
+static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy)
+{
+ hisi_sas_port_notify_deformed(sas_phy);
+}
+
+static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
+{
+ phy->phy_attached = 0;
+ phy->phy_type = 0;
+ phy->port = NULL;
+}
+
+void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+
+ if (rdy) {
+ /* Phy down but ready */
+ hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+ hisi_sas_port_notify_formed(sas_phy);
+ } else {
+ struct hisi_sas_port *port = phy->port;
+
+ /* Phy down and not ready */
+ sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
+ sas_phy_disconnected(sas_phy);
+
+ if (port) {
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ int port_id = port->id;
+
+ if (!hisi_hba->hw->get_wideport_bitmap(hisi_hba,
+ port_id))
+ port->port_attached = 0;
+ } else if (phy->phy_type & PORT_TYPE_SATA)
+ port->port_attached = 0;
+ }
+ hisi_sas_phy_disconnected(phy);
+ }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
+
+static struct scsi_transport_template *hisi_sas_stt;
+
+static struct scsi_host_template hisi_sas_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = hisi_sas_slave_configure,
+ .scan_finished = hisi_sas_scan_finished,
+ .scan_start = hisi_sas_scan_start,
+ .change_queue_depth = sas_change_queue_depth,
+ .bios_param = sas_bios_param,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+};
+
+static struct sas_domain_function_template hisi_sas_transport_ops = {
+ .lldd_dev_found = hisi_sas_dev_found,
+ .lldd_dev_gone = hisi_sas_dev_gone,
+ .lldd_execute_task = hisi_sas_queue_command,
+ .lldd_control_phy = hisi_sas_control_phy,
+ .lldd_abort_task = hisi_sas_abort_task,
+ .lldd_abort_task_set = hisi_sas_abort_task_set,
+ .lldd_clear_aca = hisi_sas_clear_aca,
+ .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset,
+ .lldd_lu_reset = hisi_sas_lu_reset,
+ .lldd_query_task = hisi_sas_query_task,
+ .lldd_port_formed = hisi_sas_port_formed,
+ .lldd_port_deformed = hisi_sas_port_deformed,
+};
+
+static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+{
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+
+ spin_lock_init(&hisi_hba->lock);
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_init(hisi_hba, i);
+ hisi_hba->port[i].port_attached = 0;
+ hisi_hba->port[i].id = -1;
+ INIT_LIST_HEAD(&hisi_hba->port[i].list);
+ }
+
+ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+ hisi_hba->devices[i].dev_type = SAS_PHY_UNUSED;
+ hisi_hba->devices[i].device_id = i;
+ hisi_hba->devices[i].dev_status = HISI_SAS_DEV_NORMAL;
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+
+ /* Completion queue structure */
+ cq->id = i;
+ cq->hisi_hba = hisi_hba;
+
+ /* Delivery queue */
+ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+ hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s,
+ &hisi_hba->cmd_hdr_dma[i], GFP_KERNEL);
+ if (!hisi_hba->cmd_hdr[i])
+ goto err_out;
+ memset(hisi_hba->cmd_hdr[i], 0, s);
+
+ /* Completion queue */
+ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+ hisi_hba->complete_hdr[i] = dma_alloc_coherent(dev, s,
+ &hisi_hba->complete_hdr_dma[i], GFP_KERNEL);
+ if (!hisi_hba->complete_hdr[i])
+ goto err_out;
+ memset(hisi_hba->complete_hdr[i], 0, s);
+ }
+
+ s = HISI_SAS_STATUS_BUF_SZ;
+ hisi_hba->status_buffer_pool = dma_pool_create("status_buffer",
+ dev, s, 16, 0);
+ if (!hisi_hba->status_buffer_pool)
+ goto err_out;
+
+ s = HISI_SAS_COMMAND_TABLE_SZ;
+ hisi_hba->command_table_pool = dma_pool_create("command_table",
+ dev, s, 16, 0);
+ if (!hisi_hba->command_table_pool)
+ goto err_out;
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ hisi_hba->itct = dma_alloc_coherent(dev, s, &hisi_hba->itct_dma,
+ GFP_KERNEL);
+ if (!hisi_hba->itct)
+ goto err_out;
+
+ memset(hisi_hba->itct, 0, s);
+
+ hisi_hba->slot_info = devm_kcalloc(dev, max_command_entries,
+ sizeof(struct hisi_sas_slot),
+ GFP_KERNEL);
+ if (!hisi_hba->slot_info)
+ goto err_out;
+
+ s = max_command_entries * sizeof(struct hisi_sas_iost);
+ hisi_hba->iost = dma_alloc_coherent(dev, s, &hisi_hba->iost_dma,
+ GFP_KERNEL);
+ if (!hisi_hba->iost)
+ goto err_out;
+
+ memset(hisi_hba->iost, 0, s);
+
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
+ hisi_hba->breakpoint = dma_alloc_coherent(dev, s,
+ &hisi_hba->breakpoint_dma, GFP_KERNEL);
+ if (!hisi_hba->breakpoint)
+ goto err_out;
+
+ memset(hisi_hba->breakpoint, 0, s);
+
+ hisi_hba->slot_index_count = max_command_entries;
+ s = hisi_hba->slot_index_count / sizeof(unsigned long);
+ hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
+ if (!hisi_hba->slot_index_tags)
+ goto err_out;
+
+ hisi_hba->sge_page_pool = dma_pool_create("status_sge", dev,
+ sizeof(struct hisi_sas_sge_page), 16, 0);
+ if (!hisi_hba->sge_page_pool)
+ goto err_out;
+
+ s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+ hisi_hba->initial_fis = dma_alloc_coherent(dev, s,
+ &hisi_hba->initial_fis_dma, GFP_KERNEL);
+ if (!hisi_hba->initial_fis)
+ goto err_out;
+ memset(hisi_hba->initial_fis, 0, s);
+
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2;
+ hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s,
+ &hisi_hba->sata_breakpoint_dma, GFP_KERNEL);
+ if (!hisi_hba->sata_breakpoint)
+ goto err_out;
+ memset(hisi_hba->sata_breakpoint, 0, s);
+
+ hisi_sas_slot_index_init(hisi_hba);
+
+ hisi_hba->wq = create_singlethread_workqueue(dev_name(dev));
+ if (!hisi_hba->wq) {
+ dev_err(dev, "sas_alloc: failed to create workqueue\n");
+ goto err_out;
+ }
+
+ return 0;
+err_out:
+ return -ENOMEM;
+}
+
+static void hisi_sas_free(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+ if (hisi_hba->cmd_hdr[i])
+ dma_free_coherent(dev, s,
+ hisi_hba->cmd_hdr[i],
+ hisi_hba->cmd_hdr_dma[i]);
+
+ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+ if (hisi_hba->complete_hdr[i])
+ dma_free_coherent(dev, s,
+ hisi_hba->complete_hdr[i],
+ hisi_hba->complete_hdr_dma[i]);
+ }
+
+ dma_pool_destroy(hisi_hba->status_buffer_pool);
+ dma_pool_destroy(hisi_hba->command_table_pool);
+ dma_pool_destroy(hisi_hba->sge_page_pool);
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ if (hisi_hba->itct)
+ dma_free_coherent(dev, s,
+ hisi_hba->itct, hisi_hba->itct_dma);
+
+ s = max_command_entries * sizeof(struct hisi_sas_iost);
+ if (hisi_hba->iost)
+ dma_free_coherent(dev, s,
+ hisi_hba->iost, hisi_hba->iost_dma);
+
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
+ if (hisi_hba->breakpoint)
+ dma_free_coherent(dev, s,
+ hisi_hba->breakpoint,
+ hisi_hba->breakpoint_dma);
+
+
+ s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+ if (hisi_hba->initial_fis)
+ dma_free_coherent(dev, s,
+ hisi_hba->initial_fis,
+ hisi_hba->initial_fis_dma);
+
+ s = max_command_entries * sizeof(struct hisi_sas_breakpoint) * 2;
+ if (hisi_hba->sata_breakpoint)
+ dma_free_coherent(dev, s,
+ hisi_hba->sata_breakpoint,
+ hisi_hba->sata_breakpoint_dma);
+
+ if (hisi_hba->wq)
+ destroy_workqueue(hisi_hba->wq);
+}
+
+static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+ const struct hisi_sas_hw *hw)
+{
+ struct resource *res;
+ struct Scsi_Host *shost;
+ struct hisi_hba *hisi_hba;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+
+ shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
+ if (!shost)
+ goto err_out;
+ hisi_hba = shost_priv(shost);
+
+ hisi_hba->hw = hw;
+ hisi_hba->pdev = pdev;
+ hisi_hba->shost = shost;
+ SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+
+ init_timer(&hisi_hba->timer);
+
+ if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr,
+ SAS_ADDR_SIZE))
+ goto err_out;
+
+ if (np) {
+ hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np,
+ "hisilicon,sas-syscon");
+ if (IS_ERR(hisi_hba->ctrl))
+ goto err_out;
+
+ if (device_property_read_u32(dev, "ctrl-reset-reg",
+ &hisi_hba->ctrl_reset_reg))
+ goto err_out;
+
+ if (device_property_read_u32(dev, "ctrl-reset-sts-reg",
+ &hisi_hba->ctrl_reset_sts_reg))
+ goto err_out;
+
+ if (device_property_read_u32(dev, "ctrl-clock-ena-reg",
+ &hisi_hba->ctrl_clock_ena_reg))
+ goto err_out;
+ }
+
+ if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy))
+ goto err_out;
+
+ if (device_property_read_u32(dev, "queue-count",
+ &hisi_hba->queue_count))
+ goto err_out;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hisi_hba->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hisi_hba->regs))
+ goto err_out;
+
+ if (hisi_sas_alloc(hisi_hba, shost)) {
+ hisi_sas_free(hisi_hba);
+ goto err_out;
+ }
+
+ return shost;
+err_out:
+ dev_err(dev, "shost alloc failed\n");
+ return NULL;
+}
+
+static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ memcpy(&hisi_hba->phy[i].dev_sas_addr,
+ hisi_hba->sas_addr,
+ SAS_ADDR_SIZE);
+}
+
+int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *hw)
+{
+ struct Scsi_Host *shost;
+ struct hisi_hba *hisi_hba;
+ struct device *dev = &pdev->dev;
+ struct asd_sas_phy **arr_phy;
+ struct asd_sas_port **arr_port;
+ struct sas_ha_struct *sha;
+ int rc, phy_nr, port_nr, i;
+
+ shost = hisi_sas_shost_alloc(pdev, hw);
+ if (!shost) {
+ rc = -ENOMEM;
+ goto err_out_ha;
+ }
+
+ sha = SHOST_TO_SAS_HA(shost);
+ hisi_hba = shost_priv(shost);
+ platform_set_drvdata(pdev, sha);
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
+ dev_err(dev, "No usable DMA addressing method\n");
+ rc = -EIO;
+ goto err_out_ha;
+ }
+
+ phy_nr = port_nr = hisi_hba->n_phy;
+
+ arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
+ arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL);
+ if (!arr_phy || !arr_port)
+ return -ENOMEM;
+
+ sha->sas_phy = arr_phy;
+ sha->sas_port = arr_port;
+ sha->core.shost = shost;
+ sha->lldd_ha = hisi_hba;
+
+ shost->transportt = hisi_sas_stt;
+ shost->max_id = HISI_SAS_MAX_DEVICES;
+ shost->max_lun = ~0;
+ shost->max_channel = 1;
+ shost->max_cmd_len = 16;
+ shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
+ shost->can_queue = hisi_hba->hw->max_command_entries;
+ shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
+
+ sha->sas_ha_name = DRV_NAME;
+ sha->dev = &hisi_hba->pdev->dev;
+ sha->lldd_module = THIS_MODULE;
+ sha->sas_addr = &hisi_hba->sas_addr[0];
+ sha->num_phys = hisi_hba->n_phy;
+ sha->core.shost = hisi_hba->shost;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
+ sha->sas_port[i] = &hisi_hba->port[i].sas_port;
+ }
+
+ hisi_sas_init_add(hisi_hba);
+
+ rc = hisi_hba->hw->hw_init(hisi_hba);
+ if (rc)
+ goto err_out_ha;
+
+ rc = scsi_add_host(shost, &pdev->dev);
+ if (rc)
+ goto err_out_ha;
+
+ rc = sas_register_ha(sha);
+ if (rc)
+ goto err_out_register_ha;
+
+ scsi_scan_host(shost);
+
+ return 0;
+
+err_out_register_ha:
+ scsi_remove_host(shost);
+err_out_ha:
+ kfree(shost);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_probe);
+
+int hisi_sas_remove(struct platform_device *pdev)
+{
+ struct sas_ha_struct *sha = platform_get_drvdata(pdev);
+ struct hisi_hba *hisi_hba = sha->lldd_ha;
+
+ scsi_remove_host(sha->core.shost);
+ sas_unregister_ha(sha);
+ sas_remove_host(sha->core.shost);
+
+ hisi_sas_free(hisi_hba);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_remove);
+
+static __init int hisi_sas_init(void)
+{
+ pr_info("hisi_sas: driver version %s\n", DRV_VERSION);
+
+ hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
+ if (!hisi_sas_stt)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static __exit void hisi_sas_exit(void)
+{
+ sas_release_transport(hisi_sas_stt);
+}
+
+module_init(hisi_sas_init);
+module_exit(hisi_sas_exit);
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
new file mode 100644
index 0000000..1abbc2e
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -0,0 +1,1880 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas_v1_hw"
+
+/* global registers need init*/
+#define DLVRY_QUEUE_ENABLE 0x0
+#define IOST_BASE_ADDR_LO 0x8
+#define IOST_BASE_ADDR_HI 0xc
+#define ITCT_BASE_ADDR_LO 0x10
+#define ITCT_BASE_ADDR_HI 0x14
+#define BROKEN_MSG_ADDR_LO 0x18
+#define BROKEN_MSG_ADDR_HI 0x1c
+#define PHY_CONTEXT 0x20
+#define PHY_STATE 0x24
+#define PHY_PORT_NUM_MA 0x28
+#define PORT_STATE 0x2c
+#define PHY_CONN_RATE 0x30
+#define HGC_TRANS_TASK_CNT_LIMIT 0x38
+#define AXI_AHB_CLK_CFG 0x3c
+#define HGC_SAS_TXFAIL_RETRY_CTRL 0x84
+#define HGC_GET_ITV_TIME 0x90
+#define DEVICE_MSG_WORK_MODE 0x94
+#define I_T_NEXUS_LOSS_TIME 0xa0
+#define BUS_INACTIVE_LIMIT_TIME 0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME 0xac
+#define CFG_AGING_TIME 0xbc
+#define CFG_AGING_TIME_ITCT_REL_OFF 0
+#define CFG_AGING_TIME_ITCT_REL_MSK (0x1 << CFG_AGING_TIME_ITCT_REL_OFF)
+#define HGC_DFX_CFG2 0xc0
+#define FIS_LIST_BADDR_L 0xc4
+#define CFG_1US_TIMER_TRSH 0xcc
+#define CFG_SAS_CONFIG 0xd4
+#define HGC_IOST_ECC_ADDR 0x140
+#define HGC_IOST_ECC_ADDR_BAD_OFF 16
+#define HGC_IOST_ECC_ADDR_BAD_MSK (0x3ff << HGC_IOST_ECC_ADDR_BAD_OFF)
+#define HGC_DQ_ECC_ADDR 0x144
+#define HGC_DQ_ECC_ADDR_BAD_OFF 16
+#define HGC_DQ_ECC_ADDR_BAD_MSK (0xfff << HGC_DQ_ECC_ADDR_BAD_OFF)
+#define HGC_INVLD_DQE_INFO 0x148
+#define HGC_INVLD_DQE_INFO_DQ_OFF 0
+#define HGC_INVLD_DQE_INFO_DQ_MSK (0xffff << HGC_INVLD_DQE_INFO_DQ_OFF)
+#define HGC_INVLD_DQE_INFO_TYPE_OFF 16
+#define HGC_INVLD_DQE_INFO_TYPE_MSK (0x1 << HGC_INVLD_DQE_INFO_TYPE_OFF)
+#define HGC_INVLD_DQE_INFO_FORCE_OFF 17
+#define HGC_INVLD_DQE_INFO_FORCE_MSK (0x1 << HGC_INVLD_DQE_INFO_FORCE_OFF)
+#define HGC_INVLD_DQE_INFO_PHY_OFF 18
+#define HGC_INVLD_DQE_INFO_PHY_MSK (0x1 << HGC_INVLD_DQE_INFO_PHY_OFF)
+#define HGC_INVLD_DQE_INFO_ABORT_OFF 19
+#define HGC_INVLD_DQE_INFO_ABORT_MSK (0x1 << HGC_INVLD_DQE_INFO_ABORT_OFF)
+#define HGC_INVLD_DQE_INFO_IPTT_OF_OFF 20
+#define HGC_INVLD_DQE_INFO_IPTT_OF_MSK (0x1 << HGC_INVLD_DQE_INFO_IPTT_OF_OFF)
+#define HGC_INVLD_DQE_INFO_SSP_ERR_OFF 21
+#define HGC_INVLD_DQE_INFO_SSP_ERR_MSK (0x1 << HGC_INVLD_DQE_INFO_SSP_ERR_OFF)
+#define HGC_INVLD_DQE_INFO_OFL_OFF 22
+#define HGC_INVLD_DQE_INFO_OFL_MSK (0x1 << HGC_INVLD_DQE_INFO_OFL_OFF)
+#define HGC_ITCT_ECC_ADDR 0x150
+#define HGC_ITCT_ECC_ADDR_BAD_OFF 16
+#define HGC_ITCT_ECC_ADDR_BAD_MSK (0x3ff << HGC_ITCT_ECC_ADDR_BAD_OFF)
+#define HGC_AXI_FIFO_ERR_INFO 0x154
+#define INT_COAL_EN 0x1bc
+#define OQ_INT_COAL_TIME 0x1c0
+#define OQ_INT_COAL_CNT 0x1c4
+#define ENT_INT_COAL_TIME 0x1c8
+#define ENT_INT_COAL_CNT 0x1cc
+#define OQ_INT_SRC 0x1d0
+#define OQ_INT_SRC_MSK 0x1d4
+#define ENT_INT_SRC1 0x1d8
+#define ENT_INT_SRC2 0x1dc
+#define ENT_INT_SRC2_DQ_CFG_ERR_OFF 25
+#define ENT_INT_SRC2_DQ_CFG_ERR_MSK (0x1 << ENT_INT_SRC2_DQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_CQ_CFG_ERR_OFF 27
+#define ENT_INT_SRC2_CQ_CFG_ERR_MSK (0x1 << ENT_INT_SRC2_CQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_AXI_WRONG_INT_OFF 28
+#define ENT_INT_SRC2_AXI_WRONG_INT_MSK (0x1 << ENT_INT_SRC2_AXI_WRONG_INT_OFF)
+#define ENT_INT_SRC2_AXI_OVERLF_INT_OFF 29
+#define ENT_INT_SRC2_AXI_OVERLF_INT_MSK (0x1 << ENT_INT_SRC2_AXI_OVERLF_INT_OFF)
+#define ENT_INT_SRC_MSK1 0x1e0
+#define ENT_INT_SRC_MSK2 0x1e4
+#define SAS_ECC_INTR 0x1e8
+#define SAS_ECC_INTR_DQ_ECC1B_OFF 0
+#define SAS_ECC_INTR_DQ_ECC1B_MSK (0x1 << SAS_ECC_INTR_DQ_ECC1B_OFF)
+#define SAS_ECC_INTR_DQ_ECCBAD_OFF 1
+#define SAS_ECC_INTR_DQ_ECCBAD_MSK (0x1 << SAS_ECC_INTR_DQ_ECCBAD_OFF)
+#define SAS_ECC_INTR_IOST_ECC1B_OFF 2
+#define SAS_ECC_INTR_IOST_ECC1B_MSK (0x1 << SAS_ECC_INTR_IOST_ECC1B_OFF)
+#define SAS_ECC_INTR_IOST_ECCBAD_OFF 3
+#define SAS_ECC_INTR_IOST_ECCBAD_MSK (0x1 << SAS_ECC_INTR_IOST_ECCBAD_OFF)
+#define SAS_ECC_INTR_ITCT_ECC1B_OFF 4
+#define SAS_ECC_INTR_ITCT_ECC1B_MSK (0x1 << SAS_ECC_INTR_ITCT_ECC1B_OFF)
+#define SAS_ECC_INTR_ITCT_ECCBAD_OFF 5
+#define SAS_ECC_INTR_ITCT_ECCBAD_MSK (0x1 << SAS_ECC_INTR_ITCT_ECCBAD_OFF)
+#define SAS_ECC_INTR_MSK 0x1ec
+#define HGC_ERR_STAT_EN 0x238
+#define DLVRY_Q_0_BASE_ADDR_LO 0x260
+#define DLVRY_Q_0_BASE_ADDR_HI 0x264
+#define DLVRY_Q_0_DEPTH 0x268
+#define DLVRY_Q_0_WR_PTR 0x26c
+#define DLVRY_Q_0_RD_PTR 0x270
+#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
+#define COMPL_Q_0_DEPTH 0x4e8
+#define COMPL_Q_0_WR_PTR 0x4ec
+#define COMPL_Q_0_RD_PTR 0x4f0
+#define HGC_ECC_ERR 0x7d0
+
+/* phy registers need init */
+#define PORT_BASE (0x800)
+
+#define PHY_CFG (PORT_BASE + 0x0)
+#define PHY_CFG_ENA_OFF 0
+#define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF 2
+#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
+#define PROG_PHY_LINK_RATE (PORT_BASE + 0xc)
+#define PROG_PHY_LINK_RATE_MAX_OFF 0
+#define PROG_PHY_LINK_RATE_MAX_MSK (0xf << PROG_PHY_LINK_RATE_MAX_OFF)
+#define PROG_PHY_LINK_RATE_MIN_OFF 4
+#define PROG_PHY_LINK_RATE_MIN_MSK (0xf << PROG_PHY_LINK_RATE_MIN_OFF)
+#define PROG_PHY_LINK_RATE_OOB_OFF 8
+#define PROG_PHY_LINK_RATE_OOB_MSK (0xf << PROG_PHY_LINK_RATE_OOB_OFF)
+#define PHY_CTRL (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET_OFF 0
+#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
+#define PHY_RATE_NEGO (PORT_BASE + 0x30)
+#define PHY_PCN (PORT_BASE + 0x44)
+#define SL_TOUT_CFG (PORT_BASE + 0x8c)
+#define SL_CONTROL (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF 0
+#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3 (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
+#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
+#define RX_IDAF_DWORD1 (PORT_BASE + 0xc8)
+#define RX_IDAF_DWORD2 (PORT_BASE + 0xcc)
+#define RX_IDAF_DWORD3 (PORT_BASE + 0xd0)
+#define RX_IDAF_DWORD4 (PORT_BASE + 0xd4)
+#define RX_IDAF_DWORD5 (PORT_BASE + 0xd8)
+#define RX_IDAF_DWORD6 (PORT_BASE + 0xdc)
+#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+#define DONE_RECEIVED_TIME (PORT_BASE + 0x12c)
+#define CON_CFG_DRIVER (PORT_BASE + 0x130)
+#define PHY_CONFIG2 (PORT_BASE + 0x1a8)
+#define PHY_CONFIG2_FORCE_TXDEEMPH_OFF 3
+#define PHY_CONFIG2_FORCE_TXDEEMPH_MSK (0x1 << PHY_CONFIG2_FORCE_TXDEEMPH_OFF)
+#define PHY_CONFIG2_TX_TRAIN_COMP_OFF 24
+#define PHY_CONFIG2_TX_TRAIN_COMP_MSK (0x1 << PHY_CONFIG2_TX_TRAIN_COMP_OFF)
+#define CHL_INT0 (PORT_BASE + 0x1b0)
+#define CHL_INT0_PHYCTRL_NOTRDY_OFF 0
+#define CHL_INT0_PHYCTRL_NOTRDY_MSK (0x1 << CHL_INT0_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT0_SN_FAIL_NGR_OFF 2
+#define CHL_INT0_SN_FAIL_NGR_MSK (0x1 << CHL_INT0_SN_FAIL_NGR_OFF)
+#define CHL_INT0_DWS_LOST_OFF 4
+#define CHL_INT0_DWS_LOST_MSK (0x1 << CHL_INT0_DWS_LOST_OFF)
+#define CHL_INT0_SL_IDAF_FAIL_OFF 10
+#define CHL_INT0_SL_IDAF_FAIL_MSK (0x1 << CHL_INT0_SL_IDAF_FAIL_OFF)
+#define CHL_INT0_ID_TIMEOUT_OFF 11
+#define CHL_INT0_ID_TIMEOUT_MSK (0x1 << CHL_INT0_ID_TIMEOUT_OFF)
+#define CHL_INT0_SL_OPAF_FAIL_OFF 12
+#define CHL_INT0_SL_OPAF_FAIL_MSK (0x1 << CHL_INT0_SL_OPAF_FAIL_OFF)
+#define CHL_INT0_SL_PS_FAIL_OFF 21
+#define CHL_INT0_SL_PS_FAIL_MSK (0x1 << CHL_INT0_SL_PS_FAIL_OFF)
+#define CHL_INT1 (PORT_BASE + 0x1b4)
+#define CHL_INT2 (PORT_BASE + 0x1b8)
+#define CHL_INT2_SL_RX_BC_ACK_OFF 2
+#define CHL_INT2_SL_RX_BC_ACK_MSK (0x1 << CHL_INT2_SL_RX_BC_ACK_OFF)
+#define CHL_INT2_SL_PHY_ENA_OFF 6
+#define CHL_INT2_SL_PHY_ENA_MSK (0x1 << CHL_INT2_SL_PHY_ENA_OFF)
+#define CHL_INT0_MSK (PORT_BASE + 0x1bc)
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF 0
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK (0x1 << CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT1_MSK (PORT_BASE + 0x1c0)
+#define CHL_INT2_MSK (PORT_BASE + 0x1c4)
+#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
+#define DMA_TX_STATUS (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY_OFF 0
+#define DMA_TX_STATUS_BUSY_MSK (0x1 << DMA_TX_STATUS_BUSY_OFF)
+#define DMA_RX_STATUS (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY_OFF 0
+#define DMA_RX_STATUS_BUSY_MSK (0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define AXI_CFG 0x5100
+#define RESET_VALUE 0x7ffff
+
+/* HW dma structures */
+/* Delivery queue header */
+/* dw0 */
+#define CMD_HDR_RESP_REPORT_OFF 5
+#define CMD_HDR_RESP_REPORT_MSK 0x20
+#define CMD_HDR_TLR_CTRL_OFF 6
+#define CMD_HDR_TLR_CTRL_MSK 0xc0
+#define CMD_HDR_PORT_OFF 17
+#define CMD_HDR_PORT_MSK 0xe0000
+#define CMD_HDR_PRIORITY_OFF 27
+#define CMD_HDR_PRIORITY_MSK 0x8000000
+#define CMD_HDR_MODE_OFF 28
+#define CMD_HDR_MODE_MSK 0x10000000
+#define CMD_HDR_CMD_OFF 29
+#define CMD_HDR_CMD_MSK 0xe0000000
+/* dw1 */
+#define CMD_HDR_VERIFY_DTL_OFF 10
+#define CMD_HDR_VERIFY_DTL_MSK 0x400
+#define CMD_HDR_SSP_FRAME_TYPE_OFF 13
+#define CMD_HDR_SSP_FRAME_TYPE_MSK 0xe000
+#define CMD_HDR_DEVICE_ID_OFF 16
+#define CMD_HDR_DEVICE_ID_MSK 0xffff0000
+/* dw2 */
+#define CMD_HDR_CFL_OFF 0
+#define CMD_HDR_CFL_MSK 0x1ff
+#define CMD_HDR_MRFL_OFF 15
+#define CMD_HDR_MRFL_MSK 0xff8000
+#define CMD_HDR_FIRST_BURST_OFF 25
+#define CMD_HDR_FIRST_BURST_MSK 0x2000000
+/* dw3 */
+#define CMD_HDR_IPTT_OFF 0
+#define CMD_HDR_IPTT_MSK 0xffff
+/* dw6 */
+#define CMD_HDR_DATA_SGL_LEN_OFF 16
+#define CMD_HDR_DATA_SGL_LEN_MSK 0xffff0000
+
+/* Completion header */
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_CMD_CMPLT_OFF 17
+#define CMPLT_HDR_CMD_CMPLT_MSK (0x1 << CMPLT_HDR_CMD_CMPLT_OFF)
+#define CMPLT_HDR_ERR_RCRD_XFRD_OFF 18
+#define CMPLT_HDR_ERR_RCRD_XFRD_MSK (0x1 << CMPLT_HDR_ERR_RCRD_XFRD_OFF)
+#define CMPLT_HDR_RSPNS_XFRD_OFF 19
+#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_IO_CFG_ERR_OFF 27
+#define CMPLT_HDR_IO_CFG_ERR_MSK (0x1 << CMPLT_HDR_IO_CFG_ERR_OFF)
+
+/* ITCT header */
+/* qw0 */
+#define ITCT_HDR_DEV_TYPE_OFF 0
+#define ITCT_HDR_DEV_TYPE_MSK (0x3ULL << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_VALID_OFF 2
+#define ITCT_HDR_VALID_MSK (0x1ULL << ITCT_HDR_VALID_OFF)
+#define ITCT_HDR_AWT_CONTROL_OFF 4
+#define ITCT_HDR_AWT_CONTROL_MSK (0x1ULL << ITCT_HDR_AWT_CONTROL_OFF)
+#define ITCT_HDR_MAX_CONN_RATE_OFF 5
+#define ITCT_HDR_MAX_CONN_RATE_MSK (0xfULL << ITCT_HDR_MAX_CONN_RATE_OFF)
+#define ITCT_HDR_VALID_LINK_NUM_OFF 9
+#define ITCT_HDR_VALID_LINK_NUM_MSK (0xfULL << ITCT_HDR_VALID_LINK_NUM_OFF)
+#define ITCT_HDR_PORT_ID_OFF 13
+#define ITCT_HDR_PORT_ID_MSK (0x7ULL << ITCT_HDR_PORT_ID_OFF)
+#define ITCT_HDR_SMP_TIMEOUT_OFF 16
+#define ITCT_HDR_SMP_TIMEOUT_MSK (0xffffULL << ITCT_HDR_SMP_TIMEOUT_OFF)
+/* qw1 */
+#define ITCT_HDR_MAX_SAS_ADDR_OFF 0
+#define ITCT_HDR_MAX_SAS_ADDR_MSK (0xffffffffffffffff << \
+ ITCT_HDR_MAX_SAS_ADDR_OFF)
+/* qw2 */
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_OFF 0
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_MSK (0xffffULL << \
+ ITCT_HDR_IT_NEXUS_LOSS_TL_OFF)
+#define ITCT_HDR_BUS_INACTIVE_TL_OFF 16
+#define ITCT_HDR_BUS_INACTIVE_TL_MSK (0xffffULL << \
+ ITCT_HDR_BUS_INACTIVE_TL_OFF)
+#define ITCT_HDR_MAX_CONN_TL_OFF 32
+#define ITCT_HDR_MAX_CONN_TL_MSK (0xffffULL << \
+ ITCT_HDR_MAX_CONN_TL_OFF)
+#define ITCT_HDR_REJ_OPEN_TL_OFF 48
+#define ITCT_HDR_REJ_OPEN_TL_MSK (0xffffULL << \
+ ITCT_HDR_REJ_OPEN_TL_OFF)
+
+/* Err record header */
+#define ERR_HDR_DMA_TX_ERR_TYPE_OFF 0
+#define ERR_HDR_DMA_TX_ERR_TYPE_MSK (0xffff << ERR_HDR_DMA_TX_ERR_TYPE_OFF)
+#define ERR_HDR_DMA_RX_ERR_TYPE_OFF 16
+#define ERR_HDR_DMA_RX_ERR_TYPE_MSK (0xffff << ERR_HDR_DMA_RX_ERR_TYPE_OFF)
+
+struct hisi_sas_complete_v1_hdr {
+ __le32 data;
+};
+
+struct hisi_sas_err_record_v1 {
+ /* dw0 */
+ __le32 dma_err_type;
+
+ /* dw1 */
+ __le32 trans_tx_fail_type;
+
+ /* dw2 */
+ __le32 trans_rx_fail_type;
+
+ /* dw3 */
+ u32 rsvd;
+};
+
+enum {
+ HISI_SAS_PHY_BCAST_ACK = 0,
+ HISI_SAS_PHY_SL_PHY_ENABLED,
+ HISI_SAS_PHY_INT_ABNORMAL,
+ HISI_SAS_PHY_INT_NR
+};
+
+enum {
+ DMA_TX_ERR_BASE = 0x0,
+ DMA_RX_ERR_BASE = 0x100,
+ TRANS_TX_FAIL_BASE = 0x200,
+ TRANS_RX_FAIL_BASE = 0x300,
+
+ /* dma tx */
+ DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x0 */
+ DMA_TX_DIF_APP_ERR, /* 0x1 */
+ DMA_TX_DIF_RPP_ERR, /* 0x2 */
+ DMA_TX_AXI_BUS_ERR, /* 0x3 */
+ DMA_TX_DATA_SGL_OVERFLOW_ERR, /* 0x4 */
+ DMA_TX_DIF_SGL_OVERFLOW_ERR, /* 0x5 */
+ DMA_TX_UNEXP_XFER_RDY_ERR, /* 0x6 */
+ DMA_TX_XFER_RDY_OFFSET_ERR, /* 0x7 */
+ DMA_TX_DATA_UNDERFLOW_ERR, /* 0x8 */
+ DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR, /* 0x9 */
+
+ /* dma rx */
+ DMA_RX_BUFFER_ECC_ERR = DMA_RX_ERR_BASE, /* 0x100 */
+ DMA_RX_DIF_CRC_ERR, /* 0x101 */
+ DMA_RX_DIF_APP_ERR, /* 0x102 */
+ DMA_RX_DIF_RPP_ERR, /* 0x103 */
+ DMA_RX_RESP_BUFFER_OVERFLOW_ERR, /* 0x104 */
+ DMA_RX_AXI_BUS_ERR, /* 0x105 */
+ DMA_RX_DATA_SGL_OVERFLOW_ERR, /* 0x106 */
+ DMA_RX_DIF_SGL_OVERFLOW_ERR, /* 0x107 */
+ DMA_RX_DATA_OFFSET_ERR, /* 0x108 */
+ DMA_RX_UNEXP_RX_DATA_ERR, /* 0x109 */
+ DMA_RX_DATA_OVERFLOW_ERR, /* 0x10a */
+ DMA_RX_DATA_UNDERFLOW_ERR, /* 0x10b */
+ DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x10c */
+
+ /* trans tx */
+ TRANS_TX_RSVD0_ERR = TRANS_TX_FAIL_BASE, /* 0x200 */
+ TRANS_TX_PHY_NOT_ENABLE_ERR, /* 0x201 */
+ TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR, /* 0x202 */
+ TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR, /* 0x203 */
+ TRANS_TX_OPEN_REJCT_BY_OTHER_ERR, /* 0x204 */
+ TRANS_TX_RSVD1_ERR, /* 0x205 */
+ TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR, /* 0x206 */
+ TRANS_TX_OPEN_REJCT_STP_BUSY_ERR, /* 0x207 */
+ TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR, /* 0x208 */
+ TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR, /* 0x209 */
+ TRANS_TX_OPEN_REJCT_BAD_DEST_ERR, /* 0x20a */
+ TRANS_TX_OPEN_BREAK_RECEIVE_ERR, /* 0x20b */
+ TRANS_TX_LOW_PHY_POWER_ERR, /* 0x20c */
+ TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR, /* 0x20d */
+ TRANS_TX_OPEN_TIMEOUT_ERR, /* 0x20e */
+ TRANS_TX_OPEN_REJCT_NO_DEST_ERR, /* 0x20f */
+ TRANS_TX_OPEN_RETRY_ERR, /* 0x210 */
+ TRANS_TX_RSVD2_ERR, /* 0x211 */
+ TRANS_TX_BREAK_TIMEOUT_ERR, /* 0x212 */
+ TRANS_TX_BREAK_REQUEST_ERR, /* 0x213 */
+ TRANS_TX_BREAK_RECEIVE_ERR, /* 0x214 */
+ TRANS_TX_CLOSE_TIMEOUT_ERR, /* 0x215 */
+ TRANS_TX_CLOSE_NORMAL_ERR, /* 0x216 */
+ TRANS_TX_CLOSE_PHYRESET_ERR, /* 0x217 */
+ TRANS_TX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x218 */
+ TRANS_TX_WITH_CLOSE_COMINIT_ERR, /* 0x219 */
+ TRANS_TX_NAK_RECEIVE_ERR, /* 0x21a */
+ TRANS_TX_ACK_NAK_TIMEOUT_ERR, /* 0x21b */
+ TRANS_TX_CREDIT_TIMEOUT_ERR, /* 0x21c */
+ TRANS_TX_IPTT_CONFLICT_ERR, /* 0x21d */
+ TRANS_TX_TXFRM_TYPE_ERR, /* 0x21e */
+ TRANS_TX_TXSMP_LENGTH_ERR, /* 0x21f */
+
+ /* trans rx */
+ TRANS_RX_FRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x300 */
+ TRANS_RX_FRAME_DONE_ERR, /* 0x301 */
+ TRANS_RX_FRAME_ERRPRM_ERR, /* 0x302 */
+ TRANS_RX_FRAME_NO_CREDIT_ERR, /* 0x303 */
+ TRANS_RX_RSVD0_ERR, /* 0x304 */
+ TRANS_RX_FRAME_OVERRUN_ERR, /* 0x305 */
+ TRANS_RX_FRAME_NO_EOF_ERR, /* 0x306 */
+ TRANS_RX_LINK_BUF_OVERRUN_ERR, /* 0x307 */
+ TRANS_RX_BREAK_TIMEOUT_ERR, /* 0x308 */
+ TRANS_RX_BREAK_REQUEST_ERR, /* 0x309 */
+ TRANS_RX_BREAK_RECEIVE_ERR, /* 0x30a */
+ TRANS_RX_CLOSE_TIMEOUT_ERR, /* 0x30b */
+ TRANS_RX_CLOSE_NORMAL_ERR, /* 0x30c */
+ TRANS_RX_CLOSE_PHYRESET_ERR, /* 0x30d */
+ TRANS_RX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x30e */
+ TRANS_RX_WITH_CLOSE_COMINIT_ERR, /* 0x30f */
+ TRANS_RX_DATA_LENGTH0_ERR, /* 0x310 */
+ TRANS_RX_BAD_HASH_ERR, /* 0x311 */
+ TRANS_RX_XRDY_ZERO_ERR, /* 0x312 */
+ TRANS_RX_SSP_FRAME_LEN_ERR, /* 0x313 */
+ TRANS_RX_TRANS_RX_RSVD1_ERR, /* 0x314 */
+ TRANS_RX_NO_BALANCE_ERR, /* 0x315 */
+ TRANS_RX_TRANS_RX_RSVD2_ERR, /* 0x316 */
+ TRANS_RX_TRANS_RX_RSVD3_ERR, /* 0x317 */
+ TRANS_RX_BAD_FRAME_TYPE_ERR, /* 0x318 */
+ TRANS_RX_SMP_FRAME_LEN_ERR, /* 0x319 */
+ TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x31a */
+};
+
+#define HISI_SAS_COMMAND_ENTRIES_V1_HW 8192
+
+#define HISI_SAS_PHY_MAX_INT_NR (HISI_SAS_PHY_INT_NR * HISI_SAS_MAX_PHYS)
+#define HISI_SAS_CQ_MAX_INT_NR (HISI_SAS_MAX_QUEUES)
+#define HISI_SAS_FATAL_INT_NR (2)
+
+#define HISI_SAS_MAX_INT_NR \
+ (HISI_SAS_PHY_MAX_INT_NR + HISI_SAS_CQ_MAX_INT_NR +\
+ HISI_SAS_FATAL_INT_NR)
+
+static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl(regs);
+}
+
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl_relaxed(regs);
+}
+
+static void hisi_sas_write32(struct hisi_hba *hisi_hba,
+ u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ writel(val, regs);
+}
+
+static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ writel(val, regs);
+}
+
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ return readl(regs);
+}
+
+static void config_phy_opt_mode_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_DC_OPT_MSK;
+ cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void config_tx_tfe_autoneg_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CONFIG2);
+
+ cfg &= ~PHY_CONFIG2_FORCE_TXDEEMPH_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CONFIG2, cfg);
+}
+
+static void config_id_frame_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct sas_identify_frame identify_frame;
+ u32 *identify_buffer;
+
+ memset(&identify_frame, 0, sizeof(identify_frame));
+ identify_frame.dev_type = SAS_END_DEVICE;
+ identify_frame.frame_type = 0;
+ identify_frame._un1 = 1;
+ identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
+ identify_frame.target_bits = SAS_PROTOCOL_NONE;
+ memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ identify_frame.phy_id = phy_no;
+ identify_buffer = (u32 *)(&identify_frame);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
+ __swab32(identify_buffer[0]));
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
+ identify_buffer[2]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
+ identify_buffer[1]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
+ identify_buffer[4]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
+ identify_buffer[3]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
+ __swab32(identify_buffer[5]));
+}
+
+static void init_id_frame_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ config_id_frame_v1_hw(hisi_hba, i);
+}
+
+static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ struct domain_device *device = sas_dev->sas_device;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 qw0, device_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+
+ memset(itct, 0, sizeof(*itct));
+
+ /* qw0 */
+ qw0 = 0;
+ switch (sas_dev->dev_type) {
+ case SAS_END_DEVICE:
+ case SAS_EDGE_EXPANDER_DEVICE:
+ case SAS_FANOUT_EXPANDER_DEVICE:
+ qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
+ break;
+ default:
+ dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
+ sas_dev->dev_type);
+ }
+
+ qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
+ (1 << ITCT_HDR_AWT_CONTROL_OFF) |
+ (device->max_linkrate << ITCT_HDR_MAX_CONN_RATE_OFF) |
+ (1 << ITCT_HDR_VALID_LINK_NUM_OFF) |
+ (device->port->id << ITCT_HDR_PORT_ID_OFF));
+ itct->qw0 = cpu_to_le64(qw0);
+
+ /* qw1 */
+ memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+ itct->sas_addr = __swab64(itct->sas_addr);
+
+ /* qw2 */
+ itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_IT_NEXUS_LOSS_TL_OFF) |
+ (0xff00ULL << ITCT_HDR_BUS_INACTIVE_TL_OFF) |
+ (0xff00ULL << ITCT_HDR_MAX_CONN_TL_OFF) |
+ (0xff00ULL << ITCT_HDR_REJ_OPEN_TL_OFF));
+}
+
+static void free_device_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ u64 dev_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+ u64 qw0;
+ u32 reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+
+ reg_val |= CFG_AGING_TIME_ITCT_REL_MSK;
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+ /* free itct */
+ udelay(1);
+ reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+ reg_val &= ~CFG_AGING_TIME_ITCT_REL_MSK;
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+ qw0 = cpu_to_le64(itct->qw0);
+ qw0 &= ~ITCT_HDR_VALID_MSK;
+ itct->qw0 = cpu_to_le64(qw0);
+}
+
+static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ unsigned long end_time;
+ u32 val;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 phy_ctrl = hisi_sas_phy_read32(hisi_hba, i, PHY_CTRL);
+
+ phy_ctrl |= PHY_CTRL_RESET_MSK;
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, phy_ctrl);
+ }
+ msleep(1); /* It is safe to wait for 50us */
+
+ /* Ensure DMA tx & rx idle */
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 dma_tx_status, dma_rx_status;
+
+ end_time = jiffies + msecs_to_jiffies(1000);
+
+ while (1) {
+ dma_tx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_TX_STATUS);
+ dma_rx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_RX_STATUS);
+
+ if (!(dma_tx_status & DMA_TX_STATUS_BUSY_MSK) &&
+ !(dma_rx_status & DMA_RX_STATUS_BUSY_MSK))
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+ }
+
+ /* Ensure axi bus idle */
+ end_time = jiffies + msecs_to_jiffies(1000);
+ while (1) {
+ u32 axi_status =
+ hisi_sas_read32(hisi_hba, AXI_CFG);
+
+ if (axi_status == 0)
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+
+ if (ACPI_HANDLE(dev)) {
+ acpi_status s;
+
+ s = acpi_evaluate_object(ACPI_HANDLE(dev), "_RST", NULL, NULL);
+ if (ACPI_FAILURE(s)) {
+ dev_err(dev, "Reset failed\n");
+ return -EIO;
+ }
+ } else if (hisi_hba->ctrl) {
+ /* Apply reset and disable clock */
+ /* clk disable reg is offset by +4 bytes from clk enable reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (RESET_VALUE != (val & RESET_VALUE)) {
+ dev_err(dev, "Reset failed\n");
+ return -EIO;
+ }
+
+ /* De-reset and enable clock */
+ /* deassert rst reg is offset by +4 bytes from assert reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (val & RESET_VALUE) {
+ dev_err(dev, "De-reset failed\n");
+ return -EIO;
+ }
+ } else
+ dev_warn(dev, "no reset method\n");
+
+ return 0;
+}
+
+static void init_reg_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ /* Global registers init*/
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
+ (u32)((1ULL << hisi_hba->queue_count) - 1));
+ hisi_sas_write32(hisi_hba, HGC_TRANS_TASK_CNT_LIMIT, 0x11);
+ hisi_sas_write32(hisi_hba, DEVICE_MSG_WORK_MODE, 0x1);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x1ff);
+ hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x401);
+ hisi_sas_write32(hisi_hba, CFG_1US_TIMER_TRSH, 0x64);
+ hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x64);
+ hisi_sas_write32(hisi_hba, BUS_INACTIVE_LIMIT_TIME, 0x2710);
+ hisi_sas_write32(hisi_hba, REJECT_TO_OPEN_LIMIT_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x7a12);
+ hisi_sas_write32(hisi_hba, HGC_DFX_CFG2, 0x9c40);
+ hisi_sas_write32(hisi_hba, FIS_LIST_BADDR_L, 0x2);
+ hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x186a0);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0xffffffff);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC_MSK, 0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0);
+ hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 0x2);
+ hisi_sas_write32(hisi_hba, CFG_SAS_CONFIG, 0x22000000);
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x88a);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CONFIG2, 0x7c080);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_RATE_NEGO, 0x415ee00);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_PCN, 0x80a80000);
+ hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0);
+ hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x13f0a);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 3);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 8);
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ /* Delivery queue */
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+
+ /* Completion queue */
+ hisi_sas_write32(hisi_hba,
+ COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+ }
+
+ /* itct */
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->itct_dma));
+
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->itct_dma));
+
+ /* iost */
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->iost_dma));
+
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->iost_dma));
+
+ /* breakpoint */
+ hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_LO,
+ lower_32_bits(hisi_hba->breakpoint_dma));
+
+ hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_HI,
+ upper_32_bits(hisi_hba->breakpoint_dma));
+}
+
+static int hw_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc;
+
+ rc = reset_hw_v1_hw(hisi_hba);
+ if (rc) {
+ dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+ return rc;
+ }
+
+ msleep(100);
+ init_reg_v1_hw(hisi_hba);
+
+ init_id_frame_v1_hw(hisi_hba);
+
+ return 0;
+}
+
+static void enable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg |= PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void disable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void start_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ config_id_frame_v1_hw(hisi_hba, phy_no);
+ config_phy_opt_mode_v1_hw(hisi_hba, phy_no);
+ config_tx_tfe_autoneg_v1_hw(hisi_hba, phy_no);
+ enable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void stop_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ disable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ stop_phy_v1_hw(hisi_hba, phy_no);
+ msleep(100);
+ start_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void start_phys_v1_hw(unsigned long data)
+{
+ struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x12a);
+ start_phy_v1_hw(hisi_hba, i);
+ }
+}
+
+static void phys_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ struct timer_list *timer = &hisi_hba->timer;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a);
+ hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
+ }
+
+ setup_timer(timer, start_phys_v1_hw, (unsigned long)hisi_hba);
+ mod_timer(timer, jiffies + HZ);
+}
+
+static void sl_notify_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 sl_control;
+
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ msleep(1);
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+}
+
+static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+ int i, bitmap = 0;
+ u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+ bitmap |= 1 << i;
+
+ return bitmap;
+}
+
+/**
+ * This function allocates across all queues to load balance.
+ * Slots are allocated from queues in a round-robin fashion.
+ *
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 r, w;
+ int queue = hisi_hba->queue;
+
+ while (1) {
+ w = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ r = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_RD_PTR + (queue * 0x14));
+ if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+ queue = (queue + 1) % hisi_hba->queue_count;
+ if (queue == hisi_hba->queue) {
+ dev_warn(dev, "could not find free slot\n");
+ return -EAGAIN;
+ }
+ continue;
+ }
+ break;
+ }
+ hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+ *q = queue;
+ *s = w;
+ return 0;
+}
+
+static void start_delivery_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+ int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+ ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+}
+
+static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ struct hisi_sas_cmd_hdr *hdr,
+ struct scatterlist *scatter,
+ int n_elem)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct scatterlist *sg;
+ int i;
+
+ if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+ dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+ n_elem);
+ return -EINVAL;
+ }
+
+ slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+ &slot->sge_page_dma);
+ if (!slot->sge_page)
+ return -ENOMEM;
+
+ for_each_sg(scatter, sg, n_elem, i) {
+ struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+ entry->data_len = cpu_to_le32(sg_dma_len(sg));
+ entry->data_off = 0;
+ }
+
+ hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
+
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+ return 0;
+}
+
+static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_port *port = slot->port;
+ struct scatterlist *sg_req, *sg_resp;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ dma_addr_t req_dma_addr;
+ unsigned int req_len, resp_len;
+ int elem, rc;
+
+ /*
+ * DMA-map SMP request, response buffers
+ */
+ /* req */
+ sg_req = &task->smp_task.smp_req;
+ elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
+ if (!elem)
+ return -ENOMEM;
+ req_len = sg_dma_len(sg_req);
+ req_dma_addr = sg_dma_address(sg_req);
+
+ /* resp */
+ sg_resp = &task->smp_task.smp_resp;
+ elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
+ if (!elem) {
+ rc = -ENOMEM;
+ goto err_out_req;
+ }
+ resp_len = sg_dma_len(sg_resp);
+ if ((req_len & 0x3) || (resp_len & 0x3)) {
+ rc = -EINVAL;
+ goto err_out_resp;
+ }
+
+ /* create header */
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
+ (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
+ (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+ (2 << CMD_HDR_CMD_OFF)); /* smp */
+
+ /* map itct entry */
+ hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF);
+
+ /* dw2 */
+ hdr->dw2 = cpu_to_le32((((req_len-4)/4) << CMD_HDR_CFL_OFF) |
+ (HISI_SAS_MAX_SMP_RESP_SZ/4 <<
+ CMD_HDR_MRFL_OFF));
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ return 0;
+
+err_out_resp:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+err_out_req:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ return rc;
+}
+
+static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port = slot->port;
+ struct sas_ssp_task *ssp_task = &task->ssp_task;
+ struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+ int has_data = 0, rc, priority = is_tmf;
+ u8 *buf_cmd, fburst = 0;
+ u32 dw1, dw2;
+
+ /* create header */
+ hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
+ (0x2 << CMD_HDR_TLR_CTRL_OFF) |
+ (port->id << CMD_HDR_PORT_OFF) |
+ (priority << CMD_HDR_PRIORITY_OFF) |
+ (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+ (1 << CMD_HDR_CMD_OFF)); /* ssp */
+
+ dw1 = 1 << CMD_HDR_VERIFY_DTL_OFF;
+
+ if (is_tmf) {
+ dw1 |= 3 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ } else {
+ switch (scsi_cmnd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ dw1 |= 2 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ has_data = 1;
+ break;
+ case DMA_FROM_DEVICE:
+ dw1 |= 1 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ has_data = 1;
+ break;
+ default:
+ dw1 |= 0 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ }
+ }
+
+ /* map itct entry */
+ dw1 |= sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ if (is_tmf) {
+ dw2 = ((sizeof(struct ssp_tmf_iu) +
+ sizeof(struct ssp_frame_hdr)+3)/4) <<
+ CMD_HDR_CFL_OFF;
+ } else {
+ dw2 = ((sizeof(struct ssp_command_iu) +
+ sizeof(struct ssp_frame_hdr)+3)/4) <<
+ CMD_HDR_CFL_OFF;
+ }
+
+ dw2 |= (HISI_SAS_MAX_SSP_RESP_SZ/4) << CMD_HDR_MRFL_OFF;
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ if (has_data) {
+ rc = prep_prd_sge_v1_hw(hisi_hba, slot, hdr, task->scatter,
+ slot->n_elem);
+ if (rc)
+ return rc;
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+ if (task->ssp_task.enable_first_burst) {
+ fburst = (1 << 7);
+ dw2 |= 1 << CMD_HDR_FIRST_BURST_OFF;
+ }
+ hdr->dw2 = cpu_to_le32(dw2);
+
+ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ if (!is_tmf) {
+ buf_cmd[9] = fburst | task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
+ memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
+ task->ssp_task.cmd->cmd_len);
+ } else {
+ buf_cmd[10] = tmf->tmf;
+ switch (tmf->tmf) {
+ case TMF_ABORT_TASK:
+ case TMF_QUERY_TASK:
+ buf_cmd[12] =
+ (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+ buf_cmd[13] =
+ tmf->tag_of_task_to_be_managed & 0xff;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* by default, task resp is complete */
+static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct hisi_sas_err_record_v1 *err_record = slot->status_buffer;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ int error = -1;
+ u32 dma_err_type = cpu_to_le32(err_record->dma_err_type);
+ u32 dma_tx_err_type = ((dma_err_type &
+ ERR_HDR_DMA_TX_ERR_TYPE_MSK)) >>
+ ERR_HDR_DMA_TX_ERR_TYPE_OFF;
+ u32 dma_rx_err_type = ((dma_err_type &
+ ERR_HDR_DMA_RX_ERR_TYPE_MSK)) >>
+ ERR_HDR_DMA_RX_ERR_TYPE_OFF;
+ u32 trans_tx_fail_type =
+ cpu_to_le32(err_record->trans_tx_fail_type);
+ u32 trans_rx_fail_type =
+ cpu_to_le32(err_record->trans_rx_fail_type);
+
+ if (dma_tx_err_type) {
+ /* dma tx err */
+ error = ffs(dma_tx_err_type)
+ - 1 + DMA_TX_ERR_BASE;
+ } else if (dma_rx_err_type) {
+ /* dma rx err */
+ error = ffs(dma_rx_err_type)
+ - 1 + DMA_RX_ERR_BASE;
+ } else if (trans_tx_fail_type) {
+ /* trans tx err */
+ error = ffs(trans_tx_fail_type)
+ - 1 + TRANS_TX_FAIL_BASE;
+ } else if (trans_rx_fail_type) {
+ /* trans rx err */
+ error = ffs(trans_rx_fail_type)
+ - 1 + TRANS_RX_FAIL_BASE;
+ }
+
+ switch (error) {
+ case DMA_TX_DATA_UNDERFLOW_ERR:
+ case DMA_RX_DATA_UNDERFLOW_ERR:
+ {
+ ts->residual = 0;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ }
+ case DMA_TX_DATA_SGL_OVERFLOW_ERR:
+ case DMA_TX_DIF_SGL_OVERFLOW_ERR:
+ case DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR:
+ case DMA_RX_DATA_OVERFLOW_ERR:
+ case TRANS_RX_FRAME_OVERRUN_ERR:
+ case TRANS_RX_LINK_BUF_OVERRUN_ERR:
+ {
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ }
+ case TRANS_TX_PHY_NOT_ENABLE_ERR:
+ {
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR:
+ case TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR:
+ case TRANS_TX_OPEN_REJCT_BY_OTHER_ERR:
+ case TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR:
+ case TRANS_TX_OPEN_REJCT_STP_BUSY_ERR:
+ case TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR:
+ case TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR:
+ case TRANS_TX_OPEN_REJCT_BAD_DEST_ERR:
+ case TRANS_TX_OPEN_BREAK_RECEIVE_ERR:
+ case TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR:
+ case TRANS_TX_OPEN_REJCT_NO_DEST_ERR:
+ case TRANS_TX_OPEN_RETRY_ERR:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_TIMEOUT_ERR:
+ {
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ case TRANS_TX_NAK_RECEIVE_ERR:
+ case TRANS_TX_ACK_NAK_TIMEOUT_ERR:
+ {
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ }
+ case TRANS_TX_CREDIT_TIMEOUT_ERR:
+ case TRANS_TX_CLOSE_NORMAL_ERR:
+ {
+ /* This will request a retry */
+ ts->stat = SAS_QUEUE_FULL;
+ slot->abort = 1;
+ break;
+ }
+ default:
+ {
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+ }
+ }
+ break;
+ case SAS_PROTOCOL_SMP:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ dev_err(dev, "slot err: SATA/STP not supported");
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int abort)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct task_status_struct *ts;
+ struct domain_device *device;
+ enum exec_status sts;
+ struct hisi_sas_complete_v1_hdr *complete_queue =
+ hisi_hba->complete_hdr[slot->cmplt_queue];
+ struct hisi_sas_complete_v1_hdr *complete_hdr;
+ u32 cmplt_hdr_data;
+
+ complete_hdr = &complete_queue[slot->cmplt_queue_slot];
+ cmplt_hdr_data = le32_to_cpu(complete_hdr->data);
+
+ if (unlikely(!task || !task->lldd_task || !task->dev))
+ return -EINVAL;
+
+ ts = &task->task_status;
+ device = task->dev;
+ sas_dev = device->lldd_dev;
+
+ task->task_state_flags &=
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+
+ memset(ts, 0, sizeof(*ts));
+ ts->resp = SAS_TASK_COMPLETE;
+
+ if (unlikely(!sas_dev || abort)) {
+ if (!sas_dev)
+ dev_dbg(dev, "slot complete: port has not device\n");
+ ts->stat = SAS_PHY_DOWN;
+ goto out;
+ }
+
+ if (cmplt_hdr_data & CMPLT_HDR_IO_CFG_ERR_MSK) {
+ u32 info_reg = hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_DQ_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq IPTT err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_TYPE_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq type err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_FORCE_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq force phy err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_PHY_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq phy id err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_ABORT_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq abort flag err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_IPTT_OF_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq IPTT or ICT err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_SSP_ERR_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq SSP frame type err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_OFL_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq order frame len err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ goto out;
+ }
+
+ if (cmplt_hdr_data & CMPLT_HDR_ERR_RCRD_XFRD_MSK &&
+ !(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK)) {
+
+ slot_err_v1_hw(hisi_hba, task, slot);
+ if (unlikely(slot->abort)) {
+ queue_work(hisi_hba->wq, &slot->abort_slot);
+ /* immediately return and do not complete */
+ return ts->stat;
+ }
+ goto out;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ struct ssp_response_iu *iu = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+ sas_ssp_task_response(dev, task, iu);
+ break;
+ }
+ case SAS_PROTOCOL_SMP:
+ {
+ void *to;
+ struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+
+ ts->stat = SAM_STAT_GOOD;
+ to = kmap_atomic(sg_page(sg_resp));
+
+ dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+ slot->status_buffer +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+ break;
+ }
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ dev_err(dev, "slot complete: SATA/STP not supported");
+ break;
+
+ default:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+
+ if (!slot->port->port_attached) {
+ dev_err(dev, "slot complete: port %d has removed\n",
+ slot->port->sas_port.id);
+ ts->stat = SAS_PHY_DOWN;
+ }
+
+out:
+ if (sas_dev && sas_dev->running_req)
+ sas_dev->running_req--;
+
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
+ sts = ts->stat;
+
+ if (task->task_done)
+ task->task_done(task);
+
+ return sts;
+}
+
+/* Interrupts */
+static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ int i, phy_no = sas_phy->id;
+ u32 irq_value, context, port_id, link_rate;
+ u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+ struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+ if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) {
+ dev_dbg(dev, "phyup: irq_value = %x not set enable bit\n",
+ irq_value);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+ if (context & 1 << phy_no) {
+ dev_err(dev, "phyup: phy%d SATA attached equipment\n",
+ phy_no);
+ goto end;
+ }
+
+ port_id = (hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA) >> (4 * phy_no))
+ & 0xf;
+ if (port_id == 0xf) {
+ dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ for (i = 0; i < 6; i++) {
+ u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
+ RX_IDAF_DWORD0 + (i * 4));
+ frame_rcvd[i] = __swab32(idaf);
+ }
+
+ /* Get the linkrate */
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ sas_phy->linkrate = link_rate;
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ memcpy(sas_phy->attached_sas_addr,
+ &id->sas_addr, SAS_ADDR_SIZE);
+ dev_info(dev, "phyup: phy%d link_rate=%d\n",
+ phy_no, link_rate);
+ phy->port_id = port_id;
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ phy->phy_type |= PORT_TYPE_SAS;
+ phy->phy_attached = 1;
+ phy->identify.device_type = id->dev_type;
+ phy->frame_rcvd_size = sizeof(struct sas_identify_frame);
+ if (phy->identify.device_type == SAS_END_DEVICE)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SSP;
+ else if (phy->identify.device_type != SAS_PHY_UNUSED)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SMP;
+ queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+ CHL_INT2_SL_PHY_ENA_MSK);
+
+ if (irq_value & CHL_INT2_SL_PHY_ENA_MSK) {
+ u32 chl_int0 = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+ chl_int0 &= ~CHL_INT0_PHYCTRL_NOTRDY_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, chl_int0);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3ce3ee);
+ }
+
+ return res;
+}
+
+static irqreturn_t int_bcast_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sha = &hisi_hba->sha;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int phy_no = sas_phy->id;
+ u32 irq_value;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+
+ if (!(irq_value & CHL_INT2_SL_RX_BC_ACK_MSK)) {
+ dev_err(dev, "bcast: irq_value = %x not set enable bit",
+ irq_value);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ sha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+ CHL_INT2_SL_RX_BC_ACK_MSK);
+
+ return res;
+}
+
+static irqreturn_t int_abnormal_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ u32 irq_value, irq_mask_old;
+ int phy_no = sas_phy->id;
+
+ /* mask_int0 */
+ irq_mask_old = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3fffff);
+
+ /* read int0 */
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+ if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK) {
+ u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ hisi_sas_phy_down(hisi_hba, phy_no,
+ (phy_state & 1 << phy_no) ? 1 : 0);
+ }
+
+ if (irq_value & CHL_INT0_ID_TIMEOUT_MSK)
+ dev_dbg(dev, "abnormal: ID_TIMEOUT phy%d identify timeout\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_DWS_LOST_MSK)
+ dev_dbg(dev, "abnormal: DWS_LOST phy%d dws lost\n", phy_no);
+
+ if (irq_value & CHL_INT0_SN_FAIL_NGR_MSK)
+ dev_dbg(dev, "abnormal: SN_FAIL_NGR phy%d sn fail ngr\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_SL_IDAF_FAIL_MSK ||
+ irq_value & CHL_INT0_SL_OPAF_FAIL_MSK)
+ dev_dbg(dev, "abnormal: SL_ID/OPAF_FAIL phy%d check adr frm err\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_SL_PS_FAIL_OFF)
+ dev_dbg(dev, "abnormal: SL_PS_FAIL phy%d fail\n", phy_no);
+
+ /* write to zero */
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, irq_value);
+
+ if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK)
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+ 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+ else
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+ irq_mask_old);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_cq *cq = p;
+ struct hisi_hba *hisi_hba = cq->hisi_hba;
+ struct hisi_sas_slot *slot;
+ int queue = cq->id;
+ struct hisi_sas_complete_v1_hdr *complete_queue =
+ (struct hisi_sas_complete_v1_hdr *)
+ hisi_hba->complete_hdr[queue];
+ u32 irq_value, rd_point, wr_point;
+
+ irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
+
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
+
+ rd_point = hisi_sas_read32(hisi_hba,
+ COMPL_Q_0_RD_PTR + (0x14 * queue));
+ wr_point = hisi_sas_read32(hisi_hba,
+ COMPL_Q_0_WR_PTR + (0x14 * queue));
+
+ while (rd_point != wr_point) {
+ struct hisi_sas_complete_v1_hdr *complete_hdr;
+ int idx;
+ u32 cmplt_hdr_data;
+
+ complete_hdr = &complete_queue[rd_point];
+ cmplt_hdr_data = cpu_to_le32(complete_hdr->data);
+ idx = (cmplt_hdr_data & CMPLT_HDR_IPTT_MSK) >>
+ CMPLT_HDR_IPTT_OFF;
+ slot = &hisi_hba->slot_info[idx];
+
+ /* The completion queue and queue slot index are not
+ * necessarily the same as the delivery queue and
+ * queue slot index.
+ */
+ slot->cmplt_queue_slot = rd_point;
+ slot->cmplt_queue = queue;
+ slot_complete_v1_hw(hisi_hba, slot, 0);
+
+ if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
+ rd_point = 0;
+ }
+
+ /* update rd_point */
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_ecc_int_v1_hw(int irq, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 ecc_int = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
+
+ if (ecc_int & SAS_ECC_INTR_DQ_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal DQ 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_DQ_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_DQ_ECC_ADDR) &
+ HGC_DQ_ECC_ADDR_BAD_MSK) >>
+ HGC_DQ_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal DQ RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_IOST_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal IOST 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_IOST_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR) &
+ HGC_IOST_ECC_ADDR_BAD_MSK) >>
+ HGC_IOST_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal IOST RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_ITCT_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR) &
+ HGC_ITCT_ECC_ADDR_BAD_MSK) >>
+ HGC_ITCT_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal TCT RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_ITCT_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal ITCT 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR, ecc_int | 0x3f);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_axi_int_v1_hw(int irq, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 axi_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC2);
+ u32 axi_info = hisi_sas_read32(hisi_hba, HGC_AXI_FIFO_ERR_INFO);
+
+ if (axi_int & ENT_INT_SRC2_DQ_CFG_ERR_MSK)
+ panic("%s: Fatal DQ_CFG_ERR interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_CQ_CFG_ERR_MSK)
+ panic("%s: Fatal CQ_CFG_ERR interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_AXI_WRONG_INT_MSK)
+ panic("%s: Fatal AXI_WRONG_INT interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_AXI_OVERLF_INT_MSK)
+ panic("%s: Fatal AXI_OVERLF_INT incorrect interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, axi_int | 0x30000000);
+
+ return IRQ_HANDLED;
+}
+
+static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
+ int_bcast_v1_hw,
+ int_phyup_v1_hw,
+ int_abnormal_v1_hw
+};
+
+static irq_handler_t fatal_interrupts[HISI_SAS_MAX_QUEUES] = {
+ fatal_ecc_int_v1_hw,
+ fatal_axi_int_v1_hw
+};
+
+static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+ int i, j, irq, rc, idx;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+
+ idx = i * HISI_SAS_PHY_INT_NR;
+ for (j = 0; j < HISI_SAS_PHY_INT_NR; j++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev,
+ "irq init: fail map phy interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, phy_interrupts[j], 0,
+ DRV_NAME " phy", phy);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "phy interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+ }
+
+ idx = hisi_hba->n_phy * HISI_SAS_PHY_INT_NR;
+ for (i = 0; i < hisi_hba->queue_count; i++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev, "irq init: could not map cq interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, cq_interrupt_v1_hw, 0,
+ DRV_NAME " cq", &hisi_hba->cq[i]);
+ if (rc) {
+ dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ idx = (hisi_hba->n_phy * HISI_SAS_PHY_INT_NR) + hisi_hba->queue_count;
+ for (i = 0; i < HISI_SAS_FATAL_INT_NR; i++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev, "irq init: could not map fatal interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
+ DRV_NAME " fatal", hisi_hba);
+ if (rc) {
+ dev_err(dev,
+ "irq init: could not request fatal interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+static int interrupt_openall_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ /* Clear interrupt status */
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT0);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, val);
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT1);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, val);
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT2);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, val);
+
+ /* Unmask interrupt */
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, 0x3ce3ee);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0x17fff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8000012a);
+
+ /* bypass chip bug mask abnormal intr */
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK,
+ 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+ }
+
+ return 0;
+}
+
+static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
+{
+ int rc;
+
+ rc = hw_init_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_init_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_openall_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ phys_init_v1_hw(hisi_hba);
+
+ return 0;
+}
+
+static const struct hisi_sas_hw hisi_sas_v1_hw = {
+ .hw_init = hisi_sas_v1_init,
+ .setup_itct = setup_itct_v1_hw,
+ .sl_notify = sl_notify_v1_hw,
+ .free_device = free_device_v1_hw,
+ .prep_smp = prep_smp_v1_hw,
+ .prep_ssp = prep_ssp_v1_hw,
+ .get_free_slot = get_free_slot_v1_hw,
+ .start_delivery = start_delivery_v1_hw,
+ .slot_complete = slot_complete_v1_hw,
+ .phy_enable = enable_phy_v1_hw,
+ .phy_disable = disable_phy_v1_hw,
+ .phy_hard_reset = phy_hard_reset_v1_hw,
+ .get_wideport_bitmap = get_wideport_bitmap_v1_hw,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V1_HW,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v1_hdr),
+};
+
+static int hisi_sas_v1_probe(struct platform_device *pdev)
+{
+ return hisi_sas_probe(pdev, &hisi_sas_v1_hw);
+}
+
+static int hisi_sas_v1_remove(struct platform_device *pdev)
+{
+ return hisi_sas_remove(pdev);
+}
+
+static const struct of_device_id sas_v1_of_match[] = {
+ { .compatible = "hisilicon,hip05-sas-v1",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sas_v1_of_match);
+
+static const struct acpi_device_id sas_v1_acpi_match[] = {
+ { "HISI0161", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(acpi, sas_v1_acpi_match);
+
+static struct platform_driver hisi_sas_v1_driver = {
+ .probe = hisi_sas_v1_probe,
+ .remove = hisi_sas_v1_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = sas_v1_of_match,
+ .acpi_match_table = ACPI_PTR(sas_v1_acpi_match),
+ },
+};
+
+module_platform_driver(hisi_sas_v1_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller v1 hw driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
new file mode 100644
index 0000000..b733747
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -0,0 +1,2214 @@
+/*
+ * Copyright (c) 2016 Linaro Ltd.
+ * Copyright (c) 2016 Hisilicon Limited.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas_v2_hw"
+
+/* global registers need init*/
+#define DLVRY_QUEUE_ENABLE 0x0
+#define IOST_BASE_ADDR_LO 0x8
+#define IOST_BASE_ADDR_HI 0xc
+#define ITCT_BASE_ADDR_LO 0x10
+#define ITCT_BASE_ADDR_HI 0x14
+#define IO_BROKEN_MSG_ADDR_LO 0x18
+#define IO_BROKEN_MSG_ADDR_HI 0x1c
+#define PHY_CONTEXT 0x20
+#define PHY_STATE 0x24
+#define PHY_PORT_NUM_MA 0x28
+#define PORT_STATE 0x2c
+#define PORT_STATE_PHY8_PORT_NUM_OFF 16
+#define PORT_STATE_PHY8_PORT_NUM_MSK (0xf << PORT_STATE_PHY8_PORT_NUM_OFF)
+#define PORT_STATE_PHY8_CONN_RATE_OFF 20
+#define PORT_STATE_PHY8_CONN_RATE_MSK (0xf << PORT_STATE_PHY8_CONN_RATE_OFF)
+#define PHY_CONN_RATE 0x30
+#define HGC_TRANS_TASK_CNT_LIMIT 0x38
+#define AXI_AHB_CLK_CFG 0x3c
+#define ITCT_CLR 0x44
+#define ITCT_CLR_EN_OFF 16
+#define ITCT_CLR_EN_MSK (0x1 << ITCT_CLR_EN_OFF)
+#define ITCT_DEV_OFF 0
+#define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF)
+#define AXI_USER1 0x48
+#define AXI_USER2 0x4c
+#define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
+#define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c
+#define SATA_INITI_D2H_STORE_ADDR_LO 0x60
+#define SATA_INITI_D2H_STORE_ADDR_HI 0x64
+#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL 0x84
+#define HGC_SAS_TXFAIL_RETRY_CTRL 0x88
+#define HGC_GET_ITV_TIME 0x90
+#define DEVICE_MSG_WORK_MODE 0x94
+#define OPENA_WT_CONTI_TIME 0x9c
+#define I_T_NEXUS_LOSS_TIME 0xa0
+#define MAX_CON_TIME_LIMIT_TIME 0xa4
+#define BUS_INACTIVE_LIMIT_TIME 0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME 0xac
+#define CFG_AGING_TIME 0xbc
+#define HGC_DFX_CFG2 0xc0
+#define HGC_IOMB_PROC1_STATUS 0x104
+#define CFG_1US_TIMER_TRSH 0xcc
+#define HGC_INVLD_DQE_INFO 0x148
+#define HGC_INVLD_DQE_INFO_FB_CH0_OFF 9
+#define HGC_INVLD_DQE_INFO_FB_CH0_MSK (0x1 << HGC_INVLD_DQE_INFO_FB_CH0_OFF)
+#define HGC_INVLD_DQE_INFO_FB_CH3_OFF 18
+#define INT_COAL_EN 0x19c
+#define OQ_INT_COAL_TIME 0x1a0
+#define OQ_INT_COAL_CNT 0x1a4
+#define ENT_INT_COAL_TIME 0x1a8
+#define ENT_INT_COAL_CNT 0x1ac
+#define OQ_INT_SRC 0x1b0
+#define OQ_INT_SRC_MSK 0x1b4
+#define ENT_INT_SRC1 0x1b8
+#define ENT_INT_SRC1_D2H_FIS_CH0_OFF 0
+#define ENT_INT_SRC1_D2H_FIS_CH0_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH0_OFF)
+#define ENT_INT_SRC1_D2H_FIS_CH1_OFF 8
+#define ENT_INT_SRC1_D2H_FIS_CH1_MSK (0x1 << ENT_INT_SRC1_D2H_FIS_CH1_OFF)
+#define ENT_INT_SRC2 0x1bc
+#define ENT_INT_SRC3 0x1c0
+#define ENT_INT_SRC3_ITC_INT_OFF 15
+#define ENT_INT_SRC3_ITC_INT_MSK (0x1 << ENT_INT_SRC3_ITC_INT_OFF)
+#define ENT_INT_SRC_MSK1 0x1c4
+#define ENT_INT_SRC_MSK2 0x1c8
+#define ENT_INT_SRC_MSK3 0x1cc
+#define ENT_INT_SRC_MSK3_ENT95_MSK_OFF 31
+#define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF)
+#define SAS_ECC_INTR_MSK 0x1ec
+#define HGC_ERR_STAT_EN 0x238
+#define DLVRY_Q_0_BASE_ADDR_LO 0x260
+#define DLVRY_Q_0_BASE_ADDR_HI 0x264
+#define DLVRY_Q_0_DEPTH 0x268
+#define DLVRY_Q_0_WR_PTR 0x26c
+#define DLVRY_Q_0_RD_PTR 0x270
+#define HYPER_STREAM_ID_EN_CFG 0xc80
+#define OQ0_INT_SRC_MSK 0xc90
+#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
+#define COMPL_Q_0_DEPTH 0x4e8
+#define COMPL_Q_0_WR_PTR 0x4ec
+#define COMPL_Q_0_RD_PTR 0x4f0
+
+/* phy registers need init */
+#define PORT_BASE (0x2000)
+
+#define PHY_CFG (PORT_BASE + 0x0)
+#define HARD_PHY_LINKRATE (PORT_BASE + 0x4)
+#define PHY_CFG_ENA_OFF 0
+#define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF 2
+#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
+#define PROG_PHY_LINK_RATE (PORT_BASE + 0x8)
+#define PROG_PHY_LINK_RATE_MAX_OFF 0
+#define PROG_PHY_LINK_RATE_MAX_MSK (0xff << PROG_PHY_LINK_RATE_MAX_OFF)
+#define PHY_CTRL (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET_OFF 0
+#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
+#define SAS_PHY_CTRL (PORT_BASE + 0x20)
+#define SL_CFG (PORT_BASE + 0x84)
+#define PHY_PCN (PORT_BASE + 0x44)
+#define SL_TOUT_CFG (PORT_BASE + 0x8c)
+#define SL_CONTROL (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF 0
+#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3 (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
+#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
+#define RX_IDAF_DWORD1 (PORT_BASE + 0xc8)
+#define RX_IDAF_DWORD2 (PORT_BASE + 0xcc)
+#define RX_IDAF_DWORD3 (PORT_BASE + 0xd0)
+#define RX_IDAF_DWORD4 (PORT_BASE + 0xd4)
+#define RX_IDAF_DWORD5 (PORT_BASE + 0xd8)
+#define RX_IDAF_DWORD6 (PORT_BASE + 0xdc)
+#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+#define DONE_RECEIVED_TIME (PORT_BASE + 0x11c)
+#define CHL_INT0 (PORT_BASE + 0x1b4)
+#define CHL_INT0_HOTPLUG_TOUT_OFF 0
+#define CHL_INT0_HOTPLUG_TOUT_MSK (0x1 << CHL_INT0_HOTPLUG_TOUT_OFF)
+#define CHL_INT0_SL_RX_BCST_ACK_OFF 1
+#define CHL_INT0_SL_RX_BCST_ACK_MSK (0x1 << CHL_INT0_SL_RX_BCST_ACK_OFF)
+#define CHL_INT0_SL_PHY_ENABLE_OFF 2
+#define CHL_INT0_SL_PHY_ENABLE_MSK (0x1 << CHL_INT0_SL_PHY_ENABLE_OFF)
+#define CHL_INT0_NOT_RDY_OFF 4
+#define CHL_INT0_NOT_RDY_MSK (0x1 << CHL_INT0_NOT_RDY_OFF)
+#define CHL_INT0_PHY_RDY_OFF 5
+#define CHL_INT0_PHY_RDY_MSK (0x1 << CHL_INT0_PHY_RDY_OFF)
+#define CHL_INT1 (PORT_BASE + 0x1b8)
+#define CHL_INT1_DMAC_TX_ECC_ERR_OFF 15
+#define CHL_INT1_DMAC_TX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
+#define CHL_INT1_DMAC_RX_ECC_ERR_OFF 17
+#define CHL_INT1_DMAC_RX_ECC_ERR_MSK (0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
+#define CHL_INT2 (PORT_BASE + 0x1bc)
+#define CHL_INT0_MSK (PORT_BASE + 0x1c0)
+#define CHL_INT1_MSK (PORT_BASE + 0x1c4)
+#define CHL_INT2_MSK (PORT_BASE + 0x1c8)
+#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
+#define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0)
+#define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4)
+#define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8)
+#define PHYCTRL_PHY_ENA_MSK (PORT_BASE + 0x2bc)
+#define SL_RX_BCAST_CHK_MSK (PORT_BASE + 0x2c0)
+#define PHYCTRL_OOB_RESTART_MSK (PORT_BASE + 0x2c4)
+#define DMA_TX_STATUS (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY_OFF 0
+#define DMA_TX_STATUS_BUSY_MSK (0x1 << DMA_TX_STATUS_BUSY_OFF)
+#define DMA_RX_STATUS (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY_OFF 0
+#define DMA_RX_STATUS_BUSY_MSK (0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define AXI_CFG (0x5100)
+#define AM_CFG_MAX_TRANS (0x5010)
+#define AM_CFG_SINGLE_PORT_MAX_TRANS (0x5014)
+
+/* HW dma structures */
+/* Delivery queue header */
+/* dw0 */
+#define CMD_HDR_RESP_REPORT_OFF 5
+#define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
+#define CMD_HDR_TLR_CTRL_OFF 6
+#define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF)
+#define CMD_HDR_PORT_OFF 18
+#define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF)
+#define CMD_HDR_PRIORITY_OFF 27
+#define CMD_HDR_PRIORITY_MSK (0x1 << CMD_HDR_PRIORITY_OFF)
+#define CMD_HDR_CMD_OFF 29
+#define CMD_HDR_CMD_MSK (0x7 << CMD_HDR_CMD_OFF)
+/* dw1 */
+#define CMD_HDR_DIR_OFF 5
+#define CMD_HDR_DIR_MSK (0x3 << CMD_HDR_DIR_OFF)
+#define CMD_HDR_RESET_OFF 7
+#define CMD_HDR_RESET_MSK (0x1 << CMD_HDR_RESET_OFF)
+#define CMD_HDR_VDTL_OFF 10
+#define CMD_HDR_VDTL_MSK (0x1 << CMD_HDR_VDTL_OFF)
+#define CMD_HDR_FRAME_TYPE_OFF 11
+#define CMD_HDR_FRAME_TYPE_MSK (0x1f << CMD_HDR_FRAME_TYPE_OFF)
+#define CMD_HDR_DEV_ID_OFF 16
+#define CMD_HDR_DEV_ID_MSK (0xffff << CMD_HDR_DEV_ID_OFF)
+/* dw2 */
+#define CMD_HDR_CFL_OFF 0
+#define CMD_HDR_CFL_MSK (0x1ff << CMD_HDR_CFL_OFF)
+#define CMD_HDR_NCQ_TAG_OFF 10
+#define CMD_HDR_NCQ_TAG_MSK (0x1f << CMD_HDR_NCQ_TAG_OFF)
+#define CMD_HDR_MRFL_OFF 15
+#define CMD_HDR_MRFL_MSK (0x1ff << CMD_HDR_MRFL_OFF)
+#define CMD_HDR_SG_MOD_OFF 24
+#define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF)
+#define CMD_HDR_FIRST_BURST_OFF 26
+#define CMD_HDR_FIRST_BURST_MSK (0x1 << CMD_HDR_SG_MOD_OFF)
+/* dw3 */
+#define CMD_HDR_IPTT_OFF 0
+#define CMD_HDR_IPTT_MSK (0xffff << CMD_HDR_IPTT_OFF)
+/* dw6 */
+#define CMD_HDR_DIF_SGL_LEN_OFF 0
+#define CMD_HDR_DIF_SGL_LEN_MSK (0xffff << CMD_HDR_DIF_SGL_LEN_OFF)
+#define CMD_HDR_DATA_SGL_LEN_OFF 16
+#define CMD_HDR_DATA_SGL_LEN_MSK (0xffff << CMD_HDR_DATA_SGL_LEN_OFF)
+
+/* Completion header */
+/* dw0 */
+#define CMPLT_HDR_RSPNS_XFRD_OFF 10
+#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_ERX_OFF 12
+#define CMPLT_HDR_ERX_MSK (0x1 << CMPLT_HDR_ERX_OFF)
+/* dw1 */
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_DEV_ID_OFF 16
+#define CMPLT_HDR_DEV_ID_MSK (0xffff << CMPLT_HDR_DEV_ID_OFF)
+
+/* ITCT header */
+/* qw0 */
+#define ITCT_HDR_DEV_TYPE_OFF 0
+#define ITCT_HDR_DEV_TYPE_MSK (0x3 << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_VALID_OFF 2
+#define ITCT_HDR_VALID_MSK (0x1 << ITCT_HDR_VALID_OFF)
+#define ITCT_HDR_MCR_OFF 5
+#define ITCT_HDR_MCR_MSK (0xf << ITCT_HDR_MCR_OFF)
+#define ITCT_HDR_VLN_OFF 9
+#define ITCT_HDR_VLN_MSK (0xf << ITCT_HDR_VLN_OFF)
+#define ITCT_HDR_PORT_ID_OFF 28
+#define ITCT_HDR_PORT_ID_MSK (0xf << ITCT_HDR_PORT_ID_OFF)
+/* qw2 */
+#define ITCT_HDR_INLT_OFF 0
+#define ITCT_HDR_INLT_MSK (0xffffULL << ITCT_HDR_INLT_OFF)
+#define ITCT_HDR_BITLT_OFF 16
+#define ITCT_HDR_BITLT_MSK (0xffffULL << ITCT_HDR_BITLT_OFF)
+#define ITCT_HDR_MCTLT_OFF 32
+#define ITCT_HDR_MCTLT_MSK (0xffffULL << ITCT_HDR_MCTLT_OFF)
+#define ITCT_HDR_RTOLT_OFF 48
+#define ITCT_HDR_RTOLT_MSK (0xffffULL << ITCT_HDR_RTOLT_OFF)
+
+struct hisi_sas_complete_v2_hdr {
+ __le32 dw0;
+ __le32 dw1;
+ __le32 act;
+ __le32 dw3;
+};
+
+struct hisi_sas_err_record_v2 {
+ /* dw0 */
+ __le32 trans_tx_fail_type;
+
+ /* dw1 */
+ __le32 trans_rx_fail_type;
+
+ /* dw2 */
+ __le16 dma_tx_err_type;
+ __le16 sipc_rx_err_type;
+
+ /* dw3 */
+ __le32 dma_rx_err_type;
+};
+
+enum {
+ HISI_SAS_PHY_PHY_UPDOWN,
+ HISI_SAS_PHY_CHNL_INT,
+ HISI_SAS_PHY_INT_NR
+};
+
+enum {
+ TRANS_TX_FAIL_BASE = 0x0, /* dw0 */
+ TRANS_RX_FAIL_BASE = 0x100, /* dw1 */
+ DMA_TX_ERR_BASE = 0x200, /* dw2 bit 15-0 */
+ SIPC_RX_ERR_BASE = 0x300, /* dw2 bit 31-16*/
+ DMA_RX_ERR_BASE = 0x400, /* dw3 */
+
+ /* trans tx*/
+ TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */
+ TRANS_TX_ERR_PHY_NOT_ENABLE, /* 0x1 */
+ TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION, /* 0x2 */
+ TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION, /* 0x3 */
+ TRANS_TX_OPEN_CNX_ERR_BY_OTHER, /* 0x4 */
+ RESERVED0, /* 0x5 */
+ TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT, /* 0x6 */
+ TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY, /* 0x7 */
+ TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED, /* 0x8 */
+ TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED, /* 0x9 */
+ TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION, /* 0xa */
+ TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD, /* 0xb */
+ TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER, /* 0xc */
+ TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED, /* 0xd */
+ TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT, /* 0xe */
+ TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION, /* 0xf */
+ TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED, /* 0x10 */
+ TRANS_TX_ERR_FRAME_TXED, /* 0x11 */
+ TRANS_TX_ERR_WITH_BREAK_TIMEOUT, /* 0x12 */
+ TRANS_TX_ERR_WITH_BREAK_REQUEST, /* 0x13 */
+ TRANS_TX_ERR_WITH_BREAK_RECEVIED, /* 0x14 */
+ TRANS_TX_ERR_WITH_CLOSE_TIMEOUT, /* 0x15 */
+ TRANS_TX_ERR_WITH_CLOSE_NORMAL, /* 0x16 for ssp*/
+ TRANS_TX_ERR_WITH_CLOSE_PHYDISALE, /* 0x17 */
+ TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x18 */
+ TRANS_TX_ERR_WITH_CLOSE_COMINIT, /* 0x19 */
+ TRANS_TX_ERR_WITH_NAK_RECEVIED, /* 0x1a for ssp*/
+ TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT, /* 0x1b for ssp*/
+ /*IO_TX_ERR_WITH_R_ERR_RECEVIED, [> 0x1b for sata/stp<] */
+ TRANS_TX_ERR_WITH_CREDIT_TIMEOUT, /* 0x1c for ssp */
+ /*IO_RX_ERR_WITH_SATA_DEVICE_LOST 0x1c for sata/stp */
+ TRANS_TX_ERR_WITH_IPTT_CONFLICT, /* 0x1d for ssp/smp */
+ TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS, /* 0x1e */
+ /*IO_TX_ERR_WITH_SYNC_RXD, [> 0x1e <] for sata/stp */
+ TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */
+
+ /* trans rx */
+ TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */
+ TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 for ssp/smp */
+ /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <] for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 for smp */
+ /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <] for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 for sata/stp*/
+ TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */
+ TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */
+ TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */
+ TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */
+ RESERVED1, /* 0x10b */
+ TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */
+ TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */
+ TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */
+ TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */
+ TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 for ssp/smp */
+ TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 for ssp */
+ /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <] for sata/stp */
+ TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 for ssp*/
+ /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <] for sata/stp */
+ TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 for ssp */
+ /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <] for sata */
+ RESERVED2, /* 0x114 */
+ RESERVED3, /* 0x115 */
+ RESERVED4, /* 0x116 */
+ RESERVED5, /* 0x117 */
+ TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */
+ TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */
+ TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */
+ RESERVED6, /* 0x11b */
+ RESERVED7, /* 0x11c */
+ RESERVED8, /* 0x11d */
+ RESERVED9, /* 0x11e */
+ TRANS_RX_R_ERR, /* 0x11f */
+
+ /* dma tx */
+ DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x200 */
+ DMA_TX_DIF_APP_ERR, /* 0x201 */
+ DMA_TX_DIF_RPP_ERR, /* 0x202 */
+ DMA_TX_DATA_SGL_OVERFLOW, /* 0x203 */
+ DMA_TX_DIF_SGL_OVERFLOW, /* 0x204 */
+ DMA_TX_UNEXP_XFER_ERR, /* 0x205 */
+ DMA_TX_UNEXP_RETRANS_ERR, /* 0x206 */
+ DMA_TX_XFER_LEN_OVERFLOW, /* 0x207 */
+ DMA_TX_XFER_OFFSET_ERR, /* 0x208 */
+ DMA_TX_RAM_ECC_ERR, /* 0x209 */
+ DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x20a */
+
+ /* sipc rx */
+ SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x300 */
+ SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x301 */
+ SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x302 */
+ SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x303 */
+ SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x304 */
+ SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x305 */
+ SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x306 */
+ SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x307 */
+ SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x308 */
+ SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x309 */
+ SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x30a */
+
+ /* dma rx */
+ DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x400 */
+ DMA_RX_DIF_APP_ERR, /* 0x401 */
+ DMA_RX_DIF_RPP_ERR, /* 0x402 */
+ DMA_RX_DATA_SGL_OVERFLOW, /* 0x403 */
+ DMA_RX_DIF_SGL_OVERFLOW, /* 0x404 */
+ DMA_RX_DATA_LEN_OVERFLOW, /* 0x405 */
+ DMA_RX_DATA_LEN_UNDERFLOW, /* 0x406 */
+ DMA_RX_DATA_OFFSET_ERR, /* 0x407 */
+ RESERVED10, /* 0x408 */
+ DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x409 */
+ DMA_RX_RESP_BUF_OVERFLOW, /* 0x40a */
+ DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x40b */
+ DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x40c */
+ DMA_RX_UNEXP_RDFRAME_ERR, /* 0x40d */
+ DMA_RX_PIO_DATA_LEN_ERR, /* 0x40e */
+ DMA_RX_RDSETUP_STATUS_ERR, /* 0x40f */
+ DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x410 */
+ DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x411 */
+ DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x412 */
+ DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x413 */
+ DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x414 */
+ DMA_RX_RDSETUP_OFFSET_ERR, /* 0x415 */
+ DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x416 */
+ DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x417 */
+ DMA_RX_RAM_ECC_ERR, /* 0x418 */
+ DMA_RX_UNKNOWN_FRM_ERR, /* 0x419 */
+};
+
+#define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
+
+#define DIR_NO_DATA 0
+#define DIR_TO_INI 1
+#define DIR_TO_DEVICE 2
+#define DIR_RESERVED 3
+
+#define SATA_PROTOCOL_NONDATA 0x1
+#define SATA_PROTOCOL_PIO 0x2
+#define SATA_PROTOCOL_DMA 0x4
+#define SATA_PROTOCOL_FPDMA 0x8
+#define SATA_PROTOCOL_ATAPI 0x10
+
+static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl(regs);
+}
+
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl_relaxed(regs);
+}
+
+static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ writel(val, regs);
+}
+
+static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba, int phy_no,
+ u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ writel(val, regs);
+}
+
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ return readl(regs);
+}
+
+static void config_phy_opt_mode_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_DC_OPT_MSK;
+ cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void config_id_frame_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct sas_identify_frame identify_frame;
+ u32 *identify_buffer;
+
+ memset(&identify_frame, 0, sizeof(identify_frame));
+ identify_frame.dev_type = SAS_END_DEVICE;
+ identify_frame.frame_type = 0;
+ identify_frame._un1 = 1;
+ identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
+ identify_frame.target_bits = SAS_PROTOCOL_NONE;
+ memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ identify_frame.phy_id = phy_no;
+ identify_buffer = (u32 *)(&identify_frame);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
+ __swab32(identify_buffer[0]));
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
+ identify_buffer[2]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
+ identify_buffer[1]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
+ identify_buffer[4]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
+ identify_buffer[3]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
+ __swab32(identify_buffer[5]));
+}
+
+static void init_id_frame_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ config_id_frame_v2_hw(hisi_hba, i);
+}
+
+static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ struct domain_device *device = sas_dev->sas_device;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 qw0, device_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_port *port = device->port->lldd_port;
+
+ memset(itct, 0, sizeof(*itct));
+
+ /* qw0 */
+ qw0 = 0;
+ switch (sas_dev->dev_type) {
+ case SAS_END_DEVICE:
+ case SAS_EDGE_EXPANDER_DEVICE:
+ case SAS_FANOUT_EXPANDER_DEVICE:
+ qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
+ break;
+ case SAS_SATA_DEV:
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
+ else
+ qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
+ break;
+ default:
+ dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
+ sas_dev->dev_type);
+ }
+
+ qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
+ (device->max_linkrate << ITCT_HDR_MCR_OFF) |
+ (1 << ITCT_HDR_VLN_OFF) |
+ (port->id << ITCT_HDR_PORT_ID_OFF));
+ itct->qw0 = cpu_to_le64(qw0);
+
+ /* qw1 */
+ memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+ itct->sas_addr = __swab64(itct->sas_addr);
+
+ /* qw2 */
+ itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_INLT_OFF) |
+ (0xff00ULL << ITCT_HDR_BITLT_OFF) |
+ (0xff00ULL << ITCT_HDR_MCTLT_OFF) |
+ (0xff00ULL << ITCT_HDR_RTOLT_OFF));
+}
+
+static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ u64 qw0, dev_id = sas_dev->device_id;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+ u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ int i;
+
+ /* clear the itct interrupt state */
+ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ ENT_INT_SRC3_ITC_INT_MSK);
+
+ /* clear the itct int*/
+ for (i = 0; i < 2; i++) {
+ /* clear the itct table*/
+ reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
+ reg_val |= ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
+ hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
+
+ udelay(10);
+ reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) {
+ dev_dbg(dev, "got clear ITCT done interrupt\n");
+
+ /* invalid the itct state*/
+ qw0 = cpu_to_le64(itct->qw0);
+ qw0 &= ~(1 << ITCT_HDR_VALID_OFF);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ ENT_INT_SRC3_ITC_INT_MSK);
+ hisi_hba->devices[dev_id].dev_type = SAS_PHY_UNUSED;
+ hisi_hba->devices[dev_id].dev_status = HISI_SAS_DEV_NORMAL;
+
+ /* clear the itct */
+ hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
+ dev_dbg(dev, "clear ITCT ok\n");
+ break;
+ }
+ }
+}
+
+static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int i, reset_val;
+ u32 val;
+ unsigned long end_time;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ /* The mask needs to be set depending on the number of phys */
+ if (hisi_hba->n_phy == 9)
+ reset_val = 0x1fffff;
+ else
+ reset_val = 0x7ffff;
+
+ /* Disable all of the DQ */
+ for (i = 0; i < HISI_SAS_MAX_QUEUES; i++)
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
+
+ /* Disable all of the PHYs */
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 phy_cfg = hisi_sas_phy_read32(hisi_hba, i, PHY_CFG);
+
+ phy_cfg &= ~PHY_CTRL_RESET_MSK;
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CFG, phy_cfg);
+ }
+ udelay(50);
+
+ /* Ensure DMA tx & rx idle */
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 dma_tx_status, dma_rx_status;
+
+ end_time = jiffies + msecs_to_jiffies(1000);
+
+ while (1) {
+ dma_tx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_TX_STATUS);
+ dma_rx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_RX_STATUS);
+
+ if (!(dma_tx_status & DMA_TX_STATUS_BUSY_MSK) &&
+ !(dma_rx_status & DMA_RX_STATUS_BUSY_MSK))
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+ }
+
+ /* Ensure axi bus idle */
+ end_time = jiffies + msecs_to_jiffies(1000);
+ while (1) {
+ u32 axi_status =
+ hisi_sas_read32(hisi_hba, AXI_CFG);
+
+ if (axi_status == 0)
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+
+ /* reset and disable clock*/
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+ reset_val);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+ reset_val);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (reset_val != (val & reset_val)) {
+ dev_err(dev, "SAS reset fail.\n");
+ return -EIO;
+ }
+
+ /* De-reset and enable clock*/
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+ reset_val);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+ reset_val);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg,
+ &val);
+ if (val & reset_val) {
+ dev_err(dev, "SAS de-reset fail.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct device_node *np = dev->of_node;
+ int i;
+
+ /* Global registers init */
+
+ /* Deal with am-max-transmissions quirk */
+ if (of_get_property(np, "hip06-sas-v2-quirk-amt", NULL)) {
+ hisi_sas_write32(hisi_hba, AM_CFG_MAX_TRANS, 0x2020);
+ hisi_sas_write32(hisi_hba, AM_CFG_SINGLE_PORT_MAX_TRANS,
+ 0x2020);
+ } /* Else, use defaults -> do nothing */
+
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
+ (u32)((1ULL << hisi_hba->queue_count) - 1));
+ hisi_sas_write32(hisi_hba, AXI_USER1, 0xc0000000);
+ hisi_sas_write32(hisi_hba, AXI_USER2, 0x10000);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL, 0x7FF);
+ hisi_sas_write32(hisi_hba, OPENA_WT_CONTI_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x1F4);
+ hisi_sas_write32(hisi_hba, MAX_CON_TIME_LIMIT_TIME, 0x4E20);
+ hisi_sas_write32(hisi_hba, BUS_INACTIVE_LIMIT_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x1);
+ hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0x0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0x7efefefe);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0x7efefefe);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffffffe);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfffff3c0);
+ for (i = 0; i < hisi_hba->queue_count; i++)
+ hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
+
+ hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
+ hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
+ hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908);
+ hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x10);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+ hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x23f801fc);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199B694);
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ /* Delivery queue */
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+
+ /* Completion queue */
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+ }
+
+ /* itct */
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->itct_dma));
+
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->itct_dma));
+
+ /* iost */
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->iost_dma));
+
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->iost_dma));
+
+ /* breakpoint */
+ hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_LO,
+ lower_32_bits(hisi_hba->breakpoint_dma));
+
+ hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_HI,
+ upper_32_bits(hisi_hba->breakpoint_dma));
+
+ /* SATA broken msg */
+ hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_LO,
+ lower_32_bits(hisi_hba->sata_breakpoint_dma));
+
+ hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_HI,
+ upper_32_bits(hisi_hba->sata_breakpoint_dma));
+
+ /* SATA initial fis */
+ hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_LO,
+ lower_32_bits(hisi_hba->initial_fis_dma));
+
+ hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_HI,
+ upper_32_bits(hisi_hba->initial_fis_dma));
+}
+
+static int hw_init_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc;
+
+ rc = reset_hw_v2_hw(hisi_hba);
+ if (rc) {
+ dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+ return rc;
+ }
+
+ msleep(100);
+ init_reg_v2_hw(hisi_hba);
+
+ init_id_frame_v2_hw(hisi_hba);
+
+ return 0;
+}
+
+static void enable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg |= PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void start_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ config_id_frame_v2_hw(hisi_hba, phy_no);
+ config_phy_opt_mode_v2_hw(hisi_hba, phy_no);
+ enable_phy_v2_hw(hisi_hba, phy_no);
+}
+
+static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ disable_phy_v2_hw(hisi_hba, phy_no);
+}
+
+static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ stop_phy_v2_hw(hisi_hba, phy_no);
+ msleep(100);
+ start_phy_v2_hw(hisi_hba, phy_no);
+}
+
+static void start_phys_v2_hw(unsigned long data)
+{
+ struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ start_phy_v2_hw(hisi_hba, i);
+}
+
+static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ struct timer_list *timer = &hisi_hba->timer;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a);
+ hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
+ }
+
+ setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba);
+ mod_timer(timer, jiffies + HZ);
+}
+
+static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 sl_control;
+
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ msleep(1);
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+}
+
+static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+ int i, bitmap = 0;
+ u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+ u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ for (i = 0; i < (hisi_hba->n_phy < 9 ? hisi_hba->n_phy : 8); i++)
+ if (phy_state & 1 << i)
+ if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+ bitmap |= 1 << i;
+
+ if (hisi_hba->n_phy == 9) {
+ u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+ if (phy_state & 1 << 8)
+ if (((port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+ PORT_STATE_PHY8_PORT_NUM_OFF) == port_id)
+ bitmap |= 1 << 9;
+ }
+
+ return bitmap;
+}
+
+/**
+ * This function allocates across all queues to load balance.
+ * Slots are allocated from queues in a round-robin fashion.
+ *
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 r, w;
+ int queue = hisi_hba->queue;
+
+ while (1) {
+ w = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ r = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_RD_PTR + (queue * 0x14));
+ if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+ queue = (queue + 1) % hisi_hba->queue_count;
+ if (queue == hisi_hba->queue) {
+ dev_warn(dev, "could not find free slot\n");
+ return -EAGAIN;
+ }
+ continue;
+ }
+ break;
+ }
+ hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+ *q = queue;
+ *s = w;
+ return 0;
+}
+
+static void start_delivery_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+ int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+
+ hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+ ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+}
+
+static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ struct hisi_sas_cmd_hdr *hdr,
+ struct scatterlist *scatter,
+ int n_elem)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct scatterlist *sg;
+ int i;
+
+ if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+ dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+ n_elem);
+ return -EINVAL;
+ }
+
+ slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+ &slot->sge_page_dma);
+ if (!slot->sge_page)
+ return -ENOMEM;
+
+ for_each_sg(scatter, sg, n_elem, i) {
+ struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+ entry->data_len = cpu_to_le32(sg_dma_len(sg));
+ entry->data_off = 0;
+ }
+
+ hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
+
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+ return 0;
+}
+
+static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_port *port = slot->port;
+ struct scatterlist *sg_req, *sg_resp;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ dma_addr_t req_dma_addr;
+ unsigned int req_len, resp_len;
+ int elem, rc;
+
+ /*
+ * DMA-map SMP request, response buffers
+ */
+ /* req */
+ sg_req = &task->smp_task.smp_req;
+ elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
+ if (!elem)
+ return -ENOMEM;
+ req_len = sg_dma_len(sg_req);
+ req_dma_addr = sg_dma_address(sg_req);
+
+ /* resp */
+ sg_resp = &task->smp_task.smp_resp;
+ elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
+ if (!elem) {
+ rc = -ENOMEM;
+ goto err_out_req;
+ }
+ resp_len = sg_dma_len(sg_resp);
+ if ((req_len & 0x3) || (resp_len & 0x3)) {
+ rc = -EINVAL;
+ goto err_out_resp;
+ }
+
+ /* create header */
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
+ (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
+ (2 << CMD_HDR_CMD_OFF)); /* smp */
+
+ /* map itct entry */
+ hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) |
+ (1 << CMD_HDR_FRAME_TYPE_OFF) |
+ (DIR_NO_DATA << CMD_HDR_DIR_OFF));
+
+ /* dw2 */
+ hdr->dw2 = cpu_to_le32((((req_len - 4) / 4) << CMD_HDR_CFL_OFF) |
+ (HISI_SAS_MAX_SMP_RESP_SZ / 4 <<
+ CMD_HDR_MRFL_OFF));
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ return 0;
+
+err_out_resp:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+err_out_req:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ return rc;
+}
+
+static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port = slot->port;
+ struct sas_ssp_task *ssp_task = &task->ssp_task;
+ struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+ int has_data = 0, rc, priority = is_tmf;
+ u8 *buf_cmd;
+ u32 dw1 = 0, dw2 = 0;
+
+ hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
+ (2 << CMD_HDR_TLR_CTRL_OFF) |
+ (port->id << CMD_HDR_PORT_OFF) |
+ (priority << CMD_HDR_PRIORITY_OFF) |
+ (1 << CMD_HDR_CMD_OFF)); /* ssp */
+
+ dw1 = 1 << CMD_HDR_VDTL_OFF;
+ if (is_tmf) {
+ dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF;
+ dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF;
+ } else {
+ dw1 |= 1 << CMD_HDR_FRAME_TYPE_OFF;
+ switch (scsi_cmnd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
+ break;
+ case DMA_FROM_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
+ break;
+ default:
+ dw1 &= ~CMD_HDR_DIR_MSK;
+ }
+ }
+
+ /* map itct entry */
+ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr)
+ + 3) / 4) << CMD_HDR_CFL_OFF) |
+ ((HISI_SAS_MAX_SSP_RESP_SZ / 4) << CMD_HDR_MRFL_OFF) |
+ (2 << CMD_HDR_SG_MOD_OFF);
+ hdr->dw2 = cpu_to_le32(dw2);
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+ if (has_data) {
+ rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+ slot->n_elem);
+ if (rc)
+ return rc;
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+
+ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ if (!is_tmf) {
+ buf_cmd[9] = task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
+ memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
+ task->ssp_task.cmd->cmd_len);
+ } else {
+ buf_cmd[10] = tmf->tmf;
+ switch (tmf->tmf) {
+ case TMF_ABORT_TASK:
+ case TMF_QUERY_TASK:
+ buf_cmd[12] =
+ (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+ buf_cmd[13] =
+ tmf->tag_of_task_to_be_managed & 0xff;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
+ struct dev_to_host_fis *d2h = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+
+ resp->frame_len = sizeof(struct dev_to_host_fis);
+ memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
+
+ ts->buf_valid_size = sizeof(*resp);
+}
+
+/* by default, task resp is complete */
+static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct hisi_sas_err_record_v2 *err_record = slot->status_buffer;
+ u32 trans_tx_fail_type = cpu_to_le32(err_record->trans_tx_fail_type);
+ u32 trans_rx_fail_type = cpu_to_le32(err_record->trans_rx_fail_type);
+ u16 dma_tx_err_type = cpu_to_le16(err_record->dma_tx_err_type);
+ u16 sipc_rx_err_type = cpu_to_le16(err_record->sipc_rx_err_type);
+ u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type);
+ int error = -1;
+
+ if (dma_rx_err_type) {
+ error = ffs(dma_rx_err_type)
+ - 1 + DMA_RX_ERR_BASE;
+ } else if (sipc_rx_err_type) {
+ error = ffs(sipc_rx_err_type)
+ - 1 + SIPC_RX_ERR_BASE;
+ } else if (dma_tx_err_type) {
+ error = ffs(dma_tx_err_type)
+ - 1 + DMA_TX_ERR_BASE;
+ } else if (trans_rx_fail_type) {
+ error = ffs(trans_rx_fail_type)
+ - 1 + TRANS_RX_FAIL_BASE;
+ } else if (trans_tx_fail_type) {
+ error = ffs(trans_tx_fail_type)
+ - 1 + TRANS_TX_FAIL_BASE;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ switch (error) {
+ case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_NO_DEST;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_PATH_BLOCKED;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_EPROTO;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+ {
+ /* not sure */
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ }
+ case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
+ {
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+ {
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ case DMA_RX_DATA_LEN_OVERFLOW:
+ {
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ }
+ case DMA_RX_DATA_LEN_UNDERFLOW:
+ case SIPC_RX_DATA_UNDERFLOW_ERR:
+ {
+ ts->residual = trans_tx_fail_type;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ }
+ case TRANS_TX_ERR_FRAME_TXED:
+ {
+ /* This will request a retry */
+ ts->stat = SAS_QUEUE_FULL;
+ slot->abort = 1;
+ break;
+ }
+ case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
+ case TRANS_TX_ERR_PHY_NOT_ENABLE:
+ case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
+ case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+ case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
+ case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_BREAK_REQUEST:
+ case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_TX_ERR_WITH_NAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
+ case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+ case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR:
+ case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
+ case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+ case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
+ case TRANS_RX_ERR_WITH_BREAK_REQUEST:
+ case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
+ case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_RX_ERR_WITH_DATA_LEN0:
+ case TRANS_RX_ERR_WITH_BAD_HASH:
+ case TRANS_RX_XRDY_WLEN_ZERO_ERR:
+ case TRANS_RX_SSP_FRM_LEN_ERR:
+ case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
+ case DMA_TX_UNEXP_XFER_ERR:
+ case DMA_TX_UNEXP_RETRANS_ERR:
+ case DMA_TX_XFER_LEN_OVERFLOW:
+ case DMA_TX_XFER_OFFSET_ERR:
+ case DMA_RX_DATA_OFFSET_ERR:
+ case DMA_RX_UNEXP_NORM_RESP_ERR:
+ case DMA_RX_UNEXP_RDFRAME_ERR:
+ case DMA_RX_UNKNOWN_FRM_ERR:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ break;
+ case SAS_PROTOCOL_SMP:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ switch (error) {
+ case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+ case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+ case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
+ {
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+ case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+ case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
+ case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+ case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
+ case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+ case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+ {
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ case DMA_RX_DATA_LEN_OVERFLOW:
+ {
+ ts->stat = SAS_DATA_OVERRUN;
+ break;
+ }
+ case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
+ case TRANS_TX_ERR_PHY_NOT_ENABLE:
+ case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
+ case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+ case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
+ case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_BREAK_REQUEST:
+ case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_TX_ERR_WITH_NAK_RECEVIED:
+ case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
+ case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+ case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT:
+ case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
+ case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+ case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR:
+ case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR:
+ case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN:
+ case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP:
+ case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
+ case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+ case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_RX_ERR_WITH_DATA_LEN0:
+ case TRANS_RX_ERR_WITH_BAD_HASH:
+ case TRANS_RX_XRDY_WLEN_ZERO_ERR:
+ case TRANS_RX_SSP_FRM_LEN_ERR:
+ case SIPC_RX_FIS_STATUS_ERR_BIT_VLD:
+ case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR:
+ case SIPC_RX_FIS_STATUS_BSY_BIT_ERR:
+ case SIPC_RX_WRSETUP_LEN_ODD_ERR:
+ case SIPC_RX_WRSETUP_LEN_ZERO_ERR:
+ case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR:
+ case SIPC_RX_SATA_UNEXP_FIS_ERR:
+ case DMA_RX_SATA_FRAME_TYPE_ERR:
+ case DMA_RX_UNEXP_RDFRAME_ERR:
+ case DMA_RX_PIO_DATA_LEN_ERR:
+ case DMA_RX_RDSETUP_STATUS_ERR:
+ case DMA_RX_RDSETUP_STATUS_DRQ_ERR:
+ case DMA_RX_RDSETUP_STATUS_BSY_ERR:
+ case DMA_RX_RDSETUP_LEN_ODD_ERR:
+ case DMA_RX_RDSETUP_LEN_ZERO_ERR:
+ case DMA_RX_RDSETUP_LEN_OVER_ERR:
+ case DMA_RX_RDSETUP_OFFSET_ERR:
+ case DMA_RX_RDSETUP_ACTIVE_ERR:
+ case DMA_RX_RDSETUP_ESTATUS_ERR:
+ case DMA_RX_UNKNOWN_FRM_ERR:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ break;
+ }
+ default:
+ {
+ ts->stat = SAS_PROTO_RESPONSE;
+ break;
+ }
+ }
+ sata_done_v2_hw(hisi_hba, task, slot);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
+ int abort)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct task_status_struct *ts;
+ struct domain_device *device;
+ enum exec_status sts;
+ struct hisi_sas_complete_v2_hdr *complete_queue =
+ hisi_hba->complete_hdr[slot->cmplt_queue];
+ struct hisi_sas_complete_v2_hdr *complete_hdr =
+ &complete_queue[slot->cmplt_queue_slot];
+
+ if (unlikely(!task || !task->lldd_task || !task->dev))
+ return -EINVAL;
+
+ ts = &task->task_status;
+ device = task->dev;
+ sas_dev = device->lldd_dev;
+
+ task->task_state_flags &=
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+
+ memset(ts, 0, sizeof(*ts));
+ ts->resp = SAS_TASK_COMPLETE;
+
+ if (unlikely(!sas_dev || abort)) {
+ if (!sas_dev)
+ dev_dbg(dev, "slot complete: port has not device\n");
+ ts->stat = SAS_PHY_DOWN;
+ goto out;
+ }
+
+ if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) &&
+ (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
+
+ slot_err_v2_hw(hisi_hba, task, slot);
+ if (unlikely(slot->abort)) {
+ queue_work(hisi_hba->wq, &slot->abort_slot);
+ /* immediately return and do not complete */
+ return ts->stat;
+ }
+ goto out;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ struct ssp_response_iu *iu = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+
+ sas_ssp_task_response(dev, task, iu);
+ break;
+ }
+ case SAS_PROTOCOL_SMP:
+ {
+ struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+ void *to;
+
+ ts->stat = SAM_STAT_GOOD;
+ to = kmap_atomic(sg_page(sg_resp));
+
+ dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+ slot->status_buffer +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+ break;
+ }
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ ts->stat = SAM_STAT_GOOD;
+ sata_done_v2_hw(hisi_hba, task, slot);
+ break;
+ }
+ default:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+
+ if (!slot->port->port_attached) {
+ dev_err(dev, "slot complete: port %d has removed\n",
+ slot->port->sas_port.id);
+ ts->stat = SAS_PHY_DOWN;
+ }
+
+out:
+ if (sas_dev && sas_dev->running_req)
+ sas_dev->running_req--;
+
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
+ sts = ts->stat;
+
+ if (task->task_done)
+ task->task_done(task);
+
+ return sts;
+}
+
+static u8 get_ata_protocol(u8 cmd, int direction)
+{
+ switch (cmd) {
+ case ATA_CMD_FPDMA_WRITE:
+ case ATA_CMD_FPDMA_READ:
+ return SATA_PROTOCOL_FPDMA;
+
+ case ATA_CMD_ID_ATA:
+ case ATA_CMD_PMP_READ:
+ case ATA_CMD_READ_LOG_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_PMP_WRITE:
+ case ATA_CMD_WRITE_LOG_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ return SATA_PROTOCOL_PIO;
+
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_READ_LOG_DMA_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_WRITE_QUEUED:
+ case ATA_CMD_WRITE_LOG_DMA_EXT:
+ return SATA_PROTOCOL_DMA;
+
+ case ATA_CMD_DOWNLOAD_MICRO:
+ case ATA_CMD_DEV_RESET:
+ case ATA_CMD_CHK_POWER:
+ case ATA_CMD_FLUSH:
+ case ATA_CMD_FLUSH_EXT:
+ case ATA_CMD_VERIFY:
+ case ATA_CMD_VERIFY_EXT:
+ case ATA_CMD_SET_FEATURES:
+ case ATA_CMD_STANDBY:
+ case ATA_CMD_STANDBYNOW1:
+ return SATA_PROTOCOL_NONDATA;
+ default:
+ if (direction == DMA_NONE)
+ return SATA_PROTOCOL_NONDATA;
+ return SATA_PROTOCOL_PIO;
+ }
+}
+
+static int get_ncq_tag_v2_hw(struct sas_task *task, u32 *tag)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ if (qc) {
+ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+ qc->tf.command == ATA_CMD_FPDMA_READ) {
+ *tag = qc->tag;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ struct sas_task *task = slot->task;
+ struct domain_device *device = task->dev;
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct hisi_sas_port *port = device->port->lldd_port;
+ u8 *buf_cmd;
+ int has_data = 0, rc = 0, hdr_tag = 0;
+ u32 dw1 = 0, dw2 = 0;
+
+ /* create header */
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
+ else
+ hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
+
+ /* dw1 */
+ switch (task->data_dir) {
+ case DMA_TO_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
+ break;
+ case DMA_FROM_DEVICE:
+ has_data = 1;
+ dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
+ break;
+ default:
+ dw1 &= ~CMD_HDR_DIR_MSK;
+ }
+
+ if (0 == task->ata_task.fis.command)
+ dw1 |= 1 << CMD_HDR_RESET_OFF;
+
+ dw1 |= (get_ata_protocol(task->ata_task.fis.command, task->data_dir))
+ << CMD_HDR_FRAME_TYPE_OFF;
+ dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ /* dw2 */
+ if (task->ata_task.use_ncq && get_ncq_tag_v2_hw(task, &hdr_tag)) {
+ task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
+ dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
+ }
+
+ dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF |
+ 2 << CMD_HDR_SG_MOD_OFF;
+ hdr->dw2 = cpu_to_le32(dw2);
+
+ /* dw3 */
+ hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+ if (has_data) {
+ rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+ slot->n_elem);
+ if (rc)
+ return rc;
+ }
+
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ buf_cmd = slot->command_table;
+
+ if (likely(!task->ata_task.device_control_reg_update))
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+ /* fill in command FIS */
+ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+
+ return 0;
+}
+
+static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+ int i, res = 0;
+ u32 context, port_id, link_rate, hard_phy_linkrate;
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+ struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
+
+ /* Check for SATA dev */
+ context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+ if (context & (1 << phy_no))
+ goto end;
+
+ if (phy_no == 8) {
+ u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+ port_id = (port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+ PORT_STATE_PHY8_PORT_NUM_OFF;
+ link_rate = (port_state & PORT_STATE_PHY8_CONN_RATE_MSK) >>
+ PORT_STATE_PHY8_CONN_RATE_OFF;
+ } else {
+ port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+ port_id = (port_id >> (4 * phy_no)) & 0xf;
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ }
+
+ if (port_id == 0xf) {
+ dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ for (i = 0; i < 6; i++) {
+ u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
+ RX_IDAF_DWORD0 + (i * 4));
+ frame_rcvd[i] = __swab32(idaf);
+ }
+
+ /* Get the linkrates */
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ sas_phy->linkrate = link_rate;
+ hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
+ HARD_PHY_LINKRATE);
+ phy->maximum_linkrate = hard_phy_linkrate & 0xf;
+ phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
+
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE);
+ dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+ phy->port_id = port_id;
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ phy->phy_type |= PORT_TYPE_SAS;
+ phy->phy_attached = 1;
+ phy->identify.device_type = id->dev_type;
+ phy->frame_rcvd_size = sizeof(struct sas_identify_frame);
+ if (phy->identify.device_type == SAS_END_DEVICE)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SSP;
+ else if (phy->identify.device_type != SAS_PHY_UNUSED)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SMP;
+ queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
+ CHL_INT0_SL_PHY_ENABLE_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
+
+ return res;
+}
+
+static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+ int res = 0;
+ u32 phy_cfg, phy_state;
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
+
+ phy_cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
+
+ return res;
+}
+
+static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ u32 irq_msk;
+ int phy_no = 0;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO)
+ >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff;
+ while (irq_msk) {
+ if (irq_msk & 1) {
+ u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT0);
+
+ if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK)
+ /* phy up */
+ if (phy_up_v2_hw(phy_no, hisi_hba)) {
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ if (irq_value & CHL_INT0_NOT_RDY_MSK)
+ /* phy down */
+ if (phy_down_v2_hw(phy_no, hisi_hba)) {
+ res = IRQ_NONE;
+ goto end;
+ }
+ }
+ irq_msk >>= 1;
+ phy_no++;
+ }
+
+end:
+ return res;
+}
+
+static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+ unsigned long flags;
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
+ CHL_INT0_SL_RX_BCST_ACK_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
+}
+
+static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 ent_msk, ent_tmp, irq_msk;
+ int phy_no = 0;
+
+ ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
+ ent_tmp = ent_msk;
+ ent_msk |= ENT_INT_SRC_MSK3_ENT95_MSK_MSK;
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_msk);
+
+ irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) >>
+ HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
+
+ while (irq_msk) {
+ if (irq_msk & (1 << phy_no)) {
+ u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT0);
+ u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT1);
+ u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT2);
+
+ if (irq_value1) {
+ if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
+ CHL_INT1_DMAC_TX_ECC_ERR_MSK))
+ panic("%s: DMAC RX/TX ecc bad error! (0x%x)",
+ dev_name(dev), irq_value1);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT1, irq_value1);
+ }
+
+ if (irq_value2)
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT2, irq_value2);
+
+
+ if (irq_value0) {
+ if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+ phy_bcast_v2_hw(phy_no, hisi_hba);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CHL_INT0, irq_value0
+ & (~CHL_INT0_HOTPLUG_TOUT_MSK)
+ & (~CHL_INT0_SL_PHY_ENABLE_MSK)
+ & (~CHL_INT0_NOT_RDY_MSK));
+ }
+ }
+ irq_msk &= ~(1 << phy_no);
+ phy_no++;
+ }
+
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_tmp);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
+{
+ struct hisi_sas_cq *cq = p;
+ struct hisi_hba *hisi_hba = cq->hisi_hba;
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_itct *itct;
+ struct hisi_sas_complete_v2_hdr *complete_queue;
+ u32 irq_value, rd_point, wr_point, dev_id;
+ int queue = cq->id;
+
+ complete_queue = hisi_hba->complete_hdr[queue];
+ irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
+
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
+
+ rd_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_RD_PTR +
+ (0x14 * queue));
+ wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
+ (0x14 * queue));
+
+ while (rd_point != wr_point) {
+ struct hisi_sas_complete_v2_hdr *complete_hdr;
+ int iptt;
+
+ complete_hdr = &complete_queue[rd_point];
+
+ /* Check for NCQ completion */
+ if (complete_hdr->act) {
+ u32 act_tmp = complete_hdr->act;
+ int ncq_tag_count = ffs(act_tmp);
+
+ dev_id = (complete_hdr->dw1 & CMPLT_HDR_DEV_ID_MSK) >>
+ CMPLT_HDR_DEV_ID_OFF;
+ itct = &hisi_hba->itct[dev_id];
+
+ /* The NCQ tags are held in the itct header */
+ while (ncq_tag_count) {
+ __le64 *ncq_tag = &itct->qw4_15[0];
+
+ ncq_tag_count -= 1;
+ iptt = (ncq_tag[ncq_tag_count / 5]
+ >> (ncq_tag_count % 5) * 12) & 0xfff;
+
+ slot = &hisi_hba->slot_info[iptt];
+ slot->cmplt_queue_slot = rd_point;
+ slot->cmplt_queue = queue;
+ slot_complete_v2_hw(hisi_hba, slot, 0);
+
+ act_tmp &= ~(1 << ncq_tag_count);
+ ncq_tag_count = ffs(act_tmp);
+ }
+ } else {
+ iptt = (complete_hdr->dw1) & CMPLT_HDR_IPTT_MSK;
+ slot = &hisi_hba->slot_info[iptt];
+ slot->cmplt_queue_slot = rd_point;
+ slot->cmplt_queue = queue;
+ slot_complete_v2_hw(hisi_hba, slot, 0);
+ }
+
+ if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
+ rd_point = 0;
+ }
+
+ /* update rd_point */
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_initial_fis *initial_fis;
+ struct dev_to_host_fis *fis;
+ u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
+ irqreturn_t res = IRQ_HANDLED;
+ u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
+ int phy_no;
+
+ phy_no = sas_phy->id;
+ initial_fis = &hisi_hba->initial_fis[phy_no];
+ fis = &initial_fis->fis;
+
+ ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK1);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk | 1 << phy_no);
+
+ ent_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC1);
+ ent_tmp = ent_int;
+ ent_int >>= ENT_INT_SRC1_D2H_FIS_CH1_OFF * (phy_no % 4);
+ if ((ent_int & ENT_INT_SRC1_D2H_FIS_CH0_MSK) == 0) {
+ dev_warn(dev, "sata int: phy%d did not receive FIS\n", phy_no);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, ent_tmp);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ if (unlikely(phy_no == 8)) {
+ u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+ port_id = (port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+ PORT_STATE_PHY8_PORT_NUM_OFF;
+ link_rate = (port_state & PORT_STATE_PHY8_CONN_RATE_MSK) >>
+ PORT_STATE_PHY8_CONN_RATE_OFF;
+ } else {
+ port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+ port_id = (port_id >> (4 * phy_no)) & 0xf;
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ }
+
+ if (port_id == 0xf) {
+ dev_err(dev, "sata int: phy%d invalid portid\n", phy_no);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ sas_phy->linkrate = link_rate;
+ hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
+ HARD_PHY_LINKRATE);
+ phy->maximum_linkrate = hard_phy_linkrate & 0xf;
+ phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
+
+ sas_phy->oob_mode = SATA_OOB_MODE;
+ /* Make up some unique SAS address */
+ attached_sas_addr[0] = 0x50;
+ attached_sas_addr[7] = phy_no;
+ memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE);
+ memcpy(sas_phy->frame_rcvd, fis, sizeof(struct dev_to_host_fis));
+ dev_info(dev, "sata int phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ phy->port_id = port_id;
+ phy->phy_type |= PORT_TYPE_SATA;
+ phy->phy_attached = 1;
+ phy->identify.device_type = SAS_SATA_DEV;
+ phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
+ phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
+ queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, ent_tmp);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk);
+
+ return res;
+}
+
+static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
+ int_phy_updown_v2_hw,
+ int_chnl_int_v2_hw,
+};
+
+/**
+ * There is a limitation in the hip06 chipset that we need
+ * to map in all mbigen interrupts, even if they are not used.
+ */
+static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+ int i, irq, rc, irq_map[128];
+
+
+ for (i = 0; i < 128; i++)
+ irq_map[i] = platform_get_irq(pdev, i);
+
+ for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) {
+ int idx = i;
+
+ irq = irq_map[idx + 1]; /* Phy up/down is irq1 */
+ if (!irq) {
+ dev_err(dev, "irq init: fail map phy interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, phy_interrupts[i], 0,
+ DRV_NAME " phy", hisi_hba);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "phy interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+ int idx = i + 72; /* First SATA interrupt is irq72 */
+
+ irq = irq_map[idx];
+ if (!irq) {
+ dev_err(dev, "irq init: fail map phy interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
+ DRV_NAME " sata", phy);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "sata interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ int idx = i + 96; /* First cq interrupt is irq96 */
+
+ irq = irq_map[idx];
+ if (!irq) {
+ dev_err(dev,
+ "irq init: could not map cq interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+ rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
+ DRV_NAME " cq", &hisi_hba->cq[i]);
+ if (rc) {
+ dev_err(dev,
+ "irq init: could not request cq interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
+{
+ int rc;
+
+ rc = hw_init_v2_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_init_v2_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ phys_init_v2_hw(hisi_hba);
+
+ return 0;
+}
+
+static const struct hisi_sas_hw hisi_sas_v2_hw = {
+ .hw_init = hisi_sas_v2_init,
+ .setup_itct = setup_itct_v2_hw,
+ .sl_notify = sl_notify_v2_hw,
+ .get_wideport_bitmap = get_wideport_bitmap_v2_hw,
+ .free_device = free_device_v2_hw,
+ .prep_smp = prep_smp_v2_hw,
+ .prep_ssp = prep_ssp_v2_hw,
+ .prep_stp = prep_ata_v2_hw,
+ .get_free_slot = get_free_slot_v2_hw,
+ .start_delivery = start_delivery_v2_hw,
+ .slot_complete = slot_complete_v2_hw,
+ .phy_enable = enable_phy_v2_hw,
+ .phy_disable = disable_phy_v2_hw,
+ .phy_hard_reset = phy_hard_reset_v2_hw,
+ .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
+};
+
+static int hisi_sas_v2_probe(struct platform_device *pdev)
+{
+ return hisi_sas_probe(pdev, &hisi_sas_v2_hw);
+}
+
+static int hisi_sas_v2_remove(struct platform_device *pdev)
+{
+ return hisi_sas_remove(pdev);
+}
+
+static const struct of_device_id sas_v2_of_match[] = {
+ { .compatible = "hisilicon,hip06-sas-v2",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sas_v2_of_match);
+
+static struct platform_driver hisi_sas_v2_driver = {
+ .probe = hisi_sas_v2_probe,
+ .remove = hisi_sas_v2_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = sas_v2_of_match,
+ },
+};
+
+module_platform_driver(hisi_sas_v2_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller v2 hw driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 8bb173e..1547bd9 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -33,7 +33,7 @@
#include <linux/transport_class.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-
+#include <linux/idr.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
@@ -42,7 +42,7 @@
#include "scsi_logging.h"
-static atomic_t scsi_host_next_hn = ATOMIC_INIT(0); /* host_no for next new host */
+static DEFINE_IDA(host_index_ida);
static void scsi_host_cls_release(struct device *dev)
@@ -217,6 +217,13 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
error = scsi_mq_setup_tags(shost);
if (error)
goto fail;
+ } else {
+ shost->bqt = blk_init_tags(shost->can_queue,
+ shost->hostt->tag_alloc_policy);
+ if (!shost->bqt) {
+ error = -ENOMEM;
+ goto fail;
+ }
}
/*
@@ -243,6 +250,12 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
if (error)
goto out_destroy_freelist;
+ /*
+ * Increase usage count temporarily here so that calling
+ * scsi_autopm_put_host() will trigger runtime idle if there is
+ * nothing else preventing suspending the device.
+ */
+ pm_runtime_get_noresume(&shost->shost_gendev);
pm_runtime_set_active(&shost->shost_gendev);
pm_runtime_enable(&shost->shost_gendev);
device_enable_async_suspend(&shost->shost_gendev);
@@ -283,6 +296,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
goto out_destroy_host;
scsi_proc_host_add(shost);
+ scsi_autopm_put_host(shost);
return error;
out_destroy_host:
@@ -326,6 +340,17 @@ static void scsi_host_dev_release(struct device *dev)
kfree(queuedata);
}
+ if (shost->shost_state == SHOST_CREATED) {
+ /*
+ * Free the shost_dev device name here if scsi_host_alloc()
+ * and scsi_host_put() have been called but neither
+ * scsi_host_add() nor scsi_host_remove() has been called.
+ * This avoids that the memory allocated for the shost_dev
+ * name is leaked.
+ */
+ kfree(dev_name(&shost->shost_dev));
+ }
+
scsi_destroy_command_freelist(shost);
if (shost_use_blk_mq(shost)) {
if (shost->tag_set.tags)
@@ -337,6 +362,8 @@ static void scsi_host_dev_release(struct device *dev)
kfree(shost->shost_data);
+ ida_simple_remove(&host_index_ida, shost->host_no);
+
if (parent)
put_device(parent);
kfree(shost);
@@ -370,6 +397,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{
struct Scsi_Host *shost;
gfp_t gfp_mask = GFP_KERNEL;
+ int index;
if (sht->unchecked_isa_dma && privsize)
gfp_mask |= __GFP_DMA;
@@ -388,11 +416,11 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
init_waitqueue_head(&shost->host_wait);
mutex_init(&shost->scan_mutex);
- /*
- * subtract one because we increment first then return, but we need to
- * know what the next host number was before increment
- */
- shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
+ index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
+ if (index < 0)
+ goto fail_kfree;
+ shost->host_no = index;
+
shost->dma_channel = 0xff;
/* These three are default values which can be overridden */
@@ -477,7 +505,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost_printk(KERN_WARNING, shost,
"error handler thread failed to spawn, error = %ld\n",
PTR_ERR(shost->ehandler));
- goto fail_kfree;
+ goto fail_index_remove;
}
shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d",
@@ -493,6 +521,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
fail_kthread:
kthread_stop(shost->ehandler);
+ fail_index_remove:
+ ida_simple_remove(&host_index_ida, shost->host_no);
fail_kfree:
kfree(shost);
return NULL;
@@ -588,6 +618,7 @@ int scsi_init_hosts(void)
void scsi_exit_hosts(void)
{
class_unregister(&shost_class);
+ ida_destroy(&host_index_ida);
}
int scsi_is_host_device(const struct device *dev)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 40669f8..5be944c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1,5 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2016 Microsemi Corporation
* Copyright 2014-2015 PMC-Sierra, Inc.
* Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
*
@@ -12,7 +13,7 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more details.
*
- * Questions/Comments/Bugfixes to storagedev@pmcs.com
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
*
*/
@@ -41,6 +42,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_transport_sas.h>
#include <scsi/scsi_dbg.h>
#include <linux/cciss_ioctl.h>
#include <linux/string.h>
@@ -54,8 +56,11 @@
#include "hpsa_cmd.h"
#include "hpsa.h"
-/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "3.4.10-0"
+/*
+ * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.'
+ * with an optional trailing '-' followed by a byte value (0-255).
+ */
+#define HPSA_DRIVER_VERSION "3.4.14-0"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
@@ -205,6 +210,16 @@ static struct board_type products[] = {
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
+static struct scsi_transport_template *hpsa_sas_transport_template;
+static int hpsa_add_sas_host(struct ctlr_info *h);
+static void hpsa_delete_sas_host(struct ctlr_info *h);
+static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node,
+ struct hpsa_scsi_dev_t *device);
+static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device);
+static struct hpsa_scsi_dev_t
+ *hpsa_find_device_by_sas_rphy(struct ctlr_info *h,
+ struct sas_rphy *rphy);
+
#define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy)
static const struct scsi_cmnd hpsa_cmd_busy;
#define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle)
@@ -230,6 +245,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
int cmd_type);
static void hpsa_free_cmd_pool(struct ctlr_info *h);
#define VPD_PAGE (1 << 8)
+#define HPSA_SIMPLE_ERROR_BITS 0x03
static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
@@ -243,7 +259,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev);
static int hpsa_slave_configure(struct scsi_device *sdev);
static void hpsa_slave_destroy(struct scsi_device *sdev);
-static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
+static void hpsa_update_scsi_devices(struct ctlr_info *h);
static int check_for_unit_attention(struct ctlr_info *h,
struct CommandList *c);
static void check_ioctl_unit_attention(struct ctlr_info *h,
@@ -274,7 +290,10 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
static void hpsa_command_resubmit_worker(struct work_struct *work);
static u32 lockup_detected(struct ctlr_info *h);
static int detect_controller_lockup(struct ctlr_info *h);
-static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device);
+static void hpsa_disable_rld_caching(struct ctlr_info *h);
+static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
+ struct ReportExtendedLUNdata *buf, int bufsize);
+static int hpsa_luns_changed(struct ctlr_info *h);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -606,7 +625,7 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
}
static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6",
- "1(+0)ADM", "UNKNOWN"
+ "1(+0)ADM", "UNKNOWN", "PHYS DRV"
};
#define HPSA_RAID_0 0
#define HPSA_RAID_4 1
@@ -615,7 +634,13 @@ static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6",
#define HPSA_RAID_51 4
#define HPSA_RAID_6 5 /* also used for RAID 60 */
#define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */
-#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
+#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 2)
+#define PHYSICAL_DRIVE (ARRAY_SIZE(raid_label) - 1)
+
+static inline bool is_logical_device(struct hpsa_scsi_dev_t *device)
+{
+ return !device->physical_device;
+}
static ssize_t raid_level_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -637,7 +662,7 @@ static ssize_t raid_level_show(struct device *dev,
}
/* Is this even a logical drive? */
- if (!is_logical_dev_addr_mode(hdev->scsi3addr)) {
+ if (!is_logical_device(hdev)) {
spin_unlock_irqrestore(&h->lock, flags);
l = snprintf(buf, PAGE_SIZE, "N/A\n");
return l;
@@ -726,8 +751,6 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
}
#define MAX_PATHS 8
-#define PATH_STRING_LEN 50
-
static ssize_t path_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -742,9 +765,7 @@ static ssize_t path_info_show(struct device *dev,
u8 path_map_index = 0;
char *active;
unsigned char phys_connector[2];
- unsigned char path[MAX_PATHS][PATH_STRING_LEN];
- memset(path, 0, MAX_PATHS * PATH_STRING_LEN);
sdev = to_scsi_device(dev);
h = sdev_to_hba(sdev);
spin_lock_irqsave(&h->devlock, flags);
@@ -764,18 +785,17 @@ static ssize_t path_info_show(struct device *dev,
else
continue;
- output_len = snprintf(path[i],
- PATH_STRING_LEN, "[%d:%d:%d:%d] %20.20s ",
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len,
+ "[%d:%d:%d:%d] %20.20s ",
h->scsi_host->host_no,
hdev->bus, hdev->target, hdev->lun,
scsi_device_type(hdev->devtype));
- if (is_ext_target(h, hdev) ||
- (hdev->devtype == TYPE_RAID) ||
- is_logical_dev_addr_mode(hdev->scsi3addr)) {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN, "%s\n",
- active);
+ if (hdev->devtype == TYPE_RAID || is_logical_device(hdev)) {
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len,
+ "%s\n", active);
continue;
}
@@ -786,37 +806,34 @@ static ssize_t path_info_show(struct device *dev,
phys_connector[0] = '0';
if (phys_connector[1] < '0')
phys_connector[1] = '0';
- if (hdev->phys_connector[i] > 0)
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN,
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len,
"PORT: %.2s ",
phys_connector);
- if (hdev->devtype == TYPE_DISK &&
- hdev->expose_state != HPSA_DO_NOT_EXPOSE) {
+ if ((hdev->devtype == TYPE_DISK || hdev->devtype == TYPE_ZBC) &&
+ hdev->expose_device) {
if (box == 0 || box == 0xFF) {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN,
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len,
"BAY: %hhu %s\n",
bay, active);
} else {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN,
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len,
"BOX: %hhu BAY: %hhu %s\n",
box, bay, active);
}
} else if (box != 0 && box != 0xFF) {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN, "BOX: %hhu %s\n",
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len, "BOX: %hhu %s\n",
box, active);
} else
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN, "%s\n", active);
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len, "%s\n", active);
}
spin_unlock_irqrestore(&h->devlock, flags);
- return snprintf(buf, output_len+1, "%s%s%s%s%s%s%s%s",
- path[0], path[1], path[2], path[3],
- path[4], path[5], path[6], path[7]);
+ return output_len;
}
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
@@ -848,7 +865,6 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_unique_id,
&dev_attr_hp_ssd_smart_path_enabled,
&dev_attr_path_info,
- &dev_attr_lockup_detected,
NULL,
};
@@ -860,6 +876,7 @@ static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_resettable,
&dev_attr_hp_ssd_smart_path_status,
&dev_attr_raid_offload_debug,
+ &dev_attr_lockup_detected,
NULL,
};
@@ -1134,25 +1151,63 @@ static int hpsa_find_target_lun(struct ctlr_info *h,
return !found;
}
-static inline void hpsa_show_dev_msg(const char *level, struct ctlr_info *h,
+static void hpsa_show_dev_msg(const char *level, struct ctlr_info *h,
struct hpsa_scsi_dev_t *dev, char *description)
{
+#define LABEL_SIZE 25
+ char label[LABEL_SIZE];
+
+ if (h == NULL || h->pdev == NULL || h->scsi_host == NULL)
+ return;
+
+ switch (dev->devtype) {
+ case TYPE_RAID:
+ snprintf(label, LABEL_SIZE, "controller");
+ break;
+ case TYPE_ENCLOSURE:
+ snprintf(label, LABEL_SIZE, "enclosure");
+ break;
+ case TYPE_DISK:
+ case TYPE_ZBC:
+ if (dev->external)
+ snprintf(label, LABEL_SIZE, "external");
+ else if (!is_logical_dev_addr_mode(dev->scsi3addr))
+ snprintf(label, LABEL_SIZE, "%s",
+ raid_label[PHYSICAL_DRIVE]);
+ else
+ snprintf(label, LABEL_SIZE, "RAID-%s",
+ dev->raid_level > RAID_UNKNOWN ? "?" :
+ raid_label[dev->raid_level]);
+ break;
+ case TYPE_ROM:
+ snprintf(label, LABEL_SIZE, "rom");
+ break;
+ case TYPE_TAPE:
+ snprintf(label, LABEL_SIZE, "tape");
+ break;
+ case TYPE_MEDIUM_CHANGER:
+ snprintf(label, LABEL_SIZE, "changer");
+ break;
+ default:
+ snprintf(label, LABEL_SIZE, "UNKNOWN");
+ break;
+ }
+
dev_printk(level, &h->pdev->dev,
- "scsi %d:%d:%d:%d: %s %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n",
+ "scsi %d:%d:%d:%d: %s %s %.8s %.16s %s SSDSmartPathCap%c En%c Exp=%d\n",
h->scsi_host->host_no, dev->bus, dev->target, dev->lun,
description,
scsi_device_type(dev->devtype),
dev->vendor,
dev->model,
- dev->raid_level > RAID_UNKNOWN ?
- "RAID-?" : raid_label[dev->raid_level],
+ label,
dev->offload_config ? '+' : '-',
dev->offload_enabled ? '+' : '-',
- dev->expose_state);
+ dev->expose_device);
}
/* Add an entry into h->dev[] array. */
-static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno,
+static int hpsa_scsi_add_entry(struct ctlr_info *h,
struct hpsa_scsi_dev_t *device,
struct hpsa_scsi_dev_t *added[], int *nadded)
{
@@ -1221,14 +1276,14 @@ lun_assigned:
added[*nadded] = device;
(*nadded)++;
hpsa_show_dev_msg(KERN_INFO, h, device,
- device->expose_state & HPSA_SCSI_ADD ? "added" : "masked");
+ device->expose_device ? "added" : "masked");
device->offload_to_be_enabled = device->offload_enabled;
device->offload_enabled = 0;
return 0;
}
/* Update an entry in h->dev[] array. */
-static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
+static void hpsa_scsi_update_entry(struct ctlr_info *h,
int entry, struct hpsa_scsi_dev_t *new_entry)
{
int offload_enabled;
@@ -1276,7 +1331,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
}
/* Replace an entry from h->dev[] array. */
-static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
+static void hpsa_scsi_replace_entry(struct ctlr_info *h,
int entry, struct hpsa_scsi_dev_t *new_entry,
struct hpsa_scsi_dev_t *added[], int *nadded,
struct hpsa_scsi_dev_t *removed[], int *nremoved)
@@ -1304,7 +1359,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
}
/* Remove an entry from h->dev[] array. */
-static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry,
+static void hpsa_scsi_remove_entry(struct ctlr_info *h, int entry,
struct hpsa_scsi_dev_t *removed[], int *nremoved)
{
/* assumes h->devlock is held */
@@ -1415,6 +1470,9 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
#define DEVICE_CHANGED 1
#define DEVICE_SAME 2
#define DEVICE_UPDATED 3
+ if (needle == NULL)
+ return DEVICE_NOT_FOUND;
+
for (i = 0; i < haystack_size; i++) {
if (haystack[i] == NULL) /* previously removed. */
continue;
@@ -1577,9 +1635,13 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h,
if (!logical_drive->offload_config)
continue;
for (j = 0; j < ndevices; j++) {
+ if (dev[j] == NULL)
+ continue;
if (dev[j]->devtype != TYPE_DISK)
continue;
- if (is_logical_dev_addr_mode(dev[j]->scsi3addr))
+ if (dev[j]->devtype != TYPE_ZBC)
+ continue;
+ if (is_logical_device(dev[j]))
continue;
if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle)
continue;
@@ -1620,9 +1682,13 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h,
int i;
for (i = 0; i < ndevices; i++) {
+ if (dev[i] == NULL)
+ continue;
if (dev[i]->devtype != TYPE_DISK)
continue;
- if (!is_logical_dev_addr_mode(dev[i]->scsi3addr))
+ if (dev[i]->devtype != TYPE_ZBC)
+ continue;
+ if (!is_logical_device(dev[i]))
continue;
/*
@@ -1638,7 +1704,50 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h,
}
}
-static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
+static int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
+{
+ int rc = 0;
+
+ if (!h->scsi_host)
+ return 1;
+
+ if (is_logical_device(device)) /* RAID */
+ rc = scsi_add_device(h->scsi_host, device->bus,
+ device->target, device->lun);
+ else /* HBA */
+ rc = hpsa_add_sas_device(h->sas_host, device);
+
+ return rc;
+}
+
+static void hpsa_remove_device(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *device)
+{
+ struct scsi_device *sdev = NULL;
+
+ if (!h->scsi_host)
+ return;
+
+ if (is_logical_device(device)) { /* RAID */
+ sdev = scsi_device_lookup(h->scsi_host, device->bus,
+ device->target, device->lun);
+ if (sdev) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ } else {
+ /*
+ * We don't expect to get here. Future commands
+ * to this device will get a selection timeout as
+ * if the device were gone.
+ */
+ hpsa_show_dev_msg(KERN_WARNING, h, device,
+ "didn't find device for removal.");
+ }
+ } else /* HBA */
+ hpsa_remove_sas_device(device);
+}
+
+static void adjust_hpsa_scsi_table(struct ctlr_info *h,
struct hpsa_scsi_dev_t *sd[], int nsds)
{
/* sd contains scsi3 addresses and devtypes, and inquiry
@@ -1650,7 +1759,15 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
unsigned long flags;
struct hpsa_scsi_dev_t **added, **removed;
int nadded, nremoved;
- struct Scsi_Host *sh = NULL;
+
+ /*
+ * A reset can cause a device status to change
+ * re-schedule the scan to see what happened.
+ */
+ if (h->reset_in_progress) {
+ h->drv_req_rescan = 1;
+ return;
+ }
added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL);
removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -1678,19 +1795,18 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry);
if (device_change == DEVICE_NOT_FOUND) {
changes++;
- hpsa_scsi_remove_entry(h, hostno, i,
- removed, &nremoved);
+ hpsa_scsi_remove_entry(h, i, removed, &nremoved);
continue; /* remove ^^^, hence i not incremented */
} else if (device_change == DEVICE_CHANGED) {
changes++;
- hpsa_scsi_replace_entry(h, hostno, i, sd[entry],
+ hpsa_scsi_replace_entry(h, i, sd[entry],
added, &nadded, removed, &nremoved);
/* Set it to NULL to prevent it from being freed
* at the bottom of hpsa_update_scsi_devices()
*/
sd[entry] = NULL;
} else if (device_change == DEVICE_UPDATED) {
- hpsa_scsi_update_entry(h, hostno, i, sd[entry]);
+ hpsa_scsi_update_entry(h, i, sd[entry]);
}
i++;
}
@@ -1718,8 +1834,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
h->ndevices, &entry);
if (device_change == DEVICE_NOT_FOUND) {
changes++;
- if (hpsa_scsi_add_entry(h, hostno, sd[i],
- added, &nadded) != 0)
+ if (hpsa_scsi_add_entry(h, sd[i], added, &nadded) != 0)
break;
sd[i] = NULL; /* prevent from being freed later. */
} else if (device_change == DEVICE_CHANGED) {
@@ -1735,8 +1850,11 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
/* Now that h->dev[]->phys_disk[] is coherent, we can enable
* any logical drives that need it enabled.
*/
- for (i = 0; i < h->ndevices; i++)
+ for (i = 0; i < h->ndevices; i++) {
+ if (h->dev[i] == NULL)
+ continue;
h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled;
+ }
spin_unlock_irqrestore(&h->devlock, flags);
@@ -1755,47 +1873,37 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
* (or if there are no changes) scsi_scan_host will do it later the
* first time through.
*/
- if (hostno == -1 || !changes)
+ if (!changes)
goto free_and_out;
- sh = h->scsi_host;
/* Notify scsi mid layer of any removed devices */
for (i = 0; i < nremoved; i++) {
- if (removed[i]->expose_state & HPSA_SCSI_ADD) {
- struct scsi_device *sdev =
- scsi_device_lookup(sh, removed[i]->bus,
- removed[i]->target, removed[i]->lun);
- if (sdev != NULL) {
- scsi_remove_device(sdev);
- scsi_device_put(sdev);
- } else {
- /*
- * We don't expect to get here.
- * future cmds to this device will get selection
- * timeout as if the device was gone.
- */
- hpsa_show_dev_msg(KERN_WARNING, h, removed[i],
- "didn't find device for removal.");
- }
- }
+ if (removed[i] == NULL)
+ continue;
+ if (removed[i]->expose_device)
+ hpsa_remove_device(h, removed[i]);
kfree(removed[i]);
removed[i] = NULL;
}
/* Notify scsi mid layer of any added devices */
for (i = 0; i < nadded; i++) {
- if (!(added[i]->expose_state & HPSA_SCSI_ADD))
+ int rc = 0;
+
+ if (added[i] == NULL)
continue;
- if (scsi_add_device(sh, added[i]->bus,
- added[i]->target, added[i]->lun) == 0)
+ if (!(added[i]->expose_device))
+ continue;
+ rc = hpsa_add_device(h, added[i]);
+ if (!rc)
continue;
- hpsa_show_dev_msg(KERN_WARNING, h, added[i],
- "addition failed, device not added.");
+ dev_warn(&h->pdev->dev,
+ "addition failed %d, device not added.", rc);
/* now we have to remove it from h->dev,
* since it didn't get added to scsi mid layer
*/
fixup_botched_add(h, added[i]);
- added[i] = NULL;
+ h->drv_req_rescan = 1;
}
free_and_out:
@@ -1829,11 +1937,24 @@ static int hpsa_slave_alloc(struct scsi_device *sdev)
h = sdev_to_hba(sdev);
spin_lock_irqsave(&h->devlock, flags);
- sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
- sdev_id(sdev), sdev->lun);
- if (likely(sd)) {
+ if (sdev_channel(sdev) == HPSA_PHYSICAL_DEVICE_BUS) {
+ struct scsi_target *starget;
+ struct sas_rphy *rphy;
+
+ starget = scsi_target(sdev);
+ rphy = target_to_rphy(starget);
+ sd = hpsa_find_device_by_sas_rphy(h, rphy);
+ if (sd) {
+ sd->target = sdev_id(sdev);
+ sd->lun = sdev->lun;
+ }
+ } else
+ sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
+ sdev_id(sdev), sdev->lun);
+
+ if (sd && sd->expose_device) {
atomic_set(&sd->ioaccel_cmds_out, 0);
- sdev->hostdata = (sd->expose_state & HPSA_SCSI_ADD) ? sd : NULL;
+ sdev->hostdata = sd;
} else
sdev->hostdata = NULL;
spin_unlock_irqrestore(&h->devlock, flags);
@@ -1847,7 +1968,7 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
int queue_depth;
sd = sdev->hostdata;
- sdev->no_uld_attach = !sd || !(sd->expose_state & HPSA_ULD_ATTACH);
+ sdev->no_uld_attach = !sd || !sd->expose_device;
if (sd)
queue_depth = sd->queue_depth != 0 ?
@@ -1955,7 +2076,7 @@ static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h,
u32 chain_size;
chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex];
- chain_size = le32_to_cpu(cp->data_len);
+ chain_size = le32_to_cpu(cp->sg[0].length);
temp64 = pci_map_single(h->pdev, chain_block, chain_size,
PCI_DMA_TODEVICE);
if (dma_mapping_error(&h->pdev->dev, temp64)) {
@@ -1976,7 +2097,7 @@ static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h,
chain_sg = cp->sg;
temp64 = le64_to_cpu(chain_sg->address);
- chain_size = le32_to_cpu(cp->data_len);
+ chain_size = le32_to_cpu(cp->sg[0].length);
pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE);
}
@@ -2210,7 +2331,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
* the normal I/O path so the controller can handle whatever's
* wrong.
*/
- if (is_logical_dev_addr_mode(dev->scsi3addr) &&
+ if (is_logical_device(dev) &&
c2->error_data.serv_response ==
IOACCEL2_SERV_RESPONSE_FAILURE) {
if (c2->error_data.status ==
@@ -2330,7 +2451,7 @@ static void complete_scsi_command(struct CommandList *cp)
* the normal I/O path so the controller can handle whatever's
* wrong.
*/
- if (is_logical_dev_addr_mode(dev->scsi3addr)) {
+ if (is_logical_device(dev)) {
if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
dev->offload_enabled = 0;
return hpsa_retry_cmd(h, cp);
@@ -2709,9 +2830,8 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
/* fill_cmd can't fail here, no data buffer to map. */
- (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
+ (void) fill_cmd(c, reset_type, h, NULL, 0, 0,
scsi3addr, TYPE_MSG);
- c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */
rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
if (rc) {
dev_warn(&h->pdev->dev, "Failed to send reset command\n");
@@ -2984,6 +3104,66 @@ out:
return rc;
}
+static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h,
+ unsigned char scsi3addr[], u16 bmic_device_index,
+ struct bmic_sense_subsystem_info *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_SENSE_SUBSYSTEM_INFORMATION, h, buf, bufsize,
+ 0, RAID_CTLR_LUNID, TYPE_CMD);
+ if (rc)
+ goto out;
+
+ c->Request.CDB[2] = bmic_device_index & 0xff;
+ c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if (rc)
+ goto out;
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_free(h, c);
+ return rc;
+}
+
+static int hpsa_bmic_id_controller(struct ctlr_info *h,
+ struct bmic_identify_controller *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_IDENTIFY_CONTROLLER, h, buf, bufsize,
+ 0, RAID_CTLR_LUNID, TYPE_CMD);
+ if (rc)
+ goto out;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if (rc)
+ goto out;
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_free(h, c);
+ return rc;
+}
+
static int hpsa_bmic_id_physical_device(struct ctlr_info *h,
unsigned char scsi3addr[], u16 bmic_device_index,
struct bmic_identify_physical_device *buf, size_t bufsize)
@@ -3010,9 +3190,154 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h,
}
out:
cmd_free(h, c);
+
return rc;
}
+/*
+ * get enclosure information
+ * struct ReportExtendedLUNdata *rlep - Used for BMIC drive number
+ * struct hpsa_scsi_dev_t *encl_dev - device entry for enclosure
+ * Uses id_physical_device to determine the box_index.
+ */
+static void hpsa_get_enclosure_info(struct ctlr_info *h,
+ unsigned char *scsi3addr,
+ struct ReportExtendedLUNdata *rlep, int rle_index,
+ struct hpsa_scsi_dev_t *encl_dev)
+{
+ int rc = -1;
+ struct CommandList *c = NULL;
+ struct ErrorInfo *ei = NULL;
+ struct bmic_sense_storage_box_params *bssbp = NULL;
+ struct bmic_identify_physical_device *id_phys = NULL;
+ struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+ u16 bmic_device_index = 0;
+
+ bmic_device_index = GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]);
+
+ if (bmic_device_index == 0xFF00 || MASKED_DEVICE(&rle->lunid[0])) {
+ rc = IO_OK;
+ goto out;
+ }
+
+ bssbp = kzalloc(sizeof(*bssbp), GFP_KERNEL);
+ if (!bssbp)
+ goto out;
+
+ id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+ if (!id_phys)
+ goto out;
+
+ rc = hpsa_bmic_id_physical_device(h, scsi3addr, bmic_device_index,
+ id_phys, sizeof(*id_phys));
+ if (rc) {
+ dev_warn(&h->pdev->dev, "%s: id_phys failed %d bdi[0x%x]\n",
+ __func__, encl_dev->external, bmic_device_index);
+ goto out;
+ }
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_SENSE_STORAGE_BOX_PARAMS, h, bssbp,
+ sizeof(*bssbp), 0, RAID_CTLR_LUNID, TYPE_CMD);
+
+ if (rc)
+ goto out;
+
+ if (id_phys->phys_connector[1] == 'E')
+ c->Request.CDB[5] = id_phys->box_index;
+ else
+ c->Request.CDB[5] = 0;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE,
+ NO_TIMEOUT);
+ if (rc)
+ goto out;
+
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ rc = -1;
+ goto out;
+ }
+
+ encl_dev->box[id_phys->active_path_number] = bssbp->phys_box_on_port;
+ memcpy(&encl_dev->phys_connector[id_phys->active_path_number],
+ bssbp->phys_connector, sizeof(bssbp->phys_connector));
+
+ rc = IO_OK;
+out:
+ kfree(bssbp);
+ kfree(id_phys);
+
+ if (c)
+ cmd_free(h, c);
+
+ if (rc != IO_OK)
+ hpsa_show_dev_msg(KERN_INFO, h, encl_dev,
+ "Error, could not get enclosure information\n");
+}
+
+static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h,
+ unsigned char *scsi3addr)
+{
+ struct ReportExtendedLUNdata *physdev;
+ u32 nphysicals;
+ u64 sa = 0;
+ int i;
+
+ physdev = kzalloc(sizeof(*physdev), GFP_KERNEL);
+ if (!physdev)
+ return 0;
+
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) {
+ dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
+ kfree(physdev);
+ return 0;
+ }
+ nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24;
+
+ for (i = 0; i < nphysicals; i++)
+ if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) {
+ sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]);
+ break;
+ }
+
+ kfree(physdev);
+
+ return sa;
+}
+
+static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr,
+ struct hpsa_scsi_dev_t *dev)
+{
+ int rc;
+ u64 sa = 0;
+
+ if (is_hba_lunid(scsi3addr)) {
+ struct bmic_sense_subsystem_info *ssi;
+
+ ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
+ if (ssi == NULL) {
+ dev_warn(&h->pdev->dev,
+ "%s: out of memory\n", __func__);
+ return;
+ }
+
+ rc = hpsa_bmic_sense_subsystem_information(h,
+ scsi3addr, 0, ssi, sizeof(*ssi));
+ if (rc == 0) {
+ sa = get_unaligned_be64(ssi->primary_world_wide_id);
+ h->sas_address = sa;
+ }
+
+ kfree(ssi);
+ } else
+ sa = hpsa_get_sas_address_from_report_physical(h, scsi3addr);
+
+ dev->sas_address = sa;
+}
+
+/* Get a device id from inquiry page 0x83 */
static int hpsa_vpd_page_supported(struct ctlr_info *h,
unsigned char scsi3addr[], u8 page)
{
@@ -3097,7 +3422,7 @@ out:
/* Get the device id from inquiry page 0x83 */
static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
- unsigned char *device_id, int buflen)
+ unsigned char *device_id, int index, int buflen)
{
int rc;
unsigned char *buf;
@@ -3109,8 +3434,10 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
return -ENOMEM;
rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);
if (rc == 0)
- memcpy(device_id, &buf[8], buflen);
+ memcpy(device_id, &buf[index], buflen);
+
kfree(buf);
+
return rc != 0;
}
@@ -3351,10 +3678,13 @@ static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char *inq_buff;
unsigned char *obdr_sig;
+ int rc = 0;
inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
- if (!inq_buff)
+ if (!inq_buff) {
+ rc = -ENOMEM;
goto bail_out;
+ }
/* Do an inquiry to the device to see what it is. */
if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
@@ -3362,9 +3692,13 @@ static int hpsa_update_device_info(struct ctlr_info *h,
/* Inquiry failed (msg printed already) */
dev_err(&h->pdev->dev,
"hpsa_update_device_info: inquiry failed\n");
+ rc = -EIO;
goto bail_out;
}
+ scsi_sanitize_inquiry_string(&inq_buff[8], 8);
+ scsi_sanitize_inquiry_string(&inq_buff[16], 16);
+
this_device->devtype = (inq_buff[0] & 0x1f);
memcpy(this_device->scsi3addr, scsi3addr, 8);
memcpy(this_device->vendor, &inq_buff[8],
@@ -3373,10 +3707,11 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->model));
memset(this_device->device_id, 0,
sizeof(this_device->device_id));
- hpsa_get_device_id(h, scsi3addr, this_device->device_id,
+ hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
sizeof(this_device->device_id));
- if (this_device->devtype == TYPE_DISK &&
+ if ((this_device->devtype == TYPE_DISK ||
+ this_device->devtype == TYPE_ZBC) &&
is_logical_dev_addr_mode(scsi3addr)) {
int volume_offline;
@@ -3411,7 +3746,7 @@ static int hpsa_update_device_info(struct ctlr_info *h,
bail_out:
kfree(inq_buff);
- return 1;
+ return rc;
}
static void hpsa_update_device_supports_aborts(struct ctlr_info *h,
@@ -3439,115 +3774,39 @@ static void hpsa_update_device_supports_aborts(struct ctlr_info *h,
}
}
-static unsigned char *ext_target_model[] = {
- "MSA2012",
- "MSA2024",
- "MSA2312",
- "MSA2324",
- "P2000 G3 SAS",
- "MSA 2040 SAS",
- NULL,
-};
-
-static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
-{
- int i;
-
- for (i = 0; ext_target_model[i]; i++)
- if (strncmp(device->model, ext_target_model[i],
- strlen(ext_target_model[i])) == 0)
- return 1;
- return 0;
-}
-
-/* Helper function to assign bus, target, lun mapping of devices.
- * Puts non-external target logical volumes on bus 0, external target logical
- * volumes on bus 1, physical devices on bus 2. and the hba on bus 3.
+/*
+ * Helper function to assign bus, target, lun mapping of devices.
* Logical drive target and lun are assigned at this time, but
* physical device lun and target assignment are deferred (assigned
* in hpsa_find_target_lun, called by hpsa_scsi_add_entry.)
- */
+*/
static void figure_bus_target_lun(struct ctlr_info *h,
u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device)
{
- u32 lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
+ u32 lunid = get_unaligned_le32(lunaddrbytes);
if (!is_logical_dev_addr_mode(lunaddrbytes)) {
/* physical device, target and lun filled in later */
if (is_hba_lunid(lunaddrbytes))
- hpsa_set_bus_target_lun(device, 3, 0, lunid & 0x3fff);
+ hpsa_set_bus_target_lun(device,
+ HPSA_HBA_BUS, 0, lunid & 0x3fff);
else
/* defer target, lun assignment for physical devices */
- hpsa_set_bus_target_lun(device, 2, -1, -1);
+ hpsa_set_bus_target_lun(device,
+ HPSA_PHYSICAL_DEVICE_BUS, -1, -1);
return;
}
/* It's a logical device */
- if (is_ext_target(h, device)) {
- /* external target way, put logicals on bus 1
- * and match target/lun numbers box
- * reports, other smart array, bus 0, target 0, match lunid
- */
+ if (device->external) {
hpsa_set_bus_target_lun(device,
- 1, (lunid >> 16) & 0x3fff, lunid & 0x00ff);
+ HPSA_EXTERNAL_RAID_VOLUME_BUS, (lunid >> 16) & 0x3fff,
+ lunid & 0x00ff);
return;
}
- hpsa_set_bus_target_lun(device, 0, 0, lunid & 0x3fff);
+ hpsa_set_bus_target_lun(device, HPSA_RAID_VOLUME_BUS,
+ 0, lunid & 0x3fff);
}
-/*
- * If there is no lun 0 on a target, linux won't find any devices.
- * For the external targets (arrays), we have to manually detect the enclosure
- * which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report
- * it for some reason. *tmpdevice is the target we're adding,
- * this_device is a pointer into the current element of currentsd[]
- * that we're building up in update_scsi_devices(), below.
- * lunzerobits is a bitmap that tracks which targets already have a
- * lun 0 assigned.
- * Returns 1 if an enclosure was added, 0 if not.
- */
-static int add_ext_target_dev(struct ctlr_info *h,
- struct hpsa_scsi_dev_t *tmpdevice,
- struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes,
- unsigned long lunzerobits[], int *n_ext_target_devs)
-{
- unsigned char scsi3addr[8];
-
- if (test_bit(tmpdevice->target, lunzerobits))
- return 0; /* There is already a lun 0 on this target. */
-
- if (!is_logical_dev_addr_mode(lunaddrbytes))
- return 0; /* It's the logical targets that may lack lun 0. */
-
- if (!is_ext_target(h, tmpdevice))
- return 0; /* Only external target devices have this problem. */
-
- if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */
- return 0;
-
- memset(scsi3addr, 0, 8);
- scsi3addr[3] = tmpdevice->target;
- if (is_hba_lunid(scsi3addr))
- return 0; /* Don't add the RAID controller here. */
-
- if (is_scsi_rev_5(h))
- return 0; /* p1210m doesn't need to do this. */
-
- if (*n_ext_target_devs >= MAX_EXT_TARGETS) {
- dev_warn(&h->pdev->dev, "Maximum number of external "
- "target devices exceeded. Check your hardware "
- "configuration.");
- return 0;
- }
-
- if (hpsa_update_device_info(h, scsi3addr, this_device, NULL))
- return 0;
- (*n_ext_target_devs)++;
- hpsa_set_bus_target_lun(this_device,
- tmpdevice->bus, tmpdevice->target, 0);
- hpsa_update_device_supports_aborts(h, this_device, scsi3addr);
- set_bit(tmpdevice->target, lunzerobits);
- return 1;
-}
/*
* Get address of physical disk used for an ioaccel2 mode command:
@@ -3577,6 +3836,27 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
return 0;
}
+static int figure_external_status(struct ctlr_info *h, int raid_ctlr_position,
+ int i, int nphysicals, int nlocal_logicals)
+{
+ /* In report logicals, local logicals are listed first,
+ * then any externals.
+ */
+ int logicals_start = nphysicals + (raid_ctlr_position == 0);
+
+ if (i == raid_ctlr_position)
+ return 0;
+
+ if (i < logicals_start)
+ return 0;
+
+ /* i is in logicals range, but still within local logicals */
+ if ((i - nphysicals - (raid_ctlr_position == 0)) < nlocal_logicals)
+ return 0;
+
+ return 1; /* it's an external lun */
+}
+
/*
* Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev,
* logdev. The number of luns in physdev and logdev are returned in
@@ -3650,19 +3930,18 @@ static u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position,
/* get physical drive ioaccel handle and queue depth */
static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
struct hpsa_scsi_dev_t *dev,
- u8 *lunaddrbytes,
+ struct ReportExtendedLUNdata *rlep, int rle_index,
struct bmic_identify_physical_device *id_phys)
{
int rc;
- struct ext_report_lun_entry *rle =
- (struct ext_report_lun_entry *) lunaddrbytes;
+ struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
dev->ioaccel_handle = rle->ioaccel_handle;
- if (PHYS_IOACCEL(lunaddrbytes) && dev->ioaccel_handle)
+ if ((rle->device_flags & 0x08) && dev->ioaccel_handle)
dev->hba_ioaccel_enabled = 1;
memset(id_phys, 0, sizeof(*id_phys));
- rc = hpsa_bmic_id_physical_device(h, lunaddrbytes,
- GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys,
+ rc = hpsa_bmic_id_physical_device(h, &rle->lunid[0],
+ GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]), id_phys,
sizeof(*id_phys));
if (!rc)
/* Reserve space for FW operations */
@@ -3673,16 +3952,15 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
DRIVE_CMDS_RESERVED_FOR_FW;
else
dev->queue_depth = DRIVE_QUEUE_DEPTH; /* conservative */
- atomic_set(&dev->ioaccel_cmds_out, 0);
- atomic_set(&dev->reset_cmds_out, 0);
}
static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device,
- u8 *lunaddrbytes,
+ struct ReportExtendedLUNdata *rlep, int rle_index,
struct bmic_identify_physical_device *id_phys)
{
- if (PHYS_IOACCEL(lunaddrbytes)
- && this_device->ioaccel_handle)
+ struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+
+ if ((rle->device_flags & 0x08) && this_device->ioaccel_handle)
this_device->hba_ioaccel_enabled = 1;
memcpy(&this_device->active_path_index,
@@ -3702,7 +3980,33 @@ static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device,
sizeof(this_device->bay));
}
-static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
+/* get number of local logical disks. */
+static int hpsa_set_local_logical_count(struct ctlr_info *h,
+ struct bmic_identify_controller *id_ctlr,
+ u32 *nlocals)
+{
+ int rc;
+
+ if (!id_ctlr) {
+ dev_warn(&h->pdev->dev, "%s: id_ctlr buffer is NULL.\n",
+ __func__);
+ return -ENOMEM;
+ }
+ memset(id_ctlr, 0, sizeof(*id_ctlr));
+ rc = hpsa_bmic_id_controller(h, id_ctlr, sizeof(*id_ctlr));
+ if (!rc)
+ if (id_ctlr->configured_logical_drive_count < 256)
+ *nlocals = id_ctlr->configured_logical_drive_count;
+ else
+ *nlocals = le16_to_cpu(
+ id_ctlr->extended_logical_unit_count);
+ else
+ *nlocals = -1;
+ return rc;
+}
+
+
+static void hpsa_update_scsi_devices(struct ctlr_info *h)
{
/* the idea here is we could get notified
* that some devices have changed, so we do a report
@@ -3717,13 +4021,16 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
struct ReportExtendedLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
struct bmic_identify_physical_device *id_phys = NULL;
+ struct bmic_identify_controller *id_ctlr = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
+ u32 nlocal_logicals = 0;
u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
int i, n_ext_target_devs, ndevs_to_allocate;
int raid_ctlr_position;
+ bool physical_device;
DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -3731,17 +4038,29 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+ id_ctlr = kzalloc(sizeof(*id_ctlr), GFP_KERNEL);
if (!currentsd || !physdev_list || !logdev_list ||
- !tmpdevice || !id_phys) {
+ !tmpdevice || !id_phys || !id_ctlr) {
dev_err(&h->pdev->dev, "out of memory\n");
goto out;
}
memset(lunzerobits, 0, sizeof(lunzerobits));
+ h->drv_req_rescan = 0; /* cancel scheduled rescan - we're doing it. */
+
if (hpsa_gather_lun_info(h, physdev_list, &nphysicals,
- logdev_list, &nlogicals))
+ logdev_list, &nlogicals)) {
+ h->drv_req_rescan = 1;
goto out;
+ }
+
+ /* Set number of local logicals (non PTRAID) */
+ if (hpsa_set_local_logical_count(h, id_ctlr, &nlocal_logicals)) {
+ dev_warn(&h->pdev->dev,
+ "%s: Can't determine number of local logical devices.\n",
+ __func__);
+ }
/* We might see up to the maximum number of logical and physical disks
* plus external target devices, and a device for the local RAID
@@ -3762,6 +4081,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
if (!currentsd[i]) {
dev_warn(&h->pdev->dev, "out of memory at %s:%d\n",
__FILE__, __LINE__);
+ h->drv_req_rescan = 1;
goto out;
}
ndev_allocated++;
@@ -3776,49 +4096,75 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
n_ext_target_devs = 0;
for (i = 0; i < nphysicals + nlogicals + 1; i++) {
u8 *lunaddrbytes, is_OBDR = 0;
+ int rc = 0;
+ int phys_dev_index = i - (raid_ctlr_position == 0);
+
+ physical_device = i < nphysicals + (raid_ctlr_position == 0);
/* Figure out where the LUN ID info is coming from */
lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
i, nphysicals, nlogicals, physdev_list, logdev_list);
/* skip masked non-disk devices */
- if (MASKED_DEVICE(lunaddrbytes))
- if (i < nphysicals + (raid_ctlr_position == 0) &&
- NON_DISK_PHYS_DEV(lunaddrbytes))
- continue;
+ if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
+ (physdev_list->LUN[phys_dev_index].device_type != 0x06) &&
+ (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
+ continue;
/* Get device type, vendor, model, device id */
- if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
- &is_OBDR))
- continue; /* skip it if we can't talk to it. */
+ rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
+ &is_OBDR);
+ if (rc == -ENOMEM) {
+ dev_warn(&h->pdev->dev,
+ "Out of memory, rescan deferred.\n");
+ h->drv_req_rescan = 1;
+ goto out;
+ }
+ if (rc) {
+ dev_warn(&h->pdev->dev,
+ "Inquiry failed, skipping device.\n");
+ continue;
+ }
+
+ /* Determine if this is a lun from an external target array */
+ tmpdevice->external =
+ figure_external_status(h, raid_ctlr_position, i,
+ nphysicals, nlocal_logicals);
+
figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes);
this_device = currentsd[ncurrent];
- /*
- * For external target devices, we have to insert a LUN 0 which
- * doesn't show up in CCISS_REPORT_PHYSICAL data, but there
- * is nonetheless an enclosure device there. We have to
- * present that otherwise linux won't find anything if
- * there is no lun 0.
+ /* Turn on discovery_polling if there are ext target devices.
+ * Event-based change notification is unreliable for those.
*/
- if (add_ext_target_dev(h, tmpdevice, this_device,
- lunaddrbytes, lunzerobits,
- &n_ext_target_devs)) {
- ncurrent++;
- this_device = currentsd[ncurrent];
+ if (!h->discovery_polling) {
+ if (tmpdevice->external) {
+ h->discovery_polling = 1;
+ dev_info(&h->pdev->dev,
+ "External target, activate discovery polling.\n");
+ }
}
+
*this_device = *tmpdevice;
+ this_device->physical_device = physical_device;
- /* do not expose masked devices */
- if (MASKED_DEVICE(lunaddrbytes) &&
- i < nphysicals + (raid_ctlr_position == 0)) {
- this_device->expose_state = HPSA_DO_NOT_EXPOSE;
- } else {
- this_device->expose_state =
- HPSA_SG_ATTACH | HPSA_ULD_ATTACH;
- }
+ /*
+ * Expose all devices except for physical devices that
+ * are masked.
+ */
+ if (MASKED_DEVICE(lunaddrbytes) && this_device->physical_device)
+ this_device->expose_device = 0;
+ else
+ this_device->expose_device = 1;
+
+
+ /*
+ * Get the SAS address for physical devices that are exposed.
+ */
+ if (this_device->physical_device && this_device->expose_device)
+ hpsa_get_sas_address(h, lunaddrbytes, this_device);
switch (this_device->devtype) {
case TYPE_ROM:
@@ -3833,20 +4179,27 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
ncurrent++;
break;
case TYPE_DISK:
- if (i < nphysicals + (raid_ctlr_position == 0)) {
+ case TYPE_ZBC:
+ if (this_device->physical_device) {
/* The disk is in HBA mode. */
/* Never use RAID mapper in HBA mode. */
this_device->offload_enabled = 0;
hpsa_get_ioaccel_drive_info(h, this_device,
- lunaddrbytes, id_phys);
- hpsa_get_path_info(this_device, lunaddrbytes,
- id_phys);
+ physdev_list, phys_dev_index, id_phys);
+ hpsa_get_path_info(this_device,
+ physdev_list, phys_dev_index, id_phys);
}
ncurrent++;
break;
case TYPE_TAPE:
case TYPE_MEDIUM_CHANGER:
+ ncurrent++;
+ break;
case TYPE_ENCLOSURE:
+ if (!this_device->external)
+ hpsa_get_enclosure_info(h, lunaddrbytes,
+ physdev_list, phys_dev_index,
+ this_device);
ncurrent++;
break;
case TYPE_RAID:
@@ -3865,7 +4218,19 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
if (ncurrent >= HPSA_MAX_DEVICES)
break;
}
- adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent);
+
+ if (h->sas_host == NULL) {
+ int rc = 0;
+
+ rc = hpsa_add_sas_host(h);
+ if (rc) {
+ dev_warn(&h->pdev->dev,
+ "Could not add sas host %d\n", rc);
+ goto out;
+ }
+ }
+
+ adjust_hpsa_scsi_table(h, currentsd, ncurrent);
out:
kfree(tmpdevice);
for (i = 0; i < ndev_allocated; i++)
@@ -3873,6 +4238,7 @@ out:
kfree(currentsd);
kfree(physdev_list);
kfree(logdev_list);
+ kfree(id_ctlr);
kfree(id_phys);
}
@@ -3978,19 +4344,14 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
case READ_6:
case READ_12:
if (*cdb_len == 6) {
- block = (((u32) cdb[2]) << 8) | cdb[3];
+ block = get_unaligned_be16(&cdb[2]);
block_cnt = cdb[4];
+ if (block_cnt == 0)
+ block_cnt = 256;
} else {
BUG_ON(*cdb_len != 12);
- block = (((u32) cdb[2]) << 24) |
- (((u32) cdb[3]) << 16) |
- (((u32) cdb[4]) << 8) |
- cdb[5];
- block_cnt =
- (((u32) cdb[6]) << 24) |
- (((u32) cdb[7]) << 16) |
- (((u32) cdb[8]) << 8) |
- cdb[9];
+ block = get_unaligned_be32(&cdb[2]);
+ block_cnt = get_unaligned_be32(&cdb[6]);
}
if (block_cnt > 0xffff)
return IO_ACCEL_INELIGIBLE;
@@ -4272,6 +4633,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
/* fill in sg elements */
if (use_sg > h->ioaccel_maxsg) {
cp->sg_count = 1;
+ cp->sg[0].length = cpu_to_le32(use_sg * sizeof(cp->sg[0]));
if (hpsa_map_ioaccel2_sg_chain_block(h, cp, c)) {
atomic_dec(&phys_disk->ioaccel_cmds_out);
scsi_dma_unmap(cmd);
@@ -4376,9 +4738,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
case WRITE_6:
is_write = 1;
case READ_6:
- first_block =
- (((u64) cmd->cmnd[2]) << 8) |
- cmd->cmnd[3];
+ first_block = get_unaligned_be16(&cmd->cmnd[2]);
block_cnt = cmd->cmnd[4];
if (block_cnt == 0)
block_cnt = 256;
@@ -4610,6 +4970,8 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
return IO_ACCEL_INELIGIBLE;
c->phys_disk = dev->phys_disk[map_index];
+ if (!c->phys_disk)
+ return IO_ACCEL_INELIGIBLE;
disk_handle = dd[map_index].ioaccel_handle;
disk_block = le64_to_cpu(map->disk_starting_blk) +
@@ -4947,7 +5309,7 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
if (unlikely(lockup_detected(h)))
return hpsa_scan_complete(h);
- hpsa_update_scsi_devices(h, h->scsi_host->host_no);
+ hpsa_update_scsi_devices(h);
hpsa_scan_complete(h);
}
@@ -4983,7 +5345,6 @@ static int hpsa_scan_finished(struct Scsi_Host *sh,
static int hpsa_scsi_host_alloc(struct ctlr_info *h)
{
struct Scsi_Host *sh;
- int error;
sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
if (sh == NULL) {
@@ -5001,17 +5362,11 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h)
sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS;
sh->cmd_per_lun = sh->can_queue;
sh->sg_tablesize = h->maxsgentries;
+ sh->transportt = hpsa_sas_transport_template;
sh->hostdata[0] = (unsigned long) h;
sh->irq = h->intr[h->intr_mode];
sh->unique_id = sh->irq;
- error = scsi_init_shared_tag_map(sh, sh->can_queue);
- if (error) {
- dev_err(&h->pdev->dev,
- "%s: scsi_init_shared_tag_map failed for controller %d\n",
- __func__, h->ctlr);
- scsi_host_put(sh);
- return error;
- }
+
h->scsi_host = sh;
return 0;
}
@@ -5167,6 +5522,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
int rc;
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
+ u8 reset_type;
char msg[48];
/* find the controller to which the command to be aborted was sent */
@@ -5205,14 +5561,25 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
if (is_hba_lunid(dev->scsi3addr))
return SUCCESS;
- hpsa_show_dev_msg(KERN_WARNING, h, dev, "resetting");
+ if (is_logical_dev_addr_mode(dev->scsi3addr))
+ reset_type = HPSA_DEVICE_RESET_MSG;
+ else
+ reset_type = HPSA_PHYS_TARGET_RESET;
+
+ sprintf(msg, "resetting %s",
+ reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ");
+ hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
+
+ h->reset_in_progress = 1;
/* send a reset to the SCSI LUN which the command was sent to */
- rc = hpsa_do_reset(h, dev, dev->scsi3addr, HPSA_RESET_TYPE_LUN,
+ rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type,
DEFAULT_REPLY_QUEUE);
- snprintf(msg, sizeof(msg), "reset %s",
- rc == 0 ? "completed successfully" : "failed");
+ sprintf(msg, "reset %s %s",
+ reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ",
+ rc == 0 ? "completed successfully" : "failed");
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
+ h->reset_in_progress = 0;
return rc == 0 ? SUCCESS : FAILED;
}
@@ -5470,7 +5837,7 @@ static int hpsa_send_abort_ioaccel2(struct ctlr_info *h,
}
static int hpsa_send_abort_both_ways(struct ctlr_info *h,
- unsigned char *scsi3addr, struct CommandList *abort, int reply_queue)
+ struct hpsa_scsi_dev_t *dev, struct CommandList *abort, int reply_queue)
{
/*
* ioccelerator mode 2 commands should be aborted via the
@@ -5479,14 +5846,16 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
* Change abort to physical device reset when abort TMF is unsupported.
*/
if (abort->cmd_type == CMD_IOACCEL2) {
- if (HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags)
+ if ((HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags) ||
+ dev->physical_device)
return hpsa_send_abort_ioaccel2(h, abort,
reply_queue);
else
- return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr,
+ return hpsa_send_reset_as_abort_ioaccel2(h,
+ dev->scsi3addr,
abort, reply_queue);
}
- return hpsa_send_abort(h, scsi3addr, abort, reply_queue);
+ return hpsa_send_abort(h, dev->scsi3addr, abort, reply_queue);
}
/* Find out which reply queue a command was meant to return on */
@@ -5624,7 +5993,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
cmd_free(h, abort);
return FAILED;
}
- rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort, reply_queue);
+ rc = hpsa_send_abort_both_ways(h, dev, abort, reply_queue);
atomic_inc(&h->abort_cmds_available);
wake_up_all(&h->abort_cmd_wait_queue);
if (rc != 0) {
@@ -6270,6 +6639,24 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[8] = (size >> 8) & 0xFF;
c->Request.CDB[9] = size & 0xFF;
break;
+ case BMIC_SENSE_DIAG_OPTIONS:
+ c->Request.CDBLen = 16;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ /* Spec says this should be BMIC_WRITE */
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_DIAG_OPTIONS;
+ break;
+ case BMIC_SET_DIAG_OPTIONS:
+ c->Request.CDBLen = 16;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type,
+ ATTR_SIMPLE, XFER_WRITE);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_WRITE;
+ c->Request.CDB[6] = BMIC_SET_DIAG_OPTIONS;
+ break;
case HPSA_CACHE_FLUSH:
c->Request.CDBLen = 12;
c->Request.type_attr_dir =
@@ -6319,6 +6706,42 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0XFF;
break;
+ case BMIC_SENSE_SUBSYSTEM_INFORMATION:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_SUBSYSTEM_INFORMATION;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ break;
+ case BMIC_SENSE_STORAGE_BOX_PARAMS:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_STORAGE_BOX_PARAMS;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ break;
+ case BMIC_IDENTIFY_CONTROLLER:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[1] = 0;
+ c->Request.CDB[2] = 0;
+ c->Request.CDB[3] = 0;
+ c->Request.CDB[4] = 0;
+ c->Request.CDB[5] = 0;
+ c->Request.CDB[6] = BMIC_IDENTIFY_CONTROLLER;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ c->Request.CDB[9] = 0;
+ break;
default:
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
BUG();
@@ -6327,6 +6750,20 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
} else if (cmd_type == TYPE_MSG) {
switch (cmd) {
+ case HPSA_PHYS_TARGET_RESET:
+ c->Request.CDBLen = 16;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
+ c->Request.Timeout = 0; /* Don't time out */
+ memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
+ c->Request.CDB[0] = HPSA_RESET;
+ c->Request.CDB[1] = HPSA_TARGET_RESET_TYPE;
+ /* Physical target reset needs no control bytes 4-7*/
+ c->Request.CDB[4] = 0x00;
+ c->Request.CDB[5] = 0x00;
+ c->Request.CDB[6] = 0x00;
+ c->Request.CDB[7] = 0x00;
+ break;
case HPSA_DEVICE_RESET_MSG:
c->Request.CDBLen = 16;
c->Request.type_attr_dir =
@@ -6440,16 +6877,6 @@ static inline void finish_cmd(struct CommandList *c)
complete(c->waiting);
}
-
-static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
-{
-#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1)
-#define HPSA_SIMPLE_ERROR_BITS 0x03
- if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
- return tag & ~HPSA_SIMPLE_ERROR_BITS;
- return tag & ~HPSA_PERF_ERROR_BITS;
-}
-
/* process completion of an indexed ("direct lookup") command */
static inline void process_indexed_cmd(struct ctlr_info *h,
u32 raw_tag)
@@ -7860,6 +8287,11 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h)
*/
static int hpsa_ctlr_needs_rescan(struct ctlr_info *h)
{
+ if (h->drv_req_rescan) {
+ h->drv_req_rescan = 0;
+ return 1;
+ }
+
if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
return 0;
@@ -7893,6 +8325,41 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h)
return 0;
}
+static int hpsa_luns_changed(struct ctlr_info *h)
+{
+ int rc = 1; /* assume there are changes */
+ struct ReportLUNdata *logdev = NULL;
+
+ /* if we can't find out if lun data has changed,
+ * assume that it has.
+ */
+
+ if (!h->lastlogicals)
+ goto out;
+
+ logdev = kzalloc(sizeof(*logdev), GFP_KERNEL);
+ if (!logdev) {
+ dev_warn(&h->pdev->dev,
+ "Out of memory, can't track lun changes.\n");
+ goto out;
+ }
+ if (hpsa_scsi_do_report_luns(h, 1, logdev, sizeof(*logdev), 0)) {
+ dev_warn(&h->pdev->dev,
+ "report luns failed, can't track lun changes.\n");
+ goto out;
+ }
+ if (memcmp(logdev, h->lastlogicals, sizeof(*logdev))) {
+ dev_info(&h->pdev->dev,
+ "Lun changes detected.\n");
+ memcpy(h->lastlogicals, logdev, sizeof(*logdev));
+ goto out;
+ } else
+ rc = 0; /* no changes detected. */
+out:
+ kfree(logdev);
+ return rc;
+}
+
static void hpsa_rescan_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
@@ -7908,6 +8375,19 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work)
hpsa_ack_ctlr_events(h);
hpsa_scan_start(h->scsi_host);
scsi_host_put(h->scsi_host);
+ } else if (h->discovery_polling) {
+ hpsa_disable_rld_caching(h);
+ if (hpsa_luns_changed(h)) {
+ struct Scsi_Host *sh = NULL;
+
+ dev_info(&h->pdev->dev,
+ "driver discovery polling rescan.\n");
+ sh = scsi_host_get(h->scsi_host);
+ if (sh != NULL) {
+ hpsa_scan_start(sh);
+ scsi_host_put(sh);
+ }
+ }
}
spin_lock_irqsave(&h->lock, flags);
if (!h->remove_in_progress)
@@ -8148,6 +8628,8 @@ reinit_after_soft_reset:
/* Enable Accelerated IO path at driver layer */
h->acciopath_status = 1;
+ /* Disable discovery polling.*/
+ h->discovery_polling = 0;
/* Turn the interrupts on so we can service requests */
@@ -8155,6 +8637,11 @@ reinit_after_soft_reset:
hpsa_hba_inquiry(h);
+ h->lastlogicals = kzalloc(sizeof(*(h->lastlogicals)), GFP_KERNEL);
+ if (!h->lastlogicals)
+ dev_info(&h->pdev->dev,
+ "Can't track change to report lun data\n");
+
/* Monitor the controller for firmware lockups */
h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker);
@@ -8227,6 +8714,71 @@ out:
kfree(flush_buf);
}
+/* Make controller gather fresh report lun data each time we
+ * send down a report luns request
+ */
+static void hpsa_disable_rld_caching(struct ctlr_info *h)
+{
+ u32 *options;
+ struct CommandList *c;
+ int rc;
+
+ /* Don't bother trying to set diag options if locked up */
+ if (unlikely(h->lockup_detected))
+ return;
+
+ options = kzalloc(sizeof(*options), GFP_KERNEL);
+ if (!options) {
+ dev_err(&h->pdev->dev,
+ "Error: failed to disable rld caching, during alloc.\n");
+ return;
+ }
+
+ c = cmd_alloc(h);
+
+ /* first, get the current diag options settings */
+ if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0,
+ RAID_CTLR_LUNID, TYPE_CMD))
+ goto errout;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if ((rc != 0) || (c->err_info->CommandStatus != 0))
+ goto errout;
+
+ /* Now, set the bit for disabling the RLD caching */
+ *options |= HPSA_DIAG_OPTS_DISABLE_RLD_CACHING;
+
+ if (fill_cmd(c, BMIC_SET_DIAG_OPTIONS, h, options, 4, 0,
+ RAID_CTLR_LUNID, TYPE_CMD))
+ goto errout;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_TODEVICE, NO_TIMEOUT);
+ if ((rc != 0) || (c->err_info->CommandStatus != 0))
+ goto errout;
+
+ /* Now verify that it got set: */
+ if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0,
+ RAID_CTLR_LUNID, TYPE_CMD))
+ goto errout;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if ((rc != 0) || (c->err_info->CommandStatus != 0))
+ goto errout;
+
+ if (*options & HPSA_DIAG_OPTS_DISABLE_RLD_CACHING)
+ goto out;
+
+errout:
+ dev_err(&h->pdev->dev,
+ "Error: failed to disable report lun data caching.\n");
+out:
+ cmd_free(h, c);
+ kfree(options);
+}
+
static void hpsa_shutdown(struct pci_dev *pdev)
{
struct ctlr_info *h;
@@ -8292,6 +8844,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
hpsa_free_performant_mode(h); /* init_one 7 */
hpsa_free_sg_chain_blocks(h); /* init_one 6 */
hpsa_free_cmd_pool(h); /* init_one 5 */
+ kfree(h->lastlogicals);
/* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */
@@ -8304,6 +8857,9 @@ static void hpsa_remove_one(struct pci_dev *pdev)
free_percpu(h->lockup_detected); /* init_one 2 */
h->lockup_detected = NULL; /* init_one 2 */
/* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */
+
+ hpsa_delete_sas_host(h);
+
kfree(h); /* init_one 1 */
}
@@ -8766,18 +9322,369 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h)
} while (1);
}
+static struct hpsa_sas_phy *hpsa_alloc_sas_phy(
+ struct hpsa_sas_port *hpsa_sas_port)
+{
+ struct hpsa_sas_phy *hpsa_sas_phy;
+ struct sas_phy *phy;
+
+ hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL);
+ if (!hpsa_sas_phy)
+ return NULL;
+
+ phy = sas_phy_alloc(hpsa_sas_port->parent_node->parent_dev,
+ hpsa_sas_port->next_phy_index);
+ if (!phy) {
+ kfree(hpsa_sas_phy);
+ return NULL;
+ }
+
+ hpsa_sas_port->next_phy_index++;
+ hpsa_sas_phy->phy = phy;
+ hpsa_sas_phy->parent_port = hpsa_sas_port;
+
+ return hpsa_sas_phy;
+}
+
+static void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy)
+{
+ struct sas_phy *phy = hpsa_sas_phy->phy;
+
+ sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy);
+ sas_phy_free(phy);
+ if (hpsa_sas_phy->added_to_port)
+ list_del(&hpsa_sas_phy->phy_list_entry);
+ kfree(hpsa_sas_phy);
+}
+
+static int hpsa_sas_port_add_phy(struct hpsa_sas_phy *hpsa_sas_phy)
+{
+ int rc;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct sas_phy *phy;
+ struct sas_identify *identify;
+
+ hpsa_sas_port = hpsa_sas_phy->parent_port;
+ phy = hpsa_sas_phy->phy;
+
+ identify = &phy->identify;
+ memset(identify, 0, sizeof(*identify));
+ identify->sas_address = hpsa_sas_port->sas_address;
+ identify->device_type = SAS_END_DEVICE;
+ identify->initiator_port_protocols = SAS_PROTOCOL_STP;
+ identify->target_port_protocols = SAS_PROTOCOL_STP;
+ phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ rc = sas_phy_add(hpsa_sas_phy->phy);
+ if (rc)
+ return rc;
+
+ sas_port_add_phy(hpsa_sas_port->port, hpsa_sas_phy->phy);
+ list_add_tail(&hpsa_sas_phy->phy_list_entry,
+ &hpsa_sas_port->phy_list_head);
+ hpsa_sas_phy->added_to_port = true;
+
+ return 0;
+}
+
+static int
+ hpsa_sas_port_add_rphy(struct hpsa_sas_port *hpsa_sas_port,
+ struct sas_rphy *rphy)
+{
+ struct sas_identify *identify;
+
+ identify = &rphy->identify;
+ identify->sas_address = hpsa_sas_port->sas_address;
+ identify->initiator_port_protocols = SAS_PROTOCOL_STP;
+ identify->target_port_protocols = SAS_PROTOCOL_STP;
+
+ return sas_rphy_add(rphy);
+}
+
+static struct hpsa_sas_port
+ *hpsa_alloc_sas_port(struct hpsa_sas_node *hpsa_sas_node,
+ u64 sas_address)
+{
+ int rc;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct sas_port *port;
+
+ hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL);
+ if (!hpsa_sas_port)
+ return NULL;
+
+ INIT_LIST_HEAD(&hpsa_sas_port->phy_list_head);
+ hpsa_sas_port->parent_node = hpsa_sas_node;
+
+ port = sas_port_alloc_num(hpsa_sas_node->parent_dev);
+ if (!port)
+ goto free_hpsa_port;
+
+ rc = sas_port_add(port);
+ if (rc)
+ goto free_sas_port;
+
+ hpsa_sas_port->port = port;
+ hpsa_sas_port->sas_address = sas_address;
+ list_add_tail(&hpsa_sas_port->port_list_entry,
+ &hpsa_sas_node->port_list_head);
+
+ return hpsa_sas_port;
+
+free_sas_port:
+ sas_port_free(port);
+free_hpsa_port:
+ kfree(hpsa_sas_port);
+
+ return NULL;
+}
+
+static void hpsa_free_sas_port(struct hpsa_sas_port *hpsa_sas_port)
+{
+ struct hpsa_sas_phy *hpsa_sas_phy;
+ struct hpsa_sas_phy *next;
+
+ list_for_each_entry_safe(hpsa_sas_phy, next,
+ &hpsa_sas_port->phy_list_head, phy_list_entry)
+ hpsa_free_sas_phy(hpsa_sas_phy);
+
+ sas_port_delete(hpsa_sas_port->port);
+ list_del(&hpsa_sas_port->port_list_entry);
+ kfree(hpsa_sas_port);
+}
+
+static struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev)
+{
+ struct hpsa_sas_node *hpsa_sas_node;
+
+ hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL);
+ if (hpsa_sas_node) {
+ hpsa_sas_node->parent_dev = parent_dev;
+ INIT_LIST_HEAD(&hpsa_sas_node->port_list_head);
+ }
+
+ return hpsa_sas_node;
+}
+
+static void hpsa_free_sas_node(struct hpsa_sas_node *hpsa_sas_node)
+{
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct hpsa_sas_port *next;
+
+ if (!hpsa_sas_node)
+ return;
+
+ list_for_each_entry_safe(hpsa_sas_port, next,
+ &hpsa_sas_node->port_list_head, port_list_entry)
+ hpsa_free_sas_port(hpsa_sas_port);
+
+ kfree(hpsa_sas_node);
+}
+
+static struct hpsa_scsi_dev_t
+ *hpsa_find_device_by_sas_rphy(struct ctlr_info *h,
+ struct sas_rphy *rphy)
+{
+ int i;
+ struct hpsa_scsi_dev_t *device;
+
+ for (i = 0; i < h->ndevices; i++) {
+ device = h->dev[i];
+ if (!device->sas_port)
+ continue;
+ if (device->sas_port->rphy == rphy)
+ return device;
+ }
+
+ return NULL;
+}
+
+static int hpsa_add_sas_host(struct ctlr_info *h)
+{
+ int rc;
+ struct device *parent_dev;
+ struct hpsa_sas_node *hpsa_sas_node;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct hpsa_sas_phy *hpsa_sas_phy;
+
+ parent_dev = &h->scsi_host->shost_gendev;
+
+ hpsa_sas_node = hpsa_alloc_sas_node(parent_dev);
+ if (!hpsa_sas_node)
+ return -ENOMEM;
+
+ hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, h->sas_address);
+ if (!hpsa_sas_port) {
+ rc = -ENODEV;
+ goto free_sas_node;
+ }
+
+ hpsa_sas_phy = hpsa_alloc_sas_phy(hpsa_sas_port);
+ if (!hpsa_sas_phy) {
+ rc = -ENODEV;
+ goto free_sas_port;
+ }
+
+ rc = hpsa_sas_port_add_phy(hpsa_sas_phy);
+ if (rc)
+ goto free_sas_phy;
+
+ h->sas_host = hpsa_sas_node;
+
+ return 0;
+
+free_sas_phy:
+ hpsa_free_sas_phy(hpsa_sas_phy);
+free_sas_port:
+ hpsa_free_sas_port(hpsa_sas_port);
+free_sas_node:
+ hpsa_free_sas_node(hpsa_sas_node);
+
+ return rc;
+}
+
+static void hpsa_delete_sas_host(struct ctlr_info *h)
+{
+ hpsa_free_sas_node(h->sas_host);
+}
+
+static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node,
+ struct hpsa_scsi_dev_t *device)
+{
+ int rc;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct sas_rphy *rphy;
+
+ hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, device->sas_address);
+ if (!hpsa_sas_port)
+ return -ENOMEM;
+
+ rphy = sas_end_device_alloc(hpsa_sas_port->port);
+ if (!rphy) {
+ rc = -ENODEV;
+ goto free_sas_port;
+ }
+
+ hpsa_sas_port->rphy = rphy;
+ device->sas_port = hpsa_sas_port;
+
+ rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy);
+ if (rc)
+ goto free_sas_port;
+
+ return 0;
+
+free_sas_port:
+ hpsa_free_sas_port(hpsa_sas_port);
+ device->sas_port = NULL;
+
+ return rc;
+}
+
+static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device)
+{
+ if (device->sas_port) {
+ hpsa_free_sas_port(device->sas_port);
+ device->sas_port = NULL;
+ }
+}
+
+static int
+hpsa_sas_get_linkerrors(struct sas_phy *phy)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_get_bay_identifier(struct sas_rphy *rphy)
+{
+ return -ENXIO;
+}
+
+static int
+hpsa_sas_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_phy_enable(struct sas_phy *phy, int enable)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_phy_setup(struct sas_phy *phy)
+{
+ return 0;
+}
+
+static void
+hpsa_sas_phy_release(struct sas_phy *phy)
+{
+}
+
+static int
+hpsa_sas_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
+{
+ return -EINVAL;
+}
+
+/* SMP = Serial Management Protocol */
+static int
+hpsa_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+struct request *req)
+{
+ return -EINVAL;
+}
+
+static struct sas_function_template hpsa_sas_transport_functions = {
+ .get_linkerrors = hpsa_sas_get_linkerrors,
+ .get_enclosure_identifier = hpsa_sas_get_enclosure_identifier,
+ .get_bay_identifier = hpsa_sas_get_bay_identifier,
+ .phy_reset = hpsa_sas_phy_reset,
+ .phy_enable = hpsa_sas_phy_enable,
+ .phy_setup = hpsa_sas_phy_setup,
+ .phy_release = hpsa_sas_phy_release,
+ .set_phy_speed = hpsa_sas_phy_speed,
+ .smp_handler = hpsa_sas_smp_handler,
+};
+
/*
* This is it. Register the PCI driver information for the cards we control
* the OS will call our registered routines when it finds one of our cards.
*/
static int __init hpsa_init(void)
{
- return pci_register_driver(&hpsa_pci_driver);
+ int rc;
+
+ hpsa_sas_transport_template =
+ sas_attach_transport(&hpsa_sas_transport_functions);
+ if (!hpsa_sas_transport_template)
+ return -ENODEV;
+
+ rc = pci_register_driver(&hpsa_pci_driver);
+
+ if (rc)
+ sas_release_transport(hpsa_sas_transport_template);
+
+ return rc;
}
static void __exit hpsa_cleanup(void)
{
pci_unregister_driver(&hpsa_pci_driver);
+ sas_release_transport(hpsa_sas_transport_template);
}
static void __attribute__((unused)) verify_offsets(void)
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 27debb3..d06bb74 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -1,5 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2016 Microsemi Corporation
* Copyright 2014-2015 PMC-Sierra, Inc.
* Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
*
@@ -12,7 +13,7 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more details.
*
- * Questions/Comments/Bugfixes to storagedev@pmcs.com
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
*
*/
#ifndef HPSA_H
@@ -33,12 +34,38 @@ struct access_method {
unsigned long (*command_completed)(struct ctlr_info *h, u8 q);
};
+/* for SAS hosts and SAS expanders */
+struct hpsa_sas_node {
+ struct device *parent_dev;
+ struct list_head port_list_head;
+};
+
+struct hpsa_sas_port {
+ struct list_head port_list_entry;
+ u64 sas_address;
+ struct sas_port *port;
+ int next_phy_index;
+ struct list_head phy_list_head;
+ struct hpsa_sas_node *parent_node;
+ struct sas_rphy *rphy;
+};
+
+struct hpsa_sas_phy {
+ struct list_head phy_list_entry;
+ struct sas_phy *phy;
+ struct hpsa_sas_port *parent_port;
+ bool added_to_port;
+};
+
struct hpsa_scsi_dev_t {
- int devtype;
+ unsigned int devtype;
int bus, target, lun; /* as presented to the OS */
unsigned char scsi3addr[8]; /* as presented to the HW */
+ u8 physical_device : 1;
+ u8 expose_device;
#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
unsigned char device_id[16]; /* from inquiry pg. 0x83 */
+ u64 sas_address;
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
@@ -75,11 +102,8 @@ struct hpsa_scsi_dev_t {
struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES];
int nphysical_disks;
int supports_aborts;
-#define HPSA_DO_NOT_EXPOSE 0x0
-#define HPSA_SG_ATTACH 0x1
-#define HPSA_ULD_ATTACH 0x2
-#define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH)
- u8 expose_state;
+ struct hpsa_sas_port *sas_port;
+ int external; /* 1-from external array 0-not <0-unknown */
};
struct reply_queue_buffer {
@@ -136,6 +160,7 @@ struct ctlr_info {
char *product_name;
struct pci_dev *pdev;
u32 board_id;
+ u64 sas_address;
void __iomem *vaddr;
unsigned long paddr;
int nr_cmds; /* Number of commands allowed on this controller */
@@ -262,7 +287,10 @@ struct ctlr_info {
spinlock_t offline_device_lock;
struct list_head offline_device_list;
int acciopath_status;
+ int drv_req_rescan;
int raid_offload_debug;
+ int discovery_polling;
+ struct ReportLUNdata *lastlogicals;
int needs_abort_tags_swizzled;
struct workqueue_struct *resubmit_wq;
struct workqueue_struct *rescan_ctlr_wq;
@@ -270,6 +298,8 @@ struct ctlr_info {
wait_queue_head_t abort_cmd_wait_queue;
wait_queue_head_t event_sync_wait_queue;
struct mutex reset_mutex;
+ u8 reset_in_progress;
+ struct hpsa_sas_node *sas_host;
};
struct offline_device_entry {
@@ -283,6 +313,7 @@ struct offline_device_entry {
#define HPSA_RESET_TYPE_BUS 0x01
#define HPSA_RESET_TYPE_TARGET 0x03
#define HPSA_RESET_TYPE_LUN 0x04
+#define HPSA_PHYS_TARGET_RESET 0x99 /* not defined by cciss spec */
#define HPSA_MSG_SEND_RETRY_LIMIT 10
#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000)
@@ -367,6 +398,11 @@ struct offline_device_entry {
#define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0
#define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4
+#define HPSA_PHYSICAL_DEVICE_BUS 0
+#define HPSA_RAID_VOLUME_BUS 1
+#define HPSA_EXTERNAL_RAID_VOLUME_BUS 2
+#define HPSA_HBA_BUS 0
+
/*
Send the command to the hardware
*/
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 47c756b..a5be153 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -1,5 +1,6 @@
/*
* Disk Array driver for HP Smart Array SAS controllers
+ * Copyright 2016 Microsemi Corporation
* Copyright 2014-2015 PMC-Sierra, Inc.
* Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
*
@@ -12,7 +13,7 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more details.
*
- * Questions/Comments/Bugfixes to storagedev@pmcs.com
+ * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
*
*/
#ifndef HPSA_CMD_H
@@ -260,8 +261,6 @@ struct ext_report_lun_entry {
u8 wwid[8];
u8 device_type;
u8 device_flags;
-#define NON_DISK_PHYS_DEV(x) ((x)[17] & 0x01)
-#define PHYS_IOACCEL(x) ((x)[17] & 0x08)
u8 lun_count; /* multi-lun device, how many luns */
u8 redundant_paths;
u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */
@@ -288,6 +287,12 @@ struct SenseSubsystem_info {
#define BMIC_FLASH_FIRMWARE 0xF7
#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15
+#define BMIC_IDENTIFY_CONTROLLER 0x11
+#define BMIC_SET_DIAG_OPTIONS 0xF4
+#define BMIC_SENSE_DIAG_OPTIONS 0xF5
+#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x80000000
+#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66
+#define BMIC_SENSE_STORAGE_BOX_PARAMS 0x65
/* Command List Structure */
union SCSI3Addr {
@@ -684,6 +689,16 @@ struct hpsa_pci_info {
u32 board_id;
};
+struct bmic_identify_controller {
+ u8 configured_logical_drive_count; /* offset 0 */
+ u8 pad1[153];
+ __le16 extended_logical_unit_count; /* offset 154 */
+ u8 pad2[136];
+ u8 controller_mode; /* offset 292 */
+ u8 pad3[32];
+};
+
+
struct bmic_identify_physical_device {
u8 scsi_bus; /* SCSI Bus number on controller */
u8 scsi_id; /* SCSI ID on this bus */
@@ -816,5 +831,30 @@ struct bmic_identify_physical_device {
u8 padding[112];
};
+struct bmic_sense_subsystem_info {
+ u8 primary_slot_number;
+ u8 reserved[3];
+ u8 chasis_serial_number[32];
+ u8 primary_world_wide_id[8];
+ u8 primary_array_serial_number[32]; /* NULL terminated */
+ u8 primary_cache_serial_number[32]; /* NULL terminated */
+ u8 reserved_2[8];
+ u8 secondary_array_serial_number[32];
+ u8 secondary_cache_serial_number[32];
+ u8 pad[332];
+};
+
+struct bmic_sense_storage_box_params {
+ u8 reserved[36];
+ u8 inquiry_valid;
+ u8 reserved_1[68];
+ u8 phys_box_on_port;
+ u8 reserved_2[22];
+ u16 connection_info;
+ u8 reserver_3[84];
+ u8 phys_connector[2];
+ u8 reserved_4[296];
+};
+
#pragma pack()
#endif /* HPSA_CMD_H */
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 057d277..fc523c3 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -2636,7 +2636,8 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
struct ibmvfc_target *tgt;
ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, wwpn: %llx,"
- " node_name: %llx%s\n", desc->desc, crq->scsi_id, crq->wwpn, crq->node_name,
+ " node_name: %llx%s\n", desc->desc, be64_to_cpu(crq->scsi_id),
+ be64_to_cpu(crq->wwpn), be64_to_cpu(crq->node_name),
ibmvfc_get_link_state(crq->link_state));
switch (be64_to_cpu(crq->event)) {
@@ -3095,7 +3096,6 @@ static struct scsi_host_template driver_template = {
.max_sectors = IBMVFC_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = ibmvfc_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 6a41c36..d9534ee 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -106,9 +106,9 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(IBMVSCSI_VERSION);
module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_id, "Largest ID value for each channel");
+MODULE_PARM_DESC(max_id, "Largest ID value for each channel [Default=64]");
module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_channel, "Largest channel value");
+MODULE_PARM_DESC(max_channel, "Largest channel value [Default=3]");
module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
module_param_named(max_requests, max_requests, int, S_IRUGO);
@@ -182,7 +182,7 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
spin_lock_irqsave(&queue->lock, flags);
crq = &queue->msgs[queue->cur];
- if (crq->valid & 0x80) {
+ if (crq->valid != VIOSRP_CRQ_FREE) {
if (++queue->cur == queue->size)
queue->cur = 0;
@@ -231,7 +231,7 @@ static void ibmvscsi_task(void *data)
/* Pull all the valid messages off the CRQ */
while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
ibmvscsi_handle_crq(crq, hostdata);
- crq->valid = 0x00;
+ crq->valid = VIOSRP_CRQ_FREE;
}
vio_enable_interrupts(vdev);
@@ -239,7 +239,7 @@ static void ibmvscsi_task(void *data)
if (crq != NULL) {
vio_disable_interrupts(vdev);
ibmvscsi_handle_crq(crq, hostdata);
- crq->valid = 0x00;
+ crq->valid = VIOSRP_CRQ_FREE;
} else {
done = 1;
}
@@ -248,25 +248,23 @@ static void ibmvscsi_task(void *data)
static void gather_partition_info(void)
{
- struct device_node *rootdn;
-
const char *ppartition_name;
const __be32 *p_number_ptr;
/* Retrieve information about this partition */
- rootdn = of_find_node_by_path("/");
- if (!rootdn) {
+ if (!of_root)
return;
- }
- ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL);
+ of_node_get(of_root);
+
+ ppartition_name = of_get_property(of_root, "ibm,partition-name", NULL);
if (ppartition_name)
strncpy(partition_name, ppartition_name,
sizeof(partition_name));
- p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL);
+ p_number_ptr = of_get_property(of_root, "ibm,partition-no", NULL);
if (p_number_ptr)
partition_number = of_read_number(p_number_ptr, 1);
- of_node_put(rootdn);
+ of_node_put(of_root);
}
static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
@@ -283,8 +281,8 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
hostdata->madapter_info.partition_number =
cpu_to_be32(partition_number);
- hostdata->madapter_info.mad_version = cpu_to_be32(1);
- hostdata->madapter_info.os_type = cpu_to_be32(2);
+ hostdata->madapter_info.mad_version = cpu_to_be32(SRP_MAD_VERSION_1);
+ hostdata->madapter_info.os_type = cpu_to_be32(SRP_MAD_OS_LINUX);
}
/**
@@ -316,7 +314,7 @@ static int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
rc = plpar_hcall_norets(H_REG_CRQ,
vdev->unit_address,
queue->msg_token, PAGE_SIZE);
- if (rc == 2) {
+ if (rc == H_CLOSED) {
/* Adapter is good, but other end is not ready */
dev_warn(hostdata->dev, "Partner adapter not ready\n");
} else if (rc != 0) {
@@ -366,7 +364,7 @@ static int ibmvscsi_init_crq_queue(struct crq_queue *queue,
rc = ibmvscsi_reset_crq_queue(queue,
hostdata);
- if (rc == 2) {
+ if (rc == H_CLOSED) {
/* Adapter is good, but other end is not ready */
dev_warn(hostdata->dev, "Partner adapter not ready\n");
retrc = 0;
@@ -474,7 +472,7 @@ static int initialize_event_pool(struct event_pool *pool,
struct srp_event_struct *evt = &pool->events[i];
memset(&evt->crq, 0x00, sizeof(evt->crq));
atomic_set(&evt->free, 1);
- evt->crq.valid = 0x80;
+ evt->crq.valid = VIOSRP_CRQ_CMD_RSP;
evt->crq.IU_length = cpu_to_be16(sizeof(*evt->xfer_iu));
evt->crq.IU_data_ptr = cpu_to_be64(pool->iu_token +
sizeof(*evt->xfer_iu) * i);
@@ -1398,7 +1396,7 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
hostdata->host->max_sectors =
be32_to_cpu(hostdata->madapter_info.port_max_txu[0]) >> 9;
- if (be32_to_cpu(hostdata->madapter_info.os_type) == 3 &&
+ if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX &&
strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
hostdata->madapter_info.srp_version);
@@ -1407,7 +1405,7 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
}
- if (be32_to_cpu(hostdata->madapter_info.os_type) == 3) {
+ if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX) {
enable_fast_fail(hostdata);
return;
}
@@ -1767,9 +1765,9 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
struct srp_event_struct *evt_struct =
(__force struct srp_event_struct *)crq->IU_data_ptr;
switch (crq->valid) {
- case 0xC0: /* initialization */
+ case VIOSRP_CRQ_INIT_RSP: /* initialization */
switch (crq->format) {
- case 0x01: /* Initialization message */
+ case VIOSRP_CRQ_INIT: /* Initialization message */
dev_info(hostdata->dev, "partner initialized\n");
/* Send back a response */
rc = ibmvscsi_send_crq(hostdata, 0xC002000000000000LL, 0);
@@ -1781,7 +1779,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
}
break;
- case 0x02: /* Initialization response */
+ case VIOSRP_CRQ_INIT_COMPLETE: /* Initialization response */
dev_info(hostdata->dev, "partner initialization complete\n");
/* Now login */
@@ -1791,7 +1789,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
}
return;
- case 0xFF: /* Hypervisor telling us the connection is closed */
+ case VIOSRP_CRQ_XPORT_EVENT: /* Hypervisor telling us the connection is closed */
scsi_block_requests(hostdata->host);
atomic_set(&hostdata->request_limit, 0);
if (crq->format == 0x06) {
@@ -1807,7 +1805,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
ibmvscsi_reset_host(hostdata);
}
return;
- case 0x80: /* real payload */
+ case VIOSRP_CRQ_CMD_RSP: /* real payload */
break;
default:
dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
@@ -1855,62 +1853,6 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
}
/**
- * ibmvscsi_get_host_config: Send the command to the server to get host
- * configuration data. The data is opaque to us.
- */
-static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
- unsigned char *buffer, int length)
-{
- struct viosrp_host_config *host_config;
- struct srp_event_struct *evt_struct;
- unsigned long flags;
- dma_addr_t addr;
- int rc;
-
- evt_struct = get_event_struct(&hostdata->pool);
- if (!evt_struct) {
- dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n");
- return -1;
- }
-
- init_event_struct(evt_struct,
- sync_completion,
- VIOSRP_MAD_FORMAT,
- info_timeout);
-
- host_config = &evt_struct->iu.mad.host_config;
-
- /* The transport length field is only 16-bit */
- length = min(0xffff, length);
-
- /* Set up a lun reset SRP command */
- memset(host_config, 0x00, sizeof(*host_config));
- host_config->common.type = cpu_to_be32(VIOSRP_HOST_CONFIG_TYPE);
- host_config->common.length = cpu_to_be16(length);
- addr = dma_map_single(hostdata->dev, buffer, length, DMA_BIDIRECTIONAL);
-
- if (dma_mapping_error(hostdata->dev, addr)) {
- if (!firmware_has_feature(FW_FEATURE_CMO))
- dev_err(hostdata->dev,
- "dma_mapping error getting host config\n");
- free_event_struct(&hostdata->pool, evt_struct);
- return -1;
- }
-
- host_config->buffer = cpu_to_be64(addr);
-
- init_completion(&evt_struct->comp);
- spin_lock_irqsave(hostdata->host->host_lock, flags);
- rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
- spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- if (rc == 0)
- wait_for_completion(&evt_struct->comp);
- dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
-
- return rc;
-}
-
-/**
* ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
* @sdev: struct scsi_device device to configure
*
@@ -2041,7 +1983,7 @@ static ssize_t show_host_partition_number(struct device *dev,
int len;
len = snprintf(buf, PAGE_SIZE, "%d\n",
- hostdata->madapter_info.partition_number);
+ be32_to_cpu(hostdata->madapter_info.partition_number));
return len;
}
@@ -2061,7 +2003,7 @@ static ssize_t show_host_mad_version(struct device *dev,
int len;
len = snprintf(buf, PAGE_SIZE, "%d\n",
- hostdata->madapter_info.mad_version);
+ be32_to_cpu(hostdata->madapter_info.mad_version));
return len;
}
@@ -2080,7 +2022,8 @@ static ssize_t show_host_os_type(struct device *dev,
struct ibmvscsi_host_data *hostdata = shost_priv(shost);
int len;
- len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
+ len = snprintf(buf, PAGE_SIZE, "%d\n",
+ be32_to_cpu(hostdata->madapter_info.os_type));
return len;
}
@@ -2095,21 +2038,14 @@ static struct device_attribute ibmvscsi_host_os_type = {
static ssize_t show_host_config(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ibmvscsi_host_data *hostdata = shost_priv(shost);
-
- /* returns null-terminated host config data */
- if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
- return strlen(buf);
- else
- return 0;
+ return 0;
}
static struct device_attribute ibmvscsi_host_config = {
.attr = {
- .name = "config",
- .mode = S_IRUGO,
- },
+ .name = "config",
+ .mode = S_IRUGO,
+ },
.show = show_host_config,
};
@@ -2289,11 +2225,15 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto init_pool_failed;
}
- host->max_lun = 8;
+ host->max_lun = IBMVSCSI_MAX_LUN;
host->max_id = max_id;
host->max_channel = max_channel;
host->max_cmd_len = 16;
+ dev_info(dev,
+ "Maximum ID: %d Maximum LUN: %llu Maximum Channel: %d\n",
+ host->max_id, host->max_lun, host->max_channel);
+
if (scsi_add_host(hostdata->host, hostdata->dev))
goto add_host_failed;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 7d64867..1067367 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -48,6 +48,7 @@ struct Scsi_Host;
#define IBMVSCSI_CMDS_PER_LUN_DEFAULT 16
#define IBMVSCSI_MAX_SECTORS_DEFAULT 256 /* 32 * 8 = default max I/O 32 pages */
#define IBMVSCSI_MAX_CMDS_PER_LUN 64
+#define IBMVSCSI_MAX_LUN 32
/* ------------------------------------------------------------
* Data Structures
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
index 1162430..c1ab8a4 100644
--- a/drivers/scsi/ibmvscsi/viosrp.h
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -51,13 +51,25 @@ union srp_iu {
u8 reserved[SRP_MAX_IU_LEN];
};
+enum viosrp_crq_headers {
+ VIOSRP_CRQ_FREE = 0x00,
+ VIOSRP_CRQ_CMD_RSP = 0x80,
+ VIOSRP_CRQ_INIT_RSP = 0xC0,
+ VIOSRP_CRQ_XPORT_EVENT = 0xFF
+};
+
+enum viosrp_crq_init_formats {
+ VIOSRP_CRQ_INIT = 0x01,
+ VIOSRP_CRQ_INIT_COMPLETE = 0x02
+};
+
enum viosrp_crq_formats {
VIOSRP_SRP_FORMAT = 0x01,
VIOSRP_MAD_FORMAT = 0x02,
VIOSRP_OS400_FORMAT = 0x03,
VIOSRP_AIX_FORMAT = 0x04,
- VIOSRP_LINUX_FORMAT = 0x06,
- VIOSRP_INLINE_FORMAT = 0x07
+ VIOSRP_LINUX_FORMAT = 0x05,
+ VIOSRP_INLINE_FORMAT = 0x06
};
enum viosrp_crq_status {
@@ -87,7 +99,6 @@ enum viosrp_mad_types {
VIOSRP_EMPTY_IU_TYPE = 0x01,
VIOSRP_ERROR_LOG_TYPE = 0x02,
VIOSRP_ADAPTER_INFO_TYPE = 0x03,
- VIOSRP_HOST_CONFIG_TYPE = 0x04,
VIOSRP_CAPABILITIES_TYPE = 0x05,
VIOSRP_ENABLE_FAST_FAIL = 0x08,
};
@@ -153,11 +164,6 @@ struct viosrp_adapter_info {
__be64 buffer;
};
-struct viosrp_host_config {
- struct mad_common common;
- __be64 buffer;
-};
-
struct viosrp_fast_fail {
struct mad_common common;
};
@@ -195,7 +201,6 @@ union mad_iu {
struct viosrp_empty_iu empty_iu;
struct viosrp_error_log error_log;
struct viosrp_adapter_info adapter_info;
- struct viosrp_host_config host_config;
struct viosrp_fast_fail fast_fail;
struct viosrp_capabilities capabilities;
};
@@ -209,7 +214,10 @@ struct mad_adapter_info_data {
char srp_version[8];
char partition_name[96];
__be32 partition_number;
+#define SRP_MAD_VERSION_1 1
__be32 mad_version;
+#define SRP_MAD_OS_LINUX 2
+#define SRP_MAD_OS_AIX 3
__be32 os_type;
__be32 port_max_txu[8]; /* per-port maximum transfer */
};
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 4e1a632..9164ce12 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -43,6 +43,7 @@ typedef struct {
unsigned dp:1; /* Data phase present */
unsigned rd:1; /* Read data in data phase */
unsigned wanted:1; /* Parport sharing busy flag */
+ unsigned int dev_no; /* Device number */
wait_queue_head_t *waiting;
struct Scsi_Host *host;
struct list_head list;
@@ -76,9 +77,10 @@ static void imm_wakeup(void *ref)
spin_lock_irqsave(&arbitration_lock, flags);
if (dev->wanted) {
- parport_claim(dev->dev);
- got_it(dev);
- dev->wanted = 0;
+ if (parport_claim(dev->dev) == 0) {
+ got_it(dev);
+ dev->wanted = 0;
+ }
}
spin_unlock_irqrestore(&arbitration_lock, flags);
}
@@ -1120,15 +1122,40 @@ static struct scsi_host_template imm_template = {
static LIST_HEAD(imm_hosts);
+/*
+ * Finds the first available device number that can be alloted to the
+ * new imm device and returns the address of the previous node so that
+ * we can add to the tail and have a list in the ascending order.
+ */
+
+static inline imm_struct *find_parent(void)
+{
+ imm_struct *dev, *par = NULL;
+ unsigned int cnt = 0;
+
+ if (list_empty(&imm_hosts))
+ return NULL;
+
+ list_for_each_entry(dev, &imm_hosts, list) {
+ if (dev->dev_no != cnt)
+ return par;
+ cnt++;
+ par = dev;
+ }
+
+ return par;
+}
+
static int __imm_attach(struct parport *pb)
{
struct Scsi_Host *host;
- imm_struct *dev;
+ imm_struct *dev, *temp;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
DEFINE_WAIT(wait);
int ports;
int modes, ppb;
int err = -ENOMEM;
+ struct pardev_cb imm_cb;
init_waitqueue_head(&waiting);
@@ -1141,9 +1168,15 @@ static int __imm_attach(struct parport *pb)
dev->mode = IMM_AUTODETECT;
INIT_LIST_HEAD(&dev->list);
- dev->dev = parport_register_device(pb, "imm", NULL, imm_wakeup,
- NULL, 0, dev);
+ temp = find_parent();
+ if (temp)
+ dev->dev_no = temp->dev_no + 1;
+ memset(&imm_cb, 0, sizeof(imm_cb));
+ imm_cb.private = dev;
+ imm_cb.wakeup = imm_wakeup;
+
+ dev->dev = parport_register_dev_model(pb, "imm", &imm_cb, dev->dev_no);
if (!dev->dev)
goto out;
@@ -1207,7 +1240,10 @@ static int __imm_attach(struct parport *pb)
host->unique_id = pb->number;
*(imm_struct **)&host->hostdata = dev;
dev->host = host;
- list_add_tail(&dev->list, &imm_hosts);
+ if (!temp)
+ list_add_tail(&dev->list, &imm_hosts);
+ else
+ list_add_tail(&dev->list, &temp->list);
err = scsi_add_host(host, NULL);
if (err)
goto out2;
@@ -1245,9 +1281,10 @@ static void imm_detach(struct parport *pb)
}
static struct parport_driver imm_driver = {
- .name = "imm",
- .attach = imm_attach,
- .detach = imm_detach,
+ .name = "imm",
+ .match_port = imm_attach,
+ .detach = imm_detach,
+ .devmodel = true,
};
static int __init imm_driver_init(void)
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 6a926ba..7a91cf3 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -110,11 +110,6 @@
#define i91u_MAXQUEUE 2
#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
-#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */
-#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */
-#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */
-#define I920_DEVICE_ID 0x0002 /* Initio's other product ID */
-
#ifdef DEBUG_i91u
static unsigned int i91u_debug = DEBUG_DEFAULT;
#endif
@@ -127,17 +122,6 @@ static int setup_debug = 0;
static void i91uSCBPost(u8 * pHcb, u8 * pScb);
-/* PCI Devices supported by this driver */
-static struct pci_device_id i91u_pci_devices[] = {
- { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { }
-};
-MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
-
#define DEBUG_INTERRUPT 0
#define DEBUG_QUEUE 0
#define DEBUG_STATE 0
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b62836d..d6a691e 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3638,7 +3638,7 @@ static struct device_attribute ipr_ioa_reset_attr = {
.store = ipr_store_reset_adapter
};
-static int ipr_iopoll(struct blk_iopoll *iop, int budget);
+static int ipr_iopoll(struct irq_poll *iop, int budget);
/**
* ipr_show_iopoll_weight - Show ipr polling mode
* @dev: class device struct
@@ -3681,34 +3681,33 @@ static ssize_t ipr_store_iopoll_weight(struct device *dev,
int i;
if (!ioa_cfg->sis64) {
- dev_info(&ioa_cfg->pdev->dev, "blk-iopoll not supported on this adapter\n");
+ dev_info(&ioa_cfg->pdev->dev, "irq_poll not supported on this adapter\n");
return -EINVAL;
}
if (kstrtoul(buf, 10, &user_iopoll_weight))
return -EINVAL;
if (user_iopoll_weight > 256) {
- dev_info(&ioa_cfg->pdev->dev, "Invalid blk-iopoll weight. It must be less than 256\n");
+ dev_info(&ioa_cfg->pdev->dev, "Invalid irq_poll weight. It must be less than 256\n");
return -EINVAL;
}
if (user_iopoll_weight == ioa_cfg->iopoll_weight) {
- dev_info(&ioa_cfg->pdev->dev, "Current blk-iopoll weight has the same weight\n");
+ dev_info(&ioa_cfg->pdev->dev, "Current irq_poll weight has the same weight\n");
return strlen(buf);
}
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++)
- blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
+ irq_poll_disable(&ioa_cfg->hrrq[i].iopoll);
}
spin_lock_irqsave(shost->host_lock, lock_flags);
ioa_cfg->iopoll_weight = user_iopoll_weight;
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
- blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
+ irq_poll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
- blk_iopoll_enable(&ioa_cfg->hrrq[i].iopoll);
}
}
spin_unlock_irqrestore(shost->host_lock, lock_flags);
@@ -4003,13 +4002,17 @@ static ssize_t ipr_store_update_fw(struct device *dev,
struct ipr_sglist *sglist;
char fname[100];
char *src;
- int len, result, dnld_size;
+ char *endline;
+ int result, dnld_size;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- len = snprintf(fname, 99, "%s", buf);
- fname[len-1] = '\0';
+ snprintf(fname, sizeof(fname), "%s", buf);
+
+ endline = strchr(fname, '\n');
+ if (endline)
+ *endline = '\0';
if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
@@ -5569,7 +5572,7 @@ static int ipr_process_hrrq(struct ipr_hrr_queue *hrr_queue, int budget,
return num_hrrq;
}
-static int ipr_iopoll(struct blk_iopoll *iop, int budget)
+static int ipr_iopoll(struct irq_poll *iop, int budget)
{
struct ipr_ioa_cfg *ioa_cfg;
struct ipr_hrr_queue *hrrq;
@@ -5585,7 +5588,7 @@ static int ipr_iopoll(struct blk_iopoll *iop, int budget)
completed_ops = ipr_process_hrrq(hrrq, budget, &doneq);
if (completed_ops < budget)
- blk_iopoll_complete(iop);
+ irq_poll_complete(iop);
spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) {
@@ -5693,8 +5696,7 @@ static irqreturn_t ipr_isr_mhrrq(int irq, void *devp)
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
if ((be32_to_cpu(*hrrq->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) ==
hrrq->toggle_bit) {
- if (!blk_iopoll_sched_prep(&hrrq->iopoll))
- blk_iopoll_sched(&hrrq->iopoll);
+ irq_poll_sched(&hrrq->iopoll);
spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
return IRQ_HANDLED;
}
@@ -6363,15 +6365,19 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
ipr_cmd->scsi_cmd = scsi_cmd;
ipr_cmd->done = ipr_scsi_eh_done;
- if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
+ if (ipr_is_gscsi(res)) {
if (scsi_cmd->underflow == 0)
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
- ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
- if (ipr_is_gscsi(res) && res->reset_occurred) {
+ if (res->reset_occurred) {
res->reset_occurred = 0;
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
}
+ }
+
+ if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
+
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
if (scsi_cmd->flags & SCMD_TAGGED)
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_SIMPLE_TASK;
@@ -6502,7 +6508,6 @@ static struct scsi_host_template driver_template = {
.shost_attrs = ipr_ioa_attrs,
.sdev_attrs = ipr_dev_attrs,
.proc_name = IPR_NAME,
- .use_blk_tags = 1,
};
/**
@@ -7671,6 +7676,63 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
return IPR_RC_JOB_RETURN;
}
+static int ipr_ioa_service_action_failed(struct ipr_cmnd *ipr_cmd)
+{
+ u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
+
+ if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT)
+ return IPR_RC_JOB_CONTINUE;
+
+ return ipr_reset_cmd_failed(ipr_cmd);
+}
+
+static void ipr_build_ioa_service_action(struct ipr_cmnd *ipr_cmd,
+ __be32 res_handle, u8 sa_code)
+{
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+
+ ioarcb->res_handle = res_handle;
+ ioarcb->cmd_pkt.cdb[0] = IPR_IOA_SERVICE_ACTION;
+ ioarcb->cmd_pkt.cdb[1] = sa_code;
+ ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+}
+
+/**
+ * ipr_ioafp_set_caching_parameters - Issue Set Cache parameters service
+ * action
+ *
+ * Return value:
+ * none
+ **/
+static int ipr_ioafp_set_caching_parameters(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data;
+
+ ENTER;
+
+ ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+
+ if (pageC4->cache_cap[0] & IPR_CAP_SYNC_CACHE) {
+ ipr_build_ioa_service_action(ipr_cmd,
+ cpu_to_be32(IPR_IOA_RES_HANDLE),
+ IPR_IOA_SA_CHANGE_CACHE_PARAMS);
+
+ ioarcb->cmd_pkt.cdb[2] = 0x40;
+
+ ipr_cmd->job_step_failed = ipr_ioa_service_action_failed;
+ ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
+ IPR_SET_SUP_DEVICE_TIMEOUT);
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+ }
+
+ LEAVE;
+ return IPR_RC_JOB_CONTINUE;
+}
+
/**
* ipr_ioafp_inquiry - Send an Inquiry to the adapter.
* @ipr_cmd: ipr command struct
@@ -7722,6 +7784,39 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page)
}
/**
+ * ipr_ioafp_pageC4_inquiry - Send a Page 0xC4 Inquiry to the adapter.
+ * @ipr_cmd: ipr command struct
+ *
+ * This function sends a Page 0xC4 inquiry to the adapter
+ * to retrieve software VPD information.
+ *
+ * Return value:
+ * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_pageC4_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
+ struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data;
+
+ ENTER;
+ ipr_cmd->job_step = ipr_ioafp_set_caching_parameters;
+ memset(pageC4, 0, sizeof(*pageC4));
+
+ if (ipr_inquiry_page_supported(page0, 0xC4)) {
+ ipr_ioafp_inquiry(ipr_cmd, 1, 0xC4,
+ (ioa_cfg->vpd_cbs_dma
+ + offsetof(struct ipr_misc_cbs,
+ pageC4_data)),
+ sizeof(struct ipr_inquiry_pageC4));
+ return IPR_RC_JOB_RETURN;
+ }
+
+ LEAVE;
+ return IPR_RC_JOB_CONTINUE;
+}
+
+/**
* ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter.
* @ipr_cmd: ipr command struct
*
@@ -7738,7 +7833,7 @@ static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd)
struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
ENTER;
- ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+ ipr_cmd->job_step = ipr_ioafp_pageC4_inquiry;
memset(cap, 0, sizeof(*cap));
if (ipr_inquiry_page_supported(page0, 0xD0)) {
@@ -8277,6 +8372,42 @@ static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd)
return IPR_RC_JOB_RETURN;
}
+static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+ ENTER;
+
+ if (ioa_cfg->sdt_state != GET_DUMP)
+ return IPR_RC_JOB_RETURN;
+
+ if (!ioa_cfg->sis64 || !ipr_cmd->u.time_left ||
+ (readl(ioa_cfg->regs.sense_interrupt_reg) &
+ IPR_PCII_MAILBOX_STABLE)) {
+
+ if (!ipr_cmd->u.time_left)
+ dev_err(&ioa_cfg->pdev->dev,
+ "Timed out waiting for Mailbox register.\n");
+
+ ioa_cfg->sdt_state = READ_DUMP;
+ ioa_cfg->dump_timeout = 0;
+ if (ioa_cfg->sis64)
+ ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT);
+ else
+ ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT);
+ ipr_cmd->job_step = ipr_reset_wait_for_dump;
+ schedule_work(&ioa_cfg->work_q);
+
+ } else {
+ ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
+ ipr_reset_start_timer(ipr_cmd,
+ IPR_CHECK_FOR_RESET_TIMEOUT);
+ }
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
/**
* ipr_reset_restore_cfg_space - Restore PCI config space.
* @ipr_cmd: ipr command struct
@@ -8326,20 +8457,11 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
if (ioa_cfg->in_ioa_bringdown) {
ipr_cmd->job_step = ipr_ioa_bringdown_done;
+ } else if (ioa_cfg->sdt_state == GET_DUMP) {
+ ipr_cmd->job_step = ipr_dump_mailbox_wait;
+ ipr_cmd->u.time_left = IPR_WAIT_FOR_MAILBOX;
} else {
ipr_cmd->job_step = ipr_reset_enable_ioa;
-
- if (GET_DUMP == ioa_cfg->sdt_state) {
- ioa_cfg->sdt_state = READ_DUMP;
- ioa_cfg->dump_timeout = 0;
- if (ioa_cfg->sis64)
- ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT);
- else
- ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT);
- ipr_cmd->job_step = ipr_reset_wait_for_dump;
- schedule_work(&ioa_cfg->work_q);
- return IPR_RC_JOB_RETURN;
- }
}
LEAVE;
@@ -10285,9 +10407,8 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
- blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
+ irq_poll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
- blk_iopoll_enable(&ioa_cfg->hrrq[i].iopoll);
}
}
@@ -10316,7 +10437,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
ioa_cfg->iopoll_weight = 0;
for (i = 1; i < ioa_cfg->hrrq_num; i++)
- blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
+ irq_poll_disable(&ioa_cfg->hrrq[i].iopoll);
}
while (ioa_cfg->in_reset_reload) {
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index e4fb17a..56c5706 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -32,15 +32,15 @@
#include <linux/libata.h>
#include <linux/list.h>
#include <linux/kref.h>
-#include <linux/blk-iopoll.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.6.2"
-#define IPR_DRIVER_DATE "(June 11, 2015)"
+#define IPR_DRIVER_VERSION "2.6.3"
+#define IPR_DRIVER_DATE "(October 17, 2015)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -216,6 +216,10 @@
#define IPR_SET_ALL_SUPPORTED_DEVICES 0x80
#define IPR_IOA_SHUTDOWN 0xF7
#define IPR_WR_BUF_DOWNLOAD_AND_SAVE 0x05
+#define IPR_IOA_SERVICE_ACTION 0xD2
+
+/* IOA Service Actions */
+#define IPR_IOA_SA_CHANGE_CACHE_PARAMS 0x14
/*
* Timeouts
@@ -279,6 +283,9 @@
#define IPR_IPL_INIT_STAGE_TIME_MASK 0x0000ffff
#define IPR_PCII_IPL_STAGE_CHANGE (0x80000000 >> 0)
+#define IPR_PCII_MAILBOX_STABLE (0x80000000 >> 4)
+#define IPR_WAIT_FOR_MAILBOX (2 * HZ)
+
#define IPR_PCII_IOA_TRANS_TO_OPER (0x80000000 >> 0)
#define IPR_PCII_IOARCB_XFER_FAILED (0x80000000 >> 3)
#define IPR_PCII_IOA_UNIT_CHECKED (0x80000000 >> 4)
@@ -510,7 +517,7 @@ struct ipr_hrr_queue {
u8 allow_cmds:1;
u8 removing_ioa:1;
- struct blk_iopoll iopoll;
+ struct irq_poll iopoll;
};
/* Command packet structure */
@@ -846,6 +853,16 @@ struct ipr_inquiry_page0 {
u8 page[IPR_INQUIRY_PAGE0_ENTRIES];
}__attribute__((packed));
+struct ipr_inquiry_pageC4 {
+ u8 peri_qual_dev_type;
+ u8 page_code;
+ u8 reserved1;
+ u8 len;
+ u8 cache_cap[4];
+#define IPR_CAP_SYNC_CACHE 0x08
+ u8 reserved2[20];
+} __packed;
+
struct ipr_hostrcb_device_data_entry {
struct ipr_vpd vpd;
struct ipr_res_addr dev_res_addr;
@@ -1319,6 +1336,7 @@ struct ipr_misc_cbs {
struct ipr_inquiry_page0 page0_data;
struct ipr_inquiry_page3 page3_data;
struct ipr_inquiry_cap cap;
+ struct ipr_inquiry_pageC4 pageC4_data;
struct ipr_mode_pages mode_pages;
struct ipr_supported_device supp_dev;
};
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 0dfcabe..77128d68 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -170,7 +170,6 @@ static struct scsi_host_template isci_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = isci_host_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -272,11 +271,11 @@ static void isci_unregister(struct isci_host *isci_host)
if (!isci_host)
return;
+ shost = to_shost(isci_host);
+ scsi_remove_host(shost);
sas_unregister_ha(&isci_host->sas_ha);
- shost = to_shost(isci_host);
sas_remove_host(shost);
- scsi_remove_host(shost);
scsi_host_put(shost);
}
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
index 680bf6f..8f0ea97 100644
--- a/drivers/scsi/iscsi_boot_sysfs.c
+++ b/drivers/scsi/iscsi_boot_sysfs.c
@@ -166,6 +166,7 @@ static struct attribute_group iscsi_boot_target_attr_group = {
iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
+iscsi_boot_rd_attr(eth_prefix, prefix-len, ISCSI_BOOT_ETH_PREFIX_LEN);
iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
@@ -181,6 +182,7 @@ static struct attribute *ethernet_attrs[] = {
&iscsi_boot_attr_eth_index.attr,
&iscsi_boot_attr_eth_flags.attr,
&iscsi_boot_attr_eth_ip.attr,
+ &iscsi_boot_attr_eth_prefix.attr,
&iscsi_boot_attr_eth_subnet.attr,
&iscsi_boot_attr_eth_origin.attr,
&iscsi_boot_attr_eth_gateway.attr,
@@ -208,6 +210,9 @@ static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
else if (attr == &iscsi_boot_attr_eth_ip.attr)
return boot_kobj->is_visible(boot_kobj->data,
ISCSI_BOOT_ETH_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_eth_prefix.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_PREFIX_LEN);
else if (attr == &iscsi_boot_attr_eth_subnet.attr)
return boot_kobj->is_visible(boot_kobj->data,
ISCSI_BOOT_ETH_SUBNET_MASK);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 0b8af18..2e4c82f 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -26,12 +26,12 @@
* Zhenyu Wang
*/
+#include <crypto/hash.h>
#include <linux/types.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/blkdev.h>
-#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
@@ -428,7 +428,7 @@ static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr,
* sufficient room.
*/
if (conn->hdrdgst_en) {
- iscsi_tcp_dgst_header(&tcp_sw_conn->tx_hash, hdr, hdrlen,
+ iscsi_tcp_dgst_header(tcp_sw_conn->tx_hash, hdr, hdrlen,
hdr + hdrlen);
hdrlen += ISCSI_DIGEST_SIZE;
}
@@ -454,7 +454,7 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct hash_desc *tx_hash = NULL;
+ struct ahash_request *tx_hash = NULL;
unsigned int hdr_spec_len;
ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len,
@@ -467,7 +467,7 @@ iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
if (conn->datadgst_en)
- tx_hash = &tcp_sw_conn->tx_hash;
+ tx_hash = tcp_sw_conn->tx_hash;
return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment,
sg, count, offset, len,
@@ -480,7 +480,7 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data,
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct hash_desc *tx_hash = NULL;
+ struct ahash_request *tx_hash = NULL;
unsigned int hdr_spec_len;
ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ?
@@ -492,7 +492,7 @@ iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data,
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
if (conn->datadgst_en)
- tx_hash = &tcp_sw_conn->tx_hash;
+ tx_hash = tcp_sw_conn->tx_hash;
iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment,
data, len, NULL, tx_hash);
@@ -543,6 +543,7 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn;
struct iscsi_tcp_conn *tcp_conn;
struct iscsi_sw_tcp_conn *tcp_sw_conn;
+ struct crypto_ahash *tfm;
cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn),
conn_idx);
@@ -552,23 +553,28 @@ iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session,
tcp_conn = conn->dd_data;
tcp_sw_conn = tcp_conn->dd_data;
- tcp_sw_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- tcp_sw_conn->tx_hash.flags = 0;
- if (IS_ERR(tcp_sw_conn->tx_hash.tfm))
+ tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm))
goto free_conn;
- tcp_sw_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- tcp_sw_conn->rx_hash.flags = 0;
- if (IS_ERR(tcp_sw_conn->rx_hash.tfm))
- goto free_tx_tfm;
- tcp_conn->rx_hash = &tcp_sw_conn->rx_hash;
+ tcp_sw_conn->tx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!tcp_sw_conn->tx_hash)
+ goto free_tfm;
+ ahash_request_set_callback(tcp_sw_conn->tx_hash, 0, NULL, NULL);
+
+ tcp_sw_conn->rx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!tcp_sw_conn->rx_hash)
+ goto free_tx_hash;
+ ahash_request_set_callback(tcp_sw_conn->rx_hash, 0, NULL, NULL);
+
+ tcp_conn->rx_hash = tcp_sw_conn->rx_hash;
return cls_conn;
-free_tx_tfm:
- crypto_free_hash(tcp_sw_conn->tx_hash.tfm);
+free_tx_hash:
+ ahash_request_free(tcp_sw_conn->tx_hash);
+free_tfm:
+ crypto_free_ahash(tfm);
free_conn:
iscsi_conn_printk(KERN_ERR, conn,
"Could not create connection due to crc32c "
@@ -607,10 +613,14 @@ static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
iscsi_sw_tcp_release_conn(conn);
- if (tcp_sw_conn->tx_hash.tfm)
- crypto_free_hash(tcp_sw_conn->tx_hash.tfm);
- if (tcp_sw_conn->rx_hash.tfm)
- crypto_free_hash(tcp_sw_conn->rx_hash.tfm);
+ ahash_request_free(tcp_sw_conn->rx_hash);
+ if (tcp_sw_conn->tx_hash) {
+ struct crypto_ahash *tfm;
+
+ tfm = crypto_ahash_reqtfm(tcp_sw_conn->tx_hash);
+ ahash_request_free(tcp_sw_conn->tx_hash);
+ crypto_free_ahash(tfm);
+ }
iscsi_tcp_conn_teardown(cls_conn);
}
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index f42ecb23..06d42d0 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -45,8 +45,8 @@ struct iscsi_sw_tcp_conn {
void (*old_write_space)(struct sock *);
/* data and header digests */
- struct hash_desc tx_hash; /* CRC32C (Tx) */
- struct hash_desc rx_hash; /* CRC32C (Rx) */
+ struct ahash_request *tx_hash; /* CRC32C (Tx) */
+ struct ahash_request *rx_hash; /* CRC32C (Rx) */
/* MIB custom statistics */
uint32_t sendpage_failures_cnt;
diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c
index 9fbf78e..c168321 100644
--- a/drivers/scsi/libfc/fc_npiv.c
+++ b/drivers/scsi/libfc/fc_npiv.c
@@ -25,7 +25,7 @@
#include <linux/export.h>
/**
- * fc_vport_create() - Create a new NPIV vport instance
+ * libfc_vport_create() - Create a new NPIV vport instance
* @vport: fc_vport structure from scsi_transport_fc
* @privsize: driver private data size to allocate along with the Scsi_Host
*/
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 60cb6dc..63a1d69 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -26,13 +26,13 @@
* Zhenyu Wang
*/
+#include <crypto/hash.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/blkdev.h>
-#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
@@ -214,7 +214,8 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
} else
sg_init_one(&sg, segment->data + segment->copied,
copied);
- crypto_hash_update(segment->hash, &sg, copied);
+ ahash_request_set_crypt(segment->hash, &sg, NULL, copied);
+ crypto_ahash_update(segment->hash);
}
segment->copied += copied;
@@ -260,7 +261,9 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
* is completely handled in hdr done function.
*/
if (segment->hash) {
- crypto_hash_final(segment->hash, segment->digest);
+ ahash_request_set_crypt(segment->hash, NULL,
+ segment->digest, 0);
+ crypto_ahash_final(segment->hash);
iscsi_tcp_segment_splice_digest(segment,
recv ? segment->recv_digest : segment->digest);
return 0;
@@ -310,13 +313,14 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
}
inline void
-iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen,
- unsigned char digest[ISCSI_DIGEST_SIZE])
+iscsi_tcp_dgst_header(struct ahash_request *hash, const void *hdr,
+ size_t hdrlen, unsigned char digest[ISCSI_DIGEST_SIZE])
{
struct scatterlist sg;
sg_init_one(&sg, hdr, hdrlen);
- crypto_hash_digest(hash, &sg, hdrlen, digest);
+ ahash_request_set_crypt(hash, &sg, digest, hdrlen);
+ crypto_ahash_digest(hash);
}
EXPORT_SYMBOL_GPL(iscsi_tcp_dgst_header);
@@ -341,7 +345,7 @@ iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
*/
static inline void
__iscsi_segment_init(struct iscsi_segment *segment, size_t size,
- iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+ iscsi_segment_done_fn_t *done, struct ahash_request *hash)
{
memset(segment, 0, sizeof(*segment));
segment->total_size = size;
@@ -349,14 +353,14 @@ __iscsi_segment_init(struct iscsi_segment *segment, size_t size,
if (hash) {
segment->hash = hash;
- crypto_hash_init(hash);
+ crypto_ahash_init(hash);
}
}
inline void
iscsi_segment_init_linear(struct iscsi_segment *segment, void *data,
size_t size, iscsi_segment_done_fn_t *done,
- struct hash_desc *hash)
+ struct ahash_request *hash)
{
__iscsi_segment_init(segment, size, done, hash);
segment->data = data;
@@ -368,7 +372,8 @@ inline int
iscsi_segment_seek_sg(struct iscsi_segment *segment,
struct scatterlist *sg_list, unsigned int sg_count,
unsigned int offset, size_t size,
- iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+ iscsi_segment_done_fn_t *done,
+ struct ahash_request *hash)
{
struct scatterlist *sg;
unsigned int i;
@@ -431,7 +436,7 @@ static void
iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
{
struct iscsi_conn *conn = tcp_conn->iscsi_conn;
- struct hash_desc *rx_hash = NULL;
+ struct ahash_request *rx_hash = NULL;
if (conn->datadgst_en &&
!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
@@ -686,7 +691,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
if (tcp_conn->in.datalen) {
struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
+ struct ahash_request *rx_hash = NULL;
struct scsi_data_buffer *sdb = scsi_in(task->sc);
/*
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index ceee9a3..90a3ca5 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -386,7 +386,6 @@ struct lpfc_vport {
uint32_t work_port_events; /* Timeout to be handled */
#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
-#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
#define WORKER_DELAYED_DISC_TMO 0x8 /* vport: delayed discovery */
#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
@@ -396,7 +395,6 @@ struct lpfc_vport {
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */
- struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc;
struct timer_list delayed_disc_tmo;
@@ -405,6 +403,7 @@ struct lpfc_vport {
uint8_t load_flag;
#define FC_LOADING 0x1 /* HBA in process of loading drvr */
#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
+#define FC_ALLOW_FDMI 0x4 /* port is ready for FDMI requests */
/* Vport Config Parameters */
uint32_t cfg_scan_down;
uint32_t cfg_lun_queue_depth;
@@ -414,10 +413,6 @@ struct lpfc_vport {
uint32_t cfg_peer_port_login;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
- uint32_t cfg_fdmi_on;
-#define LPFC_FDMI_SUPPORT 1 /* bit 0 - FDMI supported? */
-#define LPFC_FDMI_REG_DELAY 2 /* bit 1 - 60 sec registration delay */
-#define LPFC_FDMI_ALL_ATTRIB 4 /* bit 2 - register ALL attributes? */
uint32_t cfg_discovery_threads;
uint32_t cfg_log_verbose;
uint32_t cfg_max_luns;
@@ -443,6 +438,10 @@ struct lpfc_vport {
unsigned long rcv_buffer_time_stamp;
uint32_t vport_flag;
#define STATIC_VPORT 1
+
+ uint16_t fdmi_num_disc;
+ uint32_t fdmi_hba_mask;
+ uint32_t fdmi_port_mask;
};
struct hbq_s {
@@ -755,6 +754,11 @@ struct lpfc_hba {
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */
uint32_t cfg_enable_dss;
+ uint32_t cfg_fdmi_on;
+#define LPFC_FDMI_NO_SUPPORT 0 /* FDMI not supported */
+#define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */
+#define LPFC_FDMI_SMART_SAN 2 /* SmartSAN supported */
+ uint32_t cfg_enable_SmartSAN;
lpfc_vpd_t vpd; /* vital product data */
struct pci_dev *pcidev;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index f6446d7..343ae94 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -4572,19 +4572,27 @@ LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1,
255, "Identifies TYPE for additional ring configuration");
/*
-# lpfc_fdmi_on: controls FDMI support.
-# Set NOT Set
-# bit 0 = FDMI support no FDMI support
-# LPFC_FDMI_SUPPORT just turns basic support on/off
-# bit 1 = Register delay no register delay (60 seconds)
-# LPFC_FDMI_REG_DELAY 60 sec registration delay after FDMI login
-# bit 2 = All attributes Use a attribute subset
-# LPFC_FDMI_ALL_ATTRIB applies to both port and HBA attributes
-# Port attrutes subset: 1 thru 6 OR all: 1 thru 0xd 0x101 0x102 0x103
-# HBA attributes subset: 1 thru 0xb OR all: 1 thru 0xc
-# Value range [0,7]. Default value is 0.
+# lpfc_enable_SmartSAN: Sets up FDMI support for SmartSAN
+# 0 = SmartSAN functionality disabled (default)
+# 1 = SmartSAN functionality enabled
+# This parameter will override the value of lpfc_fdmi_on module parameter.
+# Value range is [0,1]. Default value is 0.
*/
-LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 7, "Enable FDMI support");
+LPFC_ATTR_R(enable_SmartSAN, 0, 0, 1, "Enable SmartSAN functionality");
+
+/*
+# lpfc_fdmi_on: Controls FDMI support.
+# 0 No FDMI support (default)
+# 1 Traditional FDMI support
+# 2 Smart SAN support
+# If lpfc_enable_SmartSAN is set 1, the driver sets lpfc_fdmi_on to value 2
+# overwriting the current value. If lpfc_enable_SmartSAN is set 0, the
+# driver uses the current value of lpfc_fdmi_on provided it has value 0 or 1.
+# A value of 2 with lpfc_enable_SmartSAN set to 0 causes the driver to
+# set lpfc_fdmi_on back to 1.
+# Value range [0,2]. Default value is 0.
+*/
+LPFC_ATTR_R(fdmi_on, 0, 0, 2, "Enable FDMI support");
/*
# Specifies the maximum number of ELS cmds we can have outstanding (for
@@ -4815,6 +4823,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_multi_ring_rctl,
&dev_attr_lpfc_multi_ring_type,
&dev_attr_lpfc_fdmi_on,
+ &dev_attr_lpfc_enable_SmartSAN,
&dev_attr_lpfc_max_luns,
&dev_attr_lpfc_enable_npiv,
&dev_attr_lpfc_fcf_failover_policy,
@@ -4887,7 +4896,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_fcp_class,
&dev_attr_lpfc_use_adisc,
&dev_attr_lpfc_first_burst_size,
- &dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns,
&dev_attr_nport_evt_cnt,
&dev_attr_npiv_info,
@@ -5247,7 +5255,7 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
spin_lock_irq(shost->host_lock);
- if (lpfc_is_link_up(phba)) {
+ if ((lpfc_is_link_up(phba)) && (!(phba->hba_flag & HBA_FCOE_MODE))) {
switch(phba->fc_linkspeed) {
case LPFC_LINK_SPEED_1GHZ:
fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
@@ -5826,6 +5834,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
+ lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
+ lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -5846,6 +5856,15 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
phba->cfg_poll = 0;
else
phba->cfg_poll = lpfc_poll;
+
+ /* Ensure fdmi_on and enable_SmartSAN don't conflict */
+ if (phba->cfg_enable_SmartSAN) {
+ phba->cfg_fdmi_on = LPFC_FDMI_SMART_SAN;
+ } else {
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT;
+ }
+
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
@@ -5879,7 +5898,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
lpfc_use_adisc_init(vport, lpfc_use_adisc);
lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
- lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
lpfc_max_luns_init(vport, lpfc_max_luns);
lpfc_scan_down_init(vport, lpfc_scan_down);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index b0e6fe4..4e55b35 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -72,6 +72,7 @@ void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
void lpfc_retry_pport_discovery(struct lpfc_hba *);
void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
+void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -167,9 +168,8 @@ void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
-int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
-void lpfc_fdmi_tmo(unsigned long);
-void lpfc_fdmi_timeout_handler(struct lpfc_vport *);
+int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
+void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
void lpfc_delayed_disc_tmo(unsigned long);
void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 8fded1f..79e261d 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -48,15 +48,26 @@
#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
-/* FDMI Port Speed definitions */
-#define HBA_PORTSPEED_1GBIT 0x0001 /* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT 0x0002 /* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT 0x0008 /* 4 GBit/sec */
-#define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */
-#define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */
-#define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */
-#define HBA_PORTSPEED_32GBIT 0x0040 /* 32 GBit/sec */
-#define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */
+/* FDMI Port Speed definitions - FC-GS-7 */
+#define HBA_PORTSPEED_1GFC 0x00000001 /* 1G FC */
+#define HBA_PORTSPEED_2GFC 0x00000002 /* 2G FC */
+#define HBA_PORTSPEED_4GFC 0x00000008 /* 4G FC */
+#define HBA_PORTSPEED_10GFC 0x00000004 /* 10G FC */
+#define HBA_PORTSPEED_8GFC 0x00000010 /* 8G FC */
+#define HBA_PORTSPEED_16GFC 0x00000020 /* 16G FC */
+#define HBA_PORTSPEED_32GFC 0x00000040 /* 32G FC */
+#define HBA_PORTSPEED_20GFC 0x00000080 /* 20G FC */
+#define HBA_PORTSPEED_40GFC 0x00000100 /* 40G FC */
+#define HBA_PORTSPEED_128GFC 0x00000200 /* 128G FC */
+#define HBA_PORTSPEED_64GFC 0x00000400 /* 64G FC */
+#define HBA_PORTSPEED_256GFC 0x00000800 /* 256G FC */
+#define HBA_PORTSPEED_UNKNOWN 0x00008000 /* Unknown */
+#define HBA_PORTSPEED_10GE 0x00010000 /* 10G E */
+#define HBA_PORTSPEED_40GE 0x00020000 /* 40G E */
+#define HBA_PORTSPEED_100GE 0x00040000 /* 100G E */
+#define HBA_PORTSPEED_25GE 0x00080000 /* 25G E */
+#define HBA_PORTSPEED_50GE 0x00100000 /* 50G E */
+#define HBA_PORTSPEED_400GE 0x00200000 /* 400G E */
#define FOURBYTES 4
@@ -287,6 +298,17 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
return 0;
}
+/**
+ * lpfc_gen_req - Build and issue a GEN_REQUEST command to the SLI Layer
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @bmp: Pointer to BPL for SLI command
+ * @inp: Pointer to data buffer for response data.
+ * @outp: Pointer to data buffer that hold the CT command.
+ * @cmpl: completion routine to call when command completes
+ * @ndlp: Destination NPort nodelist entry
+ *
+ * This function as the final part for issuing a CT command.
+ */
static int
lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
@@ -311,7 +333,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
- icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));
+ icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
if (usr_flg)
geniocb->context3 = NULL;
@@ -370,6 +392,16 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
return 0;
}
+/**
+ * lpfc_ct_cmd - Build and issue a CT command
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @inmp: Pointer to data buffer for response data.
+ * @bmp: Pointer to BPL for SLI command
+ * @ndlp: Destination NPort nodelist entry
+ * @cmpl: completion routine to call when command completes
+ *
+ * This function is called for issuing a CT command.
+ */
static int
lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
@@ -453,7 +485,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
Cnt -= 16; /* subtract length of CT header */
/* Loop through entire NameServer list of DIDs */
- while (Cnt >= sizeof (uint32_t)) {
+ while (Cnt >= sizeof(uint32_t)) {
/* Get next DID from NameServer List */
CTentry = *ctptr++;
Did = ((be32_to_cpu(CTentry)) & Mask_DID);
@@ -558,7 +590,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
}
if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY)))
goto nsout1;
- Cnt -= sizeof (uint32_t);
+ Cnt -= sizeof(uint32_t);
}
ctptr = NULL;
@@ -1146,7 +1178,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
/* fill in BDEs for command */
/* Allocate buffer for command payload */
- mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (!mp) {
rc=2;
goto ns_cmd_exit;
@@ -1160,7 +1192,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
}
/* Allocate buffer for Buffer ptr list */
- bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (!bmp) {
rc=4;
goto ns_cmd_free_mpvirt;
@@ -1204,7 +1236,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
bpl->tus.w = le32_to_cpu(bpl->tus.w);
CtReq = (struct lpfc_sli_ct_request *) mp->virt;
- memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request));
+ memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
CtReq->RevisionId.bits.InId = 0;
CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
@@ -1244,7 +1276,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
cpu_to_be16(SLI_CTNS_RNN_ID);
CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
cmpl = lpfc_cmpl_ct_cmd_rnn_id;
break;
@@ -1264,7 +1296,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
CtReq->CommandResponse.bits.CmdRsp =
cpu_to_be16(SLI_CTNS_RSNN_NN);
memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
size = sizeof(CtReq->un.rsnn.symbname);
CtReq->un.rsnn.len =
lpfc_vport_symbolic_node_name(vport,
@@ -1319,20 +1351,29 @@ ns_cmd_exit:
return 1;
}
+/**
+ * lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
+ * @phba: Pointer to HBA context object.
+ * @cmdiocb: Pointer to the command IOCBQ.
+ * @rspiocb: Pointer to the response IOCBQ.
+ *
+ * This function to handle the completion of a driver initiated FDMI
+ * CT command issued during discovery.
+ */
static void
-lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_dmabuf *inp = cmdiocb->context1;
struct lpfc_dmabuf *outp = cmdiocb->context2;
- struct lpfc_sli_ct_request *CTrsp = outp->virt;
struct lpfc_sli_ct_request *CTcmd = inp->virt;
- struct lpfc_nodelist *ndlp;
+ struct lpfc_sli_ct_request *CTrsp = outp->virt;
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
- struct lpfc_vport *vport = cmdiocb->vport;
IOCB_t *irsp = &rspiocb->iocb;
- uint32_t latt;
+ struct lpfc_nodelist *ndlp;
+ uint32_t latt, cmd, err;
latt = lpfc_els_chk_latt(vport);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
@@ -1340,91 +1381,1115 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4], latt);
if (latt || irsp->ulpStatus) {
+
+ /* Look for a retryable error */
+ if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
+ case IOERR_SLI_ABORTED:
+ case IOERR_ABORT_IN_PROGRESS:
+ case IOERR_SEQUENCE_TIMEOUT:
+ case IOERR_ILLEGAL_FRAME:
+ case IOERR_NO_RESOURCES:
+ case IOERR_ILLEGAL_COMMAND:
+ cmdiocb->retry++;
+ if (cmdiocb->retry >= LPFC_FDMI_MAX_RETRY)
+ break;
+
+ /* Retry the same FDMI command */
+ err = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING,
+ cmdiocb, 0);
+ if (err == IOCB_ERROR)
+ break;
+ return;
+ default:
+ break;
+ }
+ }
+
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"0229 FDMI cmd %04x failed, latt = %d "
"ulpStatus: x%x, rid x%x\n",
be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
irsp->un.ulpWord[4]);
- goto fail_out;
}
+ lpfc_ct_free_iocb(phba, cmdiocb);
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
- goto fail_out;
+ return;
+ /* Check for a CT LS_RJT response */
+ cmd = be16_to_cpu(fdmi_cmd);
if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0220 FDMI rsp failed Data: x%x\n",
- be16_to_cpu(fdmi_cmd));
+ "0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
+
+ /* Should we fallback to FDMI-2 / FDMI-1 ? */
+ switch (cmd) {
+ case SLI_MGMT_RHBA:
+ if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+ }
+ return;
+
+ case SLI_MGMT_RPRT:
+ if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ /* Retry the same command */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ return;
+
+ case SLI_MGMT_RPA:
+ if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+ }
+ if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ /* Retry the same command */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ return;
+ }
}
-fail_out:
- lpfc_ct_free_iocb(phba, cmdiocb);
+ /*
+ * On success, need to cycle thru FDMI registration for discovery
+ * DHBA -> DPRT -> RHBA -> RPA (physical port)
+ * DPRT -> RPRT (vports)
+ */
+ switch (cmd) {
+ case SLI_MGMT_RHBA:
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
+ break;
+
+ case SLI_MGMT_DHBA:
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+ break;
+
+ case SLI_MGMT_DPRT:
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
+ else
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ break;
+ }
+ return;
}
-static void
-lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq *rspiocb)
+
+/**
+ * lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * Called from hbeat timeout routine to check if the number of discovered
+ * ports has changed. If so, re-register thar port Attribute.
+ */
+void
+lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
{
- struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_dmabuf *inp = cmdiocb->context1;
- struct lpfc_sli_ct_request *CTcmd = inp->virt;
- uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
+ uint16_t cnt;
+
+ if (!lpfc_is_link_up(phba))
+ return;
+
+ if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
+ return;
- lpfc_cmpl_ct_cmd_fdmi(phba, cmdiocb, rspiocb);
+ cnt = lpfc_find_map_node(vport);
+ if (cnt == vport->fdmi_num_disc)
+ return;
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
return;
- /*
- * Need to cycle thru FDMI registration for discovery
- * DHBA -> DPRT -> RHBA -> RPA
- */
- switch (be16_to_cpu(fdmi_cmd)) {
- case SLI_MGMT_RHBA:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
- break;
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
+ LPFC_FDMI_PORT_ATTR_num_disc);
+ } else {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
+ LPFC_FDMI_PORT_ATTR_num_disc);
+ }
+}
- case SLI_MGMT_DHBA:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
- break;
+/* Routines for all individual HBA attributes */
+int
+lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
- case SLI_MGMT_DPRT:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
- break;
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_NODENAME);
+ return size;
+}
+int
+lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString,
+ "Emulex Corporation",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->SerialNumber,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelName,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MODEL);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelDesc,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ lpfc_vpd_t *vp = &phba->vpd;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t i, j, incr, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ /* Convert JEDEC ID to ascii for hardware version */
+ incr = vp->rev.biuRev;
+ for (i = 0; i < 8; i++) {
+ j = (incr & 0xf);
+ if (j <= 9)
+ ae->un.AttrString[7 - i] =
+ (char)((uint8_t) 0x30 +
+ (uint8_t) j);
+ else
+ ae->un.AttrString[7 - i] =
+ (char)((uint8_t) 0x61 +
+ (uint8_t) (j - 10));
+ incr = (incr >> 4);
}
+ size = FOURBYTES + 8;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, lpfc_release_version,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ else
+ strncpy(ae->un.AttrString, phba->OptionROMVersion,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s",
+ init_utsname()->sysname,
+ init_utsname()->release,
+ init_utsname()->version);
+
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ ae->un.AttrInt = cpu_to_be32(LPFC_MAX_CT_SIZE);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ len = lpfc_vport_symbolic_node_name(vport,
+ ae->un.AttrString, 256);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Nothing is defined for this currently */
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_VENDOR_INFO);
+ return size;
}
+int
+lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Each driver instance corresponds to a single port */
+ ae->un.AttrInt = cpu_to_be32(1);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_NUM_PORTS);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fabric_nodename,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_FABRIC_WWNN);
+ return size;
+}
int
-lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
+lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_BIOS_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Driver doesn't have access to this information */
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_BIOS_STATE);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "EMULEX",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_VENDOR_ID);
+ return size;
+}
+
+/* Routines for all individual PORT attributes */
+int
+lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 32);
+
+ ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+ size = FOURBYTES + 32;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ ae->un.AttrInt = 0;
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ if (phba->lmt & LMT_32Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
+ if (phba->lmt & LMT_10Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
+ if (phba->lmt & LMT_8Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
+ if (phba->lmt & LMT_4Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
+ if (phba->lmt & LMT_2Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
+ if (phba->lmt & LMT_1Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
+ } else {
+ /* FCoE links support only one speed */
+ switch (phba->fc_linkspeed) {
+ case LPFC_ASYNC_LINK_SPEED_10GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_10GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_25GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_25GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_40GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_40GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_100GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_100GE;
+ break;
+ }
+ }
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_1GFC;
+ break;
+ case LPFC_LINK_SPEED_2GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_2GFC;
+ break;
+ case LPFC_LINK_SPEED_4GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_4GFC;
+ break;
+ case LPFC_LINK_SPEED_8GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_8GFC;
+ break;
+ case LPFC_LINK_SPEED_10GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_10GFC;
+ break;
+ case LPFC_LINK_SPEED_16GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_16GFC;
+ break;
+ case LPFC_LINK_SPEED_32GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_32GFC;
+ break;
+ default:
+ ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+ break;
+ }
+ } else {
+ switch (phba->fc_linkspeed) {
+ case LPFC_ASYNC_LINK_SPEED_10GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_10GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_25GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_25GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_40GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_40GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_100GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_100GE;
+ break;
+ default:
+ ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+ break;
+ }
+ }
+
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct serv_parm *hsp;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ hsp = (struct serv_parm *)&vport->fc_sparam;
+ ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb) << 8) |
+ (uint32_t) hsp->cmn.bbRcvSizeLsb;
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString),
+ "/sys/class/scsi_host/host%d", shost->host_no);
+ len = strnlen((char *)ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
+ init_utsname()->nodename);
+
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_NODENAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP)
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT);
+ else
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NPORT);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fabric_portname,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 32);
+
+ ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+ size = FOURBYTES + 32;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ /* Link Up - operational */
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ vport->fdmi_num_disc = lpfc_find_map_node(vport);
+ ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(vport->fc_myDID);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "Smart SAN Initiator",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_SERVICE);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ memcpy((((uint8_t *)&ae->un.AttrString) +
+ sizeof(struct lpfc_name)),
+ &vport->fc_sparam.portName, sizeof(struct lpfc_name));
+ size = FOURBYTES + (2 * sizeof(struct lpfc_name));
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_GUID);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "Smart SAN Version 1.0",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelName,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_MODEL);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* SRIOV (type 3) is not supported */
+ if (vport->vpi)
+ ae->un.AttrInt = cpu_to_be32(2); /* NPIV */
+ else
+ ae->un.AttrInt = cpu_to_be32(1); /* Physical */
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_QOS);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_SECURITY);
+ return size;
+}
+
+/* RHBA attribute jump table */
+int (*lpfc_fdmi_hba_action[])
+ (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+ /* Action routine Mask bit Attribute type */
+ lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
+ lpfc_fdmi_hba_attr_manufacturer, /* bit1 RHBA_MANUFACTURER */
+ lpfc_fdmi_hba_attr_sn, /* bit2 RHBA_SERIAL_NUMBER */
+ lpfc_fdmi_hba_attr_model, /* bit3 RHBA_MODEL */
+ lpfc_fdmi_hba_attr_description, /* bit4 RHBA_MODEL_DESCRIPTION */
+ lpfc_fdmi_hba_attr_hdw_ver, /* bit5 RHBA_HARDWARE_VERSION */
+ lpfc_fdmi_hba_attr_drvr_ver, /* bit6 RHBA_DRIVER_VERSION */
+ lpfc_fdmi_hba_attr_rom_ver, /* bit7 RHBA_OPTION_ROM_VERSION */
+ lpfc_fdmi_hba_attr_fmw_ver, /* bit8 RHBA_FIRMWARE_VERSION */
+ lpfc_fdmi_hba_attr_os_ver, /* bit9 RHBA_OS_NAME_VERSION */
+ lpfc_fdmi_hba_attr_ct_len, /* bit10 RHBA_MAX_CT_PAYLOAD_LEN */
+ lpfc_fdmi_hba_attr_symbolic_name, /* bit11 RHBA_SYM_NODENAME */
+ lpfc_fdmi_hba_attr_vendor_info, /* bit12 RHBA_VENDOR_INFO */
+ lpfc_fdmi_hba_attr_num_ports, /* bit13 RHBA_NUM_PORTS */
+ lpfc_fdmi_hba_attr_fabric_wwnn, /* bit14 RHBA_FABRIC_WWNN */
+ lpfc_fdmi_hba_attr_bios_ver, /* bit15 RHBA_BIOS_VERSION */
+ lpfc_fdmi_hba_attr_bios_state, /* bit16 RHBA_BIOS_STATE */
+ lpfc_fdmi_hba_attr_vendor_id, /* bit17 RHBA_VENDOR_ID */
+};
+
+/* RPA / RPRT attribute jump table */
+int (*lpfc_fdmi_port_action[])
+ (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+ /* Action routine Mask bit Attribute type */
+ lpfc_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */
+ lpfc_fdmi_port_attr_support_speed, /* bit1 RPRT_SUPPORTED_SPEED */
+ lpfc_fdmi_port_attr_speed, /* bit2 RPRT_PORT_SPEED */
+ lpfc_fdmi_port_attr_max_frame, /* bit3 RPRT_MAX_FRAME_SIZE */
+ lpfc_fdmi_port_attr_os_devname, /* bit4 RPRT_OS_DEVICE_NAME */
+ lpfc_fdmi_port_attr_host_name, /* bit5 RPRT_HOST_NAME */
+ lpfc_fdmi_port_attr_wwnn, /* bit6 RPRT_NODENAME */
+ lpfc_fdmi_port_attr_wwpn, /* bit7 RPRT_PORTNAME */
+ lpfc_fdmi_port_attr_symbolic_name, /* bit8 RPRT_SYM_PORTNAME */
+ lpfc_fdmi_port_attr_port_type, /* bit9 RPRT_PORT_TYPE */
+ lpfc_fdmi_port_attr_class, /* bit10 RPRT_SUPPORTED_CLASS */
+ lpfc_fdmi_port_attr_fabric_wwpn, /* bit11 RPRT_FABRICNAME */
+ lpfc_fdmi_port_attr_active_fc4type, /* bit12 RPRT_ACTIVE_FC4_TYPES */
+ lpfc_fdmi_port_attr_port_state, /* bit13 RPRT_PORT_STATE */
+ lpfc_fdmi_port_attr_num_disc, /* bit14 RPRT_DISC_PORT */
+ lpfc_fdmi_port_attr_nportid, /* bit15 RPRT_PORT_ID */
+ lpfc_fdmi_smart_attr_service, /* bit16 RPRT_SMART_SERVICE */
+ lpfc_fdmi_smart_attr_guid, /* bit17 RPRT_SMART_GUID */
+ lpfc_fdmi_smart_attr_version, /* bit18 RPRT_SMART_VERSION */
+ lpfc_fdmi_smart_attr_model, /* bit19 RPRT_SMART_MODEL */
+ lpfc_fdmi_smart_attr_port_info, /* bit20 RPRT_SMART_PORT_INFO */
+ lpfc_fdmi_smart_attr_qos, /* bit21 RPRT_SMART_QOS */
+ lpfc_fdmi_smart_attr_security, /* bit22 RPRT_SMART_SECURITY */
+};
+
+/**
+ * lpfc_fdmi_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ int cmdcode, uint32_t new_mask)
{
struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *mp, *bmp;
struct lpfc_sli_ct_request *CtReq;
struct ulp_bde64 *bpl;
+ uint32_t bit_pos;
uint32_t size;
uint32_t rsp_size;
+ uint32_t mask;
struct lpfc_fdmi_reg_hba *rh;
struct lpfc_fdmi_port_entry *pe;
struct lpfc_fdmi_reg_portattr *pab = NULL;
struct lpfc_fdmi_attr_block *ab = NULL;
- struct lpfc_fdmi_attr_entry *ae;
- struct lpfc_fdmi_attr_def *ad;
- void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
- struct lpfc_iocbq *);
+ int (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad);
+ void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
- if (ndlp == NULL) {
- ndlp = lpfc_findnode_did(vport, FDMI_DID);
- if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
- return 0;
- cmpl = lpfc_cmpl_ct_cmd_fdmi; /* cmd interface */
- } else {
- cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
- }
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+ return 0;
+
+ cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
/* fill in BDEs for command */
/* Allocate buffer for command payload */
@@ -1470,573 +2535,99 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
switch (cmdcode) {
case SLI_MGMT_RHAT:
case SLI_MGMT_RHBA:
- {
- lpfc_vpd_t *vp = &phba->vpd;
- uint32_t i, j, incr;
- int len = 0;
+ rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
+ /* HBA Identifier */
+ memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
- rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
- /* HBA Identifier */
- memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
+ if (cmdcode == SLI_MGMT_RHBA) {
+ /* Registered Port List */
+ /* One entry (port) per adapter */
+ rh->rpl.EntryCnt = cpu_to_be32(1);
+ memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName,
sizeof(struct lpfc_name));
- if (cmdcode == SLI_MGMT_RHBA) {
- /* Registered Port List */
- /* One entry (port) per adapter */
- rh->rpl.EntryCnt = cpu_to_be32(1);
- memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
-
- /* point to the HBA attribute block */
- size = 2 * sizeof(struct lpfc_name) +
- FOURBYTES;
- } else {
- size = sizeof(struct lpfc_name);
- }
- ab = (struct lpfc_fdmi_attr_block *)
- ((uint8_t *)rh + size);
- ab->EntryCnt = 0;
- size += FOURBYTES;
-
- /*
- * Point to beginning of first HBA attribute entry
- */
- /* #1 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RHBA_NODENAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
- sizeof(struct lpfc_name));
- ab->EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #2 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.Manufacturer));
- ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
- strncpy(ae->un.Manufacturer, "Emulex Corporation",
- sizeof(ae->un.Manufacturer));
- len = strnlen(ae->un.Manufacturer,
- sizeof(ae->un.Manufacturer));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #3 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.SerialNumber));
- ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
- strncpy(ae->un.SerialNumber, phba->SerialNumber,
- sizeof(ae->un.SerialNumber));
- len = strnlen(ae->un.SerialNumber,
- sizeof(ae->un.SerialNumber));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #4 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.Model));
- ad->AttrType = cpu_to_be16(RHBA_MODEL);
- strncpy(ae->un.Model, phba->ModelName,
- sizeof(ae->un.Model));
- len = strnlen(ae->un.Model, sizeof(ae->un.Model));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #5 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.ModelDescription));
- ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
- strncpy(ae->un.ModelDescription, phba->ModelDesc,
- sizeof(ae->un.ModelDescription));
- len = strnlen(ae->un.ModelDescription,
- sizeof(ae->un.ModelDescription));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 8) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #6 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, 8);
- ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 8);
- /* Convert JEDEC ID to ascii for hardware version */
- incr = vp->rev.biuRev;
- for (i = 0; i < 8; i++) {
- j = (incr & 0xf);
- if (j <= 9)
- ae->un.HardwareVersion[7 - i] =
- (char)((uint8_t)0x30 +
- (uint8_t)j);
- else
- ae->un.HardwareVersion[7 - i] =
- (char)((uint8_t)0x61 +
- (uint8_t)(j - 10));
- incr = (incr >> 4);
+ /* point to the HBA attribute block */
+ size = 2 * sizeof(struct lpfc_name) +
+ FOURBYTES;
+ } else {
+ size = sizeof(struct lpfc_name);
+ }
+ ab = (struct lpfc_fdmi_attr_block *)((uint8_t *)rh + size);
+ ab->EntryCnt = 0;
+ size += FOURBYTES;
+ bit_pos = 0;
+ if (new_mask)
+ mask = new_mask;
+ else
+ mask = vport->fdmi_hba_mask;
+
+ /* Mask will dictate what attributes to build in the request */
+ while (mask) {
+ if (mask & 0x1) {
+ func = lpfc_fdmi_hba_action[bit_pos];
+ size += func(vport,
+ (struct lpfc_fdmi_attr_def *)
+ ((uint8_t *)rh + size));
+ ab->EntryCnt++;
+ if ((size + 256) >
+ (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+ goto hba_out;
}
- ab->EntryCnt++;
- size += FOURBYTES + 8;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #7 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.DriverVersion));
- ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
- strncpy(ae->un.DriverVersion, lpfc_release_version,
- sizeof(ae->un.DriverVersion));
- len = strnlen(ae->un.DriverVersion,
- sizeof(ae->un.DriverVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #8 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OptionROMVersion));
- ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
- strncpy(ae->un.OptionROMVersion, phba->OptionROMVersion,
- sizeof(ae->un.OptionROMVersion));
- len = strnlen(ae->un.OptionROMVersion,
- sizeof(ae->un.OptionROMVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #9 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FirmwareVersion));
- ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
- lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion,
- 1);
- len = strnlen(ae->un.FirmwareVersion,
- sizeof(ae->un.FirmwareVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #10 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OsNameVersion));
- ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
- snprintf(ae->un.OsNameVersion,
- sizeof(ae->un.OsNameVersion),
- "%s %s %s",
- init_utsname()->sysname,
- init_utsname()->release,
- init_utsname()->version);
- len = strnlen(ae->un.OsNameVersion,
- sizeof(ae->un.OsNameVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #11 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType =
- cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- ae->un.MaxCTPayloadLen = cpu_to_be32(LPFC_MAX_CT_SIZE);
- ab->EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /*
- * Currently switches don't seem to support the
- * following extended HBA attributes.
- */
- if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
- goto hba_out;
-
- /* #12 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.NodeSymName));
- ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
- len = lpfc_vport_symbolic_node_name(vport,
- ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
-hba_out:
- ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
- /* Total size */
- size = GID_REQUEST_SZ - 4 + size;
+ mask = mask >> 1;
+ bit_pos++;
}
+hba_out:
+ ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
+ /* Total size */
+ size = GID_REQUEST_SZ - 4 + size;
break;
case SLI_MGMT_RPRT:
case SLI_MGMT_RPA:
- {
- struct serv_parm *hsp;
- int len = 0;
-
- if (cmdcode == SLI_MGMT_RPRT) {
- rh = (struct lpfc_fdmi_reg_hba *)
- &CtReq->un.PortID;
- /* HBA Identifier */
- memcpy(&rh->hi.PortName,
- &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- pab = (struct lpfc_fdmi_reg_portattr *)
- &rh->rpl.EntryCnt;
- } else
- pab = (struct lpfc_fdmi_reg_portattr *)
- &CtReq->un.PortID;
- size = sizeof(struct lpfc_name) + FOURBYTES;
- memcpy((uint8_t *)&pab->PortName,
- (uint8_t *)&vport->fc_sparam.portName,
+ pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
+ if (cmdcode == SLI_MGMT_RPRT) {
+ rh = (struct lpfc_fdmi_reg_hba *)pab;
+ /* HBA Identifier */
+ memcpy(&rh->hi.PortName,
+ &phba->pport->fc_sparam.portName,
sizeof(struct lpfc_name));
- pab->ab.EntryCnt = 0;
-
- /* #1 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FC4Types));
- ad->AttrType =
- cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
- ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
- ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
- ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
- pab->ab.EntryCnt++;
- size += FOURBYTES + 32;
-
- /* #2 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- ae->un.SupportSpeed = 0;
- if (phba->lmt & LMT_32Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_32GBIT;
- if (phba->lmt & LMT_16Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
- if (phba->lmt & LMT_10Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
- if (phba->lmt & LMT_8Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
- if (phba->lmt & LMT_4Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT;
- if (phba->lmt & LMT_2Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT;
- if (phba->lmt & LMT_1Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT;
- ae->un.SupportSpeed =
- cpu_to_be32(ae->un.SupportSpeed);
-
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-
- /* #3 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- switch (phba->fc_linkspeed) {
- case LPFC_LINK_SPEED_1GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
- break;
- case LPFC_LINK_SPEED_2GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
- break;
- case LPFC_LINK_SPEED_4GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
- break;
- case LPFC_LINK_SPEED_8GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
- break;
- case LPFC_LINK_SPEED_10GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
- break;
- case LPFC_LINK_SPEED_16GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
- break;
- case LPFC_LINK_SPEED_32GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_32GBIT;
- break;
- default:
- ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
- break;
- }
- ae->un.PortSpeed = cpu_to_be32(ae->un.PortSpeed);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-
- /* #4 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- hsp = (struct serv_parm *)&vport->fc_sparam;
- ae->un.MaxFrameSize =
- (((uint32_t)hsp->cmn.
- bbRcvSizeMsb) << 8) | (uint32_t)hsp->cmn.
- bbRcvSizeLsb;
- ae->un.MaxFrameSize =
- cpu_to_be32(ae->un.MaxFrameSize);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #5 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OsDeviceName));
- ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
- strncpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME,
- sizeof(ae->un.OsDeviceName));
- len = strnlen((char *)ae->un.OsDeviceName,
- sizeof(ae->un.OsDeviceName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #6 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.HostName));
- snprintf(ae->un.HostName, sizeof(ae->un.HostName), "%s",
- init_utsname()->nodename);
- ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
- len = strnlen(ae->un.HostName,
- sizeof(ae->un.HostName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen =
- cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
+ pab = (struct lpfc_fdmi_reg_portattr *)
+ ((uint8_t *)pab + sizeof(struct lpfc_name));
+ }
- /*
- * Currently switches don't seem to support the
- * following extended Port attributes.
- */
- if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
- goto port_out;
-
- /* #7 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_NODENAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #8 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.PortName, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #9 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.NodeSymName));
- ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
- len = lpfc_vport_symbolic_port_name(vport,
- ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #10 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
- ae->un.PortState = 0;
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #11 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
- ae->un.SupportClass =
- cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #12 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.FabricName, &vport->fabric_nodename,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #13 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FC4Types));
- ad->AttrType =
- cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
- ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
- ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
- ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
- pab->ab.EntryCnt++;
- size += FOURBYTES + 32;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #257 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
- ae->un.PortState = 0;
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #258 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
- ae->un.PortState = lpfc_find_map_node(vport);
- ae->un.PortState = cpu_to_be32(ae->un.PortState);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #259 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
- ae->un.PortId = cpu_to_be32(vport->fc_myDID);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-port_out:
- pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
- /* Total size */
- size = GID_REQUEST_SZ - 4 + size;
+ memcpy((uint8_t *)&pab->PortName,
+ (uint8_t *)&vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ size += sizeof(struct lpfc_name) + FOURBYTES;
+ pab->ab.EntryCnt = 0;
+ bit_pos = 0;
+ if (new_mask)
+ mask = new_mask;
+ else
+ mask = vport->fdmi_port_mask;
+
+ /* Mask will dictate what attributes to build in the request */
+ while (mask) {
+ if (mask & 0x1) {
+ func = lpfc_fdmi_port_action[bit_pos];
+ size += func(vport,
+ (struct lpfc_fdmi_attr_def *)
+ ((uint8_t *)pab + size));
+ pab->ab.EntryCnt++;
+ if ((size + 256) >
+ (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+ goto port_out;
+ }
+ mask = mask >> 1;
+ bit_pos++;
}
+port_out:
+ pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
+ /* Total size */
+ if (cmdcode == SLI_MGMT_RPRT)
+ size += sizeof(struct lpfc_name);
+ size = GID_REQUEST_SZ - 4 + size;
break;
case SLI_MGMT_GHAT:
@@ -2158,41 +2749,6 @@ lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport)
}
void
-lpfc_fdmi_tmo(unsigned long ptr)
-{
- struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
- struct lpfc_hba *phba = vport->phba;
- uint32_t tmo_posted;
- unsigned long iflag;
-
- spin_lock_irqsave(&vport->work_port_lock, iflag);
- tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
- if (!tmo_posted)
- vport->work_port_events |= WORKER_FDMI_TMO;
- spin_unlock_irqrestore(&vport->work_port_lock, iflag);
-
- if (!tmo_posted)
- lpfc_worker_wake_up(phba);
- return;
-}
-
-void
-lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
-{
- struct lpfc_nodelist *ndlp;
-
- ndlp = lpfc_findnode_did(vport, FDMI_DID);
- if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
- if (init_utsname()->nodename[0] != '\0')
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
- else
- mod_timer(&vport->fc_fdmitmo, jiffies +
- msecs_to_jiffies(1000 * 60));
- }
- return;
-}
-
-void
lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
{
struct lpfc_sli *psli = &phba->sli;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 25aa9b9..a63542b 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -1054,11 +1054,11 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
{
struct dentry *dent = file->f_path.dentry;
struct lpfc_hba *phba = file->private_data;
- char dstbuf[32];
+ char dstbuf[33];
uint64_t tmp = 0;
int size;
- memset(dstbuf, 0, 32);
+ memset(dstbuf, 0, 33);
size = (nbytes < 32) ? nbytes : 32;
if (copy_from_user(dstbuf, buf, size))
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 3feeb44..7f5abb8 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -455,9 +455,9 @@ int
lpfc_issue_reg_vfi(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
- LPFC_MBOXQ_t *mboxq;
+ LPFC_MBOXQ_t *mboxq = NULL;
struct lpfc_nodelist *ndlp;
- struct lpfc_dmabuf *dmabuf;
+ struct lpfc_dmabuf *dmabuf = NULL;
int rc = 0;
/* move forward in case of SLI4 FC port loopback test and pt2pt mode */
@@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
}
}
- dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!dmabuf) {
+ mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq) {
rc = -ENOMEM;
goto fail;
}
- dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
- if (!dmabuf->virt) {
- rc = -ENOMEM;
- goto fail_free_dmabuf;
- }
- mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- rc = -ENOMEM;
- goto fail_free_coherent;
+ /* Supply CSP's only if we are fabric connect or pt-to-pt connect */
+ if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
+ dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!dmabuf) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+ if (!dmabuf->virt) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ memcpy(dmabuf->virt, &phba->fc_fabparam,
+ sizeof(struct serv_parm));
}
+
vport->port_state = LPFC_FABRIC_CFG_LINK;
- memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
- lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+ if (dmabuf)
+ lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+ else
+ lpfc_reg_vfi(mboxq, vport, 0);
mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
mboxq->vport = vport;
@@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
rc = -ENXIO;
- goto fail_free_mbox;
+ goto fail;
}
return 0;
-fail_free_mbox:
- mempool_free(mboxq, phba->mbox_mem_pool);
-fail_free_coherent:
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-fail_free_dmabuf:
- kfree(dmabuf);
fail:
+ if (mboxq)
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ if (dmabuf) {
+ if (dmabuf->virt)
+ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
+
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0289 Issue Register VFI failed: Err %d\n", rc);
@@ -678,6 +688,21 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
sp->cmn.bbRcvSizeLsb;
fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+ if (fabric_param_changed) {
+ /* Reset FDMI attribute masks based on config parameter */
+ if (phba->cfg_fdmi_on == LPFC_FDMI_NO_SUPPORT) {
+ vport->fdmi_hba_mask = 0;
+ vport->fdmi_port_mask = 0;
+ } else {
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+ else
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ }
+
+ }
memcpy(&vport->fabric_portname, &sp->portName,
sizeof(struct lpfc_name));
memcpy(&vport->fabric_nodename, &sp->nodeName,
@@ -711,9 +736,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* For FC we need to do some special processing because of the SLI
* Port's default settings of the Common Service Parameters.
*/
- if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) {
/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
- if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+ if (fabric_param_changed)
lpfc_unregister_fcf_prep(phba);
/* This should just update the VFI CSPs*/
@@ -824,13 +850,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ vport->fc_flag |= FC_PT2PT;
spin_unlock_irq(shost->host_lock);
- phba->fc_edtov = FF_DEF_EDTOV;
- phba->fc_ratov = FF_DEF_RATOV;
+ /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
+ lpfc_unregister_fcf_prep(phba);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VFI_REGISTERED;
+ spin_unlock_irq(shost->host_lock);
+ phba->fc_topology_changed = 0;
+ }
+
rc = memcmp(&vport->fc_portname, &sp->portName,
sizeof(vport->fc_portname));
- memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
if (rc >= 0) {
/* This side will initiate the PLOGI */
@@ -839,38 +873,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_unlock_irq(shost->host_lock);
/*
- * N_Port ID cannot be 0, set our to LocalID the other
- * side will be RemoteID.
+ * N_Port ID cannot be 0, set our Id to LocalID
+ * the other side will be RemoteID.
*/
/* not equal */
if (rc)
vport->fc_myDID = PT2PT_LocalID;
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
-
- lpfc_config_link(phba, mbox);
-
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto fail;
- }
-
- /*
- * For SLI4, the VFI/VPI are registered AFTER the
- * Nport with the higher WWPN sends the PLOGI with
- * an assigned NPortId.
- */
-
- /* not equal */
- if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
- lpfc_issue_reg_vfi(vport);
-
/* Decrement ndlp reference count indicating that ndlp can be
* safely released when other references to it are done.
*/
@@ -912,29 +922,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* If we are pt2pt with another NPort, force NPIV off! */
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
- spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_PT2PT;
- spin_unlock_irq(shost->host_lock);
- /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
- if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
- lpfc_unregister_fcf_prep(phba);
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
- /* The FC_VFI_REGISTERED flag will get clear in the cmpl
- * handler for unreg_vfi, but if we don't force the
- * FC_VFI_REGISTERED flag then the reg_vfi mailbox could be
- * built with the update bit set instead of just the vp bit to
- * change the Nport ID. We need to have the vp set and the
- * Upd cleared on topology changes.
- */
- spin_lock_irq(shost->host_lock);
- vport->fc_flag &= ~FC_VFI_REGISTERED;
- spin_unlock_irq(shost->host_lock);
- phba->fc_topology_changed = 0;
- lpfc_issue_reg_vfi(vport);
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto fail;
}
- /* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(vport);
return 0;
fail:
return -ENXIO;
@@ -1157,6 +1158,7 @@ flogifail:
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
spin_unlock_irq(&phba->hbalock);
+
lpfc_nlp_put(ndlp);
if (!lpfc_error_lost_link(irsp)) {
@@ -3792,14 +3794,17 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_nlp_set_state(vport, ndlp,
NLP_STE_REG_LOGIN_ISSUE);
}
+
+ ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
!= MBX_NOT_FINISHED)
goto out;
- else
- /* Decrement the ndlp reference count we
- * set for this failed mailbox command.
- */
- lpfc_nlp_put(ndlp);
+
+ /* Decrement the ndlp reference count we
+ * set for this failed mailbox command.
+ */
+ lpfc_nlp_put(ndlp);
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
/* ELS rsp: Cannot issue reg_login for <NPortid> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -3856,6 +3861,7 @@ out:
* the routine lpfc_els_free_iocb.
*/
cmdiocb->context1 = NULL;
+
}
lpfc_els_free_iocb(phba, cmdiocb);
@@ -3898,6 +3904,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb;
uint8_t *pcmd;
+ struct serv_parm *sp;
uint16_t cmdsize;
int rc;
ELS_PKT *els_pkt_ptr;
@@ -3927,6 +3934,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
"Issue ACC: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
+ case ELS_CMD_FLOGI:
case ELS_CMD_PLOGI:
cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
@@ -3944,10 +3952,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
- memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+ sp = (struct serv_parm *)pcmd;
+
+ if (flag == ELS_CMD_FLOGI) {
+ /* Copy the received service parameters back */
+ memcpy(sp, &phba->fc_fabparam,
+ sizeof(struct serv_parm));
+
+ /* Clear the F_Port bit */
+ sp->cmn.fPort = 0;
+
+ /* Mark all class service parameters as invalid */
+ sp->cls1.classValid = 0;
+ sp->cls2.classValid = 0;
+ sp->cls3.classValid = 0;
+ sp->cls4.classValid = 0;
+
+ /* Copy our worldwide names */
+ memcpy(&sp->portName, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ memcpy(&sp->nodeName, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ } else {
+ memcpy(pcmd, &vport->fc_sparam,
+ sizeof(struct serv_parm));
+ }
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
- "Issue ACC PLOGI: did:x%x flg:x%x",
+ "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
case ELS_CMD_PRLO:
@@ -4673,6 +4705,23 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
desc->length = cpu_to_be32(sizeof(desc->info));
}
+int
+lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
+{
+ if (bf_get(lpfc_read_link_stat_gec2, stat) == 0)
+ return 0;
+ desc->tag = cpu_to_be32(RDP_FEC_DESC_TAG);
+
+ desc->info.CorrectedBlocks =
+ cpu_to_be32(stat->fecCorrBlkCount);
+ desc->info.UncorrectableBlocks =
+ cpu_to_be32(stat->fecUncorrBlkCount);
+
+ desc->length = cpu_to_be32(sizeof(desc->info));
+
+ return sizeof(struct fc_fec_rdp_desc);
+}
+
void
lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
{
@@ -4681,26 +4730,26 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
desc->tag = cpu_to_be32(RDP_PORT_SPEED_DESC_TAG);
- switch (phba->sli4_hba.link_state.speed) {
- case LPFC_FC_LA_SPEED_1G:
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
rdp_speed = RDP_PS_1GB;
break;
- case LPFC_FC_LA_SPEED_2G:
+ case LPFC_LINK_SPEED_2GHZ:
rdp_speed = RDP_PS_2GB;
break;
- case LPFC_FC_LA_SPEED_4G:
+ case LPFC_LINK_SPEED_4GHZ:
rdp_speed = RDP_PS_4GB;
break;
- case LPFC_FC_LA_SPEED_8G:
+ case LPFC_LINK_SPEED_8GHZ:
rdp_speed = RDP_PS_8GB;
break;
- case LPFC_FC_LA_SPEED_10G:
+ case LPFC_LINK_SPEED_10GHZ:
rdp_speed = RDP_PS_10GB;
break;
- case LPFC_FC_LA_SPEED_16G:
+ case LPFC_LINK_SPEED_16GHZ:
rdp_speed = RDP_PS_16GB;
break;
- case LPFC_FC_LA_SPEED_32G:
+ case LPFC_LINK_SPEED_32GHZ:
rdp_speed = RDP_PS_32GB;
break;
default:
@@ -4778,15 +4827,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
struct lpfc_nodelist *ndlp = rdp_context->ndlp;
struct lpfc_vport *vport = ndlp->vport;
struct lpfc_iocbq *elsiocb;
+ struct ulp_bde64 *bpl;
IOCB_t *icmd;
uint8_t *pcmd;
struct ls_rjt *stat;
struct fc_rdp_res_frame *rdp_res;
uint32_t cmdsize;
- int rc;
+ int rc, fec_size;
if (status != SUCCESS)
goto error;
+
+ /* This will change once we know the true size of the RDP payload */
cmdsize = sizeof(struct fc_rdp_res_frame);
elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize,
@@ -4823,10 +4875,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
lpfc_rdp_res_diag_port_names(&rdp_res->diag_port_names_desc, phba);
lpfc_rdp_res_attach_port_names(&rdp_res->attached_port_names_desc,
vport, ndlp);
- rdp_res->length = cpu_to_be32(RDP_DESC_PAYLOAD_SIZE);
-
+ fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc,
+ &rdp_context->link_stat);
+ rdp_res->length = cpu_to_be32(fec_size + RDP_DESC_PAYLOAD_SIZE);
elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ /* Now that we know the true size of the payload, update the BPL */
+ bpl = (struct ulp_bde64 *)
+ (((struct lpfc_dmabuf *)(elsiocb->context3))->virt);
+ bpl->tus.f.bdeSize = (fec_size + RDP_DESC_PAYLOAD_SIZE + 8);
+ bpl->tus.f.bdeFlags = 0;
+ bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
phba->fc_stat.elsXmitACC++;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR)
@@ -4956,13 +5016,12 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
if (RDP_NPORT_ID_SIZE !=
be32_to_cpu(rdp_req->nport_id_desc.length))
goto rjt_logerr;
- rdp_context = kmalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
+ rdp_context = kzalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
if (!rdp_context) {
rjt_err = LSRJT_UNABLE_TPC;
goto error;
}
- memset(rdp_context, 0, sizeof(struct lpfc_rdp_context));
cmd = &cmdiocb->iocb;
rdp_context->ndlp = lpfc_nlp_get(ndlp);
rdp_context->ox_id = cmd->unsli3.rcvsli3.ox_id;
@@ -5173,7 +5232,6 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
rjt_err = LSRJT_CMD_UNSUPPORTED;
goto rjt;
}
- lcb_context = kmalloc(sizeof(struct lpfc_lcb_context), GFP_KERNEL);
if (phba->hba_flag & HBA_FCOE_MODE) {
rjt_err = LSRJT_CMD_UNSUPPORTED;
@@ -5204,6 +5262,12 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
goto rjt;
}
+ lcb_context = kmalloc(sizeof(*lcb_context), GFP_KERNEL);
+ if (!lcb_context) {
+ rjt_err = LSRJT_UNABLE_TPC;
+ goto rjt;
+ }
+
state = (beacon->lcb_sub_command == LPFC_LCB_ON) ? 1 : 0;
lcb_context->sub_command = beacon->lcb_sub_command;
lcb_context->type = beacon->lcb_type;
@@ -5214,6 +5278,7 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
if (lpfc_sli4_set_beacon(vport, lcb_context, state)) {
lpfc_printf_vlog(ndlp->vport, KERN_ERR,
LOG_ELS, "0193 failed to send mail box");
+ kfree(lcb_context);
lpfc_nlp_put(ndlp);
rjt_err = LSRJT_UNABLE_TPC;
goto rjt;
@@ -5733,7 +5798,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
IOCB_t *icmd = &cmdiocb->iocb;
struct serv_parm *sp;
LPFC_MBOXQ_t *mbox;
- struct ls_rjt stat;
uint32_t cmd, did;
int rc;
uint32_t fc_flag = 0;
@@ -5759,135 +5823,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 1;
}
- if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
- /* For a FLOGI we accept, then if our portname is greater
- * then the remote portname we initiate Nport login.
- */
+ (void) lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1);
- rc = memcmp(&vport->fc_portname, &sp->portName,
- sizeof(struct lpfc_name));
- if (!rc) {
- if (phba->sli_rev < LPFC_SLI_REV4) {
- mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL);
- if (!mbox)
- return 1;
- lpfc_linkdown(phba);
- lpfc_init_link(phba, mbox,
- phba->cfg_topology,
- phba->cfg_link_speed);
- mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox,
- MBX_NOWAIT);
- lpfc_set_loopback_flag(phba);
- if (rc == MBX_NOT_FINISHED)
- mempool_free(mbox, phba->mbox_mem_pool);
- return 1;
- } else {
- /* abort the flogi coming back to ourselves
- * due to external loopback on the port.
- */
- lpfc_els_abort_flogi(phba);
- return 0;
- }
- } else if (rc > 0) { /* greater than */
- spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_PT2PT_PLOGI;
- spin_unlock_irq(shost->host_lock);
+ /*
+ * If our portname is greater than the remote portname,
+ * then we initiate Nport login.
+ */
- /* If we have the high WWPN we can assign our own
- * myDID; otherwise, we have to WAIT for a PLOGI
- * from the remote NPort to find out what it
- * will be.
- */
- vport->fc_myDID = PT2PT_LocalID;
- } else
- vport->fc_myDID = PT2PT_RemoteID;
+ rc = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(struct lpfc_name));
- /*
- * The vport state should go to LPFC_FLOGI only
- * AFTER we issue a FLOGI, not receive one.
+ if (!rc) {
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ mbox = mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mbox)
+ return 1;
+ lpfc_linkdown(phba);
+ lpfc_init_link(phba, mbox,
+ phba->cfg_topology,
+ phba->cfg_link_speed);
+ mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ MBX_NOWAIT);
+ lpfc_set_loopback_flag(phba);
+ if (rc == MBX_NOT_FINISHED)
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return 1;
+ }
+
+ /* abort the flogi coming back to ourselves
+ * due to external loopback on the port.
*/
+ lpfc_els_abort_flogi(phba);
+ return 0;
+
+ } else if (rc > 0) { /* greater than */
spin_lock_irq(shost->host_lock);
- fc_flag = vport->fc_flag;
- port_state = vport->port_state;
- vport->fc_flag |= FC_PT2PT;
- vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ vport->fc_flag |= FC_PT2PT_PLOGI;
spin_unlock_irq(shost->host_lock);
- lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "3311 Rcv Flogi PS x%x new PS x%x "
- "fc_flag x%x new fc_flag x%x\n",
- port_state, vport->port_state,
- fc_flag, vport->fc_flag);
- /*
- * We temporarily set fc_myDID to make it look like we are
- * a Fabric. This is done just so we end up with the right
- * did / sid on the FLOGI ACC rsp.
+ /* If we have the high WWPN we can assign our own
+ * myDID; otherwise, we have to WAIT for a PLOGI
+ * from the remote NPort to find out what it
+ * will be.
*/
- did = vport->fc_myDID;
- vport->fc_myDID = Fabric_DID;
-
+ vport->fc_myDID = PT2PT_LocalID;
} else {
- /* Reject this request because invalid parameters */
- stat.un.b.lsRjtRsvd0 = 0;
- stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
- stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
- stat.un.b.vendorUnique = 0;
-
- /*
- * We temporarily set fc_myDID to make it look like we are
- * a Fabric. This is done just so we end up with the right
- * did / sid on the FLOGI LS_RJT rsp.
- */
- did = vport->fc_myDID;
- vport->fc_myDID = Fabric_DID;
-
- lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
- NULL);
+ vport->fc_myDID = PT2PT_RemoteID;
+ }
- /* Now lets put fc_myDID back to what its supposed to be */
- vport->fc_myDID = did;
+ /*
+ * The vport state should go to LPFC_FLOGI only
+ * AFTER we issue a FLOGI, not receive one.
+ */
+ spin_lock_irq(shost->host_lock);
+ fc_flag = vport->fc_flag;
+ port_state = vport->port_state;
+ vport->fc_flag |= FC_PT2PT;
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "3311 Rcv Flogi PS x%x new PS x%x "
+ "fc_flag x%x new fc_flag x%x\n",
+ port_state, vport->port_state,
+ fc_flag, vport->fc_flag);
- return 1;
- }
+ /*
+ * We temporarily set fc_myDID to make it look like we are
+ * a Fabric. This is done just so we end up with the right
+ * did / sid on the FLOGI ACC rsp.
+ */
+ did = vport->fc_myDID;
+ vport->fc_myDID = Fabric_DID;
- /* send our FLOGI first */
- if (vport->port_state < LPFC_FLOGI) {
- vport->fc_myDID = 0;
- lpfc_initial_flogi(vport);
- vport->fc_myDID = Fabric_DID;
- }
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
/* Send back ACC */
- lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL);
/* Now lets put fc_myDID back to what its supposed to be */
vport->fc_myDID = did;
- if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
-
- lpfc_config_link(phba, mbox);
-
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto fail;
- }
- }
-
return 0;
-fail:
- return 1;
}
/**
@@ -7339,7 +7360,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* reject till our FLOGI completes */
if ((vport->port_state < LPFC_FABRIC_CFG_LINK) &&
- (cmd != ELS_CMD_FLOGI)) {
+ (cmd != ELS_CMD_FLOGI)) {
rjt_err = LSRJT_UNABLE_TPC;
rjt_exp = LSEXP_NOTHING_MORE;
goto lsrjt;
@@ -7375,6 +7396,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
rjt_exp = LSEXP_NOTHING_MORE;
break;
}
+
if (vport->port_state < LPFC_DISC_AUTH) {
if (!(phba->pport->fc_flag & FC_PT2PT) ||
(phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -7724,6 +7746,35 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
+void
+lpfc_start_fdmi(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp;
+
+ /* If this is the first time, allocate an ndlp and initialize
+ * it. Otherwise, make sure the node is enabled and then do the
+ * login.
+ */
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
+ if (!ndlp) {
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (ndlp) {
+ lpfc_nlp_init(vport, ndlp, FDMI_DID);
+ ndlp->nlp_type |= NLP_FABRIC;
+ } else {
+ return;
+ }
+ }
+ if (!NLP_CHK_NODE_ACT(ndlp))
+ ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE);
+
+ if (ndlp) {
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+ }
+}
+
/**
* lpfc_do_scr_ns_plogi - Issue a plogi to the name server for scr
* @phba: pointer to lpfc hba data structure.
@@ -7740,7 +7791,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
void
lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
- struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+ struct lpfc_nodelist *ndlp;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
/*
@@ -7798,32 +7849,9 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
return;
}
- if (vport->cfg_fdmi_on & LPFC_FDMI_SUPPORT) {
- /* If this is the first time, allocate an ndlp and initialize
- * it. Otherwise, make sure the node is enabled and then do the
- * login.
- */
- ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
- if (!ndlp_fdmi) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
- if (ndlp_fdmi) {
- lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
- } else
- return;
- }
- if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
- ndlp_fdmi = lpfc_enable_node(vport,
- ndlp_fdmi,
- NLP_STE_NPR_NODE);
-
- if (ndlp_fdmi) {
- lpfc_nlp_set_state(vport, ndlp_fdmi,
- NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
- }
- }
+ if ((phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) &&
+ (vport->load_flag & FC_ALLOW_FDMI))
+ lpfc_start_fdmi(vport);
}
/**
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index bfc2442..25b5dcd 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
+#include <linux/lockdep.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -674,8 +675,6 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_mbox_timeout_handler(phba);
if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
lpfc_unblock_fabric_iocbs(phba);
- if (work_port_events & WORKER_FDMI_TMO)
- lpfc_fdmi_timeout_handler(vport);
if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
lpfc_ramp_down_queue_handler(phba);
if (work_port_events & WORKER_DELAYED_DISC_TMO)
@@ -1083,7 +1082,7 @@ out:
}
-static void
+void
lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
@@ -1113,8 +1112,10 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
+ if (vport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(vport);
+ else if (vport->fc_flag & FC_PT2PT)
+ lpfc_disc_start(vport);
return;
out:
@@ -1314,6 +1315,8 @@ __lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index,
{
struct lpfc_fcf_pri *fcf_pri;
+ lockdep_assert_held(&phba->hbalock);
+
fcf_pri = &phba->fcf.fcf_pri[fcf_index];
fcf_pri->fcf_rec.fcf_index = fcf_index;
/* FCF record priority */
@@ -1398,6 +1401,8 @@ __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,
struct fcf_record *new_fcf_record, uint32_t addr_mode,
uint16_t vlan_id, uint32_t flag)
{
+ lockdep_assert_held(&phba->hbalock);
+
/* Copy the fields from the HBA's FCF record */
lpfc_copy_fcf_record(fcf_rec, new_fcf_record);
/* Update other fields of driver FCF record */
@@ -2963,8 +2968,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
out_free_mem:
mempool_free(mboxq, phba->mbox_mem_pool);
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
- kfree(dmabuf);
+ if (dmabuf) {
+ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
return;
}
@@ -3035,19 +3042,22 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
uint32_t fc_flags = 0;
spin_lock_irq(&phba->hbalock);
- switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
- case LPFC_LINK_SPEED_1GHZ:
- case LPFC_LINK_SPEED_2GHZ:
- case LPFC_LINK_SPEED_4GHZ:
- case LPFC_LINK_SPEED_8GHZ:
- case LPFC_LINK_SPEED_10GHZ:
- case LPFC_LINK_SPEED_16GHZ:
- case LPFC_LINK_SPEED_32GHZ:
- phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
- break;
- default:
- phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
- break;
+ phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
+
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
+ case LPFC_LINK_SPEED_1GHZ:
+ case LPFC_LINK_SPEED_2GHZ:
+ case LPFC_LINK_SPEED_4GHZ:
+ case LPFC_LINK_SPEED_8GHZ:
+ case LPFC_LINK_SPEED_10GHZ:
+ case LPFC_LINK_SPEED_16GHZ:
+ case LPFC_LINK_SPEED_32GHZ:
+ break;
+ default:
+ phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
+ break;
+ }
}
if (phba->fc_topology &&
@@ -3448,10 +3458,10 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
spin_unlock_irq(shost->host_lock);
- } else
- /* Good status, call state machine */
- lpfc_disc_state_machine(vport, ndlp, pmb,
- NLP_EVT_CMPL_REG_LOGIN);
+ }
+
+ /* Call state machine */
+ lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -5550,15 +5560,15 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
ndlp->nlp_usg_map, ndlp);
/*
* Start issuing Fabric-Device Management Interface (FDMI) command to
- * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if
- * fdmi-on=2 (supporting RPA/hostnmae)
+ * 0xfffffa (FDMI well known port).
+ * DHBA -> DPRT -> RHBA -> RPA (physical port)
+ * DPRT -> RPRT (vports)
*/
-
- if (vport->cfg_fdmi_on & LPFC_FDMI_REG_DELAY)
- mod_timer(&vport->fc_fdmitmo,
- jiffies + msecs_to_jiffies(1000 * 60));
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
else
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+
/* decrement the node reference count held for this callback
* function.
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 2cce88e..dd20412 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1097,6 +1097,18 @@ struct fc_rdp_port_name_desc {
};
+struct fc_rdp_fec_info {
+ uint32_t CorrectedBlocks;
+ uint32_t UncorrectableBlocks;
+};
+
+#define RDP_FEC_DESC_TAG 0x00010005
+struct fc_fec_rdp_desc {
+ uint32_t tag;
+ uint32_t length;
+ struct fc_rdp_fec_info info;
+};
+
struct fc_rdp_link_error_status_payload_info {
struct fc_link_status link_status; /* 24 bytes */
uint32_t port_type; /* bits 31-30 only */
@@ -1196,14 +1208,15 @@ struct fc_rdp_res_frame {
struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13-21 */
struct fc_rdp_port_name_desc diag_port_names_desc; /* Word 22-27 */
struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28-33 */
+ struct fc_fec_rdp_desc fec_desc; /* FC Word 34 - 37 */
};
#define RDP_DESC_PAYLOAD_SIZE (sizeof(struct fc_rdp_link_service_desc) \
- + sizeof(struct fc_rdp_sfp_desc) \
- + sizeof(struct fc_rdp_port_speed_desc) \
- + sizeof(struct fc_rdp_link_error_status_desc) \
- + (sizeof(struct fc_rdp_port_name_desc) * 2))
+ + sizeof(struct fc_rdp_sfp_desc) \
+ + sizeof(struct fc_rdp_port_speed_desc) \
+ + sizeof(struct fc_rdp_link_error_status_desc) \
+ + (sizeof(struct fc_rdp_port_name_desc) * 2))
/******** FDMI ********/
@@ -1233,31 +1246,10 @@ struct lpfc_fdmi_attr_def { /* Defined in TLV format */
/* Attribute Entry */
struct lpfc_fdmi_attr_entry {
union {
- uint32_t VendorSpecific;
- uint32_t SupportClass;
- uint32_t SupportSpeed;
- uint32_t PortSpeed;
- uint32_t MaxFrameSize;
- uint32_t MaxCTPayloadLen;
- uint32_t PortState;
- uint32_t PortId;
- struct lpfc_name NodeName;
- struct lpfc_name PortName;
- struct lpfc_name FabricName;
- uint8_t FC4Types[32];
- uint8_t Manufacturer[64];
- uint8_t SerialNumber[64];
- uint8_t Model[256];
- uint8_t ModelDescription[256];
- uint8_t HardwareVersion[256];
- uint8_t DriverVersion[256];
- uint8_t OptionROMVersion[256];
- uint8_t FirmwareVersion[256];
- uint8_t OsHostName[256];
- uint8_t NodeSymName[256];
- uint8_t OsDeviceName[256];
- uint8_t OsNameVersion[256];
- uint8_t HostName[256];
+ uint32_t AttrInt;
+ uint8_t AttrTypes[32];
+ uint8_t AttrString[256];
+ struct lpfc_name AttrWWN;
} un;
};
@@ -1327,6 +1319,8 @@ struct lpfc_fdmi_reg_portattr {
#define SLI_MGMT_DPRT 0x310 /* De-register Port */
#define SLI_MGMT_DPA 0x311 /* De-register Port attributes */
+#define LPFC_FDMI_MAX_RETRY 3 /* Max retries for a FDMI command */
+
/*
* HBA Attribute Types
*/
@@ -1342,6 +1336,39 @@ struct lpfc_fdmi_reg_portattr {
#define RHBA_OS_NAME_VERSION 0xa /* 4 to 256 byte ASCII string */
#define RHBA_MAX_CT_PAYLOAD_LEN 0xb /* 32-bit unsigned int */
#define RHBA_SYM_NODENAME 0xc /* 4 to 256 byte ASCII string */
+#define RHBA_VENDOR_INFO 0xd /* 32-bit unsigned int */
+#define RHBA_NUM_PORTS 0xe /* 32-bit unsigned int */
+#define RHBA_FABRIC_WWNN 0xf /* 8 byte WWNN */
+#define RHBA_BIOS_VERSION 0x10 /* 4 to 256 byte ASCII string */
+#define RHBA_BIOS_STATE 0x11 /* 32-bit unsigned int */
+#define RHBA_VENDOR_ID 0xe0 /* 8 byte ASCII string */
+
+/* Bit mask for all individual HBA attributes */
+#define LPFC_FDMI_HBA_ATTR_wwnn 0x00000001
+#define LPFC_FDMI_HBA_ATTR_manufacturer 0x00000002
+#define LPFC_FDMI_HBA_ATTR_sn 0x00000004
+#define LPFC_FDMI_HBA_ATTR_model 0x00000008
+#define LPFC_FDMI_HBA_ATTR_description 0x00000010
+#define LPFC_FDMI_HBA_ATTR_hdw_ver 0x00000020
+#define LPFC_FDMI_HBA_ATTR_drvr_ver 0x00000040
+#define LPFC_FDMI_HBA_ATTR_rom_ver 0x00000080
+#define LPFC_FDMI_HBA_ATTR_fmw_ver 0x00000100
+#define LPFC_FDMI_HBA_ATTR_os_ver 0x00000200
+#define LPFC_FDMI_HBA_ATTR_ct_len 0x00000400
+#define LPFC_FDMI_HBA_ATTR_symbolic_name 0x00000800
+#define LPFC_FDMI_HBA_ATTR_vendor_info 0x00001000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_num_ports 0x00002000
+#define LPFC_FDMI_HBA_ATTR_fabric_wwnn 0x00004000
+#define LPFC_FDMI_HBA_ATTR_bios_ver 0x00008000
+#define LPFC_FDMI_HBA_ATTR_bios_state 0x00010000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_vendor_id 0x00020000
+
+/* Bit mask for FDMI-1 defined HBA attributes */
+#define LPFC_FDMI1_HBA_ATTR 0x000007ff
+
+/* Bit mask for FDMI-2 defined HBA attributes */
+/* Skip vendor_info and bios_state */
+#define LPFC_FDMI2_HBA_ATTR 0x0002efff
/*
* Port Attrubute Types
@@ -1353,15 +1380,65 @@ struct lpfc_fdmi_reg_portattr {
#define RPRT_OS_DEVICE_NAME 0x5 /* 4 to 256 byte ASCII string */
#define RPRT_HOST_NAME 0x6 /* 4 to 256 byte ASCII string */
#define RPRT_NODENAME 0x7 /* 8 byte WWNN */
-#define RPRT_PORTNAME 0x8 /* 8 byte WWNN */
+#define RPRT_PORTNAME 0x8 /* 8 byte WWPN */
#define RPRT_SYM_PORTNAME 0x9 /* 4 to 256 byte ASCII string */
#define RPRT_PORT_TYPE 0xa /* 32-bit unsigned int */
#define RPRT_SUPPORTED_CLASS 0xb /* 32-bit unsigned int */
-#define RPRT_FABRICNAME 0xc /* 8 byte Fabric WWNN */
+#define RPRT_FABRICNAME 0xc /* 8 byte Fabric WWPN */
#define RPRT_ACTIVE_FC4_TYPES 0xd /* 32 byte binary array */
#define RPRT_PORT_STATE 0x101 /* 32-bit unsigned int */
#define RPRT_DISC_PORT 0x102 /* 32-bit unsigned int */
#define RPRT_PORT_ID 0x103 /* 32-bit unsigned int */
+#define RPRT_SMART_SERVICE 0xf100 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_GUID 0xf101 /* 8 byte WWNN + 8 byte WWPN */
+#define RPRT_SMART_VERSION 0xf102 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_MODEL 0xf103 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_PORT_INFO 0xf104 /* 32-bit unsigned int */
+#define RPRT_SMART_QOS 0xf105 /* 32-bit unsigned int */
+#define RPRT_SMART_SECURITY 0xf106 /* 32-bit unsigned int */
+
+/* Bit mask for all individual PORT attributes */
+#define LPFC_FDMI_PORT_ATTR_fc4type 0x00000001
+#define LPFC_FDMI_PORT_ATTR_support_speed 0x00000002
+#define LPFC_FDMI_PORT_ATTR_speed 0x00000004
+#define LPFC_FDMI_PORT_ATTR_max_frame 0x00000008
+#define LPFC_FDMI_PORT_ATTR_os_devname 0x00000010
+#define LPFC_FDMI_PORT_ATTR_host_name 0x00000020
+#define LPFC_FDMI_PORT_ATTR_wwnn 0x00000040
+#define LPFC_FDMI_PORT_ATTR_wwpn 0x00000080
+#define LPFC_FDMI_PORT_ATTR_symbolic_name 0x00000100
+#define LPFC_FDMI_PORT_ATTR_port_type 0x00000200
+#define LPFC_FDMI_PORT_ATTR_class 0x00000400
+#define LPFC_FDMI_PORT_ATTR_fabric_wwpn 0x00000800
+#define LPFC_FDMI_PORT_ATTR_port_state 0x00001000
+#define LPFC_FDMI_PORT_ATTR_active_fc4type 0x00002000
+#define LPFC_FDMI_PORT_ATTR_num_disc 0x00004000
+#define LPFC_FDMI_PORT_ATTR_nportid 0x00008000
+#define LPFC_FDMI_SMART_ATTR_service 0x00010000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_guid 0x00020000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_version 0x00040000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_model 0x00080000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_port_info 0x00100000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_qos 0x00200000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_security 0x00400000 /* Vendor specific */
+
+/* Bit mask for FDMI-1 defined PORT attributes */
+#define LPFC_FDMI1_PORT_ATTR 0x0000003f
+
+/* Bit mask for FDMI-2 defined PORT attributes */
+#define LPFC_FDMI2_PORT_ATTR 0x0000ffff
+
+/* Bit mask for Smart SAN defined PORT attributes */
+#define LPFC_FDMI2_SMART_ATTR 0x007fffff
+
+/* Defines for PORT port state attribute */
+#define LPFC_FDMI_PORTSTATE_UNKNOWN 1
+#define LPFC_FDMI_PORTSTATE_ONLINE 2
+
+/* Defines for PORT port type attribute */
+#define LPFC_FDMI_PORTTYPE_UNKNOWN 0
+#define LPFC_FDMI_PORTTYPE_NPORT 1
+#define LPFC_FDMI_PORTTYPE_NLPORT 2
/*
* Begin HBA configuration parameters.
@@ -2498,10 +2575,38 @@ typedef struct {
/* Structure for MB Command READ_LINK_STAT (18) */
typedef struct {
- uint32_t rsvd1;
+ uint32_t word0;
+
+#define lpfc_read_link_stat_rec_SHIFT 0
+#define lpfc_read_link_stat_rec_MASK 0x1
+#define lpfc_read_link_stat_rec_WORD word0
+
+#define lpfc_read_link_stat_gec_SHIFT 1
+#define lpfc_read_link_stat_gec_MASK 0x1
+#define lpfc_read_link_stat_gec_WORD word0
+
+#define lpfc_read_link_stat_w02oftow23of_SHIFT 2
+#define lpfc_read_link_stat_w02oftow23of_MASK 0x3FFFFF
+#define lpfc_read_link_stat_w02oftow23of_WORD word0
+
+#define lpfc_read_link_stat_rsvd_SHIFT 24
+#define lpfc_read_link_stat_rsvd_MASK 0x1F
+#define lpfc_read_link_stat_rsvd_WORD word0
+
+#define lpfc_read_link_stat_gec2_SHIFT 29
+#define lpfc_read_link_stat_gec2_MASK 0x1
+#define lpfc_read_link_stat_gec2_WORD word0
+
+#define lpfc_read_link_stat_clrc_SHIFT 30
+#define lpfc_read_link_stat_clrc_MASK 0x1
+#define lpfc_read_link_stat_clrc_WORD word0
+
+#define lpfc_read_link_stat_clof_SHIFT 31
+#define lpfc_read_link_stat_clof_MASK 0x1
+#define lpfc_read_link_stat_clof_WORD word0
+
uint32_t linkFailureCnt;
uint32_t lossSyncCnt;
-
uint32_t lossSignalCnt;
uint32_t primSeqErrCnt;
uint32_t invalidXmitWord;
@@ -2509,6 +2614,19 @@ typedef struct {
uint32_t primSeqTimeout;
uint32_t elasticOverrun;
uint32_t arbTimeout;
+ uint32_t advRecBufCredit;
+ uint32_t curRecBufCredit;
+ uint32_t advTransBufCredit;
+ uint32_t curTransBufCredit;
+ uint32_t recEofCount;
+ uint32_t recEofdtiCount;
+ uint32_t recEofniCount;
+ uint32_t recSofcount;
+ uint32_t rsvd1;
+ uint32_t rsvd2;
+ uint32_t recDrpXriCount;
+ uint32_t fecCorrBlkCount;
+ uint32_t fecUncorrBlkCount;
} READ_LNK_VAR;
/* Structure for MB Command REG_LOGIN (19) */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 33ec4fa..608f941 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -3317,6 +3317,7 @@ struct lpfc_acqe_link {
#define LPFC_ASYNC_LINK_SPEED_20GBPS 0x5
#define LPFC_ASYNC_LINK_SPEED_25GBPS 0x6
#define LPFC_ASYNC_LINK_SPEED_40GBPS 0x7
+#define LPFC_ASYNC_LINK_SPEED_100GBPS 0x8
#define lpfc_acqe_link_duplex_SHIFT 16
#define lpfc_acqe_link_duplex_MASK 0x000000FF
#define lpfc_acqe_link_duplex_WORD word0
@@ -3447,23 +3448,50 @@ struct lpfc_acqe_fc_la {
struct lpfc_acqe_misconfigured_event {
struct {
uint32_t word0;
-#define lpfc_sli_misconfigured_port0_SHIFT 0
-#define lpfc_sli_misconfigured_port0_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port0_WORD word0
-#define lpfc_sli_misconfigured_port1_SHIFT 8
-#define lpfc_sli_misconfigured_port1_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port1_WORD word0
-#define lpfc_sli_misconfigured_port2_SHIFT 16
-#define lpfc_sli_misconfigured_port2_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port2_WORD word0
-#define lpfc_sli_misconfigured_port3_SHIFT 24
-#define lpfc_sli_misconfigured_port3_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port3_WORD word0
+#define lpfc_sli_misconfigured_port0_state_SHIFT 0
+#define lpfc_sli_misconfigured_port0_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port0_state_WORD word0
+#define lpfc_sli_misconfigured_port1_state_SHIFT 8
+#define lpfc_sli_misconfigured_port1_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port1_state_WORD word0
+#define lpfc_sli_misconfigured_port2_state_SHIFT 16
+#define lpfc_sli_misconfigured_port2_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port2_state_WORD word0
+#define lpfc_sli_misconfigured_port3_state_SHIFT 24
+#define lpfc_sli_misconfigured_port3_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port3_state_WORD word0
+ uint32_t word1;
+#define lpfc_sli_misconfigured_port0_op_SHIFT 0
+#define lpfc_sli_misconfigured_port0_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port0_op_WORD word1
+#define lpfc_sli_misconfigured_port0_severity_SHIFT 1
+#define lpfc_sli_misconfigured_port0_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port0_severity_WORD word1
+#define lpfc_sli_misconfigured_port1_op_SHIFT 8
+#define lpfc_sli_misconfigured_port1_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port1_op_WORD word1
+#define lpfc_sli_misconfigured_port1_severity_SHIFT 9
+#define lpfc_sli_misconfigured_port1_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port1_severity_WORD word1
+#define lpfc_sli_misconfigured_port2_op_SHIFT 16
+#define lpfc_sli_misconfigured_port2_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port2_op_WORD word1
+#define lpfc_sli_misconfigured_port2_severity_SHIFT 17
+#define lpfc_sli_misconfigured_port2_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port2_severity_WORD word1
+#define lpfc_sli_misconfigured_port3_op_SHIFT 24
+#define lpfc_sli_misconfigured_port3_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port3_op_WORD word1
+#define lpfc_sli_misconfigured_port3_severity_SHIFT 25
+#define lpfc_sli_misconfigured_port3_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port3_severity_WORD word1
} theEvent;
#define LPFC_SLI_EVENT_STATUS_VALID 0x00
#define LPFC_SLI_EVENT_STATUS_NOT_PRESENT 0x01
#define LPFC_SLI_EVENT_STATUS_WRONG_TYPE 0x02
#define LPFC_SLI_EVENT_STATUS_UNSUPPORTED 0x03
+#define LPFC_SLI_EVENT_STATUS_UNQUALIFIED 0x04
+#define LPFC_SLI_EVENT_STATUS_UNCERTIFIED 0x05
};
struct lpfc_acqe_sli {
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index db9446c..f57d02c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1184,8 +1184,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
lpfc_rcv_seq_check_edtov(vports[i]);
+ lpfc_fdmi_num_disc_check(vports[i]);
+ }
lpfc_destroy_vport_work_array(phba, vports);
if ((phba->link_state == LPFC_HBA_ERROR) ||
@@ -1290,6 +1292,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
jiffies +
msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
}
+ } else {
+ mod_timer(&phba->hb_tmofunc,
+ jiffies +
+ msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
}
}
@@ -2621,7 +2627,6 @@ void
lpfc_stop_vport_timers(struct lpfc_vport *vport)
{
del_timer_sync(&vport->els_tmofunc);
- del_timer_sync(&vport->fc_fdmitmo);
del_timer_sync(&vport->delayed_disc_tmo);
lpfc_can_disctmo(vport);
return;
@@ -2855,7 +2860,7 @@ lpfc_online(struct lpfc_hba *phba)
}
vports = lpfc_create_vport_work_array(phba);
- if (vports != NULL)
+ if (vports != NULL) {
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
struct Scsi_Host *shost;
shost = lpfc_shost_from_vport(vports[i]);
@@ -2872,7 +2877,8 @@ lpfc_online(struct lpfc_hba *phba)
}
spin_unlock_irq(shost->host_lock);
}
- lpfc_destroy_vport_work_array(phba, vports);
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
lpfc_unblock_mgmt_io(phba);
return 0;
@@ -3340,10 +3346,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
vport->fc_disctmo.function = lpfc_disc_timeout;
vport->fc_disctmo.data = (unsigned long)vport;
- init_timer(&vport->fc_fdmitmo);
- vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
- vport->fc_fdmitmo.data = (unsigned long)vport;
-
init_timer(&vport->els_tmofunc);
vport->els_tmofunc.function = lpfc_els_timeout;
vport->els_tmofunc.data = (unsigned long)vport;
@@ -3709,49 +3711,6 @@ lpfc_sli4_parse_latt_type(struct lpfc_hba *phba,
}
/**
- * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed
- * @phba: pointer to lpfc hba data structure.
- * @acqe_link: pointer to the async link completion queue entry.
- *
- * This routine is to parse the SLI4 link-attention link speed and translate
- * it into the base driver's link-attention link speed coding.
- *
- * Return: Link-attention link speed in terms of base driver's coding.
- **/
-static uint8_t
-lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
- struct lpfc_acqe_link *acqe_link)
-{
- uint8_t link_speed;
-
- switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
- case LPFC_ASYNC_LINK_SPEED_ZERO:
- case LPFC_ASYNC_LINK_SPEED_10MBPS:
- case LPFC_ASYNC_LINK_SPEED_100MBPS:
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- case LPFC_ASYNC_LINK_SPEED_1GBPS:
- link_speed = LPFC_LINK_SPEED_1GHZ;
- break;
- case LPFC_ASYNC_LINK_SPEED_10GBPS:
- link_speed = LPFC_LINK_SPEED_10GHZ;
- break;
- case LPFC_ASYNC_LINK_SPEED_20GBPS:
- case LPFC_ASYNC_LINK_SPEED_25GBPS:
- case LPFC_ASYNC_LINK_SPEED_40GBPS:
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- default:
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0483 Invalid link-attention link speed: x%x\n",
- bf_get(lpfc_acqe_link_speed, acqe_link));
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- }
- return link_speed;
-}
-
-/**
* lpfc_sli_port_speed_get - Get sli3 link speed code to link speed
* @phba: pointer to lpfc hba data structure.
*
@@ -3767,27 +3726,35 @@ lpfc_sli_port_speed_get(struct lpfc_hba *phba)
if (!lpfc_is_link_up(phba))
return 0;
- switch (phba->fc_linkspeed) {
- case LPFC_LINK_SPEED_1GHZ:
- link_speed = 1000;
- break;
- case LPFC_LINK_SPEED_2GHZ:
- link_speed = 2000;
- break;
- case LPFC_LINK_SPEED_4GHZ:
- link_speed = 4000;
- break;
- case LPFC_LINK_SPEED_8GHZ:
- link_speed = 8000;
- break;
- case LPFC_LINK_SPEED_10GHZ:
- link_speed = 10000;
- break;
- case LPFC_LINK_SPEED_16GHZ:
- link_speed = 16000;
- break;
- default:
- link_speed = 0;
+ if (phba->sli_rev <= LPFC_SLI_REV3) {
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
+ link_speed = 1000;
+ break;
+ case LPFC_LINK_SPEED_2GHZ:
+ link_speed = 2000;
+ break;
+ case LPFC_LINK_SPEED_4GHZ:
+ link_speed = 4000;
+ break;
+ case LPFC_LINK_SPEED_8GHZ:
+ link_speed = 8000;
+ break;
+ case LPFC_LINK_SPEED_10GHZ:
+ link_speed = 10000;
+ break;
+ case LPFC_LINK_SPEED_16GHZ:
+ link_speed = 16000;
+ break;
+ default:
+ link_speed = 0;
+ }
+ } else {
+ if (phba->sli4_hba.link_state.logical_speed)
+ link_speed =
+ phba->sli4_hba.link_state.logical_speed;
+ else
+ link_speed = phba->sli4_hba.link_state.speed;
}
return link_speed;
}
@@ -3983,7 +3950,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
la->eventTag = acqe_link->event_tag;
bf_set(lpfc_mbx_read_top_att_type, la, att_type);
bf_set(lpfc_mbx_read_top_link_spd, la,
- lpfc_sli4_parse_latt_link_speed(phba, acqe_link));
+ (bf_get(lpfc_acqe_link_speed, acqe_link)));
/* Fake the the following irrelvant fields */
bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT);
@@ -4113,22 +4080,18 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
char message[128];
uint8_t status;
uint8_t evt_type;
+ uint8_t operational = 0;
struct temp_event temp_event_data;
struct lpfc_acqe_misconfigured_event *misconfigured;
struct Scsi_Host *shost;
evt_type = bf_get(lpfc_trailer_type, acqe_sli);
- /* Special case Lancer */
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
- LPFC_SLI_INTF_IF_TYPE_2) {
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "2901 Async SLI event - Event Data1:x%08x Event Data2:"
- "x%08x SLI Event Type:%d\n",
- acqe_sli->event_data1, acqe_sli->event_data2,
- evt_type);
- return;
- }
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2901 Async SLI event - Event Data1:x%08x Event Data2:"
+ "x%08x SLI Event Type:%d\n",
+ acqe_sli->event_data1, acqe_sli->event_data2,
+ evt_type);
port_name = phba->Port[0];
if (port_name == 0x00)
@@ -4174,29 +4137,46 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
/* fetch the status for this port */
switch (phba->sli4_hba.lnk_info.lnk_no) {
case LPFC_LINK_NUMBER_0:
- status = bf_get(lpfc_sli_misconfigured_port0,
+ status = bf_get(lpfc_sli_misconfigured_port0_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port0_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_1:
- status = bf_get(lpfc_sli_misconfigured_port1,
+ status = bf_get(lpfc_sli_misconfigured_port1_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port1_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_2:
- status = bf_get(lpfc_sli_misconfigured_port2,
+ status = bf_get(lpfc_sli_misconfigured_port2_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port2_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_3:
- status = bf_get(lpfc_sli_misconfigured_port3,
+ status = bf_get(lpfc_sli_misconfigured_port3_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port3_op,
&misconfigured->theEvent);
break;
default:
- status = ~LPFC_SLI_EVENT_STATUS_VALID;
- break;
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "3296 "
+ "LPFC_SLI_EVENT_TYPE_MISCONFIGURED "
+ "event: Invalid link %d",
+ phba->sli4_hba.lnk_info.lnk_no);
+ return;
}
+ /* Skip if optic state unchanged */
+ if (phba->sli4_hba.lnk_info.optic_state == status)
+ return;
+
switch (status) {
case LPFC_SLI_EVENT_STATUS_VALID:
- return; /* no message if the sfp is okay */
+ sprintf(message, "Physical Link is functional");
+ break;
case LPFC_SLI_EVENT_STATUS_NOT_PRESENT:
sprintf(message, "Optics faulted/incorrectly "
"installed/not installed - Reseat optics, "
@@ -4211,15 +4191,26 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
sprintf(message, "Incompatible optics - Replace with "
"compatible optics for card to function.");
break;
+ case LPFC_SLI_EVENT_STATUS_UNQUALIFIED:
+ sprintf(message, "Unqualified optics - Replace with "
+ "Avago optics for Warranty and Technical "
+ "Support - Link is%s operational",
+ (operational) ? "" : " not");
+ break;
+ case LPFC_SLI_EVENT_STATUS_UNCERTIFIED:
+ sprintf(message, "Uncertified optics - Replace with "
+ "Avago-certified optics to enable link "
+ "operation - Link is%s operational",
+ (operational) ? "" : " not");
+ break;
default:
/* firmware is reporting a status we don't know about */
sprintf(message, "Unknown event status x%02x", status);
break;
}
-
+ phba->sli4_hba.lnk_info.optic_state = status;
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "3176 Misconfigured Physical Port - "
- "Port Name %c %s\n", port_name, message);
+ "3176 Port Name %c %s\n", port_name, message);
break;
case LPFC_SLI_EVENT_TYPE_REMOTE_DPORT:
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -5293,6 +5284,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
+ /* initialize optic_state to 0xFF */
+ phba->sli4_hba.lnk_info.optic_state = 0xff;
+
/* Initialize the driver internal SLI layer lists. */
lpfc_sli_setup(phba);
lpfc_sli_queue_setup(phba);
@@ -6159,6 +6153,20 @@ lpfc_create_shost(struct lpfc_hba *phba)
/* Put reference to SCSI host to driver's device private data */
pci_set_drvdata(phba->pcidev, shost);
+ /*
+ * At this point we are fully registered with PSA. In addition,
+ * any initial discovery should be completed.
+ */
+ vport->load_flag |= FC_ALLOW_FDMI;
+ if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+ else
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ }
return 0;
}
@@ -8833,9 +8841,12 @@ found:
* already mapped to this phys_id.
*/
if (cpup->irq != LPFC_VECTOR_MAP_EMPTY) {
- chann[saved_chann] =
- cpup->channel_id;
- saved_chann++;
+ if (saved_chann <=
+ LPFC_FCP_IO_CHAN_MAX) {
+ chann[saved_chann] =
+ cpup->channel_id;
+ saved_chann++;
+ }
goto out;
}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 3fa6533..4fb3581 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -231,15 +231,13 @@ lpfc_mem_free(struct lpfc_hba *phba)
if (phba->lpfc_hbq_pool)
pci_pool_destroy(phba->lpfc_hbq_pool);
phba->lpfc_hbq_pool = NULL;
-
- if (phba->rrq_pool)
- mempool_destroy(phba->rrq_pool);
+ mempool_destroy(phba->rrq_pool);
phba->rrq_pool = NULL;
/* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
- if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
+ if (phba->sli_rev == LPFC_SLI_REV4) {
mempool_destroy(phba->active_rrq_pool);
phba->active_rrq_pool = NULL;
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index ed9a2c8..193733e 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -280,38 +280,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t *lp;
IOCB_t *icmd;
struct serv_parm *sp;
+ uint32_t ed_tov;
LPFC_MBOXQ_t *mbox;
struct ls_rjt stat;
int rc;
memset(&stat, 0, sizeof (struct ls_rjt));
- if (vport->port_state <= LPFC_FDISC) {
- /* Before responding to PLOGI, check for pt2pt mode.
- * If we are pt2pt, with an outstanding FLOGI, abort
- * the FLOGI and resend it first.
- */
- if (vport->fc_flag & FC_PT2PT) {
- lpfc_els_abort_flogi(phba);
- if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
- /* If the other side is supposed to initiate
- * the PLOGI anyway, just ACC it now and
- * move on with discovery.
- */
- phba->fc_edtov = FF_DEF_EDTOV;
- phba->fc_ratov = FF_DEF_RATOV;
- /* Start discovery - this should just do
- CLEAR_LA */
- lpfc_disc_start(vport);
- } else
- lpfc_initial_flogi(vport);
- } else {
- stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
- stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
- ndlp, NULL);
- return 0;
- }
- }
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
@@ -404,30 +378,46 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Check for Nport to NPort pt2pt protocol */
if ((vport->fc_flag & FC_PT2PT) &&
!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
/* rcv'ed PLOGI decides what our NPortId will be */
vport->fc_myDID = icmd->un.rcvels.parmRo;
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (mbox == NULL)
- goto out;
- lpfc_config_link(phba, mbox);
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto out;
+
+ ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+ if (sp->cmn.edtovResolution) {
+ /* E_D_TOV ticks are in nanoseconds */
+ ed_tov = (phba->fc_edtov + 999999) / 1000000;
}
+
/*
- * For SLI4, the VFI/VPI are registered AFTER the
- * Nport with the higher WWPN sends us a PLOGI with
- * our assigned NPortId.
+ * For pt-to-pt, use the larger EDTOV
+ * RATOV = 2 * EDTOV
*/
+ if (ed_tov > phba->fc_edtov)
+ phba->fc_edtov = ed_tov;
+ phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+ /* Issue config_link / reg_vfi to account for updated TOV's */
+
if (phba->sli_rev == LPFC_SLI_REV4)
lpfc_issue_reg_vfi(vport);
+ else {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox == NULL)
+ goto out;
+ lpfc_config_link(phba, mbox);
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto out;
+ }
+ }
lpfc_can_disctmo(vport);
}
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
goto out;
@@ -1038,7 +1028,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
uint32_t *lp;
IOCB_t *irsp;
struct serv_parm *sp;
+ uint32_t ed_tov;
LPFC_MBOXQ_t *mbox;
+ int rc;
cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1094,18 +1086,63 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
ndlp->nlp_maxframe =
((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
+ if ((vport->fc_flag & FC_PT2PT) &&
+ (vport->fc_flag & FC_PT2PT_PLOGI)) {
+ ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+ if (sp->cmn.edtovResolution) {
+ /* E_D_TOV ticks are in nanoseconds */
+ ed_tov = (phba->fc_edtov + 999999) / 1000000;
+ }
+
+ /*
+ * Use the larger EDTOV
+ * RATOV = 2 * EDTOV for pt-to-pt
+ */
+ if (ed_tov > phba->fc_edtov)
+ phba->fc_edtov = ed_tov;
+ phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+ /* Issue config_link / reg_vfi to account for updated TOV's */
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ lpfc_issue_reg_vfi(vport);
+ } else {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0133 PLOGI: no memory "
+ "for config_link "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
+ goto out;
+ }
+
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto out;
+ }
+ }
+ }
+
+ lpfc_unreg_rpi(vport, ndlp);
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0133 PLOGI: no memory for reg_login "
- "Data: x%x x%x x%x x%x\n",
- ndlp->nlp_DID, ndlp->nlp_state,
- ndlp->nlp_flag, ndlp->nlp_rpi);
+ "0018 PLOGI: no memory for reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
goto out;
}
- lpfc_unreg_rpi(vport, ndlp);
-
if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
(uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
switch (ndlp->nlp_DID) {
@@ -2299,6 +2336,9 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
if (vport->phba->sli_rev < LPFC_SLI_REV4)
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_flag |= NLP_RPI_REGISTERED;
+ if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+ lpfc_unreg_rpi(vport, ndlp);
+ }
} else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
lpfc_drop_node(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 051b3b3..3bd0be6 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -3676,6 +3676,7 @@ static void
lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
struct lpfc_iocbq *rsp_iocb)
{
+ struct lpfc_hba *phba = vport->phba;
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
@@ -3685,6 +3686,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
uint32_t *lp;
uint32_t host_status = DID_OK;
uint32_t rsplen = 0;
+ uint32_t fcpDl;
uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
@@ -3755,13 +3757,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
fcprsp->rspInfo3);
scsi_set_resid(cmnd, 0);
+ fcpDl = be32_to_cpu(fcpcmd->fcpDl);
if (resp_info & RESID_UNDER) {
scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
"9025 FCP Read Underrun, expected %d, "
"residual %d Data: x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
+ fcpDl,
scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
cmnd->underflow);
@@ -3777,7 +3780,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
LOG_FCP | LOG_FCP_ERROR,
"9026 FCP Read Check Error "
"and Underrun Data: x%x x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
+ fcpDl,
scsi_get_resid(cmnd), fcpi_parm,
cmnd->cmnd[0]);
scsi_set_resid(cmnd, scsi_bufflen(cmnd));
@@ -3812,13 +3815,25 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
* Check SLI validation that all the transfer was actually done
* (fcpi_parm should be zero). Apply check only to reads.
*/
- } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
+ } else if (fcpi_parm) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
- "9029 FCP Read Check Error Data: "
+ "9029 FCP %s Check Error xri x%x Data: "
"x%x x%x x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
- be32_to_cpu(fcprsp->rspResId),
+ ((cmnd->sc_data_direction == DMA_FROM_DEVICE) ?
+ "Read" : "Write"),
+ ((phba->sli_rev == LPFC_SLI_REV4) ?
+ lpfc_cmd->cur_iocbq.sli4_xritag :
+ rsp_iocb->iocb.ulpContext),
+ fcpDl, be32_to_cpu(fcprsp->rspResId),
fcpi_parm, cmnd->cmnd[0], scsi_status);
+
+ /* There is some issue with the LPe12000 that causes it
+ * to miscalculate the fcpi_parm and falsely trip this
+ * recovery logic. Detect this case and don't error when true.
+ */
+ if (fcpi_parm > fcpDl)
+ goto out;
+
switch (scsi_status) {
case SAM_STAT_GOOD:
case SAM_STAT_CHECK_CONDITION:
@@ -3908,9 +3923,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
uint32_t logit = LOG_FCP;
/* Sanity check on return of outstanding command */
- if (!(lpfc_cmd->pCmd))
- return;
cmd = lpfc_cmd->pCmd;
+ if (!cmd)
+ return;
shost = cmd->device->host;
lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
@@ -4124,23 +4139,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
/* The sdev is not guaranteed to be valid post scsi_done upcall. */
cmd->scsi_done(cmd);
- if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- spin_lock_irqsave(&phba->hbalock, flags);
- lpfc_cmd->pCmd = NULL;
- spin_unlock_irqrestore(&phba->hbalock, flags);
-
- /*
- * If there is a thread waiting for command completion
- * wake up the thread.
- */
- spin_lock_irqsave(shost->host_lock, flags);
- if (lpfc_cmd->waitq)
- wake_up(lpfc_cmd->waitq);
- spin_unlock_irqrestore(shost->host_lock, flags);
- lpfc_release_scsi_buf(phba, lpfc_cmd);
- return;
- }
-
spin_lock_irqsave(&phba->hbalock, flags);
lpfc_cmd->pCmd = NULL;
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -4446,15 +4444,7 @@ lpfc_info(struct Scsi_Host *host)
phba->Port);
}
len = strlen(lpfcinfobuf);
- if (phba->sli_rev <= LPFC_SLI_REV3) {
- link_speed = lpfc_sli_port_speed_get(phba);
- } else {
- if (phba->sli4_hba.link_state.logical_speed)
- link_speed =
- phba->sli4_hba.link_state.logical_speed;
- else
- link_speed = phba->sli4_hba.link_state.speed;
- }
+ link_speed = lpfc_sli_port_speed_get(phba);
if (link_speed != 0)
snprintf(lpfcinfobuf + len, 384-len,
" Logical Link Speed: %d Mbps", link_speed);
@@ -5914,7 +5904,6 @@ struct scsi_host_template lpfc_template_s3 = {
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
.change_queue_depth = scsi_change_queue_depth,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -5940,7 +5929,6 @@ struct scsi_host_template lpfc_template = {
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
.change_queue_depth = scsi_change_queue_depth,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -5964,6 +5952,5 @@ struct scsi_host_template lpfc_vport_template = {
.shost_attrs = lpfc_vport_attrs,
.max_sectors = 0xFFFF,
.change_queue_depth = scsi_change_queue_depth,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f9585cd..2207726 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/lockdep.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -576,6 +577,8 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq * iocbq = NULL;
+ lockdep_assert_held(&phba->hbalock);
+
list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
if (iocbq)
phba->iocb_cnt++;
@@ -797,6 +800,7 @@ int
lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
uint16_t xritag)
{
+ lockdep_assert_held(&phba->hbalock);
if (!ndlp)
return 0;
if (!ndlp->active_rrqs_xri_bitmap)
@@ -914,6 +918,8 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
struct lpfc_nodelist *ndlp;
int found = 0;
+ lockdep_assert_held(&phba->hbalock);
+
if (piocbq->iocb_flag & LPFC_IO_FCP) {
lpfc_cmd = (struct lpfc_scsi_buf *) piocbq->context1;
ndlp = lpfc_cmd->rdata->pnode;
@@ -1003,6 +1009,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
unsigned long iflag = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ lockdep_assert_held(&phba->hbalock);
+
if (iocbq->sli4_xritag == NO_XRI)
sglq = NULL;
else
@@ -1058,6 +1066,7 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
+ lockdep_assert_held(&phba->hbalock);
/*
* Clean all volatile data fields, preserve iotag and node struct.
@@ -1080,6 +1089,8 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
static void
__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
+ lockdep_assert_held(&phba->hbalock);
+
phba->__lpfc_sli_release_iocbq(phba, iocbq);
phba->iocb_cnt--;
}
@@ -1310,6 +1321,8 @@ static int
lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
+ lockdep_assert_held(&phba->hbalock);
+
list_add_tail(&piocb->list, &pring->txcmplq);
piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
@@ -1344,6 +1357,8 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_iocbq *cmd_iocb;
+ lockdep_assert_held(&phba->hbalock);
+
list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
return cmd_iocb;
}
@@ -1367,6 +1382,9 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
uint32_t max_cmd_idx = pring->sli.sli3.numCiocb;
+
+ lockdep_assert_held(&phba->hbalock);
+
if ((pring->sli.sli3.next_cmdidx == pring->sli.sli3.cmdidx) &&
(++pring->sli.sli3.next_cmdidx >= max_cmd_idx))
pring->sli.sli3.next_cmdidx = 0;
@@ -1497,6 +1515,7 @@ static void
lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
IOCB_t *iocb, struct lpfc_iocbq *nextiocb)
{
+ lockdep_assert_held(&phba->hbalock);
/*
* Set up an iotag
*/
@@ -1606,6 +1625,8 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
IOCB_t *iocb;
struct lpfc_iocbq *nextiocb;
+ lockdep_assert_held(&phba->hbalock);
+
/*
* Check to see if:
* (a) there is anything on the txq to send
@@ -1647,6 +1668,8 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
{
struct hbq_s *hbqp = &phba->hbqs[hbqno];
+ lockdep_assert_held(&phba->hbalock);
+
if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx &&
++hbqp->next_hbqPutIdx >= hbqp->entry_count)
hbqp->next_hbqPutIdx = 0;
@@ -1747,6 +1770,7 @@ static int
lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
struct hbq_dmabuf *hbq_buf)
{
+ lockdep_assert_held(&phba->hbalock);
return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf);
}
@@ -1768,6 +1792,7 @@ lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno,
struct lpfc_hbq_entry *hbqe;
dma_addr_t physaddr = hbq_buf->dbuf.phys;
+ lockdep_assert_held(&phba->hbalock);
/* Get next HBQ entry slot to use */
hbqe = lpfc_sli_next_hbq_slot(phba, hbqno);
if (hbqe) {
@@ -1808,6 +1833,7 @@ lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno,
struct lpfc_rqe hrqe;
struct lpfc_rqe drqe;
+ lockdep_assert_held(&phba->hbalock);
hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys);
hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys);
drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys);
@@ -1986,6 +2012,8 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
struct hbq_dmabuf *hbq_buf;
uint32_t hbqno;
+ lockdep_assert_held(&phba->hbalock);
+
hbqno = tag >> 16;
if (hbqno >= LPFC_MAX_HBQS)
return NULL;
@@ -2647,6 +2675,7 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
{
struct lpfc_iocbq *cmd_iocb = NULL;
uint16_t iotag;
+ lockdep_assert_held(&phba->hbalock);
iotag = prspiocb->iocb.ulpIoTag;
@@ -2685,6 +2714,7 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
{
struct lpfc_iocbq *cmd_iocb;
+ lockdep_assert_held(&phba->hbalock);
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
@@ -3799,6 +3829,8 @@ void lpfc_reset_barrier(struct lpfc_hba *phba)
int i;
uint8_t hdrtype;
+ lockdep_assert_held(&phba->hbalock);
+
pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
if (hdrtype != 0x80 ||
(FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID &&
@@ -7861,6 +7893,7 @@ void
__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
+ lockdep_assert_held(&phba->hbalock);
/* Insert the caller's iocb in the txq tail for later processing. */
list_add_tail(&piocb->list, &pring->txq);
}
@@ -7888,6 +7921,8 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
{
struct lpfc_iocbq * nextiocb;
+ lockdep_assert_held(&phba->hbalock);
+
nextiocb = lpfc_sli_ringtx_get(phba, pring);
if (!nextiocb) {
nextiocb = *piocb;
@@ -7927,6 +7962,8 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number,
IOCB_t *iocb;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
+ lockdep_assert_held(&phba->hbalock);
+
if (piocb->iocb_cmpl && (!piocb->vport) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
@@ -8642,6 +8679,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_queue *wq;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
+ lockdep_assert_held(&phba->hbalock);
+
if (piocb->sli4_xritag == NO_XRI) {
if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
@@ -9752,6 +9791,8 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
int retval;
unsigned long iflags;
+ lockdep_assert_held(&phba->hbalock);
+
/*
* There are certain command types we don't want to abort. And we
* don't want to abort commands that are already in the process of
@@ -9854,6 +9895,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
int retval = IOCB_ERROR;
IOCB_t *icmd = NULL;
+ lockdep_assert_held(&phba->hbalock);
+
/*
* There are certain command types we don't want to abort. And we
* don't want to abort commands that are already in the process of
@@ -14842,10 +14885,12 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
struct lpfc_dmabuf *h_buf;
struct hbq_dmabuf *seq_dmabuf = NULL;
struct hbq_dmabuf *temp_dmabuf = NULL;
+ uint8_t found = 0;
INIT_LIST_HEAD(&dmabuf->dbuf.list);
dmabuf->time_stamp = jiffies;
new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+
/* Use the hdr_buf to find the sequence that this frame belongs to */
list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
temp_hdr = (struct fc_frame_header *)h_buf->virt;
@@ -14885,7 +14930,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
return seq_dmabuf;
}
/* find the correct place in the sequence to insert this frame */
- list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+ d_buf = list_entry(seq_dmabuf->dbuf.list.prev, typeof(*d_buf), list);
+ while (!found) {
temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
/*
@@ -14895,9 +14941,17 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
if (be16_to_cpu(new_hdr->fh_seq_cnt) >
be16_to_cpu(temp_hdr->fh_seq_cnt)) {
list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
- return seq_dmabuf;
+ found = 1;
+ break;
}
+
+ if (&d_buf->list == &seq_dmabuf->dbuf.list)
+ break;
+ d_buf = list_entry(d_buf->list.prev, typeof(*d_buf), list);
}
+
+ if (found)
+ return seq_dmabuf;
return NULL;
}
@@ -16173,7 +16227,7 @@ fail_fcf_read:
}
/**
- * lpfc_check_next_fcf_pri
+ * lpfc_check_next_fcf_pri_level
* phba pointer to the lpfc_hba struct for this port.
* This routine is called from the lpfc_sli4_fcf_rr_next_index_get
* routine when the rr_bmask is empty. The FCF indecies are put into the
@@ -16329,8 +16383,12 @@ next_priority:
if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
- LPFC_FCF_FLOGI_FAILED)
+ LPFC_FCF_FLOGI_FAILED) {
+ if (list_is_singular(&phba->fcf.fcf_pri_list))
+ return LPFC_FCOE_FCF_NEXT_NONE;
+
goto next_priority;
+ }
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"2845 Get next roundrobin failover FCF (x%x)\n",
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 1e916e1..cd780c2 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -442,6 +442,7 @@ struct lpfc_sli4_lnk_info {
#define LPFC_LNK_GE 0x0 /* FCoE */
#define LPFC_LNK_FC 0x1 /* FC */
uint8_t lnk_no;
+ uint8_t optic_state;
};
#define LPFC_SLI4_HANDLER_CNT (LPFC_FCP_IO_CHAN_MAX+ \
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index ea53aa6..4dc2256 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "11.0.0.0."
+#define LPFC_DRIVER_VERSION "11.0.0.10."
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 7690126..b3f85de 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -393,6 +393,14 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
*(struct lpfc_vport **)fc_vport->dd_data = vport;
vport->fc_vport = fc_vport;
+ /* At this point we are fully registered with SCSI Layer. */
+ vport->load_flag |= FC_ALLOW_FDMI;
+ if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = phba->pport->fdmi_hba_mask;
+ vport->fdmi_port_mask = phba->pport->fdmi_port_mask;
+ }
+
/*
* In SLI4, the vpi must be activated before it can be used
* by the port.
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 1412266..a6682c5 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -18,11 +18,11 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <asm/dbdma.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
-#include <asm/pci-bridge.h>
#include <asm/macio.h>
#include <scsi/scsi.h>
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index d64a769..bb23813 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -12,7 +12,6 @@
*/
#include <linux/types.h>
-#include <linux/delay.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
@@ -32,14 +31,13 @@
#define PSEUDO_DMA
#define NCR5380_implementation_fields unsigned char *pdma_base
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
-#define NCR5380_read(reg) macscsi_read(_instance, reg)
-#define NCR5380_write(reg, value) macscsi_write(_instance, reg, value)
+#define NCR5380_read(reg) macscsi_read(instance, reg)
+#define NCR5380_write(reg, value) macscsi_write(instance, reg, value)
#define NCR5380_pread macscsi_pread
#define NCR5380_pwrite macscsi_pwrite
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_intr macscsi_intr
#define NCR5380_queue_command macscsi_queue_command
@@ -51,8 +49,6 @@
#include "NCR5380.h"
-#define RESET_BOOT
-
static int setup_can_queue = -1;
module_param(setup_can_queue, int, 0);
static int setup_cmd_per_lun = -1;
@@ -65,17 +61,8 @@ static int setup_use_tagged_queuing = -1;
module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-
-/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
- * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
- * need ten times the standard value... */
-#define TOSHIBA_DELAY
-
-#ifdef TOSHIBA_DELAY
-#define AFTER_RESET_DELAY (5*HZ/2)
-#else
-#define AFTER_RESET_DELAY (HZ/2)
-#endif
+static int setup_toshiba_delay = -1;
+module_param(setup_toshiba_delay, int, 0);
/*
* NCR 5380 register access functions
@@ -94,12 +81,12 @@ static inline void macscsi_write(struct Scsi_Host *instance, int reg, int value)
#ifndef MODULE
static int __init mac_scsi_setup(char *str)
{
- int ints[7];
+ int ints[8];
(void)get_options(str, ARRAY_SIZE(ints), ints);
- if (ints[0] < 1 || ints[0] > 6) {
- pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>]]]]]\n");
+ if (ints[0] < 1) {
+ pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
return 0;
}
if (ints[0] >= 1)
@@ -114,50 +101,14 @@ static int __init mac_scsi_setup(char *str)
setup_use_tagged_queuing = ints[5];
if (ints[0] >= 6)
setup_use_pdma = ints[6];
+ if (ints[0] >= 7)
+ setup_toshiba_delay = ints[7];
return 1;
}
__setup("mac5380=", mac_scsi_setup);
#endif /* !MODULE */
-#ifdef RESET_BOOT
-/*
- * Our 'bus reset on boot' function
- */
-
-static void mac_scsi_reset_boot(struct Scsi_Host *instance)
-{
- unsigned long end;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
- /*
- * Do a SCSI reset to clean up the bus during initialization. No messing
- * with the queues, interrupts, or locks necessary here.
- */
-
- printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
- /* The min. reset hold time is 25us, so 40us should be enough */
- udelay( 50 );
- /* reset RST and interrupt */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
- for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
- barrier();
-
- printk(KERN_INFO " done\n" );
-}
-#endif
-
#ifdef PSEUDO_DMA
/*
Pseudo-DMA: (Ove Edlund)
@@ -235,9 +186,6 @@ static int macscsi_pread(struct Scsi_Host *instance,
unsigned char *d;
unsigned char *s;
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
s = hostdata->pdma_base + (INPUT_DATA_REG << 4);
d = dst;
@@ -329,9 +277,6 @@ static int macscsi_pwrite(struct Scsi_Host *instance,
unsigned char *s;
unsigned char *d;
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
s = src;
d = hostdata->pdma_base + (OUTPUT_DATA_REG << 4);
@@ -364,20 +309,22 @@ static int macscsi_pwrite(struct Scsi_Host *instance,
#define PFX DRV_MODULE_NAME ": "
static struct scsi_host_template mac_scsi_template = {
- .module = THIS_MODULE,
- .proc_name = DRV_MODULE_NAME,
- .show_info = macscsi_show_info,
- .write_info = macscsi_write_info,
- .name = "Macintosh NCR5380 SCSI",
- .info = macscsi_info,
- .queuecommand = macscsi_queue_command,
- .eh_abort_handler = macscsi_abort,
- .eh_bus_reset_handler = macscsi_bus_reset,
- .can_queue = 16,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING
+ .module = THIS_MODULE,
+ .proc_name = DRV_MODULE_NAME,
+ .show_info = macscsi_show_info,
+ .write_info = macscsi_write_info,
+ .name = "Macintosh NCR5380 SCSI",
+ .info = macscsi_info,
+ .queuecommand = macscsi_queue_command,
+ .eh_abort_handler = macscsi_abort,
+ .eh_bus_reset_handler = macscsi_bus_reset,
+ .can_queue = 16,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int __init mac_scsi_probe(struct platform_device *pdev)
@@ -432,15 +379,14 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
} else
host_flags |= FLAG_NO_PSEUDO_DMA;
-#ifdef RESET_BOOT
- mac_scsi_reset_boot(instance);
-#endif
-
#ifdef SUPPORT_TAGS
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
#endif
+ host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
- NCR5380_init(instance, host_flags);
+ error = NCR5380_init(instance, host_flags);
+ if (error)
+ goto fail_init;
if (instance->irq != NO_IRQ) {
error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
@@ -449,6 +395,8 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
goto fail_irq;
}
+ NCR5380_maybe_reset_bus(instance);
+
error = scsi_add_host(instance, NULL);
if (error)
goto fail_host;
@@ -463,6 +411,7 @@ fail_host:
free_irq(instance->irq, instance);
fail_irq:
NCR5380_exit(instance);
+fail_init:
scsi_host_put(instance);
return error;
}
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index a706927..4cf9ed9 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -179,8 +179,12 @@ mraid_mm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
/*
* The following call will block till a kioc is available
+ * or return NULL if the list head is empty for the pointer
+ * of type mraid_mmapt passed to mraid_mm_alloc_kioc
*/
kioc = mraid_mm_alloc_kioc(adp);
+ if (!kioc)
+ return -ENXIO;
/*
* User sent the old mimd_t ioctl packet. Convert it to uioc_t.
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 20c3754..fce414a 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -35,8 +35,8 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "06.807.10.00-rc1"
-#define MEGASAS_RELDATE "March 6, 2015"
+#define MEGASAS_VERSION "06.810.09.00-rc1"
+#define MEGASAS_RELDATE "Jan. 28, 2016"
/*
* Device IDs
@@ -52,6 +52,10 @@
#define PCI_DEVICE_ID_LSI_PLASMA 0x002f
#define PCI_DEVICE_ID_LSI_INVADER 0x005d
#define PCI_DEVICE_ID_LSI_FURY 0x005f
+#define PCI_DEVICE_ID_LSI_INTRUDER 0x00ce
+#define PCI_DEVICE_ID_LSI_INTRUDER_24 0x00cf
+#define PCI_DEVICE_ID_LSI_CUTLASS_52 0x0052
+#define PCI_DEVICE_ID_LSI_CUTLASS_53 0x0053
/*
* Intel HBA SSDIDs
@@ -62,6 +66,14 @@
#define MEGARAID_INTEL_RS3MC044_SSDID 0x9381
#define MEGARAID_INTEL_RS3WC080_SSDID 0x9341
#define MEGARAID_INTEL_RS3WC040_SSDID 0x9343
+#define MEGARAID_INTEL_RMS3BC160_SSDID 0x352B
+
+/*
+ * Intruder HBA SSDIDs
+ */
+#define MEGARAID_INTRUDER_SSDID1 0x9371
+#define MEGARAID_INTRUDER_SSDID2 0x9390
+#define MEGARAID_INTRUDER_SSDID3 0x9370
/*
* Intel HBA branding
@@ -78,6 +90,8 @@
"Intel(R) RAID Controller RS3WC080"
#define MEGARAID_INTEL_RS3WC040_BRANDING \
"Intel(R) RAID Controller RS3WC040"
+#define MEGARAID_INTEL_RMS3BC160_BRANDING \
+ "Intel(R) Integrated RAID Module RMS3BC160"
/*
* =====================================
@@ -138,6 +152,7 @@
#define MFI_RESET_FLAGS MFI_INIT_READY| \
MFI_INIT_MFIMODE| \
MFI_INIT_ABORT
+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01)
/*
* MFI frame flags
@@ -156,6 +171,7 @@
/* Driver internal */
#define DRV_DCMD_POLLED_MODE 0x1
+#define DRV_DCMD_SKIP_REFIRE 0x2
/*
* Definition for cmd_status
@@ -200,6 +216,7 @@
#define MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS 0x01190100
#define MR_DRIVER_SET_APP_CRASHDUMP_MODE (0xF0010000 | 0x0600)
+#define MR_DCMD_PD_GET_INFO 0x02020000
/*
* Global functions
@@ -273,6 +290,16 @@ enum MFI_STAT {
MFI_STAT_INVALID_STATUS = 0xFF
};
+enum mfi_evt_class {
+ MFI_EVT_CLASS_DEBUG = -2,
+ MFI_EVT_CLASS_PROGRESS = -1,
+ MFI_EVT_CLASS_INFO = 0,
+ MFI_EVT_CLASS_WARNING = 1,
+ MFI_EVT_CLASS_CRITICAL = 2,
+ MFI_EVT_CLASS_FATAL = 3,
+ MFI_EVT_CLASS_DEAD = 4
+};
+
/*
* Crash dump related defines
*/
@@ -364,6 +391,9 @@ enum MR_EVT_ARGS {
MR_EVT_ARGS_GENERIC,
};
+
+#define SGE_BUFFER_SIZE 4096
+#define MEGASAS_CLUSTER_ID_SIZE 16
/*
* define constants for device list query options
*/
@@ -394,6 +424,7 @@ enum MR_LD_QUERY_TYPE {
#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db
#define MR_EVT_LD_OFFLINE 0x00fc
#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152
+#define MR_EVT_CTRL_PROP_CHANGED 0x012f
enum MR_PD_STATE {
MR_PD_STATE_UNCONFIGURED_GOOD = 0x00,
@@ -407,6 +438,257 @@ enum MR_PD_STATE {
MR_PD_STATE_SYSTEM = 0x40,
};
+union MR_PD_REF {
+ struct {
+ u16 deviceId;
+ u16 seqNum;
+ } mrPdRef;
+ u32 ref;
+};
+
+/*
+ * define the DDF Type bit structure
+ */
+union MR_PD_DDF_TYPE {
+ struct {
+ union {
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u16 forcedPDGUID:1;
+ u16 inVD:1;
+ u16 isGlobalSpare:1;
+ u16 isSpare:1;
+ u16 isForeign:1;
+ u16 reserved:7;
+ u16 intf:4;
+#else
+ u16 intf:4;
+ u16 reserved:7;
+ u16 isForeign:1;
+ u16 isSpare:1;
+ u16 isGlobalSpare:1;
+ u16 inVD:1;
+ u16 forcedPDGUID:1;
+#endif
+ } pdType;
+ u16 type;
+ };
+ u16 reserved;
+ } ddf;
+ struct {
+ u32 reserved;
+ } nonDisk;
+ u32 type;
+} __packed;
+
+/*
+ * defines the progress structure
+ */
+union MR_PROGRESS {
+ struct {
+ u16 progress;
+ union {
+ u16 elapsedSecs;
+ u16 elapsedSecsForLastPercent;
+ };
+ } mrProgress;
+ u32 w;
+} __packed;
+
+/*
+ * defines the physical drive progress structure
+ */
+struct MR_PD_PROGRESS {
+ struct {
+#ifndef MFI_BIG_ENDIAN
+ u32 rbld:1;
+ u32 patrol:1;
+ u32 clear:1;
+ u32 copyBack:1;
+ u32 erase:1;
+ u32 locate:1;
+ u32 reserved:26;
+#else
+ u32 reserved:26;
+ u32 locate:1;
+ u32 erase:1;
+ u32 copyBack:1;
+ u32 clear:1;
+ u32 patrol:1;
+ u32 rbld:1;
+#endif
+ } active;
+ union MR_PROGRESS rbld;
+ union MR_PROGRESS patrol;
+ union {
+ union MR_PROGRESS clear;
+ union MR_PROGRESS erase;
+ };
+
+ struct {
+#ifndef MFI_BIG_ENDIAN
+ u32 rbld:1;
+ u32 patrol:1;
+ u32 clear:1;
+ u32 copyBack:1;
+ u32 erase:1;
+ u32 reserved:27;
+#else
+ u32 reserved:27;
+ u32 erase:1;
+ u32 copyBack:1;
+ u32 clear:1;
+ u32 patrol:1;
+ u32 rbld:1;
+#endif
+ } pause;
+
+ union MR_PROGRESS reserved[3];
+} __packed;
+
+struct MR_PD_INFO {
+ union MR_PD_REF ref;
+ u8 inquiryData[96];
+ u8 vpdPage83[64];
+ u8 notSupported;
+ u8 scsiDevType;
+
+ union {
+ u8 connectedPortBitmap;
+ u8 connectedPortNumbers;
+ };
+
+ u8 deviceSpeed;
+ u32 mediaErrCount;
+ u32 otherErrCount;
+ u32 predFailCount;
+ u32 lastPredFailEventSeqNum;
+
+ u16 fwState;
+ u8 disabledForRemoval;
+ u8 linkSpeed;
+ union MR_PD_DDF_TYPE state;
+
+ struct {
+ u8 count;
+#ifndef __BIG_ENDIAN_BITFIELD
+ u8 isPathBroken:4;
+ u8 reserved3:3;
+ u8 widePortCapable:1;
+#else
+ u8 widePortCapable:1;
+ u8 reserved3:3;
+ u8 isPathBroken:4;
+#endif
+
+ u8 connectorIndex[2];
+ u8 reserved[4];
+ u64 sasAddr[2];
+ u8 reserved2[16];
+ } pathInfo;
+
+ u64 rawSize;
+ u64 nonCoercedSize;
+ u64 coercedSize;
+ u16 enclDeviceId;
+ u8 enclIndex;
+
+ union {
+ u8 slotNumber;
+ u8 enclConnectorIndex;
+ };
+
+ struct MR_PD_PROGRESS progInfo;
+ u8 badBlockTableFull;
+ u8 unusableInCurrentConfig;
+ u8 vpdPage83Ext[64];
+ u8 powerState;
+ u8 enclPosition;
+ u32 allowedOps;
+ u16 copyBackPartnerId;
+ u16 enclPartnerDeviceId;
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u16 fdeCapable:1;
+ u16 fdeEnabled:1;
+ u16 secured:1;
+ u16 locked:1;
+ u16 foreign:1;
+ u16 needsEKM:1;
+ u16 reserved:10;
+#else
+ u16 reserved:10;
+ u16 needsEKM:1;
+ u16 foreign:1;
+ u16 locked:1;
+ u16 secured:1;
+ u16 fdeEnabled:1;
+ u16 fdeCapable:1;
+#endif
+ } security;
+ u8 mediaType;
+ u8 notCertified;
+ u8 bridgeVendor[8];
+ u8 bridgeProductIdentification[16];
+ u8 bridgeProductRevisionLevel[4];
+ u8 satBridgeExists;
+
+ u8 interfaceType;
+ u8 temperature;
+ u8 emulatedBlockSize;
+ u16 userDataBlockSize;
+ u16 reserved2;
+
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u32 piType:3;
+ u32 piFormatted:1;
+ u32 piEligible:1;
+ u32 NCQ:1;
+ u32 WCE:1;
+ u32 commissionedSpare:1;
+ u32 emergencySpare:1;
+ u32 ineligibleForSSCD:1;
+ u32 ineligibleForLd:1;
+ u32 useSSEraseType:1;
+ u32 wceUnchanged:1;
+ u32 supportScsiUnmap:1;
+ u32 reserved:18;
+#else
+ u32 reserved:18;
+ u32 supportScsiUnmap:1;
+ u32 wceUnchanged:1;
+ u32 useSSEraseType:1;
+ u32 ineligibleForLd:1;
+ u32 ineligibleForSSCD:1;
+ u32 emergencySpare:1;
+ u32 commissionedSpare:1;
+ u32 WCE:1;
+ u32 NCQ:1;
+ u32 piEligible:1;
+ u32 piFormatted:1;
+ u32 piType:3;
+#endif
+ } properties;
+
+ u64 shieldDiagCompletionTime;
+ u8 shieldCounter;
+
+ u8 linkSpeedOther;
+ u8 reserved4[2];
+
+ struct {
+#ifndef __BIG_ENDIAN_BITFIELD
+ u32 bbmErrCountSupported:1;
+ u32 bbmErrCount:31;
+#else
+ u32 bbmErrCount:31;
+ u32 bbmErrCountSupported:1;
+#endif
+ } bbmErr;
+
+ u8 reserved1[512-428];
+} __packed;
/*
* defines the physical drive address structure
@@ -446,6 +728,7 @@ struct megasas_pd_list {
u16 tid;
u8 driveType;
u8 driveState;
+ u8 interface;
} __packed;
/*
@@ -945,7 +1228,8 @@ struct megasas_ctrl_info {
*/
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:26;
+ u32 reserved:25;
+ u32 passive:1;
u32 premiumFeatureMismatch:1;
u32 ctrlPropIncompatible:1;
u32 fwVersionMismatch:1;
@@ -959,11 +1243,12 @@ struct megasas_ctrl_info {
u32 fwVersionMismatch:1;
u32 ctrlPropIncompatible:1;
u32 premiumFeatureMismatch:1;
- u32 reserved:26;
+ u32 passive:1;
+ u32 reserved:25;
#endif
} cluster;
- char clusterId[16]; /*7D4h */
+ char clusterId[MEGASAS_CLUSTER_ID_SIZE]; /*0x7D4 */
struct {
u8 maxVFsSupported; /*0x7E4*/
u8 numVFsEnabled; /*0x7E5*/
@@ -973,7 +1258,12 @@ struct megasas_ctrl_info {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:12;
+ u32 reserved:7;
+ u32 useSeqNumJbodFP:1;
+ u32 supportExtendedSSCSize:1;
+ u32 supportDiskCacheSettingForSysPDs:1;
+ u32 supportCPLDUpdate:1;
+ u32 supportTTYLogCompression:1;
u32 discardCacheDuringLDDelete:1;
u32 supportSecurityonJBOD:1;
u32 supportCacheBypassModes:1;
@@ -1013,7 +1303,12 @@ struct megasas_ctrl_info {
u32 supportCacheBypassModes:1;
u32 supportSecurityonJBOD:1;
u32 discardCacheDuringLDDelete:1;
- u32 reserved:12;
+ u32 supportTTYLogCompression:1;
+ u32 supportCPLDUpdate:1;
+ u32 supportDiskCacheSettingForSysPDs:1;
+ u32 supportExtendedSSCSize:1;
+ u32 useSeqNumJbodFP:1;
+ u32 reserved:7;
#endif
} adapterOperations3;
@@ -1046,6 +1341,8 @@ struct megasas_ctrl_info {
#define VD_EXT_DEBUG 0
+#define SCAN_PD_CHANNEL 0x1
+#define SCAN_VD_CHANNEL 0x2
enum MR_SCSI_CMD_TYPE {
READ_WRITE_LDIO = 0,
@@ -1054,6 +1351,17 @@ enum MR_SCSI_CMD_TYPE {
NON_READ_WRITE_SYSPDIO = 3,
};
+enum DCMD_TIMEOUT_ACTION {
+ INITIATE_OCR = 0,
+ KILL_ADAPTER = 1,
+ IGNORE_TIMEOUT = 2,
+};
+
+enum FW_BOOT_CONTEXT {
+ PROBE_CONTEXT = 0,
+ OCR_CONTEXT = 1,
+};
+
/* Frame Type */
#define IO_FRAME 0
#define PTHRU_FRAME 1
@@ -1100,6 +1408,7 @@ enum MR_SCSI_CMD_TYPE {
#define MFI_OB_INTR_STATUS_MASK 0x00000002
#define MFI_POLL_TIMEOUT_SECS 60
+#define MFI_IO_TIMEOUT_SECS 180
#define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ)
#define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30)
#define MEGASAS_ROUTINE_WAIT_TIME_VF 300
@@ -1117,6 +1426,7 @@ enum MR_SCSI_CMD_TYPE {
#define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000
#define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14
#define MR_MAX_MSIX_REG_ARRAY 16
+#define MR_RDPQ_MODE_OFFSET 0X00800000
/*
* register set for both 1068 and 1078 controllers
* structure extended for 1078 registers
@@ -1156,8 +1466,9 @@ struct megasas_register_set {
u32 outbound_scratch_pad ; /*00B0h*/
u32 outbound_scratch_pad_2; /*00B4h*/
+ u32 outbound_scratch_pad_3; /*00B8h*/
- u32 reserved_4[2]; /*00B8h*/
+ u32 reserved_4; /*00BCh*/
u32 inbound_low_queue_port ; /*00C0h*/
@@ -1229,7 +1540,12 @@ union megasas_sgl_frame {
typedef union _MFI_CAPABILITIES {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:25;
+ u32 reserved:20;
+ u32 support_qd_throttling:1;
+ u32 support_fp_rlbypass:1;
+ u32 support_vfid_in_ioframe:1;
+ u32 support_ext_io_size:1;
+ u32 support_ext_queue_depth:1;
u32 security_protocol_cmds_fw:1;
u32 support_core_affinity:1;
u32 support_ndrive_r1_lb:1;
@@ -1245,7 +1561,12 @@ typedef union _MFI_CAPABILITIES {
u32 support_ndrive_r1_lb:1;
u32 support_core_affinity:1;
u32 security_protocol_cmds_fw:1;
- u32 reserved:25;
+ u32 support_ext_queue_depth:1;
+ u32 support_ext_io_size:1;
+ u32 support_vfid_in_ioframe:1;
+ u32 support_fp_rlbypass:1;
+ u32 support_qd_throttling:1;
+ u32 reserved:20;
#endif
} mfi_capabilities;
__le32 reg;
@@ -1470,6 +1791,15 @@ union megasas_frame {
u8 raw_bytes[64];
};
+/**
+ * struct MR_PRIV_DEVICE - sdev private hostdata
+ * @is_tm_capable: firmware managed tm_capable flag
+ * @tm_busy: TM request is in progress
+ */
+struct MR_PRIV_DEVICE {
+ bool is_tm_capable;
+ bool tm_busy;
+};
struct megasas_cmd;
union megasas_evt_class_locale {
@@ -1659,6 +1989,19 @@ struct MR_DRV_SYSTEM_INFO {
u8 reserved[1980];
};
+enum MR_PD_TYPE {
+ UNKNOWN_DRIVE = 0,
+ PARALLEL_SCSI = 1,
+ SAS_PD = 2,
+ SATA_PD = 3,
+ FC_PD = 4,
+};
+
+/* JBOD Queue depth definitions */
+#define MEGASAS_SATA_QD 32
+#define MEGASAS_SAS_QD 64
+#define MEGASAS_DEFAULT_PD_QD 64
+
struct megasas_instance {
__le32 *producer;
@@ -1673,6 +2016,8 @@ struct megasas_instance {
dma_addr_t vf_affiliation_111_h;
struct MR_CTRL_HB_HOST_MEM *hb_host_mem;
dma_addr_t hb_host_mem_h;
+ struct MR_PD_INFO *pd_info;
+ dma_addr_t pd_info_h;
__le32 *reply_queue;
dma_addr_t reply_queue_h;
@@ -1690,6 +2035,7 @@ struct megasas_instance {
u32 crash_dump_drv_support;
u32 crash_dump_app_support;
u32 secure_jbod_support;
+ bool use_seqnum_jbod_fp; /* Added for PD sequence */
spinlock_t crashdump_lock;
struct megasas_register_set __iomem *reg_set;
@@ -1703,6 +2049,8 @@ struct megasas_instance {
u16 max_fw_cmds;
u16 max_mfi_cmds;
u16 max_scsi_cmds;
+ u16 ldio_threshold;
+ u16 cur_can_queue;
u32 max_sectors_per_req;
struct megasas_aen_event *ev;
@@ -1720,7 +2068,7 @@ struct megasas_instance {
struct megasas_evt_detail *evt_detail;
dma_addr_t evt_detail_h;
struct megasas_cmd *aen_cmd;
- struct mutex aen_mutex;
+ struct mutex hba_mutex;
struct semaphore ioctl_sem;
struct Scsi_Host *host;
@@ -1733,6 +2081,7 @@ struct megasas_instance {
u32 fw_support_ieee;
atomic_t fw_outstanding;
+ atomic_t ldio_outstanding;
atomic_t fw_reset_no_pci_access;
struct megasas_instance_template *instancet;
@@ -1748,13 +2097,14 @@ struct megasas_instance {
u8 UnevenSpanSupport;
u8 supportmax256vd;
+ u8 pd_list_not_supported;
u16 fw_supported_vd_count;
u16 fw_supported_pd_count;
u16 drv_supported_vd_count;
u16 drv_supported_pd_count;
- u8 adprecovery;
+ atomic_t adprecovery;
unsigned long last_time;
u32 mfiStatus;
u32 last_seq_num;
@@ -1769,7 +2119,9 @@ struct megasas_instance {
struct msix_entry msixentry[MEGASAS_MAX_MSIX_QUEUES];
struct megasas_irq_context irq_context[MEGASAS_MAX_MSIX_QUEUES];
u64 map_id;
+ u64 pd_seq_map_id;
struct megasas_cmd *map_update_cmd;
+ struct megasas_cmd *jbod_seq_cmd;
unsigned long bar;
long reset_flags;
struct mutex reset_mutex;
@@ -1777,10 +2129,14 @@ struct megasas_instance {
char skip_heartbeat_timer_del;
u8 requestorId;
char PlasmaFW111;
- char mpio;
+ char clusterId[MEGASAS_CLUSTER_ID_SIZE];
+ u8 peerIsPresent;
+ u8 passive;
u16 throttlequeuedepth;
u8 mask_interrupts;
+ u16 max_chain_frame_sz;
u8 is_imr;
+ u8 is_rdpq;
bool dev_handle;
};
struct MR_LD_VF_MAP {
@@ -1870,7 +2226,7 @@ struct megasas_instance_template {
u32 (*init_adapter)(struct megasas_instance *);
u32 (*build_and_issue_cmd) (struct megasas_instance *,
struct scsi_cmnd *);
- void (*issue_dcmd) (struct megasas_instance *instance,
+ int (*issue_dcmd)(struct megasas_instance *instance,
struct megasas_cmd *cmd);
};
@@ -1968,6 +2324,19 @@ struct megasas_mgmt_info {
int max_index;
};
+enum MEGASAS_OCR_CAUSE {
+ FW_FAULT_OCR = 0,
+ SCSIIO_TIMEOUT_OCR = 1,
+ MFI_IO_TIMEOUT_OCR = 2,
+};
+
+enum DCMD_RETURN_STATUS {
+ DCMD_SUCCESS = 0,
+ DCMD_TIMEOUT = 1,
+ DCMD_FAILED = 2,
+ DCMD_NOT_FIRED = 3,
+};
+
u8
MR_BuildRaidContext(struct megasas_instance *instance,
struct IO_REQUEST_INFO *io_info,
@@ -1985,6 +2354,9 @@ __le16 get_updated_dev_handle(struct megasas_instance *instance,
void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *map,
struct LD_LOAD_BALANCE_INFO *lbInfo);
int megasas_get_ctrl_info(struct megasas_instance *instance);
+/* PD sequence */
+int
+megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend);
int megasas_set_crash_dump_params(struct megasas_instance *instance,
u8 crash_buf_state);
void megasas_free_host_crash_buffer(struct megasas_instance *instance);
@@ -2000,5 +2372,10 @@ void __megasas_return_cmd(struct megasas_instance *instance,
void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
struct megasas_cmd *cmd_mfi, struct megasas_cmd_fusion *cmd_fusion);
int megasas_cmd_type(struct scsi_cmnd *cmd);
+void megasas_setup_jbod_map(struct megasas_instance *instance);
+void megasas_update_sdev_properties(struct scsi_device *sdev);
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index eaa81e5..e6ebc7a 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -83,7 +83,7 @@ module_param(throttlequeuedepth, int, S_IRUGO);
MODULE_PARM_DESC(throttlequeuedepth,
"Adapter queue depth when throttled due to I/O timeout. Default: 16");
-int resetwaittime = MEGASAS_RESET_WAIT_TIME;
+unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
module_param(resetwaittime, int, S_IRUGO);
MODULE_PARM_DESC(resetwaittime, "Wait time in seconds after I/O timeout "
"before resetting adapter. Default: 180");
@@ -92,6 +92,18 @@ int smp_affinity_enable = 1;
module_param(smp_affinity_enable, int, S_IRUGO);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
+int rdpq_enable = 1;
+module_param(rdpq_enable, int, S_IRUGO);
+MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disable Default: disable(0)");
+
+unsigned int dual_qdepth_disable;
+module_param(dual_qdepth_disable, int, S_IRUGO);
+MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0");
+
+unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
+module_param(scmd_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
@@ -104,6 +116,8 @@ static int megasas_ld_list_query(struct megasas_instance *instance,
static int megasas_issue_init_mfi(struct megasas_instance *instance);
static int megasas_register_aen(struct megasas_instance *instance,
u32 seq_num, u32 class_locale_word);
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id);
/*
* PCI ID table for all supported controllers
*/
@@ -135,6 +149,12 @@ static struct pci_device_id megasas_pci_table[] = {
/* Invader */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
/* Fury */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER)},
+ /* Intruder */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER_24)},
+ /* Intruder 24 port*/
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)},
{}
};
@@ -183,18 +203,18 @@ int
wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
int seconds);
void megasas_reset_reply_desc(struct megasas_instance *instance);
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
void megasas_fusion_ocr_wq(struct work_struct *work);
static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
int initial);
int megasas_check_mpio_paths(struct megasas_instance *instance,
struct scsi_cmnd *scmd);
-void
+int
megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
instance->instancet->fire_cmd(instance,
cmd->frame_phys_addr, 0, instance->reg_set);
+ return 0;
}
/**
@@ -260,6 +280,66 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
}
+static const char *
+format_timestamp(uint32_t timestamp)
+{
+ static char buffer[32];
+
+ if ((timestamp & 0xff000000) == 0xff000000)
+ snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
+ 0x00ffffff);
+ else
+ snprintf(buffer, sizeof(buffer), "%us", timestamp);
+ return buffer;
+}
+
+static const char *
+format_class(int8_t class)
+{
+ static char buffer[6];
+
+ switch (class) {
+ case MFI_EVT_CLASS_DEBUG:
+ return "debug";
+ case MFI_EVT_CLASS_PROGRESS:
+ return "progress";
+ case MFI_EVT_CLASS_INFO:
+ return "info";
+ case MFI_EVT_CLASS_WARNING:
+ return "WARN";
+ case MFI_EVT_CLASS_CRITICAL:
+ return "CRIT";
+ case MFI_EVT_CLASS_FATAL:
+ return "FATAL";
+ case MFI_EVT_CLASS_DEAD:
+ return "DEAD";
+ default:
+ snprintf(buffer, sizeof(buffer), "%d", class);
+ return buffer;
+ }
+}
+
+/**
+ * megasas_decode_evt: Decode FW AEN event and print critical event
+ * for information.
+ * @instance: Adapter soft state
+ */
+static void
+megasas_decode_evt(struct megasas_instance *instance)
+{
+ struct megasas_evt_detail *evt_detail = instance->evt_detail;
+ union megasas_evt_class_locale class_locale;
+ class_locale.word = le32_to_cpu(evt_detail->cl.word);
+
+ if (class_locale.members.class >= MFI_EVT_CLASS_CRITICAL)
+ dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n",
+ le32_to_cpu(evt_detail->seq_num),
+ format_timestamp(le32_to_cpu(evt_detail->time_stamp)),
+ (class_locale.members.locale),
+ format_class(class_locale.members.class),
+ evt_detail->description);
+}
+
/**
* The following functions are defined for xscale
* (deviceid : 1064R, PERC5) controllers
@@ -407,7 +487,7 @@ static int
megasas_check_reset_xscale(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+ if ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
(le32_to_cpu(*instance->consumer) ==
MEGASAS_ADPRESET_INPROG_SIGN))
return 1;
@@ -543,7 +623,7 @@ static int
megasas_check_reset_ppc(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
return 1;
return 0;
@@ -669,6 +749,7 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
&(regs)->inbound_high_queue_port);
writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
&(regs)->inbound_low_queue_port);
+ mmiowb();
spin_unlock_irqrestore(&instance->hba_lock, flags);
}
@@ -680,7 +761,7 @@ static int
megasas_check_reset_skinny(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
return 1;
return 0;
@@ -874,9 +955,8 @@ static int
megasas_check_reset_gen2(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
return 1;
- }
return 0;
}
@@ -917,25 +997,20 @@ extern struct megasas_instance_template megasas_instance_template_fusion;
int
megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
- int seconds;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
- frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
+ frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
- /*
- * Issue the frame using inbound queue port
- */
- instance->instancet->issue_dcmd(instance, cmd);
+ if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+ (instance->instancet->issue_dcmd(instance, cmd))) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
+ }
- /*
- * Wait for cmd_status to change
- */
- if (instance->requestorId)
- seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
- else
- seconds = MFI_POLL_TIMEOUT_SECS;
- return wait_and_poll(instance, cmd, seconds);
+ return wait_and_poll(instance, cmd, instance->requestorId ?
+ MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS);
}
/**
@@ -953,21 +1028,29 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd, int timeout)
{
int ret = 0;
-
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
- instance->instancet->issue_dcmd(instance, cmd);
+ if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+ (instance->instancet->issue_dcmd(instance, cmd))) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
+ }
+
if (timeout) {
ret = wait_event_timeout(instance->int_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
- if (!ret)
- return 1;
+ if (!ret) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n",
+ __func__, __LINE__);
+ return DCMD_TIMEOUT;
+ }
} else
wait_event(instance->int_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
return (cmd->cmd_status_drv == MFI_STAT_OK) ?
- 0 : 1;
+ DCMD_SUCCESS : DCMD_FAILED;
}
/**
@@ -1011,15 +1094,20 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cmd->sync_cmd = 1;
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
- instance->instancet->issue_dcmd(instance, cmd);
+ if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
+ (instance->instancet->issue_dcmd(instance, cmd))) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
+ }
if (timeout) {
ret = wait_event_timeout(instance->abort_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
if (!ret) {
- dev_err(&instance->pdev->dev, "Command timedout"
- "from %s\n", __func__);
- return 1;
+ dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n",
+ __func__, __LINE__);
+ return DCMD_TIMEOUT;
}
} else
wait_event(instance->abort_cmd_wait_q,
@@ -1028,7 +1116,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cmd->sync_cmd = 0;
megasas_return_cmd(instance, cmd);
- return 0;
+ return (cmd->cmd_status_drv == MFI_STAT_OK) ?
+ DCMD_SUCCESS : DCMD_FAILED;
}
/**
@@ -1555,7 +1644,7 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance,
return 0;
out_return_cmd:
megasas_return_cmd(instance, cmd);
- return 1;
+ return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1568,7 +1657,7 @@ static int
megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{
struct megasas_instance *instance;
- unsigned long flags;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
instance = (struct megasas_instance *)
scmd->device->host->hostdata;
@@ -1582,35 +1671,38 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
if (instance->issuepend_done == 0)
return SCSI_MLQUEUE_HOST_BUSY;
- spin_lock_irqsave(&instance->hba_lock, flags);
/* Check for an mpio path and adjust behavior */
- if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
if (megasas_check_mpio_paths(instance, scmd) ==
(DID_RESET << 16)) {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
return SCSI_MLQUEUE_HOST_BUSY;
} else {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
}
}
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
}
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
- spin_unlock_irqrestore(&instance->hba_lock, flags);
- return SCSI_MLQUEUE_HOST_BUSY;
+ mr_device_priv_data = scmd->device->hostdata;
+ if (!mr_device_priv_data) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ return 0;
}
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ if (mr_device_priv_data->tm_busy)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+
scmd->result = 0;
@@ -1633,12 +1725,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
break;
}
- if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
- dev_err(&instance->pdev->dev, "Err returned from build_and_issue_cmd\n");
- return SCSI_MLQUEUE_HOST_BUSY;
- }
-
- return 0;
+ return instance->instancet->build_and_issue_cmd(instance, scmd);
out_done:
scmd->scsi_done(scmd);
@@ -1659,13 +1746,116 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
return NULL;
}
+/*
+* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
+*
+* @sdev: OS provided scsi device
+*
+* Returns void
+*/
+void megasas_update_sdev_properties(struct scsi_device *sdev)
+{
+ u16 pd_index = 0;
+ u32 device_id, ld;
+ struct megasas_instance *instance;
+ struct fusion_context *fusion;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+ struct MR_LD_RAID *raid;
+ struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+ fusion = instance->ctrl_context;
+ mr_device_priv_data = sdev->hostdata;
+
+ if (!fusion)
+ return;
+
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+ instance->use_seqnum_jbod_fp) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ pd_sync = (void *)fusion->pd_seq_sync
+ [(instance->pd_seq_map_id - 1) & 1];
+ mr_device_priv_data->is_tm_capable =
+ pd_sync->seq[pd_index].capability.tmCapable;
+ } else {
+ device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+ + sdev->id;
+ local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
+ ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
+ raid = MR_LdRaidGet(ld, local_map_ptr);
+
+ if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
+ blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+ mr_device_priv_data->is_tm_capable =
+ raid->capability.tmCapable;
+ }
+}
+
+static void megasas_set_device_queue_depth(struct scsi_device *sdev)
+{
+ u16 pd_index = 0;
+ int ret = DCMD_FAILED;
+ struct megasas_instance *instance;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+
+ if (instance->pd_info) {
+ mutex_lock(&instance->hba_mutex);
+ ret = megasas_get_pd_info(instance, pd_index);
+ mutex_unlock(&instance->hba_mutex);
+ }
+
+ if (ret != DCMD_SUCCESS)
+ return;
+
+ if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
+
+ switch (instance->pd_list[pd_index].interface) {
+ case SAS_PD:
+ scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
+ break;
+
+ case SATA_PD:
+ scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
+ break;
+
+ default:
+ scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
+ }
+ }
+ }
+}
+
+
static int megasas_slave_configure(struct scsi_device *sdev)
{
+ u16 pd_index = 0;
+ struct megasas_instance *instance;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+ if (instance->pd_list_not_supported) {
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+ sdev->type == TYPE_DISK) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ if (instance->pd_list[pd_index].driveState !=
+ MR_PD_STATE_SYSTEM)
+ return -ENXIO;
+ }
+ }
+ megasas_set_device_queue_depth(sdev);
+ megasas_update_sdev_properties(sdev);
+
/*
* The RAID firmware may require extended timeouts.
*/
blk_queue_rq_timeout(sdev->request_queue,
- MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ scmd_timeout * HZ);
return 0;
}
@@ -1674,6 +1864,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
{
u16 pd_index = 0;
struct megasas_instance *instance ;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
instance = megasas_lookup_instance(sdev->host->host_no);
if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
@@ -1683,15 +1874,29 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
pd_index =
(sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
sdev->id;
- if (instance->pd_list[pd_index].driveState ==
- MR_PD_STATE_SYSTEM) {
- return 0;
+ if ((instance->pd_list_not_supported ||
+ instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM)) {
+ goto scan_target;
}
return -ENXIO;
}
+
+scan_target:
+ mr_device_priv_data = kzalloc(sizeof(*mr_device_priv_data),
+ GFP_KERNEL);
+ if (!mr_device_priv_data)
+ return -ENOMEM;
+ sdev->hostdata = mr_device_priv_data;
return 0;
}
+static void megasas_slave_destroy(struct scsi_device *sdev)
+{
+ kfree(sdev->hostdata);
+ sdev->hostdata = NULL;
+}
+
/*
* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
* kill adapter
@@ -1731,19 +1936,16 @@ static void megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
void megaraid_sas_kill_hba(struct megasas_instance *instance)
{
/* Set critical error to block I/O & ioctls in case caller didn't */
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+ atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
/* Wait 1 second to ensure IO or ioctls in build have posted */
msleep(1000);
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context)) {
writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
/* Flush */
readl(&instance->reg_set->doorbell);
- if (instance->mpio && instance->requestorId)
+ if (instance->requestorId && instance->peerIsPresent)
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
} else {
writel(MFI_STOP_ADP,
@@ -1772,7 +1974,7 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
spin_lock_irqsave(instance->host->host_lock, flags);
instance->flag &= ~MEGASAS_FW_BUSY;
- instance->host->can_queue = instance->max_scsi_cmds;
+ instance->host->can_queue = instance->cur_can_queue;
spin_unlock_irqrestore(instance->host->host_lock, flags);
}
}
@@ -1794,7 +1996,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
unsigned long flags;
/* If we have already declared adapter dead, donot complete cmds */
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
spin_lock_irqsave(&instance->completion_lock, flags);
@@ -1863,7 +2065,7 @@ void megasas_do_ocr(struct megasas_instance *instance)
*instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
}
instance->instancet->disable_intr(instance);
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
instance->issuepend_done = 0;
atomic_set(&instance->fw_outstanding, 0);
@@ -1943,9 +2145,7 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance,
dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
"scsi%d\n", instance->host->host_no);
- megasas_issue_blocked_cmd(instance, cmd, 0);
-
- if (dcmd->cmd_status) {
+ if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
" failed with status 0x%x for scsi%d\n",
dcmd->cmd_status, instance->host->host_no);
@@ -2055,9 +2255,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance,
dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for "
"scsi%d\n", instance->host->host_no);
- megasas_issue_blocked_cmd(instance, cmd, 0);
- if (dcmd->cmd_status) {
+ if (megasas_issue_blocked_cmd(instance, cmd, 0) != DCMD_SUCCESS) {
dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD"
" failed with status 0x%x for scsi%d\n",
dcmd->cmd_status, instance->host->host_no);
@@ -2262,21 +2461,21 @@ void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
*/
static int megasas_wait_for_outstanding(struct megasas_instance *instance)
{
- int i;
+ int i, sl, outstanding;
u32 reset_index;
u32 wait_time = MEGASAS_RESET_WAIT_TIME;
- u8 adprecovery;
unsigned long flags;
struct list_head clist_local;
struct megasas_cmd *reset_cmd;
u32 fw_state;
- u8 kill_adapter_flag;
- spin_lock_irqsave(&instance->hba_lock, flags);
- adprecovery = instance->adprecovery;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+ dev_info(&instance->pdev->dev, "%s:%d HBA is killed.\n",
+ __func__, __LINE__);
+ return FAILED;
+ }
- if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
INIT_LIST_HEAD(&clist_local);
spin_lock_irqsave(&instance->hba_lock, flags);
@@ -2287,18 +2486,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
dev_notice(&instance->pdev->dev, "HBA reset wait ...\n");
for (i = 0; i < wait_time; i++) {
msleep(1000);
- spin_lock_irqsave(&instance->hba_lock, flags);
- adprecovery = instance->adprecovery;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
- if (adprecovery == MEGASAS_HBA_OPERATIONAL)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL)
break;
}
- if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n");
- spin_lock_irqsave(&instance->hba_lock, flags);
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
+ atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
return FAILED;
}
@@ -2336,7 +2530,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
}
for (i = 0; i < resetwaittime; i++) {
- int outstanding = atomic_read(&instance->fw_outstanding);
+ outstanding = atomic_read(&instance->fw_outstanding);
if (!outstanding)
break;
@@ -2355,67 +2549,60 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
}
i = 0;
- kill_adapter_flag = 0;
+ outstanding = atomic_read(&instance->fw_outstanding);
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+
+ if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+ goto no_outstanding;
+
+ if (instance->disableOnlineCtrlReset)
+ goto kill_hba_and_failed;
do {
- fw_state = instance->instancet->read_fw_status_reg(
- instance->reg_set) & MFI_STATE_MASK;
- if ((fw_state == MFI_STATE_FAULT) &&
- (instance->disableOnlineCtrlReset == 0)) {
- if (i == 3) {
- kill_adapter_flag = 2;
- break;
- }
+ if ((fw_state == MFI_STATE_FAULT) || atomic_read(&instance->fw_outstanding)) {
+ dev_info(&instance->pdev->dev,
+ "%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, oustanding 0x%x\n",
+ __func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
+ if (i == 3)
+ goto kill_hba_and_failed;
megasas_do_ocr(instance);
- kill_adapter_flag = 1;
- /* wait for 1 secs to let FW finish the pending cmds */
- msleep(1000);
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
+ dev_info(&instance->pdev->dev, "%s:%d OCR failed and HBA is killed.\n",
+ __func__, __LINE__);
+ return FAILED;
+ }
+ dev_info(&instance->pdev->dev, "%s:%d waiting_for_outstanding: after issue OCR.\n",
+ __func__, __LINE__);
+
+ for (sl = 0; sl < 10; sl++)
+ msleep(500);
+
+ outstanding = atomic_read(&instance->fw_outstanding);
+
+ fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+ if ((!outstanding && (fw_state == MFI_STATE_OPERATIONAL)))
+ goto no_outstanding;
}
i++;
} while (i <= 3);
- if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag) {
- if (instance->disableOnlineCtrlReset == 0) {
- megasas_do_ocr(instance);
+no_outstanding:
- /* wait for 5 secs to let FW finish the pending cmds */
- for (i = 0; i < wait_time; i++) {
- int outstanding =
- atomic_read(&instance->fw_outstanding);
- if (!outstanding)
- return SUCCESS;
- msleep(1000);
- }
- }
- }
+ dev_info(&instance->pdev->dev, "%s:%d no more pending commands remain after reset handling.\n",
+ __func__, __LINE__);
+ return SUCCESS;
- if (atomic_read(&instance->fw_outstanding) ||
- (kill_adapter_flag == 2)) {
- dev_notice(&instance->pdev->dev, "pending cmds after reset\n");
- /*
- * Send signal to FW to stop processing any pending cmds.
- * The controller will be taken offline by the OS now.
- */
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
- writel(MFI_STOP_ADP,
- &instance->reg_set->doorbell);
- } else {
- writel(MFI_STOP_ADP,
- &instance->reg_set->inbound_doorbell);
- }
- megasas_dump_pending_frames(instance);
- spin_lock_irqsave(&instance->hba_lock, flags);
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
- spin_unlock_irqrestore(&instance->hba_lock, flags);
- return FAILED;
- }
+kill_hba_and_failed:
- dev_notice(&instance->pdev->dev, "no pending cmds after reset\n");
+ /* Reset not supported, kill adapter */
+ dev_info(&instance->pdev->dev, "%s:%d killing adapter scsi%d"
+ " disableOnlineCtrlReset %d fw_outstanding %d \n",
+ __func__, __LINE__, instance->host->host_no, instance->disableOnlineCtrlReset,
+ atomic_read(&instance->fw_outstanding));
+ megasas_dump_pending_frames(instance);
+ megaraid_sas_kill_hba(instance);
- return SUCCESS;
+ return FAILED;
}
/**
@@ -2436,7 +2623,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n",
scmd->cmnd[0], scmd->retries);
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n");
return FAILED;
}
@@ -2464,7 +2651,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
unsigned long flags;
if (time_after(jiffies, scmd->jiffies_at_alloc +
- (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
+ (scmd_timeout * 2) * HZ)) {
return BLK_EH_NOT_HANDLED;
}
@@ -2506,10 +2693,7 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
/*
* First wait for all commands to complete
*/
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (instance->ctrl_context)
ret = megasas_reset_fusion(scmd->device->host, 1);
else
ret = megasas_generic_reset(scmd);
@@ -2743,6 +2927,16 @@ megasas_page_size_show(struct device *cdev,
return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1);
}
+static ssize_t
+megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->ldio_outstanding));
+}
+
static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR,
megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store);
static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO,
@@ -2751,12 +2945,15 @@ static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR,
megasas_fw_crash_state_show, megasas_fw_crash_state_store);
static DEVICE_ATTR(page_size, S_IRUGO,
megasas_page_size_show, NULL);
+static DEVICE_ATTR(ldio_outstanding, S_IRUGO,
+ megasas_ldio_outstanding_show, NULL);
struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_fw_crash_buffer_size,
&dev_attr_fw_crash_buffer,
&dev_attr_fw_crash_state,
&dev_attr_page_size,
+ &dev_attr_ldio_outstanding,
NULL,
};
@@ -2770,6 +2967,7 @@ static struct scsi_host_template megasas_template = {
.proc_name = "megaraid_sas",
.slave_configure = megasas_slave_configure,
.slave_alloc = megasas_slave_alloc,
+ .slave_destroy = megasas_slave_destroy,
.queuecommand = megasas_queue_command,
.eh_device_reset_handler = megasas_reset_device,
.eh_bus_reset_handler = megasas_reset_bus_host,
@@ -2837,7 +3035,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
struct megasas_header *hdr = &cmd->frame->hdr;
unsigned long flags;
struct fusion_context *fusion = instance->ctrl_context;
- u32 opcode;
+ u32 opcode, status;
/* flag for the retry reset */
cmd->retry_for_fw_reset = 0;
@@ -2945,6 +3143,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
&& (cmd->frame->dcmd.mbox.b[1] == 1)) {
fusion->fast_path_io = 0;
spin_lock_irqsave(instance->host->host_lock, flags);
+ instance->map_update_cmd = NULL;
if (cmd->frame->hdr.cmd_status != 0) {
if (cmd->frame->hdr.cmd_status !=
MFI_STAT_NOT_FOUND)
@@ -2982,6 +3181,27 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
spin_unlock_irqrestore(&poll_aen_lock, flags);
}
+ /* FW has an updated PD sequence */
+ if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) &&
+ (cmd->frame->dcmd.mbox.b[0] == 1)) {
+
+ spin_lock_irqsave(instance->host->host_lock, flags);
+ status = cmd->frame->hdr.cmd_status;
+ instance->jbod_seq_cmd = NULL;
+ megasas_return_cmd(instance, cmd);
+
+ if (status == MFI_STAT_OK) {
+ instance->pd_seq_map_id++;
+ /* Re-register a pd sync seq num cmd */
+ if (megasas_sync_pd_seq_num(instance, true))
+ instance->use_seqnum_jbod_fp = false;
+ } else
+ instance->use_seqnum_jbod_fp = false;
+
+ spin_unlock_irqrestore(instance->host->host_lock, flags);
+ break;
+ }
+
/*
* See if got an event notification
*/
@@ -3147,13 +3367,13 @@ process_fw_state_change_wq(struct work_struct *work)
u32 wait;
unsigned long flags;
- if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_ADPRESET_SM_INFAULT) {
dev_notice(&instance->pdev->dev, "error, recovery st %x\n",
- instance->adprecovery);
+ atomic_read(&instance->adprecovery));
return ;
}
- if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
dev_notice(&instance->pdev->dev, "FW detected to be in fault"
"state, restarting it...\n");
@@ -3196,7 +3416,7 @@ process_fw_state_change_wq(struct work_struct *work)
megasas_issue_init_mfi(instance);
spin_lock_irqsave(&instance->hba_lock, flags);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
spin_unlock_irqrestore(&instance->hba_lock, flags);
instance->instancet->enable_intr(instance);
@@ -3261,14 +3481,14 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
instance->instancet->disable_intr(instance);
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
instance->issuepend_done = 0;
atomic_set(&instance->fw_outstanding, 0);
megasas_internal_reset_defer_cmds(instance);
dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n",
- fw_state, instance->adprecovery);
+ fw_state, atomic_read(&instance->adprecovery));
schedule_work(&instance->work_init);
return IRQ_HANDLED;
@@ -3348,22 +3568,14 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context))
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
&instance->reg_set->doorbell);
- } else {
+ else
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
- }
max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_WAIT_HANDSHAKE;
@@ -3374,17 +3586,10 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context))
writel(MFI_INIT_HOTPLUG,
&instance->reg_set->doorbell);
- } else
+ else
writel(MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
@@ -3401,24 +3606,11 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context)) {
writel(MFI_RESET_FLAGS,
&instance->reg_set->doorbell);
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+
+ if (instance->ctrl_context) {
for (i = 0; i < (10 * 1000); i += 20) {
if (readl(
&instance->
@@ -3639,11 +3831,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
memset(cmd->frame, 0, total_sz);
cmd->frame->io.context = cpu_to_le32(cmd->index);
cmd->frame->io.pad_0 = 0;
- if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
- (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
- (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
- (instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
- (reset_devices))
+ if (!instance->ctrl_context && reset_devices)
cmd->frame->hdr.cmd = MFI_CMD_INVALID;
}
@@ -3754,6 +3942,92 @@ int megasas_alloc_cmds(struct megasas_instance *instance)
}
/*
+ * dcmd_timeout_ocr_possible - Check if OCR is possible based on Driver/FW state.
+ * @instance: Adapter soft state
+ *
+ * Return 0 for only Fusion adapter, if driver load/unload is not in progress
+ * or FW is not under OCR.
+ */
+inline int
+dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
+
+ if (!instance->ctrl_context)
+ return KILL_ADAPTER;
+ else if (instance->unload ||
+ test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
+ return IGNORE_TIMEOUT;
+ else
+ return INITIATE_OCR;
+}
+
+static int
+megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
+{
+ int ret;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ memset(instance->pd_info, 0, sizeof(*instance->pd_info));
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->mbox.s[0] = cpu_to_le16(device_id);
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO));
+ dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO);
+ dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->pd_info_h);
+ dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_PD_INFO));
+
+ if (instance->ctrl_context && !instance->mask_interrupts)
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
+ else
+ ret = megasas_issue_polled(instance, cmd);
+
+ switch (ret) {
+ case DCMD_SUCCESS:
+ instance->pd_list[device_id].interface =
+ instance->pd_info->state.ddf.pdType.intf;
+ break;
+
+ case DCMD_TIMEOUT:
+
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ break;
+ }
+
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
+
+ return ret;
+}
+/*
* megasas_get_pd_list_info - Returns FW's pd_list structure
* @instance: Adapter soft state
* @pd_list: pd_list structure
@@ -3808,42 +4082,78 @@ megasas_get_pd_list(struct megasas_instance *instance)
if (instance->ctrl_context && !instance->mask_interrupts)
ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- /*
- * the following function will get the instance PD LIST.
- */
+ switch (ret) {
+ case DCMD_FAILED:
+ dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
+ "failed/not supported by firmware\n");
+
+ if (instance->ctrl_context)
+ megaraid_sas_kill_hba(instance);
+ else
+ instance->pd_list_not_supported = 1;
+ break;
+ case DCMD_TIMEOUT:
+
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ /*
+ * DCMD failed from AEN path.
+ * AEN path already hold reset_mutex to avoid PCI access
+ * while OCR is in progress.
+ */
+ mutex_unlock(&instance->reset_mutex);
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d \n",
+ __func__, __LINE__);
+ break;
+ }
+
+ break;
- pd_addr = ci->addr;
+ case DCMD_SUCCESS:
+ pd_addr = ci->addr;
- if (ret == 0 &&
- (le32_to_cpu(ci->count) <
- (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+ if ((le32_to_cpu(ci->count) >
+ (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
+ break;
memset(instance->local_pd_list, 0,
- MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+ MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) {
-
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].tid =
- le16_to_cpu(pd_addr->deviceId);
+ le16_to_cpu(pd_addr->deviceId);
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveType =
- pd_addr->scsiDevType;
+ pd_addr->scsiDevType;
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState =
- MR_PD_STATE_SYSTEM;
+ MR_PD_STATE_SYSTEM;
pd_addr++;
}
+
memcpy(instance->pd_list, instance->local_pd_list,
sizeof(instance->pd_list));
+ break;
+
}
pci_free_consistent(instance->pdev,
MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
ci, ci_h);
- megasas_return_cmd(instance, cmd);
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
return ret;
}
@@ -3904,33 +4214,63 @@ megasas_get_ld_list(struct megasas_instance *instance)
if (instance->ctrl_context && !instance->mask_interrupts)
ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
-
ld_count = le32_to_cpu(ci->ldCount);
- /* the following function will get the instance PD LIST */
+ switch (ret) {
+ case DCMD_FAILED:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case DCMD_TIMEOUT:
+
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ /*
+ * DCMD failed from AEN path.
+ * AEN path already hold reset_mutex to avoid PCI access
+ * while OCR is in progress.
+ */
+ mutex_unlock(&instance->reset_mutex);
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ break;
+
+ case DCMD_SUCCESS:
+ if (ld_count > instance->fw_supported_vd_count)
+ break;
- if ((ret == 0) && (ld_count <= instance->fw_supported_vd_count)) {
memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
for (ld_index = 0; ld_index < ld_count; ld_index++) {
if (ci->ldList[ld_index].state != 0) {
ids = ci->ldList[ld_index].ref.targetId;
- instance->ld_ids[ids] =
- ci->ldList[ld_index].ref.targetId;
+ instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
}
}
+
+ break;
}
- pci_free_consistent(instance->pdev,
- sizeof(struct MR_LD_LIST),
- ci,
- ci_h);
+ pci_free_consistent(instance->pdev, sizeof(struct MR_LD_LIST), ci, ci_h);
+
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
- megasas_return_cmd(instance, cmd);
return ret;
}
@@ -3992,26 +4332,61 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
dcmd->pad_0 = 0;
if (instance->ctrl_context && !instance->mask_interrupts)
- ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- tgtid_count = le32_to_cpu(ci->count);
+ switch (ret) {
+ case DCMD_FAILED:
+ dev_info(&instance->pdev->dev,
+ "DCMD not supported by firmware - %s %d\n",
+ __func__, __LINE__);
+ ret = megasas_get_ld_list(instance);
+ break;
+ case DCMD_TIMEOUT:
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ /*
+ * DCMD failed from AEN path.
+ * AEN path already hold reset_mutex to avoid PCI access
+ * while OCR is in progress.
+ */
+ mutex_unlock(&instance->reset_mutex);
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+
+ break;
+ case DCMD_SUCCESS:
+ tgtid_count = le32_to_cpu(ci->count);
+
+ if ((tgtid_count > (instance->fw_supported_vd_count)))
+ break;
- if ((ret == 0) && (tgtid_count <= (instance->fw_supported_vd_count))) {
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
ids = ci->targetId[ld_index];
instance->ld_ids[ids] = ci->targetId[ld_index];
}
+ break;
}
pci_free_consistent(instance->pdev, sizeof(struct MR_LD_TARGETID_LIST),
- ci, ci_h);
+ ci, ci_h);
- megasas_return_cmd(instance, cmd);
+ if (ret != DCMD_TIMEOUT)
+ megasas_return_cmd(instance, cmd);
return ret;
}
@@ -4125,28 +4500,73 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
dcmd->mbox.b[0] = 1;
if (instance->ctrl_context && !instance->mask_interrupts)
- ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- if (!ret) {
+ switch (ret) {
+ case DCMD_SUCCESS:
memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+ /* Save required controller information in
+ * CPU endianness format.
+ */
le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
+
+ /* Update the latest Ext VD info.
+ * From Init path, store current firmware details.
+ * From OCR path, detect any firmware properties changes.
+ * in case of Firmware upgrade without system reboot.
+ */
megasas_update_ext_vd_details(instance);
+ instance->use_seqnum_jbod_fp =
+ ctrl_info->adapterOperations3.useSeqNumJbodFP;
+
+ /*Check whether controller is iMR or MR */
instance->is_imr = (ctrl_info->memory_size ? 0 : 1);
dev_info(&instance->pdev->dev,
- "controller type\t: %s(%dMB)\n",
- instance->is_imr ? "iMR" : "MR",
- le16_to_cpu(ctrl_info->memory_size));
+ "controller type\t: %s(%dMB)\n",
+ instance->is_imr ? "iMR" : "MR",
+ le16_to_cpu(ctrl_info->memory_size));
+
+ instance->disableOnlineCtrlReset =
+ ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
+ instance->secure_jbod_support =
+ ctrl_info->adapterOperations3.supportSecurityonJBOD;
+ dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
+ instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
+ dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n",
+ instance->secure_jbod_support ? "Yes" : "No");
+ break;
+
+ case DCMD_TIMEOUT:
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ case DCMD_FAILED:
+ megaraid_sas_kill_hba(instance);
+ break;
+
}
pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
ci, ci_h);
megasas_return_cmd(instance, cmd);
+
+
return ret;
}
@@ -4196,12 +4616,28 @@ int megasas_set_crash_dump_params(struct megasas_instance *instance,
dcmd->sgl.sge32[0].length = cpu_to_le32(CRASH_DMA_BUF_SIZE);
if (instance->ctrl_context && !instance->mask_interrupts)
- ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
- megasas_return_cmd(instance, cmd);
+ if (ret == DCMD_TIMEOUT) {
+ switch (dcmd_timeout_ocr_possible(instance)) {
+ case INITIATE_OCR:
+ cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ megasas_reset_fusion(instance->host,
+ MFI_IO_TIMEOUT_OCR);
+ break;
+ case KILL_ADAPTER:
+ megaraid_sas_kill_hba(instance);
+ break;
+ case IGNORE_TIMEOUT:
+ dev_info(&instance->pdev->dev, "Ignore DCMD timeout: %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ } else
+ megasas_return_cmd(instance, cmd);
+
return ret;
}
@@ -4318,6 +4754,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
sema_init(&instance->ioctl_sem, (MEGASAS_MFI_IOCTL_CMDS));
}
+ instance->cur_can_queue = instance->max_scsi_cmds;
/*
* Create a pool of commands
*/
@@ -4481,6 +4918,62 @@ megasas_destroy_irqs(struct megasas_instance *instance) {
}
/**
+ * megasas_setup_jbod_map - setup jbod map for FP seq_number.
+ * @instance: Adapter soft state
+ * @is_probe: Driver probe check
+ *
+ * Return 0 on success.
+ */
+void
+megasas_setup_jbod_map(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion = instance->ctrl_context;
+ u32 pd_seq_map_sz;
+
+ pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+ (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1));
+
+ if (reset_devices || !fusion ||
+ !instance->ctrl_info->adapterOperations3.useSeqNumJbodFP) {
+ dev_info(&instance->pdev->dev,
+ "Jbod map is not supported %s %d\n",
+ __func__, __LINE__);
+ instance->use_seqnum_jbod_fp = false;
+ return;
+ }
+
+ if (fusion->pd_seq_sync[0])
+ goto skip_alloc;
+
+ for (i = 0; i < JBOD_MAPS_COUNT; i++) {
+ fusion->pd_seq_sync[i] = dma_alloc_coherent
+ (&instance->pdev->dev, pd_seq_map_sz,
+ &fusion->pd_seq_phys[i], GFP_KERNEL);
+ if (!fusion->pd_seq_sync[i]) {
+ dev_err(&instance->pdev->dev,
+ "Failed to allocate memory from %s %d\n",
+ __func__, __LINE__);
+ if (i == 1) {
+ dma_free_coherent(&instance->pdev->dev,
+ pd_seq_map_sz, fusion->pd_seq_sync[0],
+ fusion->pd_seq_phys[0]);
+ fusion->pd_seq_sync[0] = NULL;
+ }
+ instance->use_seqnum_jbod_fp = false;
+ return;
+ }
+ }
+
+skip_alloc:
+ if (!megasas_sync_pd_seq_num(instance, false) &&
+ !megasas_sync_pd_seq_num(instance, true))
+ instance->use_seqnum_jbod_fp = true;
+ else
+ instance->use_seqnum_jbod_fp = false;
+}
+
+/**
* megasas_init_fw - Initializes the FW
* @instance: Adapter soft state
*
@@ -4498,6 +4991,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
unsigned long bar_list;
int i, loop, fw_msix_count = 0;
struct IOV_111 *iovPtr;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
/* Find first memory bar */
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
@@ -4523,6 +5019,10 @@ static int megasas_init_fw(struct megasas_instance *instance)
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
+ case PCI_DEVICE_ID_LSI_INTRUDER:
+ case PCI_DEVICE_ID_LSI_INTRUDER_24:
+ case PCI_DEVICE_ID_LSI_CUTLASS_52:
+ case PCI_DEVICE_ID_LSI_CUTLASS_53:
instance->instancet = &megasas_instance_template_fusion;
break;
case PCI_DEVICE_ID_LSI_SAS1078R:
@@ -4575,37 +5075,35 @@ static int megasas_init_fw(struct megasas_instance *instance)
scratch_pad_2 = readl
(&instance->reg_set->outbound_scratch_pad_2);
/* Check max MSI-X vectors */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) {
- instance->msix_vectors = (scratch_pad_2
- & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
- fw_msix_count = instance->msix_vectors;
- if (msix_vectors)
- instance->msix_vectors =
- min(msix_vectors,
- instance->msix_vectors);
- } else if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)
- || (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
- /* Invader/Fury supports more than 8 MSI-X */
- instance->msix_vectors = ((scratch_pad_2
- & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
- >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
- fw_msix_count = instance->msix_vectors;
- /* Save 1-15 reply post index address to local memory
- * Index 0 is already saved from reg offset
- * MPI2_REPLY_POST_HOST_INDEX_OFFSET
- */
- for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) {
- instance->reply_post_host_index_addr[loop] =
- (u32 __iomem *)
- ((u8 __iomem *)instance->reg_set +
- MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET
- + (loop * 0x10));
+ if (fusion) {
+ if (fusion->adapter_type == THUNDERBOLT_SERIES) { /* Thunderbolt Series*/
+ instance->msix_vectors = (scratch_pad_2
+ & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
+ fw_msix_count = instance->msix_vectors;
+ } else { /* Invader series supports more than 8 MSI-x vectors*/
+ instance->msix_vectors = ((scratch_pad_2
+ & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
+ >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
+ if (rdpq_enable)
+ instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
+ 1 : 0;
+ fw_msix_count = instance->msix_vectors;
+ /* Save 1-15 reply post index address to local memory
+ * Index 0 is already saved from reg offset
+ * MPI2_REPLY_POST_HOST_INDEX_OFFSET
+ */
+ for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) {
+ instance->reply_post_host_index_addr[loop] =
+ (u32 __iomem *)
+ ((u8 __iomem *)instance->reg_set +
+ MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET
+ + (loop * 0x10));
+ }
}
if (msix_vectors)
instance->msix_vectors = min(msix_vectors,
instance->msix_vectors);
- } else
+ } else /* MFI adapters */
instance->msix_vectors = 1;
/* Don't bother allocating more MSI-X vectors than cpus */
instance->msix_vectors = min(instance->msix_vectors,
@@ -4625,6 +5123,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
dev_info(&instance->pdev->dev,
"current msix/online cpus\t: (%d/%d)\n",
instance->msix_vectors, (unsigned int)num_online_cpus());
+ dev_info(&instance->pdev->dev,
+ "RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled");
+
+ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
+ (unsigned long)instance);
if (instance->msix_vectors ?
megasas_setup_irqs_msix(instance, 1) :
@@ -4646,13 +5149,13 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (instance->instancet->init_adapter(instance))
goto fail_init_adapter;
- tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
- (unsigned long)instance);
instance->instancet->enable_intr(instance);
dev_err(&instance->pdev->dev, "INIT adapter done\n");
+ megasas_setup_jbod_map(instance);
+
/** for passthrough
* the following function will get the PD LIST.
*/
@@ -4686,9 +5189,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2);
- instance->disableOnlineCtrlReset =
- ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
- instance->mpio = ctrl_info->adapterOperations2.mpio;
+ instance->peerIsPresent = ctrl_info->cluster.peerIsPresent;
+ instance->passive = ctrl_info->cluster.passive;
+ memcpy(instance->clusterId, ctrl_info->clusterId, sizeof(instance->clusterId));
instance->UnevenSpanSupport =
ctrl_info->adapterOperations2.supportUnevenSpans;
if (instance->UnevenSpanSupport) {
@@ -4700,18 +5203,22 @@ static int megasas_init_fw(struct megasas_instance *instance)
}
if (ctrl_info->host_interface.SRIOV) {
- if (!ctrl_info->adapterOperations2.activePassive)
- instance->PlasmaFW111 = 1;
-
- if (!instance->PlasmaFW111)
- instance->requestorId =
- ctrl_info->iov.requestorId;
- else {
- iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET);
- instance->requestorId = iovPtr->requestorId;
+ instance->requestorId = ctrl_info->iov.requestorId;
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) {
+ if (!ctrl_info->adapterOperations2.activePassive)
+ instance->PlasmaFW111 = 1;
+
+ dev_info(&instance->pdev->dev, "SR-IOV: firmware type: %s\n",
+ instance->PlasmaFW111 ? "1.11" : "new");
+
+ if (instance->PlasmaFW111) {
+ iovPtr = (struct IOV_111 *)
+ ((unsigned char *)ctrl_info + IOV_111_OFFSET);
+ instance->requestorId = iovPtr->requestorId;
+ }
}
- dev_warn(&instance->pdev->dev, "I am VF "
- "requestorId %d\n", instance->requestorId);
+ dev_info(&instance->pdev->dev, "SRIOV: VF requestorId %d\n",
+ instance->requestorId);
}
instance->crash_dump_fw_support =
@@ -4732,8 +5239,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->crash_dump_buf = NULL;
}
- instance->secure_jbod_support =
- ctrl_info->adapterOperations3.supportSecurityonJBOD;
dev_info(&instance->pdev->dev,
"pci id\t\t: (0x%04x)/(0x%04x)/(0x%04x)/(0x%04x)\n",
@@ -4743,16 +5248,14 @@ static int megasas_init_fw(struct megasas_instance *instance)
le16_to_cpu(ctrl_info->pci.sub_device_id));
dev_info(&instance->pdev->dev, "unevenspan support : %s\n",
instance->UnevenSpanSupport ? "yes" : "no");
- dev_info(&instance->pdev->dev, "disable ocr : %s\n",
- instance->disableOnlineCtrlReset ? "yes" : "no");
dev_info(&instance->pdev->dev, "firmware crash dump : %s\n",
instance->crash_dump_drv_support ? "yes" : "no");
- dev_info(&instance->pdev->dev, "secure jbod : %s\n",
- instance->secure_jbod_support ? "yes" : "no");
+ dev_info(&instance->pdev->dev, "jbod sync map : %s\n",
+ instance->use_seqnum_jbod_fp ? "yes" : "no");
instance->max_sectors_per_req = instance->max_num_sge *
- PAGE_SIZE / 512;
+ SGE_BUFFER_SIZE / 512;
if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
instance->max_sectors_per_req = tmp_sectors;
@@ -4764,6 +5267,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->throttlequeuedepth =
MEGASAS_THROTTLE_QUEUE_DEPTH;
+ if (resetwaittime > MEGASAS_RESET_WAIT_TIME)
+ resetwaittime = MEGASAS_RESET_WAIT_TIME;
+
+ if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT))
+ scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT;
/* Launch SR-IOV heartbeat timer */
if (instance->requestorId) {
@@ -4867,10 +5375,8 @@ megasas_get_seq_num(struct megasas_instance *instance,
dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h);
dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info));
- if (megasas_issue_blocked_cmd(instance, cmd, 30))
- dev_err(&instance->pdev->dev, "Command timedout"
- "from %s\n", __func__);
- else {
+ if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS) ==
+ DCMD_SUCCESS) {
/*
* Copy the data back into callers buffer
*/
@@ -4879,7 +5385,9 @@ megasas_get_seq_num(struct megasas_instance *instance,
eli->clear_seq_num = el_info->clear_seq_num;
eli->shutdown_seq_num = el_info->shutdown_seq_num;
eli->boot_seq_num = el_info->boot_seq_num;
- }
+ } else
+ dev_err(&instance->pdev->dev, "DCMD failed "
+ "from %s\n", __func__);
pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
el_info, el_info_h);
@@ -5049,7 +5557,6 @@ static int megasas_start_aen(struct megasas_instance *instance)
static int megasas_io_attach(struct megasas_instance *instance)
{
struct Scsi_Host *host = instance->host;
- u32 error;
/*
* Export parameters required by SCSI mid-layer
@@ -5092,19 +5599,11 @@ static int megasas_io_attach(struct megasas_instance *instance)
host->max_cmd_len = 16;
/* Fusion only supports host reset */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (instance->ctrl_context) {
host->hostt->eh_device_reset_handler = NULL;
host->hostt->eh_bus_reset_handler = NULL;
- }
- error = scsi_init_shared_tag_map(host, host->can_queue);
- if (error) {
- dev_err(&instance->pdev->dev,
- "Failed to shared tag from %s %d\n",
- __func__, __LINE__);
- return -ENODEV;
+ host->hostt->eh_target_reset_handler = megasas_reset_target_fusion;
+ host->hostt->eh_abort_handler = megasas_task_abort_fusion;
}
/*
@@ -5218,6 +5717,10 @@ static int megasas_probe_one(struct pci_dev *pdev,
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
+ case PCI_DEVICE_ID_LSI_INTRUDER:
+ case PCI_DEVICE_ID_LSI_INTRUDER_24:
+ case PCI_DEVICE_ID_LSI_CUTLASS_52:
+ case PCI_DEVICE_ID_LSI_CUTLASS_53:
{
instance->ctrl_context_pages =
get_order(sizeof(struct fusion_context));
@@ -5231,6 +5734,11 @@ static int megasas_probe_one(struct pci_dev *pdev,
fusion = instance->ctrl_context;
memset(fusion, 0,
((1 << PAGE_SHIFT) << instance->ctrl_context_pages));
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA))
+ fusion->adapter_type = THUNDERBOLT_SERIES;
+ else
+ fusion->adapter_type = INVADER_SERIES;
}
break;
default: /* For all other supported controllers */
@@ -5281,7 +5789,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->flag_ieee = 0;
instance->ev = NULL;
instance->issuepend_done = 1;
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
instance->is_imr = 0;
instance->evt_detail = pci_alloc_consistent(pdev,
@@ -5295,6 +5803,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
goto fail_alloc_dma_buf;
}
+ instance->pd_info = pci_alloc_consistent(pdev,
+ sizeof(struct MR_PD_INFO), &instance->pd_info_h);
+
+ if (!instance->pd_info)
+ dev_err(&instance->pdev->dev, "Failed to alloc mem for pd_info\n");
+
/*
* Initialize locks and queues
*/
@@ -5310,8 +5824,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
spin_lock_init(&instance->hba_lock);
spin_lock_init(&instance->completion_lock);
- mutex_init(&instance->aen_mutex);
mutex_init(&instance->reset_mutex);
+ mutex_init(&instance->hba_mutex);
/*
* Initialize PCI related and misc parameters
@@ -5333,10 +5847,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->disableOnlineCtrlReset = 1;
instance->UnevenSpanSupport = 0;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (instance->ctrl_context) {
INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
INIT_WORK(&instance->crash_init, megasas_fusion_crash_dump_wq);
} else
@@ -5416,10 +5927,7 @@ fail_io_attach:
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (instance->ctrl_context)
megasas_release_fusion(instance);
else
megasas_release_mfi(instance);
@@ -5432,6 +5940,10 @@ fail_alloc_dma_buf:
instance->evt_detail,
instance->evt_detail_h);
+ if (instance->pd_info)
+ pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+ instance->pd_info,
+ instance->pd_info_h);
if (instance->producer)
pci_free_consistent(pdev, sizeof(u32), instance->producer,
instance->producer_h);
@@ -5456,7 +5968,7 @@ static void megasas_flush_cache(struct megasas_instance *instance)
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
cmd = megasas_get_cmd(instance);
@@ -5478,9 +5990,12 @@ static void megasas_flush_cache(struct megasas_instance *instance)
dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
- if (megasas_issue_blocked_cmd(instance, cmd, 30))
- dev_err(&instance->pdev->dev, "Command timedout"
- " from %s\n", __func__);
+ if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+ != DCMD_SUCCESS) {
+ dev_err(&instance->pdev->dev,
+ "return from %s %d\n", __func__, __LINE__);
+ return;
+ }
megasas_return_cmd(instance, cmd);
}
@@ -5496,7 +6011,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return;
cmd = megasas_get_cmd(instance);
@@ -5506,10 +6021,14 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
if (instance->aen_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->aen_cmd, 30);
+ instance->aen_cmd, MFI_IO_TIMEOUT_SECS);
if (instance->map_update_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->map_update_cmd, 30);
+ instance->map_update_cmd, MFI_IO_TIMEOUT_SECS);
+ if (instance->jbod_seq_cmd)
+ megasas_issue_blocked_abort_cmd(instance,
+ instance->jbod_seq_cmd, MFI_IO_TIMEOUT_SECS);
+
dcmd = &cmd->frame->dcmd;
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -5523,9 +6042,12 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
dcmd->data_xfer_len = 0;
dcmd->opcode = cpu_to_le32(opcode);
- if (megasas_issue_blocked_cmd(instance, cmd, 30))
- dev_err(&instance->pdev->dev, "Command timedout"
- "from %s\n", __func__);
+ if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS)
+ != DCMD_SUCCESS) {
+ dev_err(&instance->pdev->dev,
+ "return from %s %d\n", __func__, __LINE__);
+ return;
+ }
megasas_return_cmd(instance, cmd);
}
@@ -5628,12 +6150,7 @@ megasas_resume(struct pci_dev *pdev)
instance->msix_vectors))
goto fail_reenable_msix;
- switch (instance->pdev->device) {
- case PCI_DEVICE_ID_LSI_FUSION:
- case PCI_DEVICE_ID_LSI_PLASMA:
- case PCI_DEVICE_ID_LSI_INVADER:
- case PCI_DEVICE_ID_LSI_FURY:
- {
+ if (instance->ctrl_context) {
megasas_reset_reply_desc(instance);
if (megasas_ioc_init_fusion(instance)) {
megasas_free_cmds(instance);
@@ -5642,14 +6159,11 @@ megasas_resume(struct pci_dev *pdev)
}
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
- }
- break;
- default:
+ } else {
*instance->producer = 0;
*instance->consumer = 0;
if (megasas_issue_init_mfi(instance))
goto fail_init_mfi;
- break;
}
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
@@ -5674,6 +6188,7 @@ megasas_resume(struct pci_dev *pdev)
}
instance->instancet->enable_intr(instance);
+ megasas_setup_jbod_map(instance);
instance->unload = 0;
/*
@@ -5690,6 +6205,10 @@ fail_init_mfi:
instance->evt_detail,
instance->evt_detail_h);
+ if (instance->pd_info)
+ pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+ instance->pd_info,
+ instance->pd_info_h);
if (instance->producer)
pci_free_consistent(pdev, sizeof(u32), instance->producer,
instance->producer_h);
@@ -5721,6 +6240,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
struct Scsi_Host *host;
struct megasas_instance *instance;
struct fusion_context *fusion;
+ u32 pd_seq_map_sz;
instance = pci_get_drvdata(pdev);
instance->unload = 1;
@@ -5769,12 +6289,11 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (instance->msix_vectors)
pci_disable_msix(instance->pdev);
- switch (instance->pdev->device) {
- case PCI_DEVICE_ID_LSI_FUSION:
- case PCI_DEVICE_ID_LSI_PLASMA:
- case PCI_DEVICE_ID_LSI_INVADER:
- case PCI_DEVICE_ID_LSI_FURY:
+ if (instance->ctrl_context) {
megasas_release_fusion(instance);
+ pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+ (sizeof(struct MR_PD_CFG_SEQ) *
+ (MAX_PHYSICAL_DEVICES - 1));
for (i = 0; i < 2 ; i++) {
if (fusion->ld_map[i])
dma_free_coherent(&instance->pdev->dev,
@@ -5784,11 +6303,15 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (fusion->ld_drv_map[i])
free_pages((ulong)fusion->ld_drv_map[i],
fusion->drv_map_pages);
+ if (fusion->pd_seq_sync[i])
+ dma_free_coherent(&instance->pdev->dev,
+ pd_seq_map_sz,
+ fusion->pd_seq_sync[i],
+ fusion->pd_seq_phys[i]);
}
free_pages((ulong)instance->ctrl_context,
instance->ctrl_context_pages);
- break;
- default:
+ } else {
megasas_release_mfi(instance);
pci_free_consistent(pdev, sizeof(u32),
instance->producer,
@@ -5796,7 +6319,6 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_free_consistent(pdev, sizeof(u32),
instance->consumer,
instance->consumer_h);
- break;
}
kfree(instance->ctrl_info);
@@ -5805,6 +6327,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
instance->evt_detail, instance->evt_detail_h);
+ if (instance->pd_info)
+ pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
+ instance->pd_info,
+ instance->pd_info_h);
if (instance->vf_affiliation)
pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
sizeof(struct MR_LD_VF_AFFILIATION),
@@ -5930,7 +6456,7 @@ static int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd)
for (i = 0; i < megasas_mgmt_info.max_index; i++) {
local_instance = megasas_mgmt_info.instance[i];
if (local_instance && local_instance->crash_dump_drv_support) {
- if ((local_instance->adprecovery ==
+ if ((atomic_read(&local_instance->adprecovery) ==
MEGASAS_HBA_OPERATIONAL) &&
!megasas_set_crash_dump_params(local_instance,
crash_support)) {
@@ -6067,7 +6593,15 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* cmd to the SCSI mid-layer
*/
cmd->sync_cmd = 1;
- megasas_issue_blocked_cmd(instance, cmd, 0);
+ if (megasas_issue_blocked_cmd(instance, cmd, 0) == DCMD_NOT_FIRED) {
+ cmd->sync_cmd = 0;
+ dev_err(&instance->pdev->dev,
+ "return -EBUSY from %s %d opcode 0x%x cmd->cmd_status_drv 0x%x\n",
+ __func__, __LINE__, cmd->frame->dcmd.opcode,
+ cmd->cmd_status_drv);
+ return -EBUSY;
+ }
+
cmd->sync_cmd = 0;
if (instance->unload == 1) {
@@ -6122,12 +6656,13 @@ out:
}
for (i = 0; i < ioc->sge_count; i++) {
- if (kbuff_arr[i])
+ if (kbuff_arr[i]) {
dma_free_coherent(&instance->pdev->dev,
le32_to_cpu(kern_sge32[i].length),
kbuff_arr[i],
le32_to_cpu(kern_sge32[i].phys_addr));
kbuff_arr[i] = NULL;
+ }
}
megasas_return_cmd(instance, cmd);
@@ -6170,7 +6705,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_err(&instance->pdev->dev, "Controller in crit error\n");
error = -ENODEV;
goto out_kfree_ioc;
@@ -6189,7 +6724,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
for (i = 0; i < wait_time; i++) {
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
break;
}
@@ -6204,7 +6739,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
}
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
dev_err(&instance->pdev->dev, "timed out while"
@@ -6246,7 +6781,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
if (!instance)
return -ENODEV;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
return -ENODEV;
}
@@ -6257,7 +6792,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
for (i = 0; i < wait_time; i++) {
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock,
flags);
break;
@@ -6274,7 +6809,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
}
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
dev_err(&instance->pdev->dev, "timed out while waiting"
"for HBA to recover\n");
@@ -6282,10 +6817,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
}
spin_unlock_irqrestore(&instance->hba_lock, flags);
- mutex_lock(&instance->aen_mutex);
+ mutex_lock(&instance->reset_mutex);
error = megasas_register_aen(instance, aen.seq_num,
aen.class_locale_word);
- mutex_unlock(&instance->aen_mutex);
+ mutex_unlock(&instance->reset_mutex);
return error;
}
@@ -6316,6 +6851,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
int i;
int error = 0;
compat_uptr_t ptr;
+ u32 local_sense_off;
+ u32 local_sense_len;
+ u32 user_sense_off;
if (clear_user(ioc, sizeof(*ioc)))
return -EFAULT;
@@ -6333,11 +6871,16 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
* sense_len is not null, so prepare the 64bit value under
* the same condition.
*/
- if (ioc->sense_len) {
+ if (get_user(local_sense_off, &ioc->sense_off) ||
+ get_user(local_sense_len, &ioc->sense_len) ||
+ get_user(user_sense_off, &cioc->sense_off))
+ return -EFAULT;
+
+ if (local_sense_len) {
void __user **sense_ioc_ptr =
- (void __user **)(ioc->frame.raw + ioc->sense_off);
+ (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off);
compat_uptr_t *sense_cioc_ptr =
- (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
+ (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off);
if (get_user(ptr, sense_cioc_ptr) ||
put_user(compat_ptr(ptr), sense_ioc_ptr))
return -EFAULT;
@@ -6478,6 +7021,7 @@ megasas_aen_polling(struct work_struct *work)
int i, j, doscan = 0;
u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
int error;
+ u8 dcmd_ret = DCMD_SUCCESS;
if (!instance) {
printk(KERN_ERR "invalid instance!\n");
@@ -6490,228 +7034,135 @@ megasas_aen_polling(struct work_struct *work)
wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
/* Don't run the event workqueue thread if OCR is running */
- for (i = 0; i < wait_time; i++) {
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
- break;
- if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
- dev_notice(&instance->pdev->dev, "%s waiting for "
- "controller reset to finish for scsi%d\n",
- __func__, instance->host->host_no);
- }
- msleep(1000);
- }
+ mutex_lock(&instance->reset_mutex);
instance->ev = NULL;
host = instance->host;
if (instance->evt_detail) {
+ megasas_decode_evt(instance);
switch (le32_to_cpu(instance->evt_detail->code)) {
- case MR_EVT_PD_INSERTED:
- if (megasas_get_pd_list(instance) == 0) {
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- pd_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, i, j, 0);
-
- if (instance->pd_list[pd_index].driveState
- == MR_PD_STATE_SYSTEM) {
- if (!sdev1)
- scsi_add_device(host, i, j, 0);
-
- if (sdev1)
- scsi_device_put(sdev1);
- }
- }
- }
- }
- doscan = 0;
- break;
+ case MR_EVT_PD_INSERTED:
case MR_EVT_PD_REMOVED:
- if (megasas_get_pd_list(instance) == 0) {
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- pd_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, i, j, 0);
-
- if (instance->pd_list[pd_index].driveState
- == MR_PD_STATE_SYSTEM) {
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
- }
- }
- }
- }
- doscan = 0;
+ dcmd_ret = megasas_get_pd_list(instance);
+ if (dcmd_ret == DCMD_SUCCESS)
+ doscan = SCAN_PD_CHANNEL;
break;
case MR_EVT_LD_OFFLINE:
case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
- if (!instance->requestorId ||
- (instance->requestorId &&
- megasas_get_ld_vf_affiliation(instance, 0))) {
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
-
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
- if (instance->ld_ids[ld_index]
- != 0xff) {
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
- }
- }
- }
- doscan = 0;
- }
- break;
case MR_EVT_LD_CREATED:
if (!instance->requestorId ||
- (instance->requestorId &&
- megasas_get_ld_vf_affiliation(instance, 0))) {
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0;
- j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
- if (instance->ld_ids[ld_index]
- != 0xff) {
- if (!sdev1)
- scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- }
- if (sdev1)
- scsi_device_put(sdev1);
- }
- }
- doscan = 0;
- }
+ (instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+ dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+ if (dcmd_ret == DCMD_SUCCESS)
+ doscan = SCAN_VD_CHANNEL;
+
break;
+
case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
case MR_EVT_FOREIGN_CFG_IMPORTED:
case MR_EVT_LD_STATE_CHANGE:
- doscan = 1;
+ dcmd_ret = megasas_get_pd_list(instance);
+
+ if (dcmd_ret != DCMD_SUCCESS)
+ break;
+
+ if (!instance->requestorId ||
+ (instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+ dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+ if (dcmd_ret != DCMD_SUCCESS)
+ break;
+
+ doscan = SCAN_VD_CHANNEL | SCAN_PD_CHANNEL;
+ dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
+ instance->host->host_no);
break;
+
+ case MR_EVT_CTRL_PROP_CHANGED:
+ dcmd_ret = megasas_get_ctrl_info(instance);
+ break;
default:
doscan = 0;
break;
}
} else {
dev_err(&instance->pdev->dev, "invalid evt_detail!\n");
+ mutex_unlock(&instance->reset_mutex);
kfree(ev);
return;
}
- if (doscan) {
- dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
- instance->host->host_no);
- if (megasas_get_pd_list(instance) == 0) {
- for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
- pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
- sdev1 = scsi_device_lookup(host, i, j, 0);
- if (instance->pd_list[pd_index].driveState ==
- MR_PD_STATE_SYSTEM) {
- if (!sdev1) {
- scsi_add_device(host, i, j, 0);
- }
- if (sdev1)
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
+ mutex_unlock(&instance->reset_mutex);
+
+ if (doscan & SCAN_PD_CHANNEL) {
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+ sdev1 = scsi_device_lookup(host, i, j, 0);
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ if (!sdev1)
+ scsi_add_device(host, i, j, 0);
+ else
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
}
}
}
}
+ }
- if (!instance->requestorId ||
- (instance->requestorId &&
- megasas_get_ld_vf_affiliation(instance, 0))) {
- if (megasas_ld_list_query(instance,
- MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
- megasas_get_ld_list(instance);
- for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
- for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
- j++) {
- ld_index =
- (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
- sdev1 = scsi_device_lookup(host,
- MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- if (instance->ld_ids[ld_index]
- != 0xff) {
- if (!sdev1)
- scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
- else
- scsi_device_put(sdev1);
- } else {
- if (sdev1) {
- scsi_remove_device(sdev1);
- scsi_device_put(sdev1);
- }
+ if (doscan & SCAN_VD_CHANNEL) {
+ for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+ sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ if (instance->ld_ids[ld_index] != 0xff) {
+ if (!sdev1)
+ scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+ else
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
}
}
}
}
}
- if (instance->aen_cmd != NULL) {
- kfree(ev);
- return ;
- }
-
- seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+ if (dcmd_ret == DCMD_SUCCESS)
+ seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+ else
+ seq_num = instance->last_seq_num;
/* Register AEN with FW for latest sequence number plus 1 */
class_locale.members.reserved = 0;
class_locale.members.locale = MR_EVT_LOCALE_ALL;
class_locale.members.class = MR_EVT_CLASS_DEBUG;
- mutex_lock(&instance->aen_mutex);
+
+ if (instance->aen_cmd != NULL) {
+ kfree(ev);
+ return;
+ }
+
+ mutex_lock(&instance->reset_mutex);
error = megasas_register_aen(instance, seq_num,
class_locale.word);
- mutex_unlock(&instance->aen_mutex);
-
if (error)
- dev_err(&instance->pdev->dev, "register aen failed error %x\n", error);
+ dev_err(&instance->pdev->dev,
+ "register aen failed error %x\n", error);
+ mutex_unlock(&instance->reset_mutex);
kfree(ev);
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index be57b18..e413113 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -741,14 +741,12 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
u8 physArm, span;
u64 row;
u8 retval = TRUE;
- u8 do_invader = 0;
u64 *pdBlock = &io_info->pdBlock;
__le16 *pDevHandle = &io_info->devHandle;
u32 logArm, rowMod, armQ, arm;
+ struct fusion_context *fusion;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
- instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- do_invader = 1;
+ fusion = instance->ctrl_context;
/*Get row and span from io_info for Uneven Span IO.*/
row = io_info->start_row;
@@ -779,7 +777,8 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
else {
*pDevHandle = cpu_to_le16(MR_PD_INVALID);
if ((raid->level >= 5) &&
- (!do_invader || (do_invader &&
+ ((fusion->adapter_type == THUNDERBOLT_SERIES) ||
+ ((fusion->adapter_type == INVADER_SERIES) &&
(raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
else if (raid->level == 1) {
@@ -823,13 +822,12 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
u8 physArm, span;
u64 row;
u8 retval = TRUE;
- u8 do_invader = 0;
u64 *pdBlock = &io_info->pdBlock;
__le16 *pDevHandle = &io_info->devHandle;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
- instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- do_invader = 1;
row = mega_div64_32(stripRow, raid->rowDataSize);
@@ -875,7 +873,8 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
/* set dev handle as invalid. */
*pDevHandle = cpu_to_le16(MR_PD_INVALID);
if ((raid->level >= 5) &&
- (!do_invader || (do_invader &&
+ ((fusion->adapter_type == THUNDERBOLT_SERIES) ||
+ ((fusion->adapter_type == INVADER_SERIES) &&
(raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
else if (raid->level == 1) {
@@ -909,6 +908,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
struct RAID_CONTEXT *pRAID_Context,
struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN)
{
+ struct fusion_context *fusion;
struct MR_LD_RAID *raid;
u32 ld, stripSize, stripe_mask;
u64 endLba, endStrip, endRow, start_row, start_strip;
@@ -929,6 +929,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
isRead = io_info->isRead;
io_info->IoforUnevenSpan = 0;
io_info->start_span = SPAN_INVALID;
+ fusion = instance->ctrl_context;
ld = MR_TargetIdToLdGet(ldTgtId, map);
raid = MR_LdRaidGet(ld, map);
@@ -1019,6 +1020,8 @@ MR_BuildRaidContext(struct megasas_instance *instance,
/* assume this IO needs the full row - we'll adjust if not true */
regSize = stripSize;
+ io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock;
+
/* Check if we can send this I/O via FastPath */
if (raid->capability.fpCapable) {
if (isRead)
@@ -1092,8 +1095,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
cpu_to_le16(raid->fpIoTimeoutForLd ?
raid->fpIoTimeoutForLd :
map->raidMap.fpPdIoTimeoutSec);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
pRAID_Context->regLockFlags = (isRead) ?
raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
else
@@ -1198,10 +1200,6 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
span_row_width +=
MR_LdSpanPtrGet
(ld, count, map)->spanRowDataSize;
- printk(KERN_INFO "megasas:"
- "span %x rowDataSize %x\n",
- count, MR_LdSpanPtrGet
- (ld, count, map)->spanRowDataSize);
}
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index f0837cc..98a848b 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -91,7 +91,10 @@ void megasas_start_timer(struct megasas_instance *instance,
struct timer_list *timer,
void *fn, unsigned long interval);
extern struct megasas_mgmt_info megasas_mgmt_info;
-extern int resetwaittime;
+extern unsigned int resetwaittime;
+extern unsigned int dual_qdepth_disable;
+static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
+static void megasas_free_reply_fusion(struct megasas_instance *instance);
@@ -201,58 +204,72 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
&instance->reg_set->inbound_low_queue_port);
writel(le32_to_cpu(req_desc->u.high),
&instance->reg_set->inbound_high_queue_port);
+ mmiowb();
spin_unlock_irqrestore(&instance->hba_lock, flags);
#endif
}
-
/**
- * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool
- * @instance: Adapter soft state
+ * megasas_fusion_update_can_queue - Do all Adapter Queue depth related calculations here
+ * @instance: Adapter soft state
+ * fw_boot_context: Whether this function called during probe or after OCR
+ *
+ * This function is only for fusion controllers.
+ * Update host can queue, if firmware downgrade max supported firmware commands.
+ * Firmware upgrade case will be skiped because underlying firmware has
+ * more resource than exposed to the OS.
+ *
*/
-static void megasas_teardown_frame_pool_fusion(
- struct megasas_instance *instance)
+static void
+megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_context)
{
- int i;
- struct fusion_context *fusion = instance->ctrl_context;
-
- u16 max_cmd = instance->max_fw_cmds;
+ u16 cur_max_fw_cmds = 0;
+ u16 ldio_threshold = 0;
+ struct megasas_register_set __iomem *reg_set;
- struct megasas_cmd_fusion *cmd;
+ reg_set = instance->reg_set;
- if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
- dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, "
- "sense pool : %p\n", fusion->sg_dma_pool,
- fusion->sense_dma_pool);
- return;
- }
+ cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF;
- /*
- * Return all frames to pool
- */
- for (i = 0; i < max_cmd; i++) {
+ if (dual_qdepth_disable || !cur_max_fw_cmds)
+ cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+ else
+ ldio_threshold =
+ (instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF) - MEGASAS_FUSION_IOCTL_CMDS;
+
+ dev_info(&instance->pdev->dev,
+ "Current firmware maximum commands: %d\t LDIO threshold: %d\n",
+ cur_max_fw_cmds, ldio_threshold);
+
+ if (fw_boot_context == OCR_CONTEXT) {
+ cur_max_fw_cmds = cur_max_fw_cmds - 1;
+ if (cur_max_fw_cmds <= instance->max_fw_cmds) {
+ instance->cur_can_queue =
+ cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS +
+ MEGASAS_FUSION_IOCTL_CMDS);
+ instance->host->can_queue = instance->cur_can_queue;
+ instance->ldio_threshold = ldio_threshold;
+ }
+ } else {
+ instance->max_fw_cmds = cur_max_fw_cmds;
+ instance->ldio_threshold = ldio_threshold;
- cmd = fusion->cmd_list[i];
+ if (!instance->is_rdpq)
+ instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
- if (cmd->sg_frame)
- pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
- cmd->sg_frame_phys_addr);
+ /*
+ * Reduce the max supported cmds by 1. This is to ensure that the
+ * reply_q_sz (1 more than the max cmd that driver may send)
+ * does not exceed max cmds that the FW can support
+ */
+ instance->max_fw_cmds = instance->max_fw_cmds-1;
- if (cmd->sense)
- pci_pool_free(fusion->sense_dma_pool, cmd->sense,
- cmd->sense_phys_addr);
+ instance->max_scsi_cmds = instance->max_fw_cmds -
+ (MEGASAS_FUSION_INTERNAL_CMDS +
+ MEGASAS_FUSION_IOCTL_CMDS);
+ instance->cur_can_queue = instance->max_scsi_cmds;
}
-
- /*
- * Now destroy the pool itself
- */
- pci_pool_destroy(fusion->sg_dma_pool);
- pci_pool_destroy(fusion->sense_dma_pool);
-
- fusion->sg_dma_pool = NULL;
- fusion->sense_dma_pool = NULL;
}
-
/**
* megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
* @instance: Adapter soft state
@@ -262,87 +279,86 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
{
int i;
struct fusion_context *fusion = instance->ctrl_context;
+ struct megasas_cmd_fusion *cmd;
- u32 max_cmds, req_sz, reply_sz, io_frames_sz;
+ /* SG, Sense */
+ for (i = 0; i < instance->max_fw_cmds; i++) {
+ cmd = fusion->cmd_list[i];
+ if (cmd) {
+ if (cmd->sg_frame)
+ pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
+ cmd->sg_frame_phys_addr);
+ if (cmd->sense)
+ pci_pool_free(fusion->sense_dma_pool, cmd->sense,
+ cmd->sense_phys_addr);
+ }
+ }
+ if (fusion->sg_dma_pool) {
+ pci_pool_destroy(fusion->sg_dma_pool);
+ fusion->sg_dma_pool = NULL;
+ }
+ if (fusion->sense_dma_pool) {
+ pci_pool_destroy(fusion->sense_dma_pool);
+ fusion->sense_dma_pool = NULL;
+ }
- req_sz = fusion->request_alloc_sz;
- reply_sz = fusion->reply_alloc_sz;
- io_frames_sz = fusion->io_frames_alloc_sz;
- max_cmds = instance->max_fw_cmds;
+ /* Reply Frame, Desc*/
+ if (instance->is_rdpq)
+ megasas_free_rdpq_fusion(instance);
+ else
+ megasas_free_reply_fusion(instance);
- /* Free descriptors and request Frames memory */
+ /* Request Frame, Desc*/
if (fusion->req_frames_desc)
- dma_free_coherent(&instance->pdev->dev, req_sz,
- fusion->req_frames_desc,
- fusion->req_frames_desc_phys);
-
- if (fusion->reply_frames_desc) {
- pci_pool_free(fusion->reply_frames_desc_pool,
- fusion->reply_frames_desc,
- fusion->reply_frames_desc_phys);
- pci_pool_destroy(fusion->reply_frames_desc_pool);
- }
-
- if (fusion->io_request_frames) {
+ dma_free_coherent(&instance->pdev->dev,
+ fusion->request_alloc_sz, fusion->req_frames_desc,
+ fusion->req_frames_desc_phys);
+ if (fusion->io_request_frames)
pci_pool_free(fusion->io_request_frames_pool,
- fusion->io_request_frames,
- fusion->io_request_frames_phys);
+ fusion->io_request_frames,
+ fusion->io_request_frames_phys);
+ if (fusion->io_request_frames_pool) {
pci_pool_destroy(fusion->io_request_frames_pool);
+ fusion->io_request_frames_pool = NULL;
}
- /* Free the Fusion frame pool */
- megasas_teardown_frame_pool_fusion(instance);
- /* Free all the commands in the cmd_list */
- for (i = 0; i < max_cmds; i++)
+ /* cmd_list */
+ for (i = 0; i < instance->max_fw_cmds; i++)
kfree(fusion->cmd_list[i]);
- /* Free the cmd_list buffer itself */
kfree(fusion->cmd_list);
- fusion->cmd_list = NULL;
-
}
/**
- * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames
+ * megasas_create_sg_sense_fusion - Creates DMA pool for cmd frames
* @instance: Adapter soft state
*
*/
-static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
+static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
{
int i;
u32 max_cmd;
struct fusion_context *fusion;
struct megasas_cmd_fusion *cmd;
- u32 total_sz_chain_frame;
fusion = instance->ctrl_context;
max_cmd = instance->max_fw_cmds;
- total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME;
- /*
- * Use DMA pool facility provided by PCI layer
- */
-
- fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion",
- instance->pdev,
- total_sz_chain_frame, 4,
- 0);
- if (!fusion->sg_dma_pool) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
- return -ENOMEM;
- }
- fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion",
- instance->pdev,
- SCSI_SENSE_BUFFERSIZE, 64, 0);
+ fusion->sg_dma_pool =
+ pci_pool_create("mr_sg", instance->pdev,
+ instance->max_chain_frame_sz, 4, 0);
+ /* SCSI_SENSE_BUFFERSIZE = 96 bytes */
+ fusion->sense_dma_pool =
+ pci_pool_create("mr_sense", instance->pdev,
+ SCSI_SENSE_BUFFERSIZE, 64, 0);
- if (!fusion->sense_dma_pool) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n");
- pci_pool_destroy(fusion->sg_dma_pool);
- fusion->sg_dma_pool = NULL;
+ if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
@@ -350,160 +366,280 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
* Allocate and attach a frame to each of the commands in cmd_list
*/
for (i = 0; i < max_cmd; i++) {
-
cmd = fusion->cmd_list[i];
-
cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
- GFP_KERNEL,
- &cmd->sg_frame_phys_addr);
+ GFP_KERNEL, &cmd->sg_frame_phys_addr);
cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
- GFP_KERNEL, &cmd->sense_phys_addr);
- /*
- * megasas_teardown_frame_pool_fusion() takes care of freeing
- * whatever has been allocated
- */
+ GFP_KERNEL, &cmd->sense_phys_addr);
if (!cmd->sg_frame || !cmd->sense) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n");
- megasas_teardown_frame_pool_fusion(instance);
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
}
return 0;
}
-/**
- * megasas_alloc_cmds_fusion - Allocates the command packets
- * @instance: Adapter soft state
- *
- *
- * Each frame has a 32-bit field called context. This context is used to get
- * back the megasas_cmd_fusion from the frame when a frame gets completed
- * In this driver, the 32 bit values are the indices into an array cmd_list.
- * This array is used only to look up the megasas_cmd_fusion given the context.
- * The free commands themselves are maintained in a linked list called cmd_pool.
- *
- * cmds are formed in the io_request and sg_frame members of the
- * megasas_cmd_fusion. The context field is used to get a request descriptor
- * and is used as SMID of the cmd.
- * SMID value range is from 1 to max_fw_cmds.
- */
int
-megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
{
- int i, j, count;
- u32 max_cmd, io_frames_sz;
+ u32 max_cmd, i;
struct fusion_context *fusion;
- struct megasas_cmd_fusion *cmd;
- union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
- u32 offset;
- dma_addr_t io_req_base_phys;
- u8 *io_req_base;
fusion = instance->ctrl_context;
max_cmd = instance->max_fw_cmds;
+ /*
+ * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
+ * Allocate the dynamic array first and then allocate individual
+ * commands.
+ */
+ fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
+ GFP_KERNEL);
+ if (!fusion->cmd_list) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < max_cmd; i++) {
+ fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
+ GFP_KERNEL);
+ if (!fusion->cmd_list[i]) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+int
+megasas_alloc_request_fusion(struct megasas_instance *instance)
+{
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
fusion->req_frames_desc =
dma_alloc_coherent(&instance->pdev->dev,
- fusion->request_alloc_sz,
- &fusion->req_frames_desc_phys, GFP_KERNEL);
-
+ fusion->request_alloc_sz,
+ &fusion->req_frames_desc_phys, GFP_KERNEL);
if (!fusion->req_frames_desc) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "request_frames\n");
- goto fail_req_desc;
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ fusion->io_request_frames_pool =
+ pci_pool_create("mr_ioreq", instance->pdev,
+ fusion->io_frames_alloc_sz, 16, 0);
+
+ if (!fusion->io_request_frames_pool) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
+ fusion->io_request_frames =
+ pci_pool_alloc(fusion->io_request_frames_pool,
+ GFP_KERNEL, &fusion->io_request_frames_phys);
+ if (!fusion->io_request_frames) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int
+megasas_alloc_reply_fusion(struct megasas_instance *instance)
+{
+ int i, count;
+ struct fusion_context *fusion;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+ fusion = instance->ctrl_context;
+
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
fusion->reply_frames_desc_pool =
- pci_pool_create("reply_frames pool", instance->pdev,
+ pci_pool_create("mr_reply", instance->pdev,
fusion->reply_alloc_sz * count, 16, 0);
if (!fusion->reply_frames_desc_pool) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "reply_frame pool\n");
- goto fail_reply_desc;
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
- fusion->reply_frames_desc =
- pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
- &fusion->reply_frames_desc_phys);
- if (!fusion->reply_frames_desc) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "reply_frame pool\n");
- pci_pool_destroy(fusion->reply_frames_desc_pool);
- goto fail_reply_desc;
+ fusion->reply_frames_desc[0] =
+ pci_pool_alloc(fusion->reply_frames_desc_pool,
+ GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
+ if (!fusion->reply_frames_desc[0]) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
-
- reply_desc = fusion->reply_frames_desc;
+ reply_desc = fusion->reply_frames_desc[0];
for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
reply_desc->Words = cpu_to_le64(ULLONG_MAX);
- io_frames_sz = fusion->io_frames_alloc_sz;
+ /* This is not a rdpq mode, but driver still populate
+ * reply_frame_desc array to use same msix index in ISR path.
+ */
+ for (i = 0; i < (count - 1); i++)
+ fusion->reply_frames_desc[i + 1] =
+ fusion->reply_frames_desc[i] +
+ (fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
- fusion->io_request_frames_pool =
- pci_pool_create("io_request_frames pool", instance->pdev,
- fusion->io_frames_alloc_sz, 16, 0);
+ return 0;
+}
- if (!fusion->io_request_frames_pool) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "io_request_frame pool\n");
- goto fail_io_frames;
+int
+megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
+{
+ int i, j, count;
+ struct fusion_context *fusion;
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+
+ fusion = instance->ctrl_context;
+
+ fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
+ sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+ &fusion->rdpq_phys);
+ if (!fusion->rdpq_virt) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
- fusion->io_request_frames =
- pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
- &fusion->io_request_frames_phys);
- if (!fusion->io_request_frames) {
- dev_err(&instance->pdev->dev, "Could not allocate memory for "
- "io_request_frames frames\n");
- pci_pool_destroy(fusion->io_request_frames_pool);
- goto fail_io_frames;
+ memset(fusion->rdpq_virt, 0,
+ sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
+ instance->pdev, fusion->reply_alloc_sz, 16, 0);
+
+ if (!fusion->reply_frames_desc_pool) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
}
- /*
- * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
- * Allocate the dynamic array first and then allocate individual
- * commands.
- */
- fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
- * max_cmd, GFP_KERNEL);
+ for (i = 0; i < count; i++) {
+ fusion->reply_frames_desc[i] =
+ pci_pool_alloc(fusion->reply_frames_desc_pool,
+ GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
+ if (!fusion->reply_frames_desc[i]) {
+ dev_err(&instance->pdev->dev,
+ "Failed from %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
- if (!fusion->cmd_list) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc "
- "memory for cmd_list_fusion\n");
- goto fail_cmd_list;
+ fusion->rdpq_virt[i].RDPQBaseAddress =
+ fusion->reply_frames_desc_phys[i];
+
+ reply_desc = fusion->reply_frames_desc[i];
+ for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
+ reply_desc->Words = cpu_to_le64(ULLONG_MAX);
}
+ return 0;
+}
- max_cmd = instance->max_fw_cmds;
- for (i = 0; i < max_cmd; i++) {
- fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
- GFP_KERNEL);
- if (!fusion->cmd_list[i]) {
- dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
+static void
+megasas_free_rdpq_fusion(struct megasas_instance *instance) {
+
+ int i;
+ struct fusion_context *fusion;
- for (j = 0; j < i; j++)
- kfree(fusion->cmd_list[j]);
+ fusion = instance->ctrl_context;
- kfree(fusion->cmd_list);
- fusion->cmd_list = NULL;
- goto fail_cmd_list;
- }
+ for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
+ if (fusion->reply_frames_desc[i])
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc[i],
+ fusion->reply_frames_desc_phys[i]);
}
- /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
- io_req_base = fusion->io_request_frames +
- MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
- io_req_base_phys = fusion->io_request_frames_phys +
- MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+ if (fusion->reply_frames_desc_pool)
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+ if (fusion->rdpq_virt)
+ pci_free_consistent(instance->pdev,
+ sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+ fusion->rdpq_virt, fusion->rdpq_phys);
+}
+
+static void
+megasas_free_reply_fusion(struct megasas_instance *instance) {
+
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ if (fusion->reply_frames_desc[0])
+ pci_pool_free(fusion->reply_frames_desc_pool,
+ fusion->reply_frames_desc[0],
+ fusion->reply_frames_desc_phys[0]);
+
+ if (fusion->reply_frames_desc_pool)
+ pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+}
+
+
+/**
+ * megasas_alloc_cmds_fusion - Allocates the command packets
+ * @instance: Adapter soft state
+ *
+ *
+ * Each frame has a 32-bit field called context. This context is used to get
+ * back the megasas_cmd_fusion from the frame when a frame gets completed
+ * In this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd_fusion given the context.
+ * The free commands themselves are maintained in a linked list called cmd_pool.
+ *
+ * cmds are formed in the io_request and sg_frame members of the
+ * megasas_cmd_fusion. The context field is used to get a request descriptor
+ * and is used as SMID of the cmd.
+ * SMID value range is from 1 to max_fw_cmds.
+ */
+int
+megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *cmd;
+ u32 offset;
+ dma_addr_t io_req_base_phys;
+ u8 *io_req_base;
+
+
+ fusion = instance->ctrl_context;
+
+ if (megasas_alloc_cmdlist_fusion(instance))
+ goto fail_exit;
+
+ if (megasas_alloc_request_fusion(instance))
+ goto fail_exit;
+
+ if (instance->is_rdpq) {
+ if (megasas_alloc_rdpq_fusion(instance))
+ goto fail_exit;
+ } else
+ if (megasas_alloc_reply_fusion(instance))
+ goto fail_exit;
+
+
+ /* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
+ io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+ io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
/*
* Add all the commands to command pool (fusion->cmd_pool)
*/
/* SMID 0 is reserved. Set SMID/index from 1 */
- for (i = 0; i < max_cmd; i++) {
+ for (i = 0; i < instance->max_fw_cmds; i++) {
cmd = fusion->cmd_list[i];
offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
@@ -521,35 +657,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
cmd->io_request_phys_addr = io_req_base_phys + offset;
}
- /*
- * Create a frame pool and assign one frame to each cmd
- */
- if (megasas_create_frame_pool_fusion(instance)) {
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
- megasas_free_cmds_fusion(instance);
- goto fail_req_desc;
- }
+ if (megasas_create_sg_sense_fusion(instance))
+ goto fail_exit;
return 0;
-fail_cmd_list:
- pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
- fusion->io_request_frames_phys);
- pci_pool_destroy(fusion->io_request_frames_pool);
-fail_io_frames:
- dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
- fusion->reply_frames_desc,
- fusion->reply_frames_desc_phys);
- pci_pool_free(fusion->reply_frames_desc_pool,
- fusion->reply_frames_desc,
- fusion->reply_frames_desc_phys);
- pci_pool_destroy(fusion->reply_frames_desc_pool);
-
-fail_reply_desc:
- dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
- fusion->req_frames_desc,
- fusion->req_frames_desc_phys);
-fail_req_desc:
+fail_exit:
+ megasas_free_cmds_fusion(instance);
return -ENOMEM;
}
@@ -579,11 +693,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
msleep(20);
}
- if (frame_hdr->cmd_status == 0xff)
- return -ETIME;
-
- return (frame_hdr->cmd_status == MFI_STAT_OK) ?
- 0 : 1;
+ if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
+ return DCMD_TIMEOUT;
+ else if (frame_hdr->cmd_status == MFI_STAT_OK)
+ return DCMD_SUCCESS;
+ else
+ return DCMD_FAILED;
}
/**
@@ -596,15 +711,17 @@ int
megasas_ioc_init_fusion(struct megasas_instance *instance)
{
struct megasas_init_frame *init_frame;
- struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
+ struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
dma_addr_t ioc_init_handle;
struct megasas_cmd *cmd;
- u8 ret;
+ u8 ret, cur_rdpq_mode;
struct fusion_context *fusion;
union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
int i;
struct megasas_header *frame_hdr;
const char *sys_info;
+ MFI_CAPABILITIES *drv_ops;
+ u32 scratch_pad_2;
fusion = instance->ctrl_context;
@@ -616,6 +733,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_get_cmd;
}
+ scratch_pad_2 = readl
+ (&instance->reg_set->outbound_scratch_pad_2);
+
+ cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
+
+ if (instance->is_rdpq && !cur_rdpq_mode) {
+ dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
+ " from RDPQ mode to non RDPQ mode\n");
+ ret = 1;
+ goto fail_fw_init;
+ }
+
IOCInitMessage =
dma_alloc_coherent(&instance->pdev->dev,
sizeof(struct MPI2_IOC_INIT_REQUEST),
@@ -637,7 +766,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
- IOCInitMessage->ReplyDescriptorPostQueueAddress = cpu_to_le64(fusion->reply_frames_desc_phys);
+ IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
+ cpu_to_le64(fusion->rdpq_phys) :
+ cpu_to_le64(fusion->reply_frames_desc_phys[0]);
+ IOCInitMessage->MsgFlags = instance->is_rdpq ?
+ MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
init_frame = (struct megasas_init_frame *)cmd->frame;
@@ -652,20 +785,26 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
init_frame->cmd = MFI_CMD_INIT;
init_frame->cmd_status = 0xFF;
+ drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations);
+
/* driver support Extended MSIX */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- init_frame->driver_operations.
- mfi_capabilities.support_additional_msix = 1;
+ if (fusion->adapter_type == INVADER_SERIES)
+ drv_ops->mfi_capabilities.support_additional_msix = 1;
/* driver supports HA / Remote LUN over Fast Path interface */
- init_frame->driver_operations.mfi_capabilities.support_fp_remote_lun
- = 1;
- init_frame->driver_operations.mfi_capabilities.support_max_255lds
- = 1;
- init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb
- = 1;
- init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw
- = 1;
+ drv_ops->mfi_capabilities.support_fp_remote_lun = 1;
+
+ drv_ops->mfi_capabilities.support_max_255lds = 1;
+ drv_ops->mfi_capabilities.support_ndrive_r1_lb = 1;
+ drv_ops->mfi_capabilities.security_protocol_cmds_fw = 1;
+
+ if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN)
+ drv_ops->mfi_capabilities.support_ext_io_size = 1;
+
+ drv_ops->mfi_capabilities.support_fp_rlbypass = 1;
+ if (!dual_qdepth_disable)
+ drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
+
+ drv_ops->mfi_capabilities.support_qd_throttling = 1;
/* Convert capability to LE32 */
cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
@@ -726,6 +865,87 @@ fail_get_cmd:
return ret;
}
+/**
+ * megasas_sync_pd_seq_num - JBOD SEQ MAP
+ * @instance: Adapter soft state
+ * @pend: set to 1, if it is pended jbod map.
+ *
+ * Issue Jbod map to the firmware. If it is pended command,
+ * issue command and return. If it is first instance of jbod map
+ * issue and receive command.
+ */
+int
+megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
+ int ret = 0;
+ u32 pd_seq_map_sz;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct fusion_context *fusion = instance->ctrl_context;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+ dma_addr_t pd_seq_h;
+
+ pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)];
+ pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)];
+ pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+ (sizeof(struct MR_PD_CFG_SEQ) *
+ (MAX_PHYSICAL_DEVICES - 1));
+
+ cmd = megasas_get_cmd(instance);
+ if (!cmd) {
+ dev_err(&instance->pdev->dev,
+ "Could not get mfi cmd. Fail from %s %d\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ memset(pd_sync, 0, pd_seq_map_sz);
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = cpu_to_le32(pd_seq_map_sz);
+ dcmd->opcode = cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO);
+ dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(pd_seq_h);
+ dcmd->sgl.sge32[0].length = cpu_to_le32(pd_seq_map_sz);
+
+ if (pend) {
+ dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG;
+ dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_WRITE);
+ instance->jbod_seq_cmd = cmd;
+ instance->instancet->issue_dcmd(instance, cmd);
+ return 0;
+ }
+
+ dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+
+ /* Below code is only for non pended DCMD */
+ if (instance->ctrl_context && !instance->mask_interrupts)
+ ret = megasas_issue_blocked_cmd(instance, cmd,
+ MFI_IO_TIMEOUT_SECS);
+ else
+ ret = megasas_issue_polled(instance, cmd);
+
+ if (le32_to_cpu(pd_sync->count) > MAX_PHYSICAL_DEVICES) {
+ dev_warn(&instance->pdev->dev,
+ "driver supports max %d JBOD, but FW reports %d\n",
+ MAX_PHYSICAL_DEVICES, le32_to_cpu(pd_sync->count));
+ ret = -EINVAL;
+ }
+
+ if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+ megaraid_sas_kill_hba(instance);
+
+ if (ret == DCMD_SUCCESS)
+ instance->pd_seq_map_id++;
+
+ megasas_return_cmd(instance, cmd);
+ return ret;
+}
+
/*
* megasas_get_ld_map_info - Returns FW's ld_map structure
* @instance: Adapter soft state
@@ -799,10 +1019,13 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
if (instance->ctrl_context && !instance->mask_interrupts)
ret = megasas_issue_blocked_cmd(instance, cmd,
- MEGASAS_BLOCKED_CMD_TIMEOUT);
+ MFI_IO_TIMEOUT_SECS);
else
ret = megasas_issue_polled(instance, cmd);
+ if (ret == DCMD_TIMEOUT && instance->ctrl_context)
+ megaraid_sas_kill_hba(instance);
+
megasas_return_cmd(instance, cmd);
return ret;
@@ -961,6 +1184,18 @@ megasas_display_intel_branding(struct megasas_instance *instance)
break;
}
break;
+ case PCI_DEVICE_ID_LSI_CUTLASS_52:
+ case PCI_DEVICE_ID_LSI_CUTLASS_53:
+ switch (instance->pdev->subsystem_device) {
+ case MEGARAID_INTEL_RMS3BC160_SSDID:
+ dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
+ instance->host->host_no,
+ MEGARAID_INTEL_RMS3BC160_BRANDING);
+ break;
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -977,19 +1212,14 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
{
struct megasas_register_set __iomem *reg_set;
struct fusion_context *fusion;
- u32 max_cmd;
+ u32 max_cmd, scratch_pad_2;
int i = 0, count;
fusion = instance->ctrl_context;
reg_set = instance->reg_set;
- /*
- * Get various operational parameters from status register
- */
- instance->max_fw_cmds =
- instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
- instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
+ megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
/*
* Reduce the max supported cmds by 1. This is to ensure that the
@@ -1016,15 +1246,40 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
(max_cmd + 1)); /* Extra 1 for SMID 0 */
+ scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2);
+ /* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set,
+ * Firmware support extended IO chain frame which is 4 times more than
+ * legacy Firmware.
+ * Legacy Firmware - Frame size is (8 * 128) = 1K
+ * 1M IO Firmware - Frame size is (8 * 128 * 4) = 4K
+ */
+ if (scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK)
+ instance->max_chain_frame_sz =
+ ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >>
+ MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_1MB_IO;
+ else
+ instance->max_chain_frame_sz =
+ ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >>
+ MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_256K_IO;
+
+ if (instance->max_chain_frame_sz < MEGASAS_CHAIN_FRAME_SZ_MIN) {
+ dev_warn(&instance->pdev->dev, "frame size %d invalid, fall back to legacy max frame size %d\n",
+ instance->max_chain_frame_sz,
+ MEGASAS_CHAIN_FRAME_SZ_MIN);
+ instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN;
+ }
+
fusion->max_sge_in_main_msg =
- (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
- offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
+ - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
fusion->max_sge_in_chain =
- MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION);
+ instance->max_chain_frame_sz
+ / sizeof(union MPI2_SGE_IO_UNION);
- instance->max_num_sge = rounddown_pow_of_two(
- fusion->max_sge_in_main_msg + fusion->max_sge_in_chain - 2);
+ instance->max_num_sge =
+ rounddown_pow_of_two(fusion->max_sge_in_main_msg
+ + fusion->max_sge_in_chain - 2);
/* Used for pass thru MFI frame (DCMD) */
fusion->chain_offset_mfi_pthru =
@@ -1186,8 +1441,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
fusion = instance->ctrl_context;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr;
sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
sgl_ptr_end->Flags = 0;
@@ -1204,11 +1458,9 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl));
sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl));
sgl_ptr->Flags = 0;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES)
if (i == sge_count - 1)
sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST;
- }
sgl_ptr++;
sg_processed = i + 1;
@@ -1217,10 +1469,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
(sge_count > fusion->max_sge_in_main_msg)) {
struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
if ((le16_to_cpu(cmd->io_request->IoFlags) &
MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
@@ -1236,10 +1485,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
sg_chain = sgl_ptr;
/* Prepare chain element */
sg_chain->NextChainOffset = 0;
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT;
else
sg_chain->Flags =
@@ -1250,7 +1496,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
sgl_ptr =
(struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
- memset(sgl_ptr, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
+ memset(sgl_ptr, 0, instance->max_chain_frame_sz);
}
}
@@ -1554,10 +1800,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
local_map_ptr, start_lba_lo);
io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
cmd->request_desc->SCSIIO.RequestFlags =
- (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
+ (MPI2_REQ_DESCRIPT_FLAGS_FP_IO
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
if (io_request->RaidContext.regLockFlags ==
REGION_TYPE_UNUSED)
cmd->request_desc->SCSIIO.RequestFlags =
@@ -1582,7 +1827,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
if ((raidLUN[0] == 1) &&
- (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 2)) {
+ (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) {
instance->dev_handle = !(instance->dev_handle);
io_info.devHandle =
local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].devHandle[instance->dev_handle];
@@ -1598,10 +1843,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
cmd->request_desc->SCSIIO.RequestFlags =
(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
- if (io_request->RaidContext.regLockFlags ==
- REGION_TYPE_UNUSED)
+ if (fusion->adapter_type == INVADER_SERIES) {
+ if (io_info.do_fp_rlbypass ||
+ (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED))
cmd->request_desc->SCSIIO.RequestFlags =
(MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
@@ -1689,7 +1933,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
/* build request descriptor */
cmd->request_desc->SCSIIO.RequestFlags =
- (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ (MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
cmd->request_desc->SCSIIO.DevHandle = devHandle;
@@ -1722,7 +1966,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
u16 timeout_limit;
struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
struct RAID_CONTEXT *pRAID_Context;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
struct fusion_context *fusion = instance->ctrl_context;
+ pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id - 1) & 1];
device_id = MEGASAS_DEV_INDEX(scmd);
pd_index = MEGASAS_PD_INDEX(scmd);
@@ -1731,16 +1977,38 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
io_request = cmd->io_request;
/* get RAID_Context pointer */
pRAID_Context = &io_request->RaidContext;
+ pRAID_Context->regLockFlags = 0;
+ pRAID_Context->regLockRowLBA = 0;
+ pRAID_Context->regLockLength = 0;
io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
io_request->LUN[1] = scmd->device->lun;
pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
- pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
- pRAID_Context->configSeqNum = 0;
- local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
- io_request->DevHandle =
- local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ /* If FW supports PD sequence number */
+ if (instance->use_seqnum_jbod_fp &&
+ instance->pd_list[pd_index].driveType == TYPE_DISK) {
+ /* TgtId must be incremented by 255 as jbod seq number is index
+ * below raid map
+ */
+ pRAID_Context->VirtualDiskTgtId =
+ cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->configSeqNum = pd_sync->seq[pd_index].seqNum;
+ io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
+ pRAID_Context->regLockFlags |=
+ (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+ } else if (fusion->fast_path_io) {
+ pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+ pRAID_Context->configSeqNum = 0;
+ local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ } else {
+ /* Want to send all IO via FW path */
+ pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+ pRAID_Context->configSeqNum = 0;
+ io_request->DevHandle = cpu_to_le16(0xFFFF);
+ }
cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
cmd->request_desc->SCSIIO.MSIxIndex =
@@ -1755,29 +2023,23 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
(MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value);
+ pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
} else {
/* system pd Fast Path */
io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
- pRAID_Context->regLockFlags = 0;
- pRAID_Context->regLockRowLBA = 0;
- pRAID_Context->regLockLength = 0;
timeout_limit = (scmd->device->type == TYPE_DISK) ?
255 : 0xFFFF;
pRAID_Context->timeoutValue =
cpu_to_le16((os_timeout_value > timeout_limit) ?
timeout_limit : os_timeout_value);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
- cmd->request_desc->SCSIIO.RequestFlags |=
- (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
- MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ if (fusion->adapter_type == INVADER_SERIES) {
pRAID_Context->Type = MPI2_TYPE_CUDA;
pRAID_Context->nseg = 0x1;
io_request->IoFlags |=
cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
}
cmd->request_desc->SCSIIO.RequestFlags =
- (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ (MPI2_REQ_DESCRIPT_FLAGS_FP_IO <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
}
}
@@ -1796,7 +2058,7 @@ megasas_build_io_fusion(struct megasas_instance *instance,
struct scsi_cmnd *scp,
struct megasas_cmd_fusion *cmd)
{
- u32 sge_count;
+ u16 sge_count;
u8 cmd_type;
struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
@@ -1854,7 +2116,11 @@ megasas_build_io_fusion(struct megasas_instance *instance,
return 1;
}
+ /* numSGE store lower 8 bit of sge_count.
+ * numSGEExt store higher 8 bit of sge_count
+ */
io_request->RaidContext.numSGE = sge_count;
+ io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8);
io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
@@ -1911,13 +2177,21 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
fusion = instance->ctrl_context;
+ if ((megasas_cmd_type(scmd) == READ_WRITE_LDIO) &&
+ instance->ldio_threshold &&
+ (atomic_inc_return(&instance->ldio_outstanding) >
+ instance->ldio_threshold)) {
+ atomic_dec(&instance->ldio_outstanding);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+
cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
index = cmd->index;
req_desc = megasas_get_request_descriptor(instance, index-1);
if (!req_desc)
- return 1;
+ return SCSI_MLQUEUE_HOST_BUSY;
req_desc->Words = 0;
cmd->request_desc = req_desc;
@@ -1926,7 +2200,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
megasas_return_cmd_fusion(instance, cmd);
dev_err(&instance->pdev->dev, "Error building command\n");
cmd->request_desc = NULL;
- return 1;
+ return SCSI_MLQUEUE_HOST_BUSY;
}
req_desc = cmd->request_desc;
@@ -1968,16 +2242,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
struct LD_LOAD_BALANCE_INFO *lbinfo;
int threshold_reply_count = 0;
struct scsi_cmnd *scmd_local = NULL;
+ struct MR_TASK_MANAGE_REQUEST *mr_tm_req;
+ struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req;
fusion = instance->ctrl_context;
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
return IRQ_HANDLED;
- desc = fusion->reply_frames_desc;
- desc += ((MSIxIndex * fusion->reply_alloc_sz)/
- sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
- fusion->last_reply_idx[MSIxIndex];
+ desc = fusion->reply_frames_desc[MSIxIndex] +
+ fusion->last_reply_idx[MSIxIndex];
reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
@@ -2009,6 +2283,16 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
extStatus = scsi_io_req->RaidContext.exStatus;
switch (scsi_io_req->Function) {
+ case MPI2_FUNCTION_SCSI_TASK_MGMT:
+ mr_tm_req = (struct MR_TASK_MANAGE_REQUEST *)
+ cmd_fusion->io_request;
+ mpi_tm_req = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *)
+ &mr_tm_req->TmRequest;
+ dev_dbg(&instance->pdev->dev, "TM completion:"
+ "type: 0x%x TaskMID: 0x%x\n",
+ mpi_tm_req->TaskType, mpi_tm_req->TaskMID);
+ complete(&cmd_fusion->done);
+ break;
case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/
/* Update load balancing info */
device_id = MEGASAS_DEV_INDEX(scmd_local);
@@ -2031,6 +2315,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
map_cmd_status(cmd_fusion, status, extStatus);
scsi_io_req->RaidContext.status = 0;
scsi_io_req->RaidContext.exStatus = 0;
+ if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+ atomic_dec(&instance->ldio_outstanding);
megasas_return_cmd_fusion(instance, cmd_fusion);
scsi_dma_unmap(scmd_local);
scmd_local->scsi_done(scmd_local);
@@ -2062,9 +2348,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
/* Get the next reply descriptor */
if (!fusion->last_reply_idx[MSIxIndex])
- desc = fusion->reply_frames_desc +
- ((MSIxIndex * fusion->reply_alloc_sz)/
- sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
+ desc = fusion->reply_frames_desc[MSIxIndex];
else
desc++;
@@ -2084,10 +2368,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
* pending to be completed
*/
if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
writel(((MSIxIndex & 0x7) << 24) |
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[MSIxIndex/8]);
@@ -2103,8 +2384,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
return IRQ_NONE;
wmb();
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
writel(((MSIxIndex & 0x7) << 24) |
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[MSIxIndex/8]);
@@ -2134,7 +2414,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
/* If we have already declared adapter dead, donot complete cmds */
spin_lock_irqsave(&instance->hba_lock, flags);
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
spin_unlock_irqrestore(&instance->hba_lock, flags);
return;
}
@@ -2227,8 +2507,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
io_req = cmd->io_request;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end =
(struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL;
sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
@@ -2248,7 +2527,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
- mpi25_ieee_chain->Length = cpu_to_le32(MEGASAS_MAX_SZ_CHAIN_FRAME);
+ mpi25_ieee_chain->Length = cpu_to_le32(instance->max_chain_frame_sz);
return 0;
}
@@ -2292,7 +2571,7 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
* @cmd: mfi cmd pointer
*
*/
-void
+int
megasas_issue_dcmd_fusion(struct megasas_instance *instance,
struct megasas_cmd *cmd)
{
@@ -2300,10 +2579,13 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance,
req_desc = build_mpt_cmd(instance, cmd);
if (!req_desc) {
- dev_err(&instance->pdev->dev, "Couldn't issue MFI pass thru cmd\n");
- return;
+ dev_info(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return DCMD_NOT_FIRED;
}
+
megasas_fire_cmd_fusion(instance, req_desc);
+ return DCMD_SUCCESS;
}
/**
@@ -2384,6 +2666,70 @@ static int
megasas_adp_reset_fusion(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
+ u32 host_diag, abs_state, retry;
+
+ /* Now try to reset the chip */
+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_1ST_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_2ND_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_3RD_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_4TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_5TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+
+ /* Check that the diag write enable (DRWE) bit is on */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ retry = 0;
+ while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
+ msleep(100);
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 100) {
+ dev_warn(&instance->pdev->dev,
+ "Host diag unlock failed from %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+ if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
+ return -1;
+
+ /* Send chip reset command */
+ writel(host_diag | HOST_DIAG_RESET_ADAPTER,
+ &instance->reg_set->fusion_host_diag);
+ msleep(3000);
+
+ /* Make sure reset adapter bit is cleared */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ retry = 0;
+ while (host_diag & HOST_DIAG_RESET_ADAPTER) {
+ msleep(100);
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 1000) {
+ dev_warn(&instance->pdev->dev,
+ "Diag reset adapter never cleared %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+ if (host_diag & HOST_DIAG_RESET_ADAPTER)
+ return -1;
+
+ abs_state = instance->instancet->read_fw_status_reg(instance->reg_set)
+ & MFI_STATE_MASK;
+ retry = 0;
+
+ while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) {
+ msleep(100);
+ abs_state = instance->instancet->
+ read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+ }
+ if (abs_state <= MFI_STATE_FW_INIT) {
+ dev_warn(&instance->pdev->dev,
+ "fw state < MFI_STATE_FW_INIT, state = 0x%x %s %d\n",
+ abs_state, __func__, __LINE__);
+ return -1;
+ }
+
return 0;
}
@@ -2400,7 +2746,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
/* This function waits for outstanding commands on fusion to complete */
int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
- int iotimeout, int *convert)
+ int reason, int *convert)
{
int i, outstanding, retval = 0, hb_seconds_missed = 0;
u32 fw_state;
@@ -2416,14 +2762,22 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
retval = 1;
goto out;
}
+
+ if (reason == MFI_IO_TIMEOUT_OCR) {
+ dev_info(&instance->pdev->dev,
+ "MFI IO is timed out, initiating OCR\n");
+ retval = 1;
+ goto out;
+ }
+
/* If SR-IOV VF mode & heartbeat timeout, don't wait */
- if (instance->requestorId && !iotimeout) {
+ if (instance->requestorId && !reason) {
retval = 1;
goto out;
}
/* If SR-IOV VF mode & I/O timeout, check for HB timeout */
- if (instance->requestorId && iotimeout) {
+ if (instance->requestorId && reason) {
if (instance->hb_host_mem->HB.fwCounter !=
instance->hb_host_mem->HB.driverCounter) {
instance->hb_host_mem->HB.driverCounter =
@@ -2472,17 +2826,18 @@ out:
void megasas_reset_reply_desc(struct megasas_instance *instance)
{
- int i, count;
+ int i, j, count;
struct fusion_context *fusion;
union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
fusion = instance->ctrl_context;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
- for (i = 0 ; i < count ; i++)
+ for (i = 0 ; i < count ; i++) {
fusion->last_reply_idx[i] = 0;
- reply_desc = fusion->reply_frames_desc;
- for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
- reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+ reply_desc = fusion->reply_frames_desc[i];
+ for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
+ reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+ }
}
/*
@@ -2497,6 +2852,7 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
struct megasas_cmd *cmd_mfi;
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
u16 smid;
+ bool refire_cmd = 0;
fusion = instance->ctrl_context;
@@ -2512,55 +2868,516 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
continue;
req_desc = megasas_get_request_descriptor
(instance, smid - 1);
- if (req_desc && (cmd_mfi->frame->dcmd.opcode !=
- cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)))
+ refire_cmd = req_desc && ((cmd_mfi->frame->dcmd.opcode !=
+ cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) &&
+ (cmd_mfi->frame->dcmd.opcode !=
+ cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO)))
+ && !(cmd_mfi->flags & DRV_DCMD_SKIP_REFIRE);
+ if (refire_cmd)
megasas_fire_cmd_fusion(instance, req_desc);
else
megasas_return_cmd(instance, cmd_mfi);
}
}
+/*
+ * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
+ * @instance: per adapter struct
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ *
+ * Returns SUCCESS if no IOs pending to SCSI device, else return FAILED
+ */
+
+static int megasas_track_scsiio(struct megasas_instance *instance,
+ int id, int channel)
+{
+ int i, found = 0;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion;
+ fusion = instance->ctrl_context;
+
+ for (i = 0 ; i < instance->max_scsi_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ if (cmd_fusion->scmd &&
+ (cmd_fusion->scmd->device->id == id &&
+ cmd_fusion->scmd->device->channel == channel)) {
+ dev_info(&instance->pdev->dev,
+ "SCSI commands pending to target"
+ "channel %d id %d \tSMID: 0x%x\n",
+ channel, id, cmd_fusion->index);
+ scsi_print_command(cmd_fusion->scmd);
+ found = 1;
+ break;
+ }
+ }
+
+ return found ? FAILED : SUCCESS;
+}
+
+/**
+ * megasas_tm_response_code - translation of device response code
+ * @ioc: per adapter object
+ * @mpi_reply: MPI reply returned by firmware
+ *
+ * Return nothing.
+ */
+static void
+megasas_tm_response_code(struct megasas_instance *instance,
+ struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply)
+{
+ char *desc;
+
+ switch (mpi_reply->ResponseCode) {
+ case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
+ desc = "task management request completed";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
+ desc = "invalid frame";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+ desc = "task management request not supported";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
+ desc = "task management request failed";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+ desc = "task management request succeeded";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+ desc = "invalid lun";
+ break;
+ case 0xA:
+ desc = "overlapped tag attempted";
+ break;
+ case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+ desc = "task queued, however not sent to target";
+ break;
+ default:
+ desc = "unknown";
+ break;
+ }
+ dev_dbg(&instance->pdev->dev, "response_code(%01x): %s\n",
+ mpi_reply->ResponseCode, desc);
+ dev_dbg(&instance->pdev->dev,
+ "TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo"
+ " 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
+ mpi_reply->TerminationCount, mpi_reply->DevHandle,
+ mpi_reply->Function, mpi_reply->TaskType,
+ mpi_reply->IOCStatus, mpi_reply->IOCLogInfo);
+}
+
+/**
+ * megasas_issue_tm - main routine for sending tm requests
+ * @instance: per adapter struct
+ * @device_handle: device handle
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
+ * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in megaraid_sas_fusion.c)
+ * @smid_task: smid assigned to the task
+ * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
+ * Context: user
+ *
+ * MegaRaid use MPT interface for Task Magement request.
+ * A generic API for sending task management requests to firmware.
+ *
+ * Return SUCCESS or FAILED.
+ */
+static int
+megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
+ uint channel, uint id, u16 smid_task, u8 type)
+{
+ struct MR_TASK_MANAGE_REQUEST *mr_request;
+ struct MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_request;
+ unsigned long timeleft;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct megasas_cmd *cmd_mfi;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ struct fusion_context *fusion;
+ struct megasas_cmd_fusion *scsi_lookup;
+ int rc;
+ struct MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply;
+
+ fusion = instance->ctrl_context;
+
+ cmd_mfi = megasas_get_cmd(instance);
+
+ if (!cmd_mfi) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ cmd_fusion = megasas_get_cmd_fusion(instance,
+ instance->max_scsi_cmds + cmd_mfi->index);
+
+ /* Save the smid. To be used for returning the cmd */
+ cmd_mfi->context.smid = cmd_fusion->index;
+
+ req_desc = megasas_get_request_descriptor(instance,
+ (cmd_fusion->index - 1));
+ if (!req_desc) {
+ dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+ __func__, __LINE__);
+ megasas_return_cmd(instance, cmd_mfi);
+ return -ENOMEM;
+ }
+
+ cmd_fusion->request_desc = req_desc;
+ req_desc->Words = 0;
+
+ scsi_lookup = fusion->cmd_list[smid_task - 1];
+
+ mr_request = (struct MR_TASK_MANAGE_REQUEST *) cmd_fusion->io_request;
+ memset(mr_request, 0, sizeof(struct MR_TASK_MANAGE_REQUEST));
+ mpi_request = (struct MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest;
+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ mpi_request->DevHandle = cpu_to_le16(device_handle);
+ mpi_request->TaskType = type;
+ mpi_request->TaskMID = cpu_to_le16(smid_task);
+ mpi_request->LUN[1] = 0;
+
+
+ req_desc = cmd_fusion->request_desc;
+ req_desc->HighPriority.SMID = cpu_to_le16(cmd_fusion->index);
+ req_desc->HighPriority.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ req_desc->HighPriority.MSIxIndex = 0;
+ req_desc->HighPriority.LMID = 0;
+ req_desc->HighPriority.Reserved1 = 0;
+
+ if (channel < MEGASAS_MAX_PD_CHANNELS)
+ mr_request->tmReqFlags.isTMForPD = 1;
+ else
+ mr_request->tmReqFlags.isTMForLD = 1;
+
+ init_completion(&cmd_fusion->done);
+ megasas_fire_cmd_fusion(instance, req_desc);
+
+ timeleft = wait_for_completion_timeout(&cmd_fusion->done, 50 * HZ);
+
+ if (!timeleft) {
+ dev_err(&instance->pdev->dev,
+ "task mgmt type 0x%x timed out\n", type);
+ cmd_mfi->flags |= DRV_DCMD_SKIP_REFIRE;
+ mutex_unlock(&instance->reset_mutex);
+ rc = megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR);
+ mutex_lock(&instance->reset_mutex);
+ return rc;
+ }
+
+ mpi_reply = (struct MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->TMReply;
+ megasas_tm_response_code(instance, mpi_reply);
+
+ megasas_return_cmd(instance, cmd_mfi);
+ rc = SUCCESS;
+ switch (type) {
+ case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+ if (scsi_lookup->scmd == NULL)
+ break;
+ else {
+ instance->instancet->disable_intr(instance);
+ msleep(1000);
+ megasas_complete_cmd_dpc_fusion
+ ((unsigned long)instance);
+ instance->instancet->enable_intr(instance);
+ if (scsi_lookup->scmd == NULL)
+ break;
+ }
+ rc = FAILED;
+ break;
+
+ case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+ if ((channel == 0xFFFFFFFF) && (id == 0xFFFFFFFF))
+ break;
+ instance->instancet->disable_intr(instance);
+ msleep(1000);
+ megasas_complete_cmd_dpc_fusion
+ ((unsigned long)instance);
+ rc = megasas_track_scsiio(instance, id, channel);
+ instance->instancet->enable_intr(instance);
+
+ break;
+ case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
+ case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
+ break;
+ default:
+ rc = FAILED;
+ break;
+ }
+
+ return rc;
+
+}
+
+/*
+ * megasas_fusion_smid_lookup : Look for fusion command correpspodning to SCSI
+ * @instance: per adapter struct
+ *
+ * Return Non Zero index, if SMID found in outstanding commands
+ */
+static u16 megasas_fusion_smid_lookup(struct scsi_cmnd *scmd)
+{
+ int i, ret = 0;
+ struct megasas_instance *instance;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion;
+
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+ fusion = instance->ctrl_context;
+
+ for (i = 0; i < instance->max_scsi_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ if (cmd_fusion->scmd && (cmd_fusion->scmd == scmd)) {
+ scmd_printk(KERN_NOTICE, scmd, "Abort request is for"
+ " SMID: %d\n", cmd_fusion->index);
+ ret = cmd_fusion->index;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+* megasas_get_tm_devhandle - Get devhandle for TM request
+* @sdev- OS provided scsi device
+*
+* Returns- devhandle/targetID of SCSI device
+*/
+static u16 megasas_get_tm_devhandle(struct scsi_device *sdev)
+{
+ u16 pd_index = 0;
+ u32 device_id;
+ struct megasas_instance *instance;
+ struct fusion_context *fusion;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+ u16 devhandle = (u16)ULONG_MAX;
+
+ instance = (struct megasas_instance *)sdev->host->hostdata;
+ fusion = instance->ctrl_context;
+
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+ if (instance->use_seqnum_jbod_fp) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ pd_sync = (void *)fusion->pd_seq_sync
+ [(instance->pd_seq_map_id - 1) & 1];
+ devhandle = pd_sync->seq[pd_index].devHandle;
+ } else
+ sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable"
+ " without JBOD MAP support from %s %d\n", __func__, __LINE__);
+ } else {
+ device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+ + sdev->id;
+ devhandle = device_id;
+ }
+
+ return devhandle;
+}
+
+/*
+ * megasas_task_abort_fusion : SCSI task abort function for fusion adapters
+ * @scmd : pointer to scsi command object
+ *
+ * Return SUCCESS, if command aborted else FAILED
+ */
+
+int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
+{
+ struct megasas_instance *instance;
+ u16 smid, devhandle;
+ struct fusion_context *fusion;
+ int ret;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
+ mr_device_priv_data = scmd->device->hostdata;
+
+
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+ fusion = instance->ctrl_context;
+
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
+ dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+ "SCSI host:%d\n", instance->host->host_no);
+ ret = FAILED;
+ return ret;
+ }
+
+ if (!mr_device_priv_data) {
+ sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+ "scmd(%p)\n", scmd);
+ scmd->result = DID_NO_CONNECT << 16;
+ ret = SUCCESS;
+ goto out;
+ }
+
+
+ if (!mr_device_priv_data->is_tm_capable) {
+ ret = FAILED;
+ goto out;
+ }
+
+ mutex_lock(&instance->reset_mutex);
+
+ smid = megasas_fusion_smid_lookup(scmd);
+
+ if (!smid) {
+ ret = SUCCESS;
+ scmd_printk(KERN_NOTICE, scmd, "Command for which abort is"
+ " issued is not found in oustanding commands\n");
+ mutex_unlock(&instance->reset_mutex);
+ goto out;
+ }
+
+ devhandle = megasas_get_tm_devhandle(scmd->device);
+
+ if (devhandle == (u16)ULONG_MAX) {
+ ret = SUCCESS;
+ sdev_printk(KERN_INFO, scmd->device,
+ "task abort issued for invalid devhandle\n");
+ mutex_unlock(&instance->reset_mutex);
+ goto out;
+ }
+ sdev_printk(KERN_INFO, scmd->device,
+ "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
+ scmd, devhandle);
+
+ mr_device_priv_data->tm_busy = 1;
+ ret = megasas_issue_tm(instance, devhandle,
+ scmd->device->channel, scmd->device->id, smid,
+ MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+ mr_device_priv_data->tm_busy = 0;
+
+ mutex_unlock(&instance->reset_mutex);
+out:
+ sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
+ ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ return ret;
+}
+
+/*
+ * megasas_reset_target_fusion : target reset function for fusion adapters
+ * scmd: SCSI command pointer
+ *
+ * Returns SUCCESS if all commands associated with target aborted else FAILED
+ */
+
+int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
+{
+
+ struct megasas_instance *instance;
+ int ret = FAILED;
+ u16 devhandle;
+ struct fusion_context *fusion;
+ struct MR_PRIV_DEVICE *mr_device_priv_data;
+ mr_device_priv_data = scmd->device->hostdata;
+
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+ fusion = instance->ctrl_context;
+
+ if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
+ dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
+ "SCSI host:%d\n", instance->host->host_no);
+ ret = FAILED;
+ return ret;
+ }
+
+ if (!mr_device_priv_data) {
+ sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
+ "scmd(%p)\n", scmd);
+ scmd->result = DID_NO_CONNECT << 16;
+ ret = SUCCESS;
+ goto out;
+ }
+
+
+ if (!mr_device_priv_data->is_tm_capable) {
+ ret = FAILED;
+ goto out;
+ }
+
+ mutex_lock(&instance->reset_mutex);
+ devhandle = megasas_get_tm_devhandle(scmd->device);
+
+ if (devhandle == (u16)ULONG_MAX) {
+ ret = SUCCESS;
+ sdev_printk(KERN_INFO, scmd->device,
+ "target reset issued for invalid devhandle\n");
+ mutex_unlock(&instance->reset_mutex);
+ goto out;
+ }
+
+ sdev_printk(KERN_INFO, scmd->device,
+ "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
+ scmd, devhandle);
+ mr_device_priv_data->tm_busy = 1;
+ ret = megasas_issue_tm(instance, devhandle,
+ scmd->device->channel, scmd->device->id, 0,
+ MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
+ mr_device_priv_data->tm_busy = 0;
+ mutex_unlock(&instance->reset_mutex);
+out:
+ scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
+ (ret == SUCCESS) ? "SUCCESS" : "FAILED");
+
+ return ret;
+}
+
+/*SRIOV get other instance in cluster if any*/
+struct megasas_instance *megasas_get_peer_instance(struct megasas_instance *instance)
+{
+ int i;
+
+ for (i = 0; i < MAX_MGMT_ADAPTERS; i++) {
+ if (megasas_mgmt_info.instance[i] &&
+ (megasas_mgmt_info.instance[i] != instance) &&
+ megasas_mgmt_info.instance[i]->requestorId &&
+ megasas_mgmt_info.instance[i]->peerIsPresent &&
+ (memcmp((megasas_mgmt_info.instance[i]->clusterId),
+ instance->clusterId, MEGASAS_CLUSTER_ID_SIZE) == 0))
+ return megasas_mgmt_info.instance[i];
+ }
+ return NULL;
+}
+
/* Check for a second path that is currently UP */
int megasas_check_mpio_paths(struct megasas_instance *instance,
struct scsi_cmnd *scmd)
{
- int i, j, retval = (DID_RESET << 16);
-
- if (instance->mpio && instance->requestorId) {
- for (i = 0 ; i < MAX_MGMT_ADAPTERS ; i++)
- for (j = 0 ; j < MAX_LOGICAL_DRIVES; j++)
- if (megasas_mgmt_info.instance[i] &&
- (megasas_mgmt_info.instance[i] != instance) &&
- megasas_mgmt_info.instance[i]->mpio &&
- megasas_mgmt_info.instance[i]->requestorId
- &&
- (megasas_mgmt_info.instance[i]->ld_ids[j]
- == scmd->device->id)) {
- retval = (DID_NO_CONNECT << 16);
- goto out;
- }
+ struct megasas_instance *peer_instance = NULL;
+ int retval = (DID_RESET << 16);
+
+ if (instance->peerIsPresent) {
+ peer_instance = megasas_get_peer_instance(instance);
+ if ((peer_instance) &&
+ (atomic_read(&peer_instance->adprecovery) ==
+ MEGASAS_HBA_OPERATIONAL))
+ retval = (DID_NO_CONNECT << 16);
}
-out:
return retval;
}
/* Core fusion reset function */
-int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
+int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
{
- int retval = SUCCESS, i, retry = 0, convert = 0;
+ int retval = SUCCESS, i, convert = 0;
struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion;
struct fusion_context *fusion;
- u32 host_diag, abs_state, status_reg, reset_adapter;
+ u32 abs_state, status_reg, reset_adapter;
u32 io_timeout_in_crash_mode = 0;
struct scsi_cmnd *scmd_local = NULL;
+ struct scsi_device *sdev;
instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context;
mutex_lock(&instance->reset_mutex);
- if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
dev_warn(&instance->pdev->dev, "Hardware critical error, "
"returning FAILED for scsi%d.\n",
instance->host->host_no);
@@ -2572,10 +3389,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
/* IO timeout detected, forcibly put FW in FAULT state */
if (abs_state != MFI_STATE_FAULT && instance->crash_dump_buf &&
- instance->crash_dump_app_support && iotimeout) {
- dev_info(&instance->pdev->dev, "IO timeout is detected, "
+ instance->crash_dump_app_support && reason) {
+ dev_info(&instance->pdev->dev, "IO/DCMD timeout is detected, "
"forcibly FAULT Firmware\n");
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
status_reg = readl(&instance->reg_set->doorbell);
writel(status_reg | MFI_STATE_FORCE_OCR,
&instance->reg_set->doorbell);
@@ -2587,10 +3404,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
dev_dbg(&instance->pdev->dev, "waiting for [%d] "
"seconds for crash dump collection and OCR "
"to be done\n", (io_timeout_in_crash_mode * 3));
- } while ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
+ } while ((atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) &&
(io_timeout_in_crash_mode < 80));
- if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+ if (atomic_read(&instance->adprecovery) == MEGASAS_HBA_OPERATIONAL) {
dev_info(&instance->pdev->dev, "OCR done for IO "
"timeout case\n");
retval = SUCCESS;
@@ -2607,18 +3424,18 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
del_timer_sync(&instance->sriov_heartbeat_timer);
set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
- instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
instance->instancet->disable_intr(instance);
msleep(1000);
/* First try waiting for commands to complete */
- if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
+ if (megasas_wait_for_outstanding_fusion(instance, reason,
&convert)) {
- instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_INFAULT);
dev_warn(&instance->pdev->dev, "resetting fusion "
"adapter scsi%d.\n", instance->host->host_no);
if (convert)
- iotimeout = 0;
+ reason = 0;
/* Now return commands back to the OS */
for (i = 0 ; i < instance->max_scsi_cmds; i++) {
@@ -2628,6 +3445,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
scmd_local->result =
megasas_check_mpio_paths(instance,
scmd_local);
+ if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+ atomic_dec(&instance->ldio_outstanding);
megasas_return_cmd_fusion(instance, cmd_fusion);
scsi_dma_unmap(scmd_local);
scmd_local->scsi_done(scmd_local);
@@ -2652,151 +3471,39 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
}
/* Let SR-IOV VF & PF sync up if there was a HB failure */
- if (instance->requestorId && !iotimeout) {
+ if (instance->requestorId && !reason) {
msleep(MEGASAS_OCR_SETTLE_TIME_VF);
- /* Look for a late HB update after VF settle time */
- if (abs_state == MFI_STATE_OPERATIONAL &&
- (instance->hb_host_mem->HB.fwCounter !=
- instance->hb_host_mem->HB.driverCounter)) {
- instance->hb_host_mem->HB.driverCounter =
- instance->hb_host_mem->HB.fwCounter;
- dev_warn(&instance->pdev->dev, "SR-IOV:"
- "Late FW heartbeat update for "
- "scsi%d.\n",
- instance->host->host_no);
- } else {
- /* In VF mode, first poll for FW ready */
- for (i = 0;
- i < (MEGASAS_RESET_WAIT_TIME * 1000);
- i += 20) {
- status_reg =
- instance->instancet->
- read_fw_status_reg(
- instance->reg_set);
- abs_state = status_reg &
- MFI_STATE_MASK;
- if (abs_state == MFI_STATE_READY) {
- dev_warn(&instance->pdev->dev,
- "SR-IOV: FW was found"
- "to be in ready state "
- "for scsi%d.\n",
- instance->host->host_no);
- break;
- }
- msleep(20);
- }
- if (abs_state != MFI_STATE_READY) {
- dev_warn(&instance->pdev->dev, "SR-IOV: "
- "FW not in ready state after %d"
- " seconds for scsi%d, status_reg = "
- "0x%x.\n",
- MEGASAS_RESET_WAIT_TIME,
- instance->host->host_no,
- status_reg);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- instance->adprecovery =
- MEGASAS_HW_CRITICAL_ERROR;
- retval = FAILED;
- goto out;
- }
- }
+ goto transition_to_ready;
}
/* Now try to reset the chip */
for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
- writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_1ST_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_2ND_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_3RD_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_4TH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_5TH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_6TH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
-
- /* Check that the diag write enable (DRWE) bit is on */
- host_diag = readl(&instance->reg_set->fusion_host_diag);
- retry = 0;
- while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
- msleep(100);
- host_diag =
- readl(&instance->reg_set->fusion_host_diag);
- if (retry++ == 100) {
- dev_warn(&instance->pdev->dev,
- "Host diag unlock failed! "
- "for scsi%d\n",
- instance->host->host_no);
- break;
- }
- }
- if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
- continue;
- /* Send chip reset command */
- writel(host_diag | HOST_DIAG_RESET_ADAPTER,
- &instance->reg_set->fusion_host_diag);
- msleep(3000);
-
- /* Make sure reset adapter bit is cleared */
- host_diag = readl(&instance->reg_set->fusion_host_diag);
- retry = 0;
- while (host_diag & HOST_DIAG_RESET_ADAPTER) {
- msleep(100);
- host_diag =
- readl(&instance->reg_set->fusion_host_diag);
- if (retry++ == 1000) {
- dev_warn(&instance->pdev->dev,
- "Diag reset adapter never "
- "cleared for scsi%d!\n",
- instance->host->host_no);
- break;
- }
- }
- if (host_diag & HOST_DIAG_RESET_ADAPTER)
+ if (instance->instancet->adp_reset
+ (instance, instance->reg_set))
continue;
-
- abs_state =
- instance->instancet->read_fw_status_reg(
- instance->reg_set) & MFI_STATE_MASK;
- retry = 0;
-
- while ((abs_state <= MFI_STATE_FW_INIT) &&
- (retry++ < 1000)) {
- msleep(100);
- abs_state =
- instance->instancet->read_fw_status_reg(
- instance->reg_set) & MFI_STATE_MASK;
- }
- if (abs_state <= MFI_STATE_FW_INIT) {
- dev_warn(&instance->pdev->dev, "firmware "
- "state < MFI_STATE_FW_INIT, state = "
- "0x%x for scsi%d\n", abs_state,
- instance->host->host_no);
- continue;
- }
-
+transition_to_ready:
/* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) {
- dev_warn(&instance->pdev->dev, "Failed to "
- "transition controller to ready "
- "for scsi%d.\n",
- instance->host->host_no);
- continue;
+ dev_warn(&instance->pdev->dev,
+ "Failed to transition controller to ready for "
+ "scsi%d.\n", instance->host->host_no);
+ if (instance->requestorId && !reason)
+ goto fail_kill_adapter;
+ else
+ continue;
}
-
megasas_reset_reply_desc(instance);
+ megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
+
if (megasas_ioc_init_fusion(instance)) {
dev_warn(&instance->pdev->dev,
- "megasas_ioc_init_fusion() failed!"
- " for scsi%d\n",
- instance->host->host_no);
- continue;
+ "megasas_ioc_init_fusion() failed! for "
+ "scsi%d\n", instance->host->host_no);
+ if (instance->requestorId && !reason)
+ goto fail_kill_adapter;
+ else
+ continue;
}
megasas_refire_mgmt_cmd(instance);
@@ -2816,10 +3523,15 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
+ megasas_setup_jbod_map(instance);
+
+ shost_for_each_device(sdev, shost)
+ megasas_update_sdev_properties(sdev);
+
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
/* Restart SR-IOV heartbeat */
if (instance->requestorId) {
@@ -2848,6 +3560,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
retval = SUCCESS;
goto out;
}
+fail_kill_adapter:
/* Reset failed, kill the adapter */
dev_warn(&instance->pdev->dev, "Reset failed, killing "
"adapter scsi%d.\n", instance->host->host_no);
@@ -2864,7 +3577,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
}
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+ atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
}
out:
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index ced6dc0..80eaee2 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -35,8 +35,13 @@
#define _MEGARAID_SAS_FUSION_H_
/* Fusion defines */
-#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024
+#define MEGASAS_CHAIN_FRAME_SZ_MIN 1024
#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009)
+#define MEGASAS_MAX_CHAIN_SHIFT 5
+#define MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK 0x400000
+#define MEGASAS_MAX_CHAIN_SIZE_MASK 0x3E0
+#define MEGASAS_256K_IO 128
+#define MEGASAS_1MB_IO (MEGASAS_256K_IO * 4)
#define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256
#define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0
#define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1
@@ -89,6 +94,12 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
#define MEGASAS_FP_CMD_LEN 16
#define MEGASAS_FUSION_IN_RESET 0
#define THRESHOLD_REPLY_COUNT 50
+#define JBOD_MAPS_COUNT 2
+
+enum MR_FUSION_ADAPTER_TYPE {
+ THUNDERBOLT_SERIES = 0,
+ INVADER_SERIES = 1,
+};
/*
* Raid Context structure which describes MegaRAID specific IO Parameters
@@ -117,7 +128,9 @@ struct RAID_CONTEXT {
u8 numSGE;
__le16 configSeqNum;
u8 spanArm;
- u8 resvd2[3];
+ u8 priority;
+ u8 numSGEExt;
+ u8 resvd2;
};
#define RAID_CTX_SPANARM_ARM_SHIFT (0)
@@ -163,7 +176,9 @@ enum REGION_TYPE {
#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
-#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
+#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01)
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03)
+#define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06)
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
@@ -264,6 +279,100 @@ union MPI2_SCSI_IO_CDB_UNION {
struct MPI2_SGE_SIMPLE_UNION SGE;
};
+/****************************************************************************
+* SCSI Task Management messages
+****************************************************************************/
+
+/*SCSI Task Management Request Message */
+struct MPI2_SCSI_TASK_MANAGE_REQUEST {
+ u16 DevHandle; /*0x00 */
+ u8 ChainOffset; /*0x02 */
+ u8 Function; /*0x03 */
+ u8 Reserved1; /*0x04 */
+ u8 TaskType; /*0x05 */
+ u8 Reserved2; /*0x06 */
+ u8 MsgFlags; /*0x07 */
+ u8 VP_ID; /*0x08 */
+ u8 VF_ID; /*0x09 */
+ u16 Reserved3; /*0x0A */
+ u8 LUN[8]; /*0x0C */
+ u32 Reserved4[7]; /*0x14 */
+ u16 TaskMID; /*0x30 */
+ u16 Reserved5; /*0x32 */
+};
+
+
+/*SCSI Task Management Reply Message */
+struct MPI2_SCSI_TASK_MANAGE_REPLY {
+ u16 DevHandle; /*0x00 */
+ u8 MsgLength; /*0x02 */
+ u8 Function; /*0x03 */
+ u8 ResponseCode; /*0x04 */
+ u8 TaskType; /*0x05 */
+ u8 Reserved1; /*0x06 */
+ u8 MsgFlags; /*0x07 */
+ u8 VP_ID; /*0x08 */
+ u8 VF_ID; /*0x09 */
+ u16 Reserved2; /*0x0A */
+ u16 Reserved3; /*0x0C */
+ u16 IOCStatus; /*0x0E */
+ u32 IOCLogInfo; /*0x10 */
+ u32 TerminationCount; /*0x14 */
+ u32 ResponseInfo; /*0x18 */
+};
+
+struct MR_TM_REQUEST {
+ char request[128];
+};
+
+struct MR_TM_REPLY {
+ char reply[128];
+};
+
+/* SCSI Task Management Request Message */
+struct MR_TASK_MANAGE_REQUEST {
+ /*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */
+ struct MR_TM_REQUEST TmRequest;
+ union {
+ struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u32 reserved1:30;
+ u32 isTMForPD:1;
+ u32 isTMForLD:1;
+#else
+ u32 isTMForLD:1;
+ u32 isTMForPD:1;
+ u32 reserved1:30;
+#endif
+ u32 reserved2;
+ } tmReqFlags;
+ struct MR_TM_REPLY TMReply;
+ };
+};
+
+/* TaskType values */
+
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02)
+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
+#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_ASYNC_EVENT (0x0A)
+
+/* ResponseCode values */
+
+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00)
+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02)
+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04)
+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05)
+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08)
+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09)
+#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A)
+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
+
/*
* RAID SCSI IO Request Message
* Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST
@@ -486,6 +595,7 @@ struct MPI2_IOC_INIT_REQUEST {
#define MAX_PHYSICAL_DEVICES 256
#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
+#define MR_DCMD_SYSTEM_PD_MAP_GET_INFO 0x0200e102
#define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/
#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111 0x03200200
#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS 0x03150200
@@ -533,7 +643,9 @@ struct MR_SPAN_BLOCK_INFO {
struct MR_LD_RAID {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved4:7;
+ u32 reserved4:5;
+ u32 fpBypassRegionLock:1;
+ u32 tmCapable:1;
u32 fpNonRWCapable:1;
u32 fpReadAcrossStripe:1;
u32 fpWriteAcrossStripe:1;
@@ -555,7 +667,9 @@ struct MR_LD_RAID {
u32 fpWriteAcrossStripe:1;
u32 fpReadAcrossStripe:1;
u32 fpNonRWCapable:1;
- u32 reserved4:7;
+ u32 tmCapable:1;
+ u32 fpBypassRegionLock:1;
+ u32 reserved4:5;
#endif
} capability;
__le32 reserved6;
@@ -625,7 +739,7 @@ struct IO_REQUEST_INFO {
u8 fpOkForIo;
u8 IoforUnevenSpan;
u8 start_span;
- u8 reserved;
+ u8 do_fp_rlbypass;
u64 start_row;
u8 span_arm; /* span[7:5], arm[4:0] */
u8 pd_after_lb;
@@ -680,6 +794,7 @@ struct megasas_cmd_fusion {
u32 sync_cmd_idx;
u32 index;
u8 pd_r1_lb;
+ struct completion done;
};
struct LD_LOAD_BALANCE_INFO {
@@ -789,6 +904,36 @@ struct MR_FW_RAID_MAP_EXT {
struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_EXT];
};
+/*
+ * * define MR_PD_CFG_SEQ structure for system PDs
+ * */
+struct MR_PD_CFG_SEQ {
+ u16 seqNum;
+ u16 devHandle;
+ struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u8 reserved:7;
+ u8 tmCapable:1;
+#else
+ u8 tmCapable:1;
+ u8 reserved:7;
+#endif
+ } capability;
+ u8 reserved[3];
+} __packed;
+
+struct MR_PD_CFG_SEQ_NUM_SYNC {
+ __le32 size;
+ __le32 count;
+ struct MR_PD_CFG_SEQ seq[1];
+} __packed;
+
+struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
+ u64 RDPQBaseAddress;
+ u32 Reserved1;
+ u32 Reserved2;
+};
+
struct fusion_context {
struct megasas_cmd_fusion **cmd_list;
dma_addr_t req_frames_desc_phys;
@@ -801,8 +946,8 @@ struct fusion_context {
struct dma_pool *sg_dma_pool;
struct dma_pool *sense_dma_pool;
- dma_addr_t reply_frames_desc_phys;
- union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
+ dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
+ union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
struct dma_pool *reply_frames_desc_pool;
u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
@@ -812,6 +957,8 @@ struct fusion_context {
u32 reply_alloc_sz;
u32 io_frames_alloc_sz;
+ struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
+ dma_addr_t rdpq_phys;
u16 max_sge_in_main_msg;
u16 max_sge_in_chain;
@@ -828,9 +975,12 @@ struct fusion_context {
u32 current_map_sz;
u32 drv_map_sz;
u32 drv_map_pages;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_seq_sync[JBOD_MAPS_COUNT];
+ dma_addr_t pd_seq_phys[JBOD_MAPS_COUNT];
u8 fast_path_io;
struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT];
LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT];
+ u8 adapter_type;
};
union desc_value {
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 555367f..1753e42 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -29,6 +29,7 @@
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/spinlock.h>
+#include <linux/pci.h>
#include <asm/dbdma.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -38,7 +39,6 @@
#include <asm/processor.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
#include <asm/macio.h>
#include <scsi/scsi.h>
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig
deleted file mode 100644
index 657b45c..0000000
--- a/drivers/scsi/mpt2sas/Kconfig
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# Kernel configuration file for the MPT2SAS
-#
-# This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2014 LSI Corporation
-# (mailto:DL-MPTFusionLinux@lsi.com)
-
-# 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 the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-
-# 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.
-
-# NO WARRANTY
-# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
-# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
-# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
-# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
-# solely responsible for determining the appropriateness of using and
-# distributing the Program and assumes all risks associated with its
-# exercise of rights under this Agreement, including but not limited to
-# the risks and costs of program errors, damage to or loss of data,
-# programs or equipment, and unavailability or interruption of operations.
-
-# DISCLAIMER OF LIABILITY
-# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
-# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-config SCSI_MPT2SAS
- tristate "LSI MPT Fusion SAS 2.0 Device Driver"
- depends on PCI && SCSI
- select SCSI_SAS_ATTRS
- select RAID_ATTRS
- ---help---
- This driver supports PCI-Express SAS 6Gb/s Host Adapters.
-
-config SCSI_MPT2SAS_MAX_SGE
- int "LSI MPT Fusion Max number of SG Entries (16 - 128)"
- depends on PCI && SCSI && SCSI_MPT2SAS
- default "128"
- range 16 128
- ---help---
- This option allows you to specify the maximum number of scatter-
- gather entries per I/O. The driver default is 128, which matches
- SAFE_PHYS_SEGMENTS. However, it may decreased down to 16.
- Decreasing this parameter will reduce memory requirements
- on a per controller instance.
-
-config SCSI_MPT2SAS_LOGGING
- bool "LSI MPT Fusion logging facility"
- depends on PCI && SCSI && SCSI_MPT2SAS
- ---help---
- This turns on a logging facility.
diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile
deleted file mode 100644
index 728f047..0000000
--- a/drivers/scsi/mpt2sas/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# mpt2sas makefile
-obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o
-mpt2sas-y += mpt2sas_base.o \
- mpt2sas_config.o \
- mpt2sas_scsih.o \
- mpt2sas_transport.o \
- mpt2sas_ctl.o
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
deleted file mode 100644
index 7fc6f23..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ /dev/null
@@ -1,1170 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2.h
- * Title: MPI Message independent structures and definitions
- * including System Interface Register Set and
- * scatter/gather formats.
- * Creation Date: June 21, 2006
- *
- * mpi2.h Version: 02.00.35
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 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.
- * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
- * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MSI-x index mask and shift for Reply Post Host
- * Index register.
- * Added function code for Host Based Discovery Action.
- * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
- * Added defines for product-specific range of message
- * function codes, 0xF0 to 0xFF.
- * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added alternative defines for the SGE Direction bit.
- * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT.
- * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
- * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MPI2_FUNCTION_SEND_HOST_MESSAGE.
- * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT.
- * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT.
- * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT.
- * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT.
- * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT.
- * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added Hard Reset delay timings.
- * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT.
- * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT.
- * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT.
- * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET.
- * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT.
- * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT.
- * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT.
- * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
- * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT.
- * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_H
-#define MPI2_H
-
-
-/*****************************************************************************
-*
-* MPI Version Definitions
-*
-*****************************************************************************/
-
-#define MPI2_VERSION_MAJOR (0x02)
-#define MPI2_VERSION_MINOR (0x00)
-#define MPI2_VERSION_MAJOR_MASK (0xFF00)
-#define MPI2_VERSION_MAJOR_SHIFT (8)
-#define MPI2_VERSION_MINOR_MASK (0x00FF)
-#define MPI2_VERSION_MINOR_SHIFT (0)
-#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
- MPI2_VERSION_MINOR)
-
-#define MPI2_VERSION_02_00 (0x0200)
-
-/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x23)
-#define MPI2_HEADER_VERSION_DEV (0x00)
-#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
-#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
-#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF)
-#define MPI2_HEADER_VERSION_DEV_SHIFT (0)
-#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV)
-
-
-/*****************************************************************************
-*
-* IOC State Definitions
-*
-*****************************************************************************/
-
-#define MPI2_IOC_STATE_RESET (0x00000000)
-#define MPI2_IOC_STATE_READY (0x10000000)
-#define MPI2_IOC_STATE_OPERATIONAL (0x20000000)
-#define MPI2_IOC_STATE_FAULT (0x40000000)
-
-#define MPI2_IOC_STATE_MASK (0xF0000000)
-#define MPI2_IOC_STATE_SHIFT (28)
-
-/* Fault state range for prodcut specific codes */
-#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000)
-#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF)
-
-
-/*****************************************************************************
-*
-* System Interface Register Definitions
-*
-*****************************************************************************/
-
-typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
-{
- U32 Doorbell; /* 0x00 */
- U32 WriteSequence; /* 0x04 */
- U32 HostDiagnostic; /* 0x08 */
- U32 Reserved1; /* 0x0C */
- U32 DiagRWData; /* 0x10 */
- U32 DiagRWAddressLow; /* 0x14 */
- U32 DiagRWAddressHigh; /* 0x18 */
- U32 Reserved2[5]; /* 0x1C */
- U32 HostInterruptStatus; /* 0x30 */
- U32 HostInterruptMask; /* 0x34 */
- U32 DCRData; /* 0x38 */
- U32 DCRAddress; /* 0x3C */
- U32 Reserved3[2]; /* 0x40 */
- U32 ReplyFreeHostIndex; /* 0x48 */
- U32 Reserved4[8]; /* 0x4C */
- U32 ReplyPostHostIndex; /* 0x6C */
- U32 Reserved5; /* 0x70 */
- U32 HCBSize; /* 0x74 */
- U32 HCBAddressLow; /* 0x78 */
- U32 HCBAddressHigh; /* 0x7C */
- U32 Reserved6[16]; /* 0x80 */
- U32 RequestDescriptorPostLow; /* 0xC0 */
- U32 RequestDescriptorPostHigh; /* 0xC4 */
- U32 Reserved7[14]; /* 0xC8 */
-} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
- Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t;
-
-/*
- * Defines for working with the Doorbell register.
- */
-#define MPI2_DOORBELL_OFFSET (0x00000000)
-
-/* IOC --> System values */
-#define MPI2_DOORBELL_USED (0x08000000)
-#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000)
-#define MPI2_DOORBELL_WHO_INIT_SHIFT (24)
-#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF)
-#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF)
-
-/* System --> IOC values */
-#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000)
-#define MPI2_DOORBELL_FUNCTION_SHIFT (24)
-#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000)
-#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16)
-
-
-/*
- * Defines for the WriteSequence register
- */
-#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004)
-#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F)
-#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0)
-#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF)
-#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4)
-#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB)
-#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2)
-#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7)
-#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD)
-
-/*
- * Defines for the HostDiagnostic register
- */
-#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008)
-
-#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800)
-#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000)
-#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800)
-
-#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400)
-#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200)
-#define MPI2_DIAG_HCB_MODE (0x00000100)
-#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080)
-#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040)
-#define MPI2_DIAG_RESET_HISTORY (0x00000020)
-#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010)
-#define MPI2_DIAG_RESET_ADAPTER (0x00000004)
-#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002)
-
-/*
- * Offsets for DiagRWData and address
- */
-#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010)
-#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014)
-#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018)
-
-/*
- * Defines for the HostInterruptStatus register
- */
-#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030)
-#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000)
-#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS
-#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000)
-#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008)
-#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001)
-#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS
-
-/*
- * Defines for the HostInterruptMask register
- */
-#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034)
-#define MPI2_HIM_RESET_IRQ_MASK (0x40000000)
-#define MPI2_HIM_REPLY_INT_MASK (0x00000008)
-#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK
-#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001)
-#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK
-
-/*
- * Offsets for DCRData and address
- */
-#define MPI2_DCR_DATA_OFFSET (0x00000038)
-#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C)
-
-/*
- * Offset for the Reply Free Queue
- */
-#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048)
-
-/*
- * Defines for the Reply Descriptor Post Queue
- */
-#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C)
-#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF)
-#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000)
-#define MPI2_RPHI_MSIX_INDEX_SHIFT (24)
-#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /* MPI v2.5 only */
-
-/*
- * Defines for the HCBSize and address
- */
-#define MPI2_HCB_SIZE_OFFSET (0x00000074)
-#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000)
-#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001)
-
-#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078)
-#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C)
-
-/*
- * Offsets for the Request Queue
- */
-#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0)
-#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4)
-
-
-/* Hard Reset delay timings */
-#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000)
-#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000)
-#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000)
-
-/*****************************************************************************
-*
-* Message Descriptors
-*
-*****************************************************************************/
-
-/* Request Descriptors */
-
-/* Default Request Descriptor */
-typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 DescriptorTypeDependent; /* 0x06 */
-} MPI2_DEFAULT_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR,
- Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t;
-
-/* defines for the RequestFlags field */
-#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
-#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
-#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)
-
-
-/* High Priority Request Descriptor */
-typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 Reserved1; /* 0x06 */
-} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
- Mpi2HighPriorityRequestDescriptor_t,
- MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t;
-
-
-/* SCSI IO Request Descriptor */
-typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 DevHandle; /* 0x06 */
-} MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
- Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t;
-
-
-/* SCSI Target Request Descriptor */
-typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 IoIndex; /* 0x06 */
-} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_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;
- 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;
-
-
-/* Reply Descriptors */
-
-/* Default Reply Descriptor */
-typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- 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_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)
-#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF)
-
-/* Address Reply Descriptor */
-typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U32 ReplyFrameAddress; /* 0x04 */
-} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR,
- Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t;
-
-#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00)
-
-
-/* SCSI IO Success Reply Descriptor */
-typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 TaskTag; /* 0x04 */
- U16 Reserved1; /* 0x06 */
-} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
- Mpi2SCSIIOSuccessReplyDescriptor_t,
- MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t;
-
-
-/* TargetAssist Success Reply Descriptor */
-typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U8 SequenceNumber; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 IoIndex; /* 0x06 */
-} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
- Mpi2TargetAssistSuccessReplyDescriptor_t,
- MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t;
-
-
-/* Target Command Buffer Reply Descriptor */
-typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U8 VP_ID; /* 0x02 */
- U8 Flags; /* 0x03 */
- U16 InitiatorDevHandle; /* 0x04 */
- U16 IoIndex; /* 0x06 */
-} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
- Mpi2TargetCommandBufferReplyDescriptor_t,
- MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t;
-
-/* defines for Flags field */
-#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;
- 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;
-
-
-
-/*****************************************************************************
-*
-* Message Functions
-*
-*****************************************************************************/
-
-#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
-#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */
-#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */
-#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */
-#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */
-#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */
-#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */
-#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */
-#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */
-#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */
-#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */
-#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */
-#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */
-#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */
-#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */
-#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */
-#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */
-#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */
-#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */
-#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */
-#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */
-#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */
-#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*/
-/* Host Based Discovery Action */
-#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F)
-/* Power Management Control */
-#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30)
-/* Send Host Message */
-#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31)
-/* beginning of product-specific range */
-#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0)
-/* end of product-specific range */
-#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF)
-
-
-
-
-/* Doorbell functions */
-#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
-#define MPI2_FUNCTION_HANDSHAKE (0x42)
-
-
-/*****************************************************************************
-*
-* IOC Status Values
-*
-*****************************************************************************/
-
-/* mask for IOCStatus status value */
-#define MPI2_IOCSTATUS_MASK (0x7FFF)
-
-/****************************************************************************
-* Common IOCStatus values for all replies
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_SUCCESS (0x0000)
-#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001)
-#define MPI2_IOCSTATUS_BUSY (0x0002)
-#define MPI2_IOCSTATUS_INVALID_SGL (0x0003)
-#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004)
-#define MPI2_IOCSTATUS_INVALID_VPID (0x0005)
-#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006)
-#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007)
-#define MPI2_IOCSTATUS_INVALID_STATE (0x0008)
-#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009)
-
-/****************************************************************************
-* Config IOCStatus values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020)
-#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021)
-#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022)
-#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023)
-#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024)
-#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025)
-
-/****************************************************************************
-* SCSI IO Reply
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040)
-#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042)
-#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043)
-#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044)
-#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045)
-#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046)
-#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047)
-#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048)
-#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049)
-#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A)
-#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B)
-#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C)
-
-/****************************************************************************
-* For use by SCSI Initiator and SCSI Target end-to-end data protection
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D)
-#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E)
-#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F)
-
-/****************************************************************************
-* SCSI Target values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062)
-#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063)
-#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064)
-#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065)
-#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
-#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D)
-#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E)
-#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F)
-#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070)
-#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071)
-
-/****************************************************************************
-* Serial Attached SCSI values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090)
-#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091)
-
-/****************************************************************************
-* Diagnostic Buffer Post / Diagnostic Release values
-****************************************************************************/
-
-#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)
-
-/****************************************************************************
-* IOCLogInfo Types
-****************************************************************************/
-
-#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000)
-#define MPI2_IOCLOGINFO_TYPE_SHIFT (28)
-#define MPI2_IOCLOGINFO_TYPE_NONE (0x0)
-#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1)
-#define MPI2_IOCLOGINFO_TYPE_FC (0x2)
-#define MPI2_IOCLOGINFO_TYPE_SAS (0x3)
-#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4)
-#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF)
-
-
-/*****************************************************************************
-*
-* Standard Message Structures
-*
-*****************************************************************************/
-
-/****************************************************************************
-* Request Message Header for all request messages
-****************************************************************************/
-
-typedef struct _MPI2_REQUEST_HEADER
-{
- U16 FunctionDependent1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 FunctionDependent2; /* 0x04 */
- U8 FunctionDependent3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
-} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER,
- MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t;
-
-
-/****************************************************************************
-* Default Reply
-****************************************************************************/
-
-typedef struct _MPI2_DEFAULT_REPLY
-{
- U16 FunctionDependent1; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 FunctionDependent2; /* 0x04 */
- U8 FunctionDependent3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U16 FunctionDependent5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY,
- MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t;
-
-
-/* common version structure/union used in messages and configuration pages */
-
-typedef struct _MPI2_VERSION_STRUCT
-{
- U8 Dev; /* 0x00 */
- U8 Unit; /* 0x01 */
- U8 Minor; /* 0x02 */
- U8 Major; /* 0x03 */
-} MPI2_VERSION_STRUCT;
-
-typedef union _MPI2_VERSION_UNION
-{
- MPI2_VERSION_STRUCT Struct;
- U32 Word;
-} MPI2_VERSION_UNION;
-
-
-/* LUN field defines, common to many structures */
-#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF)
-#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000)
-#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF)
-#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000)
-#define MPI2_LUN_LEVEL_1_WORD (0xFF00)
-#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00)
-
-
-/*****************************************************************************
-*
-* Fusion-MPT MPI Scatter Gather Elements
-*
-*****************************************************************************/
-
-/****************************************************************************
-* MPI Simple Element structures
-****************************************************************************/
-
-typedef struct _MPI2_SGE_SIMPLE32
-{
- U32 FlagsLength;
- U32 Address;
-} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32,
- Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t;
-
-typedef struct _MPI2_SGE_SIMPLE64
-{
- U32 FlagsLength;
- U64 Address;
-} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64,
- Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t;
-
-typedef struct _MPI2_SGE_SIMPLE_UNION
-{
- U32 FlagsLength;
- union
- {
- U32 Address32;
- U64 Address64;
- } u;
-} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION,
- Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t;
-
-
-/****************************************************************************
-* MPI Chain Element structures
-****************************************************************************/
-
-typedef struct _MPI2_SGE_CHAIN32
-{
- U16 Length;
- U8 NextChainOffset;
- U8 Flags;
- U32 Address;
-} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32,
- Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t;
-
-typedef struct _MPI2_SGE_CHAIN64
-{
- U16 Length;
- U8 NextChainOffset;
- U8 Flags;
- U64 Address;
-} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64,
- Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t;
-
-typedef struct _MPI2_SGE_CHAIN_UNION
-{
- U16 Length;
- U8 NextChainOffset;
- U8 Flags;
- union
- {
- U32 Address32;
- U64 Address64;
- } u;
-} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION,
- Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t;
-
-
-/****************************************************************************
-* MPI Transaction Context Element structures
-****************************************************************************/
-
-typedef struct _MPI2_SGE_TRANSACTION32
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[1];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32,
- Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t;
-
-typedef struct _MPI2_SGE_TRANSACTION64
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[2];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64,
- Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t;
-
-typedef struct _MPI2_SGE_TRANSACTION96
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[3];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96,
- Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t;
-
-typedef struct _MPI2_SGE_TRANSACTION128
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[4];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128,
- Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128;
-
-typedef struct _MPI2_SGE_TRANSACTION_UNION
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- union
- {
- U32 TransactionContext32[1];
- U32 TransactionContext64[2];
- U32 TransactionContext96[3];
- U32 TransactionContext128[4];
- } u;
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION,
- Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t;
-
-
-/****************************************************************************
-* MPI SGE union for IO SGL's
-****************************************************************************/
-
-typedef struct _MPI2_MPI_SGE_IO_UNION
-{
- union
- {
- MPI2_SGE_SIMPLE_UNION Simple;
- MPI2_SGE_CHAIN_UNION Chain;
- } u;
-} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION,
- Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t;
-
-
-/****************************************************************************
-* MPI SGE union for SGL's with Simple and Transaction elements
-****************************************************************************/
-
-typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION
-{
- union
- {
- MPI2_SGE_SIMPLE_UNION Simple;
- MPI2_SGE_TRANSACTION_UNION Transaction;
- } u;
-} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION,
- Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t;
-
-
-/****************************************************************************
-* All MPI SGE types union
-****************************************************************************/
-
-typedef struct _MPI2_MPI_SGE_UNION
-{
- union
- {
- MPI2_SGE_SIMPLE_UNION Simple;
- MPI2_SGE_CHAIN_UNION Chain;
- MPI2_SGE_TRANSACTION_UNION Transaction;
- } u;
-} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION,
- Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t;
-
-
-/****************************************************************************
-* MPI SGE field definition and masks
-****************************************************************************/
-
-/* Flags field bit definitions */
-
-#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80)
-#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40)
-#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30)
-#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08)
-#define MPI2_SGE_FLAGS_DIRECTION (0x04)
-#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02)
-#define MPI2_SGE_FLAGS_END_OF_LIST (0x01)
-
-#define MPI2_SGE_FLAGS_SHIFT (24)
-
-#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF)
-#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF)
-
-/* Element Type */
-
-#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00)
-#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10)
-#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30)
-#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30)
-
-/* Address location */
-
-#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00)
-
-/* Direction */
-
-#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00)
-#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04)
-
-#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST)
-#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC)
-
-/* Address Size */
-
-#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
-#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
-
-/* Context Size */
-
-#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00)
-#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02)
-#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04)
-#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06)
-
-#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000)
-#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16)
-
-/****************************************************************************
-* MPI SGE operation Macros
-****************************************************************************/
-
-/* SIMPLE FlagsLength manipulations... */
-#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT)
-#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT)
-#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK)
-#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK)
-
-#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l))
-
-#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength)
-#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength)
-#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l)
-
-/* CAUTION - The following are READ-MODIFY-WRITE! */
-#define MPI2_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f)
-#define MPI2_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_SGE_LENGTH(l)
-
-#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT)
-
-
-/*****************************************************************************
-*
-* Fusion-MPT IEEE Scatter Gather Elements
-*
-*****************************************************************************/
-
-/****************************************************************************
-* IEEE Simple Element structures
-****************************************************************************/
-
-typedef struct _MPI2_IEEE_SGE_SIMPLE32
-{
- U32 Address;
- U32 FlagsLength;
-} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32,
- Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t;
-
-typedef struct _MPI2_IEEE_SGE_SIMPLE64
-{
- U64 Address;
- U32 Length;
- U16 Reserved1;
- U8 Reserved2;
- U8 Flags;
-} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64,
- Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t;
-
-typedef union _MPI2_IEEE_SGE_SIMPLE_UNION
-{
- MPI2_IEEE_SGE_SIMPLE32 Simple32;
- MPI2_IEEE_SGE_SIMPLE64 Simple64;
-} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION,
- Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t;
-
-
-/****************************************************************************
-* IEEE Chain Element structures
-****************************************************************************/
-
-typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32;
-
-typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64;
-
-typedef union _MPI2_IEEE_SGE_CHAIN_UNION
-{
- MPI2_IEEE_SGE_CHAIN32 Chain32;
- MPI2_IEEE_SGE_CHAIN64 Chain64;
-} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION,
- Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t;
-
-
-/****************************************************************************
-* All IEEE SGE types union
-****************************************************************************/
-
-typedef struct _MPI2_IEEE_SGE_UNION
-{
- union
- {
- MPI2_IEEE_SGE_SIMPLE_UNION Simple;
- MPI2_IEEE_SGE_CHAIN_UNION Chain;
- } u;
-} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION,
- Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t;
-
-
-/****************************************************************************
-* IEEE SGE field definitions and masks
-****************************************************************************/
-
-/* Flags field bit definitions */
-
-#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80)
-
-#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24)
-
-#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF)
-
-/* Element Type */
-
-#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00)
-#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
-
-/* Data Location Address Space */
-
-#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03)
-#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00)
- /* IEEE Simple Element only */
-#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01)
- /* IEEE Simple Element only */
-#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02)
-#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
- /* IEEE Simple Element only */
-#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03)
- /* IEEE Chain Element only */
-#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \
- (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */
-
-/****************************************************************************
-* IEEE SGE operation Macros
-****************************************************************************/
-
-/* SIMPLE FlagsLength manipulations... */
-#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT)
-#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT)
-#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK)
-
-#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l))
-
-#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength)
-#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength)
-#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l)
-
-/* CAUTION - The following are READ-MODIFY-WRITE! */
-#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f)
-#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l)
-
-
-
-
-/*****************************************************************************
-*
-* Fusion-MPT MPI/IEEE Scatter Gather Unions
-*
-*****************************************************************************/
-
-typedef union _MPI2_SIMPLE_SGE_UNION
-{
- MPI2_SGE_SIMPLE_UNION MpiSimple;
- MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
-} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION,
- Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t;
-
-
-typedef union _MPI2_SGE_IO_UNION
-{
- MPI2_SGE_SIMPLE_UNION MpiSimple;
- MPI2_SGE_CHAIN_UNION MpiChain;
- MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
- MPI2_IEEE_SGE_CHAIN_UNION IeeeChain;
-} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION,
- Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t;
-
-
-/****************************************************************************
-*
-* Values for SGLFlags field, used in many request messages with an SGL
-*
-****************************************************************************/
-
-/* values for MPI SGL Data Location Address Space subfield */
-#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C)
-#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00)
-#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04)
-#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08)
-#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C)
-/* values for SGL Type subfield */
-#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03)
-#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00)
-#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01)
-#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02)
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
deleted file mode 100644
index ee8d2d6..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ /dev/null
@@ -1,3068 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_cnfg.h
- * Title: MPI Configuration messages and pages
- * Creation Date: November 10, 2006
- *
- * mpi2_cnfg.h Version: 02.00.29
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 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 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 SupportedPhysDisks field to RAID Volume Page 1 and
- * added related defines.
- * 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.
- * 07-30-09 02.00.12 Added IO Unit Page 7.
- * Added new device ids.
- * Added SAS IO Unit Page 5.
- * Added partial and slumber power management capable flags
- * to SAS Device Page 0 Flags field.
- * Added PhyInfo defines for power condition.
- * Added Ethernet configuration pages.
- * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
- * Added SAS PHY Page 4 structure and defines.
- * 02-10-10 02.00.14 Modified the comments for the configuration page
- * structures that contain an array of data. The host
- * should use the "count" field in the page data (e.g. the
- * NumPhys field) to determine the number of valid elements
- * in the array.
- * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
- * Added PowerManagementCapabilities to IO Unit Page 7.
- * Added PortWidthModGroup field to
- * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
- * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
- * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
- * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
- * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
- * define.
- * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
- * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
- * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing)
- * defines.
- * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to
- * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
- * the Pinout field.
- * Added BoardTemperature and BoardTemperatureUnits fields
- * to MPI2_CONFIG_PAGE_IO_UNIT_7.
- * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
- * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
- * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST.
- * Added IO Unit Page 8, IO Unit Page 9,
- * and IO Unit Page 10.
- * Added SASNotifyPrimitiveMasks field to
- * MPI2_CONFIG_PAGE_IOC_7.
- * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec).
- * 05-25-11 02.00.20 Cleaned up a few comments.
- * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities
- * for PCIe link as obsolete.
- * Added SpinupFlags field containing a Disable Spin-up
- * bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of
- * SAS IO Unit Page 4.
- * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
- * Added UEFIVersion field to BIOS Page 1 and defined new
- * BiosOptions bits.
- * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
- * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
- * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as
- * obsolete for MPI v2.5 and later.
- * Added some defines for 12G SAS speeds.
- * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK.
- * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to
- * match the specification.
- * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for
- * MPI2_CONFIG_PAGE_MAN_7.
- * Added EnclosureLevel and ConnectorName fields to
- * MPI2_CONFIG_PAGE_SAS_DEV_0.
- * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for
- * MPI2_CONFIG_PAGE_SAS_DEV_0.
- * Added EnclosureLevel field to
- * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
- * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for
- * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
- * 01-08-14 02.00.28 Added more defines for the BiosOptions field of
- * MPI2_CONFIG_PAGE_BIOS_1.
- * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and
- * more defines for the BiosOptions field.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_CNFG_H
-#define MPI2_CNFG_H
-
-/*****************************************************************************
-* Configuration Page Header and defines
-*****************************************************************************/
-
-/* Config Page Header */
-typedef struct _MPI2_CONFIG_PAGE_HEADER
-{
- U8 PageVersion; /* 0x00 */
- U8 PageLength; /* 0x01 */
- U8 PageNumber; /* 0x02 */
- U8 PageType; /* 0x03 */
-} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER,
- Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t;
-
-typedef union _MPI2_CONFIG_PAGE_HEADER_UNION
-{
- MPI2_CONFIG_PAGE_HEADER Struct;
- U8 Bytes[4];
- U16 Word16[2];
- U32 Word32;
-} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION,
- Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion;
-
-/* Extended Config Page Header */
-typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER
-{
- U8 PageVersion; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 PageNumber; /* 0x02 */
- U8 PageType; /* 0x03 */
- U16 ExtPageLength; /* 0x04 */
- U8 ExtPageType; /* 0x06 */
- U8 Reserved2; /* 0x07 */
-} MPI2_CONFIG_EXTENDED_PAGE_HEADER,
- MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER,
- Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t;
-
-typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
-{
- MPI2_CONFIG_PAGE_HEADER Struct;
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext;
- U8 Bytes[8];
- U16 Word16[4];
- U32 Word32[2];
-} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION,
- Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion;
-
-
-/* PageType field values */
-#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00)
-#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10)
-#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20)
-#define MPI2_CONFIG_PAGEATTR_MASK (0xF0)
-
-#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00)
-#define MPI2_CONFIG_PAGETYPE_IOC (0x01)
-#define MPI2_CONFIG_PAGETYPE_BIOS (0x02)
-#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08)
-#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09)
-#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A)
-#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F)
-#define MPI2_CONFIG_PAGETYPE_MASK (0x0F)
-
-#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF)
-
-
-/* ExtPageType field values */
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13)
-#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14)
-#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15)
-#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16)
-#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18)
-#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
-#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A)
-
-
-/*****************************************************************************
-* PageAddress defines
-*****************************************************************************/
-
-/* RAID Volume PageAddress format */
-#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
-#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000)
-
-#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF)
-
-
-/* RAID Physical Disk PageAddress format */
-#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000)
-#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000)
-#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000)
-
-#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF)
-#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF)
-
-
-/* SAS Expander PageAddress format */
-#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000)
-#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000)
-#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000)
-
-#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF)
-#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000)
-#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16)
-
-
-/* SAS Device PageAddress format */
-#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
-#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000)
-
-#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF)
-
-
-/* SAS PHY PageAddress format */
-#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000)
-#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000)
-
-#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF)
-#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF)
-
-
-/* SAS Port PageAddress format */
-#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000)
-#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000)
-
-#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF)
-
-
-/* SAS Enclosure PageAddress format */
-#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
-#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000)
-
-#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF)
-
-
-/* RAID Configuration PageAddress format */
-#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000)
-#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000)
-#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000)
-
-#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF)
-
-
-/* Driver Persistent Mapping PageAddress format */
-#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000)
-
-#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000)
-#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16)
-#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF)
-
-
-/* Ethernet PageAddress format */
-#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000)
-
-#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
-
-
-
-/****************************************************************************
-* Configuration messages
-****************************************************************************/
-
-/* Configuration Request Message */
-typedef struct _MPI2_CONFIG_REQUEST
-{
- U8 Action; /* 0x00 */
- U8 SGLFlags; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 ExtPageLength; /* 0x04 */
- U8 ExtPageType; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U8 Reserved2; /* 0x0C */
- U8 ProxyVF_ID; /* 0x0D */
- U16 Reserved4; /* 0x0E */
- U32 Reserved3; /* 0x10 */
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */
- U32 PageAddress; /* 0x18 */
- MPI2_SGE_IO_UNION PageBufferSGE; /* 0x1C */
-} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST,
- Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t;
-
-/* values for the Action field */
-#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00)
-#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01)
-#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02)
-#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03)
-#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04)
-#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05)
-#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06)
-#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* Config Reply Message */
-typedef struct _MPI2_CONFIG_REPLY
-{
- U8 Action; /* 0x00 */
- U8 SGLFlags; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 ExtPageLength; /* 0x04 */
- U8 ExtPageType; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U16 Reserved2; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */
-} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY,
- Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t;
-
-
-
-/*****************************************************************************
-*
-* C o n f i g u r a t i o n P a g e s
-*
-*****************************************************************************/
-
-/****************************************************************************
-* Manufacturing Config pages
-****************************************************************************/
-
-#define MPI2_MFGPAGE_VENDORID_LSI (0x1000)
-
-/* SAS */
-#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070)
-#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072)
-#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074)
-#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076)
-#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077)
-#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064)
-#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065)
-
-#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E)
-
-#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
-#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
-#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
-#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083)
-#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084)
-#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085)
-#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086)
-#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087)
-#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
-
-
-
-
-/* Manufacturing Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 ChipName[16]; /* 0x04 */
- U8 ChipRevision[8]; /* 0x14 */
- U8 BoardName[16]; /* 0x1C */
- U8 BoardAssembly[16]; /* 0x2C */
- U8 BoardTracerNumber[16]; /* 0x3C */
-} MPI2_CONFIG_PAGE_MAN_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0,
- Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t;
-
-#define MPI2_MANUFACTURING0_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 VPD[256]; /* 0x04 */
-} MPI2_CONFIG_PAGE_MAN_1,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1,
- Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t;
-
-#define MPI2_MANUFACTURING1_PAGEVERSION (0x00)
-
-
-typedef struct _MPI2_CHIP_REVISION_ID
-{
- U16 DeviceID; /* 0x00 */
- U8 PCIRevisionID; /* 0x02 */
- U8 Reserved; /* 0x03 */
-} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID,
- Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t;
-
-
-/* Manufacturing Page 2 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
- */
-#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS
-#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_2
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */
- U32 HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */
-} MPI2_CONFIG_PAGE_MAN_2,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2,
- Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t;
-
-#define MPI2_MANUFACTURING2_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 3 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
- */
-#ifndef MPI2_MAN_PAGE_3_INFO_WORDS
-#define MPI2_MAN_PAGE_3_INFO_WORDS (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_3
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */
- U32 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */
-} MPI2_CONFIG_PAGE_MAN_3,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3,
- Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t;
-
-#define MPI2_MANUFACTURING3_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 4 */
-
-typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS
-{
- U8 PowerSaveFlags; /* 0x00 */
- U8 InternalOperationsSleepTime; /* 0x01 */
- U8 InternalOperationsRunTime; /* 0x02 */
- U8 HostIdleTime; /* 0x03 */
-} MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
- MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
- Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t;
-
-/* defines for the PowerSaveFlags field */
-#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03)
-#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00)
-#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01)
-#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02)
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_4
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Flags; /* 0x08 */
- U8 InquirySize; /* 0x0C */
- U8 Reserved2; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- U8 InquiryData[56]; /* 0x10 */
- U32 RAID0VolumeSettings; /* 0x48 */
- U32 RAID1EVolumeSettings; /* 0x4C */
- U32 RAID1VolumeSettings; /* 0x50 */
- U32 RAID10VolumeSettings; /* 0x54 */
- U32 Reserved4; /* 0x58 */
- U32 Reserved5; /* 0x5C */
- MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /* 0x60 */
- U8 MaxOCEDisks; /* 0x64 */
- U8 ResyncRate; /* 0x65 */
- U16 DataScrubDuration; /* 0x66 */
- U8 MaxHotSpares; /* 0x68 */
- U8 MaxPhysDisksPerVol; /* 0x69 */
- U8 MaxPhysDisks; /* 0x6A */
- U8 MaxVolumes; /* 0x6B */
-} MPI2_CONFIG_PAGE_MAN_4,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4,
- Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t;
-
-#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A)
-
-/* Manufacturing Page 4 Flags field */
-#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000)
-#define MPI2_MANPAGE4_METADATA_512MB (0x00000000)
-
-#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000)
-#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000)
-#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000)
-
-#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00)
-#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000)
-#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400)
-#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800)
-#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00)
-
-#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300)
-#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000)
-#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100)
-#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200)
-
-#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080)
-#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040)
-#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020)
-#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010)
-#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008)
-#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004)
-#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002)
-#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001)
-
-
-/* Manufacturing Page 5 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
-#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_MANUFACTURING5_ENTRY
-{
- U64 WWID; /* 0x00 */
- U64 DeviceName; /* 0x08 */
-} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY,
- Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t;
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_5
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhys; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
- MPI2_MANUFACTURING5_ENTRY Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */
-} MPI2_CONFIG_PAGE_MAN_5,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5,
- Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t;
-
-#define MPI2_MANUFACTURING5_PAGEVERSION (0x03)
-
-
-/* Manufacturing Page 6 */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_6
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 ProductSpecificInfo;/* 0x04 */
-} MPI2_CONFIG_PAGE_MAN_6,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6,
- Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t;
-
-#define MPI2_MANUFACTURING6_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 7 */
-
-typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
-{
- U32 Pinout; /* 0x00 */
- U8 Connector[16]; /* 0x04 */
- U8 Location; /* 0x14 */
- U8 ReceptacleID; /* 0x15 */
- U16 Slot; /* 0x16 */
- U32 Reserved2; /* 0x18 */
-} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,
- Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t;
-
-/* defines for the Pinout field */
-#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00)
-#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8)
-
-#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF)
-#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00)
-#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01)
-#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02)
-#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04)
-#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05)
-#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06)
-#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08)
-#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09)
-#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A)
-#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B)
-#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C)
-#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D)
-
-/* defines for the Location field */
-#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01)
-#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02)
-#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04)
-#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08)
-#define MPI2_MANPAGE7_LOCATION_AUTO (0x10)
-#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20)
-#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
-#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_7
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U32 Flags; /* 0x0C */
- U8 EnclosureName[16]; /* 0x10 */
- U8 NumPhys; /* 0x20 */
- U8 Reserved3; /* 0x21 */
- U16 Reserved4; /* 0x22 */
- MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */
-} MPI2_CONFIG_PAGE_MAN_7,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,
- Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t;
-
-#define MPI2_MANUFACTURING7_PAGEVERSION (0x01)
-
-/* defines for the Flags field */
-#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008)
-#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
-#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
-
-
-/*
- * Generic structure to use for product-specific manufacturing pages
- * (currently Manufacturing Page 8 through Manufacturing Page 31).
- */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_PS
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 ProductSpecificInfo;/* 0x04 */
-} MPI2_CONFIG_PAGE_MAN_PS,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS,
- Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t;
-
-#define MPI2_MANUFACTURING8_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING9_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING10_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING11_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING12_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING13_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING14_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING15_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING16_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING17_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING18_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING19_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING20_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING21_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING22_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING23_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING24_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING25_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING26_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING27_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING28_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING29_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING30_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING31_PAGEVERSION (0x00)
-
-
-/****************************************************************************
-* IO Unit Config Pages
-****************************************************************************/
-
-/* IO Unit Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U64 UniqueValue; /* 0x04 */
- MPI2_VERSION_UNION NvdataVersionDefault; /* 0x08 */
- MPI2_VERSION_UNION NvdataVersionPersistent; /* 0x0A */
-} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0,
- Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t;
-
-#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02)
-
-
-/* IO Unit Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Flags; /* 0x04 */
-} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1,
- Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t;
-
-#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04)
-
-/* IO Unit Page 1 Flags defines */
-#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000)
-#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800)
-#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600)
-#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9)
-#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000)
-#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200)
-#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400)
-#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100)
-#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040)
-#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020)
-#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004)
-
-
-/* IO Unit Page 3 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for GPIOCount at runtime.
- */
-#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
-#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 GPIOCount; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U16 GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */
-} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3,
- Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t;
-
-#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01)
-
-/* defines for IO Unit Page 3 GPIOVal field */
-#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC)
-#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2)
-#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000)
-#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 the value returned for 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 (0xFFFF0000)
-#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)
-
-
-/* IO Unit Page 7 */
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 Reserved1; /* 0x04 */
- U8 PCIeWidth; /* 0x06 */
- U8 PCIeSpeed; /* 0x07 */
- U32 ProcessorState; /* 0x08 */
- U32 PowerManagementCapabilities; /* 0x0C */
- U16 IOCTemperature; /* 0x10 */
- U8 IOCTemperatureUnits; /* 0x12 */
- U8 IOCSpeed; /* 0x13 */
- U16 BoardTemperature; /* 0x14 */
- U8 BoardTemperatureUnits; /* 0x16 */
- U8 Reserved3; /* 0x17 */
- U32 Reserved4; /* 0x18 */
- U32 Reserved5; /* 0x1C */
- U32 Reserved6; /* 0x20 */
- U32 Reserved7; /* 0x24 */
-} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
- Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
-
-#define MPI2_IOUNITPAGE7_PAGEVERSION (0x04)
-
-/* defines for IO Unit Page 7 PCIeWidth field */
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02)
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04)
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08)
-
-/* defines for IO Unit Page 7 PCIeSpeed field */
-#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00)
-#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01)
-#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02)
-
-/* defines for IO Unit Page 7 ProcessorState field */
-#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F)
-#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0)
-
-#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00)
-#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01)
-#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02)
-
-/* defines for IO Unit Page 7 PowerManagementCapabilities field */
-#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400)
-#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200)
-#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100)
-#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */
-#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */
-
-/* defines for IO Unit Page 7 IOCTemperatureUnits field */
-#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
-#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
-#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02)
-
-/* defines for IO Unit Page 7 IOCSpeed field */
-#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01)
-#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02)
-#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04)
-#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08)
-
-/* defines for IO Unit Page 7 BoardTemperatureUnits field */
-#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00)
-#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01)
-#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02)
-
-/* IO Unit Page 8 */
-
-#define MPI2_IOUNIT8_NUM_THRESHOLDS (4)
-
-typedef struct _MPI2_IOUNIT8_SENSOR {
- U16 Flags; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U16
- Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */
- U32 Reserved2; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U32 Reserved4; /* 0x14 */
-} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR,
-Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t;
-
-/* defines for IO Unit Page 8 Sensor Flags field */
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008)
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004)
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002)
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumSensors at runtime.
- */
-#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES
-#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U8 NumSensors; /* 0x0C */
- U8 PollingInterval; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_IOUNIT8_SENSOR
- Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */
-} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8,
-Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t;
-
-#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00)
-
-
-/* IO Unit Page 9 */
-
-typedef struct _MPI2_IOUNIT9_SENSOR {
- U16 CurrentTemperature; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U8 Flags; /* 0x04 */
- U8 Reserved2; /* 0x05 */
- U16 Reserved3; /* 0x06 */
- U32 Reserved4; /* 0x08 */
- U32 Reserved5; /* 0x0C */
-} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR,
-Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t;
-
-/* defines for IO Unit Page 9 Sensor Flags field */
-#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumSensors at runtime.
- */
-#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES
-#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U8 NumSensors; /* 0x0C */
- U8 Reserved4; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_IOUNIT9_SENSOR
- Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */
-} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9,
-Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t;
-
-#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00)
-
-
-/* IO Unit Page 10 */
-
-typedef struct _MPI2_IOUNIT10_FUNCTION {
- U8 CreditPercent; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
-} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION,
-Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t;
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumFunctions at runtime.
- */
-#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES
-#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumFunctions; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
- MPI2_IOUNIT10_FUNCTION
- Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/* 0x10 */
-} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10,
-Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t;
-
-#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01)
-
-
-
-/****************************************************************************
-* IOC Config Pages
-****************************************************************************/
-
-/* IOC Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U16 VendorID; /* 0x0C */
- U16 DeviceID; /* 0x0E */
- U8 RevisionID; /* 0x10 */
- U8 Reserved3; /* 0x11 */
- U16 Reserved4; /* 0x12 */
- U32 ClassCode; /* 0x14 */
- U16 SubsystemVendorID; /* 0x18 */
- U16 SubsystemID; /* 0x1A */
-} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0,
- Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t;
-
-#define MPI2_IOCPAGE0_PAGEVERSION (0x02)
-
-
-/* IOC Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Flags; /* 0x04 */
- U32 CoalescingTimeout; /* 0x08 */
- U8 CoalescingDepth; /* 0x0C */
- U8 PCISlotNum; /* 0x0D */
- U8 PCIBusNum; /* 0x0E */
- U8 PCIDomainSegment; /* 0x0F */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
-} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1,
- Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t;
-
-#define MPI2_IOCPAGE1_PAGEVERSION (0x05)
-
-/* defines for IOC Page 1 Flags field */
-#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001)
-
-#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF)
-#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF)
-#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF)
-
-/* IOC Page 6 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_6
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 CapabilitiesFlags; /* 0x04 */
- U8 MaxDrivesRAID0; /* 0x08 */
- U8 MaxDrivesRAID1; /* 0x09 */
- U8 MaxDrivesRAID1E; /* 0x0A */
- U8 MaxDrivesRAID10; /* 0x0B */
- U8 MinDrivesRAID0; /* 0x0C */
- U8 MinDrivesRAID1; /* 0x0D */
- U8 MinDrivesRAID1E; /* 0x0E */
- U8 MinDrivesRAID10; /* 0x0F */
- U32 Reserved1; /* 0x10 */
- U8 MaxGlobalHotSpares; /* 0x14 */
- U8 MaxPhysDisks; /* 0x15 */
- U8 MaxVolumes; /* 0x16 */
- U8 MaxConfigs; /* 0x17 */
- U8 MaxOCEDisks; /* 0x18 */
- U8 Reserved2; /* 0x19 */
- U16 Reserved3; /* 0x1A */
- U32 SupportedStripeSizeMapRAID0; /* 0x1C */
- U32 SupportedStripeSizeMapRAID1E; /* 0x20 */
- U32 SupportedStripeSizeMapRAID10; /* 0x24 */
- U32 Reserved4; /* 0x28 */
- U32 Reserved5; /* 0x2C */
- U16 DefaultMetadataSize; /* 0x30 */
- U16 Reserved6; /* 0x32 */
- U16 MaxBadBlockTableEntries; /* 0x34 */
- U16 Reserved7; /* 0x36 */
- U32 IRNvsramVersion; /* 0x38 */
-} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6,
- Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t;
-
-#define MPI2_IOCPAGE6_PAGEVERSION (0x05)
-
-/* defines for IOC Page 6 CapabilitiesFlags */
-#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002)
-#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001)
-
-
-/* IOC Page 7 */
-
-#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4)
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_7
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */
- U16 SASBroadcastPrimitiveMasks; /* 0x18 */
- U16 SASNotifyPrimitiveMasks; /* 0x1A */
- U32 Reserved3; /* 0x1C */
-} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7,
- Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t;
-
-#define MPI2_IOCPAGE7_PAGEVERSION (0x02)
-
-
-/* IOC Page 8 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_8
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumDevsPerEnclosure; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U16 MaxPersistentEntries; /* 0x08 */
- U16 MaxNumPhysicalMappedIDs; /* 0x0A */
- U16 Flags; /* 0x0C */
- U16 Reserved3; /* 0x0E */
- U16 IRVolumeMappingFlags; /* 0x10 */
- U16 Reserved4; /* 0x12 */
- U32 Reserved5; /* 0x14 */
-} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8,
- Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t;
-
-#define MPI2_IOCPAGE8_PAGEVERSION (0x00)
-
-/* defines for IOC Page 8 Flags field */
-#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020)
-#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010)
-
-#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E)
-#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000)
-#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002)
-
-#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001)
-#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000)
-
-/* defines for IOC Page 8 IRVolumeMappingFlags */
-#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003)
-#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000)
-#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001)
-
-
-/****************************************************************************
-* BIOS Config Pages
-****************************************************************************/
-
-/* BIOS Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 BiosOptions; /* 0x04 */
- U32 IOCSettings; /* 0x08 */
- U8 SSUTimeout; /* 0x0C */
- U8 Reserved1; /* 0x0D */
- U16 Reserved2; /* 0x0E */
- U32 DeviceSettings; /* 0x10 */
- U16 NumberOfDevices; /* 0x14 */
- U16 UEFIVersion; /* 0x16 */
- U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */
- U16 IOTimeoutSequential; /* 0x1A */
- U16 IOTimeoutOther; /* 0x1C */
- U16 IOTimeoutBlockDevicesRM; /* 0x1E */
-} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,
- Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t;
-
-#define MPI2_BIOSPAGE1_PAGEVERSION (0x07)
-
-/* values for BIOS Page 1 BiosOptions field */
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000)
-
-#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400)
-
-#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300)
-#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000)
-#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100)
-#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200)
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300)
-
-#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0)
-#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000)
-
-#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006)
-#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000)
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002)
-#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004)
-
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001)
-
-/* values for BIOS Page 1 IOCSettings field */
-#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000)
-#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000)
-#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000)
-
-#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0)
-#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000)
-#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040)
-#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080)
-
-#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030)
-#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000)
-#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010)
-#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020)
-#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030)
-
-#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008)
-
-/* values for BIOS Page 1 DeviceSettings field */
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001)
-
-/* defines for BIOS Page 1 UEFIVersion field */
-#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00)
-#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8)
-#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF)
-#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0)
-
-
-
-/* BIOS Page 2 */
-
-typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER
-{
- U32 Reserved1; /* 0x00 */
- U32 Reserved2; /* 0x04 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
- U32 Reserved5; /* 0x10 */
- U32 Reserved6; /* 0x14 */
-} MPI2_BOOT_DEVICE_ADAPTER_ORDER,
- MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER,
- Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t;
-
-typedef struct _MPI2_BOOT_DEVICE_SAS_WWID
-{
- U64 SASAddress; /* 0x00 */
- U8 LUN[8]; /* 0x08 */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
-} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID,
- Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t;
-
-typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT
-{
- U64 EnclosureLogicalID; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- U16 SlotNumber; /* 0x10 */
- U16 Reserved3; /* 0x12 */
- U32 Reserved4; /* 0x14 */
-} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
- MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
- Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t;
-
-typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME
-{
- U64 DeviceName; /* 0x00 */
- U8 LUN[8]; /* 0x08 */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
-} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME,
- Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t;
-
-typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE
-{
- MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder;
- MPI2_BOOT_DEVICE_SAS_WWID SasWwid;
- MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot;
- MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName;
-} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE,
- Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t;
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_2
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U32 Reserved3; /* 0x0C */
- U32 Reserved4; /* 0x10 */
- U32 Reserved5; /* 0x14 */
- U32 Reserved6; /* 0x18 */
- U8 ReqBootDeviceForm; /* 0x1C */
- U8 Reserved7; /* 0x1D */
- U16 Reserved8; /* 0x1E */
- MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /* 0x20 */
- U8 ReqAltBootDeviceForm; /* 0x38 */
- U8 Reserved9; /* 0x39 */
- U16 Reserved10; /* 0x3A */
- MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /* 0x3C */
- U8 CurrentBootDeviceForm; /* 0x58 */
- U8 Reserved11; /* 0x59 */
- U16 Reserved12; /* 0x5A */
- MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /* 0x58 */
-} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2,
- Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t;
-
-#define MPI2_BIOSPAGE2_PAGEVERSION (0x04)
-
-/* values for BIOS Page 2 BootDeviceForm fields */
-#define MPI2_BIOSPAGE2_FORM_MASK (0x0F)
-#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00)
-#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05)
-#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06)
-#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07)
-
-
-/* BIOS Page 3 */
-
-typedef struct _MPI2_ADAPTER_INFO
-{
- U8 PciBusNumber; /* 0x00 */
- U8 PciDeviceAndFunctionNumber; /* 0x01 */
- U16 AdapterFlags; /* 0x02 */
-} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO,
- Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t;
-
-#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001)
-#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002)
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_3
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 GlobalFlags; /* 0x04 */
- U32 BiosVersion; /* 0x08 */
- MPI2_ADAPTER_INFO AdapterOrder[4]; /* 0x0C */
- U32 Reserved1; /* 0x1C */
-} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3,
- Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t;
-
-#define MPI2_BIOSPAGE3_PAGEVERSION (0x00)
-
-/* values for BIOS Page 3 GlobalFlags */
-#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002)
-#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004)
-#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010)
-
-#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0)
-#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000)
-#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020)
-#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040)
-
-
-/* BIOS Page 4 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
-#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_BIOS4_ENTRY
-{
- U64 ReassignmentWWID; /* 0x00 */
- U64 ReassignmentDeviceName; /* 0x08 */
-} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY,
- Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t;
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_4
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhys; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- MPI2_BIOS4_ENTRY Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /* 0x08 */
-} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4,
- Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t;
-
-#define MPI2_BIOSPAGE4_PAGEVERSION (0x01)
-
-
-/****************************************************************************
-* RAID Volume Config Pages
-****************************************************************************/
-
-/* RAID Volume Page 0 */
-
-typedef struct _MPI2_RAIDVOL0_PHYS_DISK
-{
- U8 RAIDSetNum; /* 0x00 */
- U8 PhysDiskMap; /* 0x01 */
- U8 PhysDiskNum; /* 0x02 */
- U8 Reserved; /* 0x03 */
-} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK,
- Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t;
-
-/* defines for the PhysDiskMap field */
-#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01)
-#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02)
-
-typedef struct _MPI2_RAIDVOL0_SETTINGS
-{
- U16 Settings; /* 0x00 */
- U8 HotSparePool; /* 0x01 */
- U8 Reserved; /* 0x02 */
-} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS,
- Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t;
-
-/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */
-#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01)
-#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02)
-#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04)
-#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08)
-#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10)
-#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20)
-#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40)
-#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80)
-
-/* RAID Volume Page 0 VolumeSettings defines */
-#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008)
-#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004)
-
-#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003)
-#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000)
-#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001)
-#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhysDisks at runtime.
- */
-#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
-#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 DevHandle; /* 0x04 */
- U8 VolumeState; /* 0x06 */
- U8 VolumeType; /* 0x07 */
- U32 VolumeStatusFlags; /* 0x08 */
- MPI2_RAIDVOL0_SETTINGS VolumeSettings; /* 0x0C */
- U64 MaxLBA; /* 0x10 */
- U32 StripeSize; /* 0x18 */
- U16 BlockSize; /* 0x1C */
- U16 Reserved1; /* 0x1E */
- U8 SupportedPhysDisks; /* 0x20 */
- U8 ResyncRate; /* 0x21 */
- U16 DataScrubDuration; /* 0x22 */
- U8 NumPhysDisks; /* 0x24 */
- U8 Reserved2; /* 0x25 */
- U8 Reserved3; /* 0x26 */
- U8 InactiveStatus; /* 0x27 */
- MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */
-} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0,
- Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t;
-
-#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A)
-
-/* values for RAID VolumeState */
-#define MPI2_RAID_VOL_STATE_MISSING (0x00)
-#define MPI2_RAID_VOL_STATE_FAILED (0x01)
-#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02)
-#define MPI2_RAID_VOL_STATE_ONLINE (0x03)
-#define MPI2_RAID_VOL_STATE_DEGRADED (0x04)
-#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05)
-
-/* values for RAID VolumeType */
-#define MPI2_RAID_VOL_TYPE_RAID0 (0x00)
-#define MPI2_RAID_VOL_TYPE_RAID1E (0x01)
-#define MPI2_RAID_VOL_TYPE_RAID1 (0x02)
-#define MPI2_RAID_VOL_TYPE_RAID10 (0x05)
-#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF)
-
-/* values for RAID Volume Page 0 VolumeStatusFlags field */
-#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080)
-#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020)
-#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008)
-#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004)
-#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002)
-#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001)
-
-/* values for RAID Volume Page 0 SupportedPhysDisks field */
-#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08)
-#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04)
-#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02)
-#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01)
-
-/* values for RAID Volume Page 0 InactiveStatus field */
-#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00)
-#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01)
-#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02)
-#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03)
-#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04)
-#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05)
-#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06)
-
-
-/* RAID Volume Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 DevHandle; /* 0x04 */
- U16 Reserved0; /* 0x06 */
- U8 GUID[24]; /* 0x08 */
- U8 Name[16]; /* 0x20 */
- U64 WWID; /* 0x30 */
- U32 Reserved1; /* 0x38 */
- U32 Reserved2; /* 0x3C */
-} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1,
- Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t;
-
-#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03)
-
-
-/****************************************************************************
-* RAID Physical Disk Config Pages
-****************************************************************************/
-
-/* RAID Physical Disk Page 0 */
-
-typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS
-{
- U16 Reserved1; /* 0x00 */
- U8 HotSparePool; /* 0x02 */
- U8 Reserved2; /* 0x03 */
-} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS,
- Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t;
-
-/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */
-
-typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA
-{
- U8 VendorID[8]; /* 0x00 */
- U8 ProductID[16]; /* 0x08 */
- U8 ProductRevLevel[4]; /* 0x18 */
- U8 SerialNum[32]; /* 0x1C */
-} MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
- MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
- Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t;
-
-typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 DevHandle; /* 0x04 */
- U8 Reserved1; /* 0x06 */
- U8 PhysDiskNum; /* 0x07 */
- MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /* 0x10 */
- U32 Reserved3; /* 0x4C */
- U8 PhysDiskState; /* 0x50 */
- U8 OfflineReason; /* 0x51 */
- U8 IncompatibleReason; /* 0x52 */
- U8 PhysDiskAttributes; /* 0x53 */
- U32 PhysDiskStatusFlags; /* 0x54 */
- U64 DeviceMaxLBA; /* 0x58 */
- U64 HostMaxLBA; /* 0x60 */
- U64 CoercedMaxLBA; /* 0x68 */
- U16 BlockSize; /* 0x70 */
- U16 Reserved5; /* 0x72 */
- U32 Reserved6; /* 0x74 */
-} MPI2_CONFIG_PAGE_RD_PDISK_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0,
- Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t;
-
-#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05)
-
-/* PhysDiskState defines */
-#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00)
-#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01)
-#define MPI2_RAID_PD_STATE_OFFLINE (0x02)
-#define MPI2_RAID_PD_STATE_ONLINE (0x03)
-#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04)
-#define MPI2_RAID_PD_STATE_DEGRADED (0x05)
-#define MPI2_RAID_PD_STATE_REBUILDING (0x06)
-#define MPI2_RAID_PD_STATE_OPTIMAL (0x07)
-
-/* OfflineReason defines */
-#define MPI2_PHYSDISK0_ONLINE (0x00)
-#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01)
-#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03)
-#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04)
-#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05)
-#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06)
-#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF)
-
-/* IncompatibleReason defines */
-#define MPI2_PHYSDISK0_COMPATIBLE (0x00)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF)
-
-/* PhysDiskAttributes defines */
-#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C)
-#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08)
-#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04)
-
-#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03)
-#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02)
-#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01)
-
-/* PhysDiskStatusFlags defines */
-#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040)
-#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020)
-#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010)
-#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000)
-#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008)
-#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004)
-#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002)
-#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001)
-
-
-/* RAID Physical Disk Page 1 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhysDiskPaths at runtime.
- */
-#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
-#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1)
-#endif
-
-typedef struct _MPI2_RAIDPHYSDISK1_PATH
-{
- U16 DevHandle; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U64 WWID; /* 0x04 */
- U64 OwnerWWID; /* 0x0C */
- U8 OwnerIdentifier; /* 0x14 */
- U8 Reserved2; /* 0x15 */
- U16 Flags; /* 0x16 */
-} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH,
- Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t;
-
-/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */
-#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004)
-#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002)
-#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001)
-
-typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhysDiskPaths; /* 0x04 */
- U8 PhysDiskNum; /* 0x05 */
- U16 Reserved1; /* 0x06 */
- U32 Reserved2; /* 0x08 */
- MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */
-} MPI2_CONFIG_PAGE_RD_PDISK_1,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1,
- Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t;
-
-#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02)
-
-
-/****************************************************************************
-* values for fields used by several types of SAS Config Pages
-****************************************************************************/
-
-/* values for NegotiatedLinkRates fields */
-#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0)
-#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4)
-#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F)
-/* link rates used for Negotiated Physical and Logical Link Rate */
-#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00)
-#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01)
-#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02)
-#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03)
-#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04)
-#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05)
-#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06)
-#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08)
-#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09)
-#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A)
-
-
-/* values for AttachedPhyInfo fields */
-#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040)
-#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020)
-#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010)
-
-#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F)
-#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000)
-#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001)
-#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002)
-#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003)
-#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004)
-#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005)
-#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006)
-#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007)
-#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008)
-
-
-/* values for PhyInfo fields */
-#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000)
-
-#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
-#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27)
-#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
-#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
-#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
-
-#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000)
-#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000)
-#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000)
-#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000)
-#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000)
-#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000)
-
-#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000)
-#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000)
-#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000)
-#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000)
-#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000)
-#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000)
-#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000)
-#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000)
-#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000)
-#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000)
-
-#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000)
-#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000)
-#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000)
-#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000)
-
-#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00)
-#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8)
-
-#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0)
-#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000)
-#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010)
-#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020)
-
-
-/* values for SAS ProgrammedLinkRate fields */
-#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0)
-#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00)
-#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80)
-#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90)
-#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0)
-#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0)
-#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F)
-#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00)
-#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08)
-#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09)
-#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A)
-
-
-/* values for SAS HwLinkRate fields */
-#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0)
-#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80)
-#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90)
-#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0)
-#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0)
-#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F)
-#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08)
-#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09)
-#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A)
-
-
-
-/****************************************************************************
-* SAS IO Unit Config Pages
-****************************************************************************/
-
-/* SAS IO Unit Page 0 */
-
-typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA
-{
- U8 Port; /* 0x00 */
- U8 PortFlags; /* 0x01 */
- U8 PhyFlags; /* 0x02 */
- U8 NegotiatedLinkRate; /* 0x03 */
- U32 ControllerPhyDeviceInfo;/* 0x04 */
- U16 AttachedDevHandle; /* 0x08 */
- U16 ControllerDevHandle; /* 0x0A */
- U32 DiscoveryStatus; /* 0x0C */
- U32 Reserved; /* 0x10 */
-} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA,
- Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t;
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT0_PHY_MAX
-#define MPI2_SAS_IOUNIT0_PHY_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U8 NumPhys; /* 0x0C */
- U8 Reserved2; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /* 0x10 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0,
- Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t;
-
-#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05)
-
-/* values for SAS IO Unit Page 0 PortFlags */
-#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08)
-#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01)
-
-/* values for SAS IO Unit Page 0 PhyFlags */
-#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10)
-#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
-
-/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */
-
-/* values for SAS IO Unit Page 0 DiscoveryStatus */
-#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
-#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000)
-#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000)
-#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000)
-#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000)
-#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
-#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000)
-#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000)
-#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000)
-#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800)
-#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400)
-#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200)
-#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100)
-#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080)
-#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040)
-#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020)
-#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010)
-#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004)
-#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002)
-#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001)
-
-
-/* SAS IO Unit Page 1 */
-
-typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA
-{
- U8 Port; /* 0x00 */
- U8 PortFlags; /* 0x01 */
- U8 PhyFlags; /* 0x02 */
- U8 MaxMinLinkRate; /* 0x03 */
- U32 ControllerPhyDeviceInfo; /* 0x04 */
- U16 MaxTargetPortConnectTime; /* 0x08 */
- U16 Reserved1; /* 0x0A */
-} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA,
- Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t;
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT1_PHY_MAX
-#define MPI2_SAS_IOUNIT1_PHY_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 ControlFlags; /* 0x08 */
- U16 SASNarrowMaxQueueDepth; /* 0x0A */
- U16 AdditionalControlFlags; /* 0x0C */
- U16 SASWideMaxQueueDepth; /* 0x0E */
- U8 NumPhys; /* 0x10 */
- U8 SATAMaxQDepth; /* 0x11 */
- U8 ReportDeviceMissingDelay; /* 0x12 */
- U8 IODeviceMissingDelay; /* 0x13 */
- MPI2_SAS_IO_UNIT1_PHY_DATA PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /* 0x14 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_1,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1,
- Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t;
-
-#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09)
-
-/* values for SAS IO Unit Page 1 ControlFlags */
-#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000)
-
-#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600)
-#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9)
-#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0)
-#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1)
-#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2)
-
-#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010)
-#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008)
-#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004)
-#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002)
-#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
-
-/* values for SAS IO Unit Page 1 AdditionalControlFlags */
-#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080)
-#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
-#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020)
-#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010)
-#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008)
-#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004)
-#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002)
-#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001)
-
-/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */
-#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F)
-#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80)
-
-/* values for SAS IO Unit Page 1 PortFlags */
-#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01)
-
-/* values for SAS IO Unit Page 1 PhyFlags */
-#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10)
-#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
-
-/* values for SAS IO Unit Page 1 MaxMinLinkRate */
-#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0)
-#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80)
-#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90)
-#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0)
-#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F)
-#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08)
-#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09)
-#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A)
-
-/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
-
-
-/* SAS IO Unit Page 4 */
-
-typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP
-{
- U8 MaxTargetSpinup; /* 0x00 */
- U8 SpinupDelay; /* 0x01 */
- U8 SpinupFlags; /* 0x02 */
- U8 Reserved1; /* 0x03 */
-} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP,
- Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t;
-
-/* defines for SAS IO Unit Page 4 SpinupFlags */
-#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT4_PHY_MAX
-#define MPI2_SAS_IOUNIT4_PHY_MAX (4)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- MPI2_SAS_IOUNIT4_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */
- U32 Reserved1; /* 0x18 */
- U32 Reserved2; /* 0x1C */
- U32 Reserved3; /* 0x20 */
- U8 BootDeviceWaitTime; /* 0x24 */
- U8 Reserved4; /* 0x25 */
- U16 Reserved5; /* 0x26 */
- U8 NumPhys; /* 0x28 */
- U8 PEInitialSpinupDelay; /* 0x29 */
- U8 PEReplyDelay; /* 0x2A */
- U8 Flags; /* 0x2B */
- U8 PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /* 0x2C */
-} MPI2_CONFIG_PAGE_SASIOUNIT_4,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4,
- Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t;
-
-#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02)
-
-/* defines for Flags field */
-#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01)
-
-/* defines for PHY field */
-#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03)
-
-
-/* SAS IO Unit Page 5 */
-
-typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
- U8 ControlFlags; /* 0x00 */
- U8 PortWidthModGroup; /* 0x01 */
- U16 InactivityTimerExponent; /* 0x02 */
- U8 SATAPartialTimeout; /* 0x04 */
- U8 Reserved2; /* 0x05 */
- U8 SATASlumberTimeout; /* 0x06 */
- U8 Reserved3; /* 0x07 */
- U8 SASPartialTimeout; /* 0x08 */
- U8 Reserved4; /* 0x09 */
- U8 SASSlumberTimeout; /* 0x0A */
- U8 Reserved5; /* 0x0B */
-} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
- MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
- Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t;
-
-/* defines for ControlFlags field */
-#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08)
-#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04)
-#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02)
-#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01)
-
-/* defines for PortWidthModeGroup field */
-#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF)
-
-/* defines for InactivityTimerExponent field */
-#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12)
-#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8)
-#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4)
-#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0)
-
-#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7)
-#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6)
-#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5)
-#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4)
-#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3)
-#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2)
-#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1)
-#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
-#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhys; /* 0x08 */
- U8 Reserved1; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 Reserved3; /* 0x0C */
- MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings
- [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_5,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
- Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
-
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01)
-
-
-/* SAS IO Unit Page 6 */
-
-typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS {
- U8 CurrentStatus; /* 0x00 */
- U8 CurrentModulation; /* 0x01 */
- U8 CurrentUtilization; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 Reserved2; /* 0x04 */
-} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
- MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
- Mpi2SasIOUnit6PortWidthModGroupStatus_t,
- MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
-
-/* defines for CurrentStatus field */
-#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00)
-#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01)
-#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02)
-#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03)
-#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04)
-#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05)
-#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06)
-#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07)
-
-/* defines for CurrentModulation field */
-#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00)
-#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01)
-#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02)
-#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumGroups at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
-#define MPI2_SAS_IOUNIT6_GROUP_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- U8 NumGroups; /* 0x10 */
- U8 Reserved3; /* 0x11 */
- U16 Reserved4; /* 0x12 */
- MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
- PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_6,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
- Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
-
-#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00)
-
-
-/* SAS IO Unit Page 7 */
-
-typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS {
- U8 Flags; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U8 Threshold75Pct; /* 0x04 */
- U8 Threshold50Pct; /* 0x05 */
- U8 Threshold25Pct; /* 0x06 */
- U8 Reserved3; /* 0x07 */
-} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
- MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
- Mpi2SasIOUnit7PortWidthModGroupSettings_t,
- MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
-
-/* defines for Flags field */
-#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01)
-
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumGroups at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
-#define MPI2_SAS_IOUNIT7_GROUP_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 SamplingInterval; /* 0x08 */
- U8 WindowLength; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Reserved2; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U8 NumGroups; /* 0x14 */
- U8 Reserved4; /* 0x15 */
- U16 Reserved5; /* 0x16 */
- MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
- PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_7,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
- Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
-
-#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00)
-
-
-/* SAS IO Unit Page 8 */
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 PowerManagementCapabilities;/* 0x0C */
- U32 Reserved2; /* 0x10 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_8,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
- Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
-
-#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00)
-
-/* defines for PowerManagementCapabilities field */
-#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000)
-#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800)
-#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400)
-#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200)
-#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001)
-
-
-
-/* SAS IO Unit Page 16 */
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U64 TimeStamp; /* 0x08 */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
- U32 FastPathPendedRequests; /* 0x18 */
- U32 FastPathUnPendedRequests; /* 0x1C */
- U32 FastPathHostRequestStarts; /* 0x20 */
- U32 FastPathFirmwareRequestStarts; /* 0x24 */
- U32 FastPathHostCompletions; /* 0x28 */
- U32 FastPathFirmwareCompletions; /* 0x2C */
- U32 NonFastPathRequestStarts; /* 0x30 */
- U32 NonFastPathHostCompletions; /* 0x30 */
-} MPI2_CONFIG_PAGE_SASIOUNIT16,
-MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16,
-Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t;
-
-#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00)
-
-
-/****************************************************************************
-* SAS Expander Config Pages
-****************************************************************************/
-
-/* SAS Expander Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 PhysicalPort; /* 0x08 */
- U8 ReportGenLength; /* 0x09 */
- U16 EnclosureHandle; /* 0x0A */
- U64 SASAddress; /* 0x0C */
- U32 DiscoveryStatus; /* 0x14 */
- U16 DevHandle; /* 0x18 */
- U16 ParentDevHandle; /* 0x1A */
- U16 ExpanderChangeCount; /* 0x1C */
- U16 ExpanderRouteIndexes; /* 0x1E */
- U8 NumPhys; /* 0x20 */
- U8 SASLevel; /* 0x21 */
- U16 Flags; /* 0x22 */
- U16 STPBusInactivityTimeLimit; /* 0x24 */
- U16 STPMaxConnectTimeLimit; /* 0x26 */
- U16 STP_SMP_NexusLossTime; /* 0x28 */
- U16 MaxNumRoutedSasAddresses; /* 0x2A */
- 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 (0x06)
-
-/* values for SAS Expander Page 0 DiscoveryStatus field */
-#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
-#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000)
-#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000)
-#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000)
-#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000)
-#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
-#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000)
-#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000)
-#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000)
-#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800)
-#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400)
-#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200)
-#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100)
-#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080)
-#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040)
-#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020)
-#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010)
-#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004)
-#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002)
-#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)
-#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200)
-#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100)
-#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080)
-#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010)
-#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004)
-#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002)
-#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001)
-
-
-/* SAS Expander Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 PhysicalPort; /* 0x08 */
- U8 Reserved1; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U8 NumPhys; /* 0x0C */
- U8 Phy; /* 0x0D */
- U16 NumTableEntriesProgrammed; /* 0x0E */
- U8 ProgrammedLinkRate; /* 0x10 */
- U8 HwLinkRate; /* 0x11 */
- U16 AttachedDevHandle; /* 0x12 */
- U32 PhyInfo; /* 0x14 */
- U32 AttachedDeviceInfo; /* 0x18 */
- U16 ExpanderDevHandle; /* 0x1C */
- U8 ChangeCount; /* 0x1E */
- U8 NegotiatedLinkRate; /* 0x1F */
- U8 PhyIdentifier; /* 0x20 */
- U8 AttachedPhyIdentifier; /* 0x21 */
- U8 Reserved3; /* 0x22 */
- U8 DiscoveryInfo; /* 0x23 */
- U32 AttachedPhyInfo; /* 0x24 */
- U8 ZoneGroup; /* 0x28 */
- U8 SelfConfigStatus; /* 0x29 */
- U16 Reserved4; /* 0x2A */
-} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1,
- Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t;
-
-#define MPI2_SASEXPANDER1_PAGEVERSION (0x02)
-
-/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
-
-/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
-
-/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
-
-/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
-
-/* values for SAS Expander Page 1 DiscoveryInfo field */
-#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04)
-#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02)
-#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01)
-
-/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
-
-/****************************************************************************
-* SAS Device Config Pages
-****************************************************************************/
-
-/* SAS Device Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 Slot; /* 0x08 */
- U16 EnclosureHandle; /* 0x0A */
- U64 SASAddress; /* 0x0C */
- U16 ParentDevHandle; /* 0x14 */
- U8 PhyNum; /* 0x16 */
- U8 AccessStatus; /* 0x17 */
- U16 DevHandle; /* 0x18 */
- U8 AttachedPhyIdentifier; /* 0x1A */
- U8 ZoneGroup; /* 0x1B */
- U32 DeviceInfo; /* 0x1C */
- U16 Flags; /* 0x20 */
- U8 PhysicalPort; /* 0x22 */
- U8 MaxPortConnections; /* 0x23 */
- U64 DeviceName; /* 0x24 */
- U8 PortGroups; /* 0x2C */
- U8 DmaGroup; /* 0x2D */
- U8 ControlGroup; /* 0x2E */
- U8 EnclosureLevel; /* 0x2F */
- U8 ConnectorName[4]; /* 0x30 */
- U32 Reserved3; /* 0x34 */
-} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0,
- Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t;
-
-#define MPI2_SASDEVICE0_PAGEVERSION (0x09)
-
-/* values for SAS Device Page 0 AccessStatus field */
-#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04)
-#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05)
-#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06)
-#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07)
-/* specific values for SATA Init failures */
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F)
-
-/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */
-
-/* values for SAS Device Page 0 Flags field */
-#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000)
-#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000)
-#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200)
-#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
-#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
-#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002)
-#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
-
-
-/* SAS Device Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U64 SASAddress; /* 0x0C */
- U32 Reserved2; /* 0x14 */
- U16 DevHandle; /* 0x18 */
- U16 Reserved3; /* 0x1A */
- U8 InitialRegDeviceFIS[20];/* 0x1C */
-} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1,
- Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t;
-
-#define MPI2_SASDEVICE1_PAGEVERSION (0x01)
-
-
-/****************************************************************************
-* SAS PHY Config Pages
-****************************************************************************/
-
-/* SAS PHY Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 OwnerDevHandle; /* 0x08 */
- U16 Reserved1; /* 0x0A */
- U16 AttachedDevHandle; /* 0x0C */
- U8 AttachedPhyIdentifier; /* 0x0E */
- U8 Reserved2; /* 0x0F */
- U32 AttachedPhyInfo; /* 0x10 */
- U8 ProgrammedLinkRate; /* 0x14 */
- U8 HwLinkRate; /* 0x15 */
- U8 ChangeCount; /* 0x16 */
- U8 Flags; /* 0x17 */
- U32 PhyInfo; /* 0x18 */
- U8 NegotiatedLinkRate; /* 0x1C */
- U8 Reserved3; /* 0x1D */
- U16 Reserved4; /* 0x1E */
-} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0,
- Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t;
-
-#define MPI2_SASPHY0_PAGEVERSION (0x03)
-
-/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
-
-/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
-
-/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
-
-/* values for SAS PHY Page 0 Flags field */
-#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01)
-
-/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
-
-
-/* SAS PHY Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 InvalidDwordCount; /* 0x0C */
- U32 RunningDisparityErrorCount; /* 0x10 */
- U32 LossDwordSynchCount; /* 0x14 */
- U32 PhyResetProblemCount; /* 0x18 */
-} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1,
- Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t;
-
-#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 the value returned for 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 the value returned for 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 PHY Page 4 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 Reserved1; /* 0x08 */
- U8 Reserved2; /* 0x0A */
- U8 Flags; /* 0x0B */
- U8 InitialFrame[28]; /* 0x0C */
-} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4,
- Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t;
-
-#define MPI2_SASPHY4_PAGEVERSION (0x00)
-
-/* values for the Flags field */
-#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02)
-#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01)
-
-
-
-
-/****************************************************************************
-* SAS Port Config Pages
-****************************************************************************/
-
-/* SAS Port Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 PortNumber; /* 0x08 */
- U8 PhysicalPort; /* 0x09 */
- U8 PortWidth; /* 0x0A */
- U8 PhysicalPortWidth; /* 0x0B */
- U8 ZoneGroup; /* 0x0C */
- U8 Reserved1; /* 0x0D */
- U16 Reserved2; /* 0x0E */
- U64 SASAddress; /* 0x10 */
- U32 DeviceInfo; /* 0x18 */
- U32 Reserved3; /* 0x1C */
- U32 Reserved4; /* 0x20 */
-} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0,
- Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t;
-
-#define MPI2_SASPORT0_PAGEVERSION (0x00)
-
-/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */
-
-
-/****************************************************************************
-* SAS Enclosure Config Pages
-****************************************************************************/
-
-/* SAS Enclosure Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U64 EnclosureLogicalID; /* 0x0C */
- U16 Flags; /* 0x14 */
- U16 EnclosureHandle; /* 0x16 */
- U16 NumSlots; /* 0x18 */
- U16 StartSlot; /* 0x1A */
- U8 Reserved2; /* 0x1C */
- U8 EnclosureLevel; /* 0x1D */
- U16 SEPDevHandle; /* 0x1E */
- U32 Reserved3; /* 0x20 */
- U32 Reserved4; /* 0x24 */
-} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
- Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t;
-
-#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04)
-
-/* values for SAS Enclosure Page 0 Flags field */
-#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005)
-
-
-/****************************************************************************
-* Log Config Page
-****************************************************************************/
-
-/* Log Page 0 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumLogEntries at runtime.
- */
-#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
-#define MPI2_LOG_0_NUM_LOG_ENTRIES (1)
-#endif
-
-#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C)
-
-typedef struct _MPI2_LOG_0_ENTRY
-{
- U64 TimeStamp; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U16 LogSequence; /* 0x0C */
- U16 LogEntryQualifier; /* 0x0E */
- U8 VP_ID; /* 0x10 */
- U8 VF_ID; /* 0x11 */
- U16 Reserved2; /* 0x12 */
- U8 LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */
-} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY,
- Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t;
-
-/* values for Log Page 0 LogEntry LogEntryQualifier field */
-#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000)
-#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001)
-#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002)
-#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000)
-#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF)
-
-typedef struct _MPI2_CONFIG_PAGE_LOG_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- U16 NumLogEntries; /* 0x10 */
- U16 Reserved3; /* 0x12 */
- MPI2_LOG_0_ENTRY LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */
-} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0,
- Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t;
-
-#define MPI2_LOG_0_PAGEVERSION (0x02)
-
-
-/****************************************************************************
-* RAID Config Page
-****************************************************************************/
-
-/* RAID Page 0 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumElements at runtime.
- */
-#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
-#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1)
-#endif
-
-typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT
-{
- U16 ElementFlags; /* 0x00 */
- U16 VolDevHandle; /* 0x02 */
- U8 HotSparePool; /* 0x04 */
- U8 PhysDiskNum; /* 0x05 */
- U16 PhysDiskDevHandle; /* 0x06 */
-} MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
- MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
- Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t;
-
-/* values for the ElementFlags field */
-#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F)
-#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000)
-#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001)
-#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002)
-#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003)
-
-
-typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 NumHotSpares; /* 0x08 */
- U8 NumPhysDisks; /* 0x09 */
- U8 NumVolumes; /* 0x0A */
- U8 ConfigNum; /* 0x0B */
- U32 Flags; /* 0x0C */
- U8 ConfigGUID[24]; /* 0x10 */
- U32 Reserved1; /* 0x28 */
- U8 NumElements; /* 0x2C */
- U8 Reserved2; /* 0x2D */
- U16 Reserved3; /* 0x2E */
- MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */
-} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
- Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t;
-
-#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00)
-
-/* values for RAID Configuration Page 0 Flags field */
-#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001)
-
-
-/****************************************************************************
-* Driver Persistent Mapping Config Pages
-****************************************************************************/
-
-/* Driver Persistent Mapping Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY
-{
- U64 PhysicalIdentifier; /* 0x00 */
- U16 MappingInformation; /* 0x08 */
- U16 DeviceIndex; /* 0x0A */
- U32 PhysicalBitsMapping; /* 0x0C */
- U32 Reserved1; /* 0x10 */
-} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
- Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t;
-
-typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /* 0x08 */
-} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
- Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t;
-
-#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00)
-
-/* values for Driver Persistent Mapping Page 0 MappingInformation field */
-#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0)
-#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4)
-#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F)
-
-
-/****************************************************************************
-* Ethernet Config Pages
-****************************************************************************/
-
-/* Ethernet Page 0 */
-
-/* IP address (union of IPv4 and IPv6) */
-typedef union _MPI2_ETHERNET_IP_ADDR {
- U32 IPv4Addr;
- U32 IPv6Addr[4];
-} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR,
- Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t;
-
-#define MPI2_ETHERNET_HOST_NAME_LENGTH (32)
-
-typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 NumInterfaces; /* 0x08 */
- U8 Reserved0; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Status; /* 0x0C */
- U8 MediaState; /* 0x10 */
- U8 Reserved2; /* 0x11 */
- U16 Reserved3; /* 0x12 */
- U8 MacAddress[6]; /* 0x14 */
- U8 Reserved4; /* 0x1A */
- U8 Reserved5; /* 0x1B */
- MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */
- MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */
- MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */
- MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */
- MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */
- MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */
- U8 HostName
- [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
-} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0,
- Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t;
-
-#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00)
-
-/* values for Ethernet Page 0 Status field */
-#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000)
-#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000)
-#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000)
-#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100)
-#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080)
-#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040)
-#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020)
-#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010)
-#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008)
-#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004)
-#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002)
-#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001)
-
-/* values for Ethernet Page 0 MediaState field */
-#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80)
-#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00)
-#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80)
-
-#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07)
-#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00)
-#define MPI2_ETHPG0_MS_10MBIT (0x01)
-#define MPI2_ETHPG0_MS_100MBIT (0x02)
-#define MPI2_ETHPG0_MS_1GBIT (0x03)
-
-
-/* Ethernet Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved0; /* 0x08 */
- U32 Flags; /* 0x0C */
- U8 MediaState; /* 0x10 */
- U8 Reserved1; /* 0x11 */
- U16 Reserved2; /* 0x12 */
- U8 MacAddress[6]; /* 0x14 */
- U8 Reserved3; /* 0x1A */
- U8 Reserved4; /* 0x1B */
- MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */
- MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */
- MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */
- MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */
- MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */
- U32 Reserved5; /* 0x6C */
- U32 Reserved6; /* 0x70 */
- U32 Reserved7; /* 0x74 */
- U32 Reserved8; /* 0x78 */
- U8 HostName
- [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
-} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1,
- Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t;
-
-#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00)
-
-/* values for Ethernet Page 1 Flags field */
-#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100)
-#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080)
-#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040)
-#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020)
-#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010)
-#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008)
-#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004)
-#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002)
-#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001)
-
-/* values for Ethernet Page 1 MediaState field */
-#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80)
-#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00)
-#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80)
-
-#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07)
-#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00)
-#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01)
-#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02)
-#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03)
-
-
-/****************************************************************************
-* Extended Manufacturing Config Pages
-****************************************************************************/
-
-/*
- * Generic structure to use for product-specific extended manufacturing pages
- * (currently Extended Manufacturing Page 40 through Extended Manufacturing
- * Page 60).
- */
-
-typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 ProductSpecificInfo; /* 0x08 */
-} MPI2_CONFIG_PAGE_EXT_MAN_PS,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS,
- Mpi2ExtManufacturingPagePS_t,
- MPI2_POINTER pMpi2ExtManufacturingPagePS_t;
-
-/* PageVersion should be provided by product-specific code */
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
deleted file mode 100644
index eea1a16..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright (c) 2000-2014 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.15
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 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 because 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.
- * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for
- * both SCSI IO Error Reply and SCSI Task Management Reply.
- * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
- * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
- * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
- * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
- * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
- * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command
- * Priority to match SAM-4.
- * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.
- * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY,
- * replacing the Reserved4 field.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_INIT_H
-#define MPI2_INIT_H
-
-/*****************************************************************************
-*
-* SCSI Initiator Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* SCSI IO messages and associated structures
-****************************************************************************/
-
-typedef struct
-{
- U8 CDB[20]; /* 0x00 */
- U32 PrimaryReferenceTag; /* 0x14 */
- U16 PrimaryApplicationTag; /* 0x18 */
- U16 PrimaryApplicationTagMask; /* 0x1A */
- U32 TransferLength; /* 0x1C */
-} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
- Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
-
-typedef union
-{
- U8 CDB32[32];
- MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
- MPI2_SGE_SIMPLE_UNION SGE;
-} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION,
- Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t;
-
-/* SCSI IO Request Message */
-typedef struct _MPI2_SCSI_IO_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U32 SenseBufferLowAddress; /* 0x0C */
- U16 SGLFlags; /* 0x10 */
- U8 SenseBufferLength; /* 0x12 */
- U8 Reserved4; /* 0x13 */
- U8 SGLOffset0; /* 0x14 */
- U8 SGLOffset1; /* 0x15 */
- U8 SGLOffset2; /* 0x16 */
- U8 SGLOffset3; /* 0x17 */
- U32 SkipCount; /* 0x18 */
- U32 DataLength; /* 0x1C */
- U32 BidirectionalDataLength; /* 0x20 */
- U16 IoFlags; /* 0x24 */
- U16 EEDPFlags; /* 0x26 */
- U32 EEDPBlockSize; /* 0x28 */
- U32 SecondaryReferenceTag; /* 0x2C */
- U16 SecondaryApplicationTag; /* 0x30 */
- U16 ApplicationTagTranslationMask; /* 0x32 */
- U8 LUN[8]; /* 0x34 */
- U32 Control; /* 0x3C */
- MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
-
-#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
- MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion;
-#endif
-
- MPI2_SGE_IO_UNION SGL; /* 0x60 */
-
-} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
- Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
-
-/* SCSI IO MsgFlags bits */
-
-/* MsgFlags for SenseBufferAddressSpace */
-#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C)
-#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00)
-#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04)
-#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08)
-#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C)
-
-/* SCSI IO SGLFlags bits */
-
-/* base values for Data Location Address Space */
-#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C)
-#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00)
-#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04)
-#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08)
-#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C)
-
-/* base values for Type */
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03)
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00)
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01)
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02)
-
-/* shift values for each sub-field */
-#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12)
-#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8)
-#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4)
-#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0)
-
-/* number of SGLOffset fields */
-#define MPI2_SCSIIO_NUM_SGLOFFSETS (4)
-
-/* SCSI IO IoFlags bits */
-
-/* Large CDB Address Space */
-#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000)
-#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000)
-#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000)
-#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000)
-#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000)
-
-#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000)
-#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800)
-#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400)
-#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200)
-#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF)
-
-/* SCSI IO EEDPFlags bits */
-
-#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
-#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000)
-#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000)
-#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000)
-
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
-
-#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008)
-
-#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007)
-#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001)
-#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
-#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
-#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007)
-
-/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */
-
-/* SCSI IO Control bits */
-#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000)
-#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26)
-
-#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000)
-#define MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION (24)
-#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000)
-#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
-#define MPI2_SCSIIO_CONTROL_READ (0x02000000)
-#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000)
-
-#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800)
-#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11)
-/* alternate name for the previous field; called Command Priority in SAM-4 */
-#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800)
-#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT (11)
-
-#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700)
-#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000)
-#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100)
-#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200)
-#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400)
-
-#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0)
-#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000)
-#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040)
-#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080)
-
-
-/* SCSI IO Error Reply Message */
-typedef struct _MPI2_SCSI_IO_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U8 SCSIStatus; /* 0x0C */
- U8 SCSIState; /* 0x0D */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 TransferCount; /* 0x14 */
- U32 SenseCount; /* 0x18 */
- U32 ResponseInfo; /* 0x1C */
- U16 TaskTag; /* 0x20 */
- U16 SCSIStatusQualifier; /* 0x22 */
- U32 BidirectionalTransferCount; /* 0x24 */
- U32 Reserved5; /* 0x28 */
- U32 Reserved6; /* 0x2C */
-} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY,
- Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t;
-
-/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */
-
-#define MPI2_SCSI_STATUS_GOOD (0x00)
-#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02)
-#define MPI2_SCSI_STATUS_CONDITION_MET (0x04)
-#define MPI2_SCSI_STATUS_BUSY (0x08)
-#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10)
-#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14)
-#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18)
-#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */
-#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28)
-#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30)
-#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40)
-
-/* SCSI IO Reply SCSIState flags */
-
-#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10)
-#define MPI2_SCSI_STATE_TERMINATED (0x08)
-#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04)
-#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02)
-#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01)
-
-/* masks and shifts for the ResponseInfo field */
-
-#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF)
-#define MPI2_SCSI_RI_SHIFT_REASONCODE (0)
-
-#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF)
-
-
-/****************************************************************************
-* SCSI Task Management messages
-****************************************************************************/
-
-/* SCSI Task Management Request Message */
-typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Reserved1; /* 0x04 */
- U8 TaskType; /* 0x05 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U8 LUN[8]; /* 0x0C */
- U32 Reserved4[7]; /* 0x14 */
- U16 TaskMID; /* 0x30 */
- U16 Reserved5; /* 0x32 */
-} MPI2_SCSI_TASK_MANAGE_REQUEST,
- MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST,
- Mpi2SCSITaskManagementRequest_t,
- MPI2_POINTER pMpi2SCSITaskManagementRequest_t;
-
-/* TaskType values */
-
-#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
-#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02)
-#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
-#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
-#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
-#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_ASYNC_EVENT (0x0A)
-
-/* obsolete TaskType name */
-#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \
- (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT)
-
-/* MsgFlags bits */
-
-#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10)
-
-#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01)
-
-
-
-/* SCSI Task Management Reply Message */
-typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 ResponseCode; /* 0x04 */
- U8 TaskType; /* 0x05 */
- U8 Reserved1; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 TerminationCount; /* 0x14 */
- U32 ResponseInfo; /* 0x18 */
-} MPI2_SCSI_TASK_MANAGE_REPLY,
- MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
- Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t;
-
-/* ResponseCode values */
-
-#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00)
-#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02)
-#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04)
-#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05)
-#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08)
-#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09)
-#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A)
-#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
-
-/* masks and shifts for the ResponseInfo field */
-
-#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0)
-#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8)
-#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16)
-#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24)
-
-
-/****************************************************************************
-* SCSI Enclosure Processor messages
-****************************************************************************/
-
-/* SCSI Enclosure Processor Request Message */
-typedef struct _MPI2_SEP_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Action; /* 0x04 */
- U8 Flags; /* 0x05 */
- U8 Reserved1; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 SlotStatus; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U32 Reserved4; /* 0x14 */
- U32 Reserved5; /* 0x18 */
- U16 Slot; /* 0x1C */
- U16 EnclosureHandle; /* 0x1E */
-} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST,
- Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t;
-
-/* Action defines */
-#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00)
-#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01)
-
-/* Flags defines */
-#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00)
-#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01)
-
-/* SlotStatus defines */
-#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000)
-#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
-#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
-#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)
-
-
-/* SCSI Enclosure Processor Reply Message */
-typedef struct _MPI2_SEP_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Action; /* 0x04 */
- U8 Flags; /* 0x05 */
- U8 Reserved1; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 SlotStatus; /* 0x14 */
- U32 Reserved4; /* 0x18 */
- U16 Slot; /* 0x1C */
- U16 EnclosureHandle; /* 0x1E */
-} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY,
- Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t;
-
-/* SlotStatus defines */
-#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000)
-#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
-#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
-#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)
-
-
-#endif
-
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
deleted file mode 100644
index b02de48..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ /dev/null
@@ -1,1708 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_ioc.h
- * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
- * Creation Date: October 11, 2006
- *
- * mpi2_ioc.h Version: 02.00.24
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 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.
- * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
- * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
- * Added new product id family for 2208.
- * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
- * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
- * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
- * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
- * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
- * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
- * Added Host Based Discovery Phy Event data.
- * Added defines for ProductID Product field
- * (MPI2_FW_HEADER_PID_).
- * Modified values for SAS ProductID Family
- * (MPI2_FW_HEADER_PID_FAMILY_).
- * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
- * Added PowerManagementControl Request structures and
- * defines.
- * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
- * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
- * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
- * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added
- * SASNotifyPrimitiveMasks field to
- * MPI2_EVENT_NOTIFICATION_REQUEST.
- * Added Temperature Threshold Event.
- * Added Host Message Event.
- * Added Send Host Message request and reply.
- * 05-25-11 02.00.18 For Extended Image Header, added
- * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and
- * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines.
- * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define.
- * 08-24-11 02.00.19 Added PhysicalPort field to
- * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure.
- * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete.
- * 03-29-12 02.00.21 Added a product specific range to event values.
- * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE.
- * Added ElapsedSeconds field to
- * MPI2_EVENT_DATA_IR_OPERATION_STATUS.
- * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE
- * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY.
- * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE.
- * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
- * Added Encrypted Hash Extended Image.
- * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_IOC_H
-#define MPI2_IOC_H
-
-/*****************************************************************************
-*
-* IOC Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* IOCInit message
-****************************************************************************/
-
-/* IOCInit Request message */
-typedef struct _MPI2_IOC_INIT_REQUEST
-{
- U8 WhoInit; /* 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 */
- U16 MsgVersion; /* 0x0C */
- U16 HeaderVersion; /* 0x0E */
- U32 Reserved5; /* 0x10 */
- U16 Reserved6; /* 0x14 */
- U8 Reserved7; /* 0x16 */
- U8 HostMSIxVectors; /* 0x17 */
- U16 Reserved8; /* 0x18 */
- U16 SystemRequestFrameSize; /* 0x1A */
- U16 ReplyDescriptorPostQueueDepth; /* 0x1C */
- U16 ReplyFreeQueueDepth; /* 0x1E */
- U32 SenseBufferAddressHigh; /* 0x20 */
- U32 SystemReplyAddressHigh; /* 0x24 */
- U64 SystemRequestFrameBaseAddress; /* 0x28 */
- U64 ReplyDescriptorPostQueueAddress;/* 0x30 */
- U64 ReplyFreeQueueAddress; /* 0x38 */
- U64 TimeStamp; /* 0x40 */
-} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST,
- Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t;
-
-/* WhoInit values */
-#define MPI2_WHOINIT_NOT_INITIALIZED (0x00)
-#define MPI2_WHOINIT_SYSTEM_BIOS (0x01)
-#define MPI2_WHOINIT_ROM_BIOS (0x02)
-#define MPI2_WHOINIT_PCI_PEER (0x03)
-#define MPI2_WHOINIT_HOST_DRIVER (0x04)
-#define MPI2_WHOINIT_MANUFACTURER (0x05)
-
-/* MsgFlags */
-#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01)
-
-/* MsgVersion */
-#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00)
-#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8)
-#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF)
-#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0)
-
-/* HeaderVersion */
-#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00)
-#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8)
-#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF)
-#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0)
-
-/* minimum depth for a Reply Descriptor Post Queue */
-#define MPI2_RDPQ_DEPTH_MIN (16)
-
-/* Reply Descriptor Post Queue Array Entry */
-typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
- U64 RDPQBaseAddress; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
-} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY,
-MPI2_POINTER PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY,
-Mpi2IOCInitRDPQArrayEntry, MPI2_POINTER pMpi2IOCInitRDPQArrayEntry;
-
-/* IOCInit Reply message */
-typedef struct _MPI2_IOC_INIT_REPLY
-{
- U8 WhoInit; /* 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 */
-} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY,
- Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t;
-
-
-/****************************************************************************
-* IOCFacts message
-****************************************************************************/
-
-/* IOCFacts Request message */
-typedef struct _MPI2_IOC_FACTS_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- 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 */
-} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST,
- Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t;
-
-
-/* IOCFacts Reply message */
-typedef struct _MPI2_IOC_FACTS_REPLY
-{
- U16 MsgVersion; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 HeaderVersion; /* 0x04 */
- U8 IOCNumber; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U16 IOCExceptions; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U8 MaxChainDepth; /* 0x14 */
- U8 WhoInit; /* 0x15 */
- U8 NumberOfPorts; /* 0x16 */
- U8 MaxMSIxVectors; /* 0x17 */
- U16 RequestCredit; /* 0x18 */
- U16 ProductID; /* 0x1A */
- U32 IOCCapabilities; /* 0x1C */
- MPI2_VERSION_UNION FWVersion; /* 0x20 */
- U16 IOCRequestFrameSize; /* 0x24 */
- U16 Reserved3; /* 0x26 */
- U16 MaxInitiators; /* 0x28 */
- U16 MaxTargets; /* 0x2A */
- U16 MaxSasExpanders; /* 0x2C */
- U16 MaxEnclosures; /* 0x2E */
- U16 ProtocolFlags; /* 0x30 */
- U16 HighPriorityCredit; /* 0x32 */
- U16 MaxReplyDescriptorPostQueueDepth; /* 0x34 */
- U8 ReplyFrameSize; /* 0x36 */
- U8 MaxVolumes; /* 0x37 */
- U16 MaxDevHandle; /* 0x38 */
- U16 MaxPersistentEntries; /* 0x3A */
- U16 MinDevHandle; /* 0x3C */
- U16 Reserved4; /* 0x3E */
-} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY,
- Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t;
-
-/* MsgVersion */
-#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00)
-#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8)
-#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF)
-#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0)
-
-/* HeaderVersion */
-#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00)
-#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8)
-#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF)
-#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0)
-
-/* IOCExceptions */
-#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200)
-#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100)
-
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060)
-
-#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010)
-#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008)
-#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004)
-#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002)
-#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001)
-
-/* defines for WhoInit field are after the IOCInit Request */
-
-/* ProductID field uses MPI2_FW_HEADER_PID_ */
-
-/* IOCCapabilities */
-#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
-#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
-#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)
-#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100)
-#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080)
-#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040)
-#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020)
-#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010)
-#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008)
-#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
-
-/* ProtocolFlags */
-#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
-#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002)
-
-
-/****************************************************************************
-* PortFacts message
-****************************************************************************/
-
-/* PortFacts Request message */
-typedef struct _MPI2_PORT_FACTS_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 PortNumber; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
-} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST,
- Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t;
-
-/* PortFacts Reply message */
-typedef struct _MPI2_PORT_FACTS_REPLY
-{
- U16 Reserved1; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 PortNumber; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U8 Reserved5; /* 0x14 */
- U8 PortType; /* 0x15 */
- U16 Reserved6; /* 0x16 */
- U16 MaxPostedCmdBuffers; /* 0x18 */
- U16 Reserved7; /* 0x1A */
-} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY,
- Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t;
-
-/* PortType values */
-#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00)
-#define MPI2_PORTFACTS_PORTTYPE_FC (0x10)
-#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20)
-#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30)
-#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31)
-
-
-/****************************************************************************
-* PortEnable message
-****************************************************************************/
-
-/* PortEnable Request message */
-typedef struct _MPI2_PORT_ENABLE_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Reserved2; /* 0x04 */
- U8 PortFlags; /* 0x05 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
-} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST,
- Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t;
-
-
-/* PortEnable Reply message */
-typedef struct _MPI2_PORT_ENABLE_REPLY
-{
- U16 Reserved1; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Reserved2; /* 0x04 */
- U8 PortFlags; /* 0x05 */
- 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 */
-} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY,
- Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t;
-
-
-/****************************************************************************
-* EventNotification message
-****************************************************************************/
-
-/* EventNotification Request message */
-#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4)
-
-typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- 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 */
- U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */
- U16 SASBroadcastPrimitiveMasks; /* 0x24 */
- U16 SASNotifyPrimitiveMasks; /* 0x26 */
- U32 Reserved8; /* 0x28 */
-} MPI2_EVENT_NOTIFICATION_REQUEST,
- MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST,
- Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t;
-
-
-/* EventNotification Reply message */
-typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
-{
- U16 EventDataLength; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 AckRequired; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U16 Event; /* 0x14 */
- U16 Reserved4; /* 0x16 */
- U32 EventContext; /* 0x18 */
- U32 EventData[1]; /* 0x1C */
-} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY,
- Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t;
-
-/* AckRequired */
-#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00)
-#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01)
-
-/* Event */
-#define MPI2_EVENT_LOG_DATA (0x0001)
-#define MPI2_EVENT_STATE_CHANGE (0x0002)
-#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005)
-#define MPI2_EVENT_EVENT_CHANGE (0x000A)
-#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */
-#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F)
-#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014)
-#define MPI2_EVENT_SAS_DISCOVERY (0x0016)
-#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017)
-#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018)
-#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019)
-#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C)
-#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D)
-#define MPI2_EVENT_IR_VOLUME (0x001E)
-#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)
-#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
-#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024)
-#define MPI2_EVENT_SAS_QUIESCE (0x0025)
-#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026)
-#define MPI2_EVENT_TEMP_THRESHOLD (0x0027)
-#define MPI2_EVENT_HOST_MESSAGE (0x0028)
-#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E)
-#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F)
-
-/* Log Entry Added Event data */
-
-/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */
-#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C)
-
-typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED
-{
- U64 TimeStamp; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U16 LogSequence; /* 0x0C */
- U16 LogEntryQualifier; /* 0x0E */
- U8 VP_ID; /* 0x10 */
- U8 VF_ID; /* 0x11 */
- U16 Reserved2; /* 0x12 */
- U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */
-} MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
- Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t;
-
-/* GPIO Interrupt Event data */
-
-typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT {
- U8 GPIONum; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
-} MPI2_EVENT_DATA_GPIO_INTERRUPT,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT,
- Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t;
-
-/* Temperature Threshold Event data */
-
-typedef struct _MPI2_EVENT_DATA_TEMPERATURE {
- U16 Status; /* 0x00 */
- U8 SensorNum; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U16 CurrentTemperature; /* 0x04 */
- U16 Reserved2; /* 0x06 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
-} MPI2_EVENT_DATA_TEMPERATURE,
-MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE,
-Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t;
-
-/* Temperature Threshold Event data Status bits */
-#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008)
-#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004)
-#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002)
-#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001)
-
-
-/* Host Message Event data */
-
-typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE {
- U8 SourceVF_ID; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Reserved3; /* 0x04 */
- U32 HostData[1]; /* 0x08 */
-} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE,
-Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t;
-
-
-/* Hard Reset Received Event data */
-
-typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
-{
- U8 Reserved1; /* 0x00 */
- U8 Port; /* 0x01 */
- U16 Reserved2; /* 0x02 */
-} MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
- Mpi2EventDataHardResetReceived_t,
- MPI2_POINTER pMpi2EventDataHardResetReceived_t;
-
-/* Task Set Full Event data */
-/* this event is obsolete */
-
-typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
-{
- U16 DevHandle; /* 0x00 */
- U16 CurrentDepth; /* 0x02 */
-} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL,
- Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t;
-
-
-/* SAS Device Status Change Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
-{
- U16 TaskTag; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 PhysicalPort; /* 0x03 */
- U8 ASC; /* 0x04 */
- U8 ASCQ; /* 0x05 */
- U16 DevHandle; /* 0x06 */
- U32 Reserved2; /* 0x08 */
- U64 SASAddress; /* 0x0C */
- U8 LUN[8]; /* 0x14 */
-} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
- Mpi2EventDataSasDeviceStatusChange_t,
- 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_EXPANDER_REDUCED_FUNCTIONALITY (0x11)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12)
-
-
-/* Integrated RAID Operation Status Event data */
-
-typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS
-{
- U16 VolDevHandle; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U8 RAIDOperation; /* 0x04 */
- U8 PercentComplete; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U32 ElapsedSeconds; /* 0x08 */
-} MPI2_EVENT_DATA_IR_OPERATION_STATUS,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,
- Mpi2EventDataIrOperationStatus_t,
- MPI2_POINTER pMpi2EventDataIrOperationStatus_t;
-
-/* Integrated RAID Operation Status Event data RAIDOperation values */
-#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00)
-#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01)
-#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02)
-#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03)
-#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04)
-
-
-/* Integrated RAID Volume Event data */
-
-typedef struct _MPI2_EVENT_DATA_IR_VOLUME
-{
- U16 VolDevHandle; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 NewValue; /* 0x04 */
- U32 PreviousValue; /* 0x08 */
-} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME,
- Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t;
-
-/* Integrated RAID Volume Event data ReasonCode values */
-#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01)
-#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02)
-#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03)
-
-
-/* Integrated RAID Physical Disk Event data */
-
-typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK
-{
- U16 Reserved1; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 PhysDiskNum; /* 0x03 */
- U16 PhysDiskDevHandle; /* 0x04 */
- U16 Reserved2; /* 0x06 */
- U16 Slot; /* 0x08 */
- U16 EnclosureHandle; /* 0x0A */
- U32 NewValue; /* 0x0C */
- U32 PreviousValue; /* 0x10 */
-} MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
- Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t;
-
-/* Integrated RAID Physical Disk Event data ReasonCode values */
-#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01)
-#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02)
-#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03)
-
-
-/* Integrated RAID Configuration Change List Event data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumElements at runtime.
- */
-#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT
-#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1)
-#endif
-
-typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT
-{
- U16 ElementFlags; /* 0x00 */
- U16 VolDevHandle; /* 0x02 */
- U8 ReasonCode; /* 0x04 */
- U8 PhysDiskNum; /* 0x05 */
- U16 PhysDiskDevHandle; /* 0x06 */
-} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT,
- Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t;
-
-/* IR Configuration Change List Event data ElementFlags values */
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F)
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000)
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001)
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002)
-
-/* IR Configuration Change List Event data ReasonCode values */
-#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01)
-#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02)
-#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03)
-#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04)
-#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05)
-#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06)
-#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07)
-#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08)
-#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09)
-
-typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST
-{
- U8 NumElements; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 Reserved2; /* 0x02 */
- U8 ConfigNum; /* 0x03 */
- U32 Flags; /* 0x04 */
- MPI2_EVENT_IR_CONFIG_ELEMENT ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT]; /* 0x08 */
-} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
- Mpi2EventDataIrConfigChangeList_t,
- MPI2_POINTER pMpi2EventDataIrConfigChangeList_t;
-
-/* IR Configuration Change List Event data Flags values */
-#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001)
-
-
-/* SAS Discovery Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY
-{
- U8 Flags; /* 0x00 */
- U8 ReasonCode; /* 0x01 */
- U8 PhysicalPort; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 DiscoveryStatus; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_DISCOVERY,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY,
- Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t;
-
-/* SAS Discovery Event data Flags values */
-#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02)
-#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01)
-
-/* SAS Discovery Event data ReasonCode values */
-#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01)
-#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02)
-
-/* SAS Discovery Event data DiscoveryStatus values */
-#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
-#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000)
-#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000)
-#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000)
-#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000)
-#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
-#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000)
-#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000)
-#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000)
-#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800)
-#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400)
-#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200)
-#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100)
-#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080)
-#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040)
-#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020)
-#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010)
-#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004)
-#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002)
-#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001)
-
-
-/* SAS Broadcast Primitive Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE
-{
- U8 PhyNum; /* 0x00 */
- U8 Port; /* 0x01 */
- U8 PortWidth; /* 0x02 */
- U8 Primitive; /* 0x03 */
-} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
- Mpi2EventDataSasBroadcastPrimitive_t,
- MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t;
-
-/* defines for the Primitive field */
-#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01)
-#define MPI2_EVENT_PRIMITIVE_SES (0x02)
-#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03)
-#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04)
-#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05)
-#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06)
-#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07)
-#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08)
-
-/* SAS Notify Primitive Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE {
- U8 PhyNum; /* 0x00 */
- U8 Port; /* 0x01 */
- U8 Reserved1; /* 0x02 */
- U8 Primitive; /* 0x03 */
-} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE,
-MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE,
-Mpi2EventDataSasNotifyPrimitive_t,
-MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t;
-
-/* defines for the Primitive field */
-#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01)
-#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02)
-#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03)
-#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04)
-
-
-/* SAS Initiator Device Status Change Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE
-{
- U8 ReasonCode; /* 0x00 */
- U8 PhysicalPort; /* 0x01 */
- U16 DevHandle; /* 0x02 */
- U64 SASAddress; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
- Mpi2EventDataSasInitDevStatusChange_t,
- MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t;
-
-/* SAS Initiator Device Status Change event ReasonCode values */
-#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01)
-#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02)
-
-
-/* SAS Initiator Device Table Overflow Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
-{
- U16 MaxInit; /* 0x00 */
- U16 CurrentInit; /* 0x02 */
- U64 SASAddress; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
- Mpi2EventDataSasInitTableOverflow_t,
- MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t;
-
-
-/* SAS Topology Change List Event data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumEntries at runtime.
- */
-#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT
-#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1)
-#endif
-
-typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY
-{
- U16 AttachedDevHandle; /* 0x00 */
- U8 LinkRate; /* 0x02 */
- U8 PhyStatus; /* 0x03 */
-} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY,
- Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t;
-
-typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
-{
- U16 EnclosureHandle; /* 0x00 */
- U16 ExpanderDevHandle; /* 0x02 */
- U8 NumPhys; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U8 NumEntries; /* 0x08 */
- U8 StartPhyNum; /* 0x09 */
- U8 ExpStatus; /* 0x0A */
- U8 PhysicalPort; /* 0x0B */
- MPI2_EVENT_SAS_TOPO_PHY_ENTRY PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/
-} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
- Mpi2EventDataSasTopologyChangeList_t,
- MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t;
-
-/* values for the ExpStatus field */
-#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00)
-#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01)
-#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02)
-#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03)
-#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04)
-
-/* defines for the LinkRate field */
-#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0)
-#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4)
-#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F)
-#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0)
-
-#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00)
-#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01)
-#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02)
-#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03)
-#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04)
-#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05)
-#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06)
-#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08)
-#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
-#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
-
-/* values for the PhyStatus field */
-#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80)
-#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10)
-/* values for the PhyStatus ReasonCode sub-field */
-#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F)
-#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01)
-#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02)
-#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03)
-#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04)
-#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05)
-
-
-/* SAS Enclosure Device Status Change Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE
-{
- U16 EnclosureHandle; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 PhysicalPort; /* 0x03 */
- U64 EnclosureLogicalID; /* 0x04 */
- U16 NumSlots; /* 0x0C */
- U16 StartSlot; /* 0x0E */
- U32 PhyBits; /* 0x10 */
-} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
- Mpi2EventDataSasEnclDevStatusChange_t,
- MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t;
-
-/* SAS Enclosure Device Status Change event ReasonCode values */
-#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01)
-#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
- * */
-
-
-/* SAS Quiesce Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE {
- U8 ReasonCode; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Reserved3; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_QUIESCE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
- Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
-
-/* SAS Quiesce Event data ReasonCode values */
-#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01)
-#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02)
-
-
-/* Host Based Discovery Phy Event data */
-
-typedef struct _MPI2_EVENT_HBD_PHY_SAS {
- U8 Flags; /* 0x00 */
- U8 NegotiatedLinkRate; /* 0x01 */
- U8 PhyNum; /* 0x02 */
- U8 PhysicalPort; /* 0x03 */
- U32 Reserved1; /* 0x04 */
- U8 InitialFrame[28]; /* 0x08 */
-} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS,
- Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t;
-
-/* values for the Flags field */
-#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02)
-#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01)
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for
- * the NegotiatedLinkRate field */
-
-typedef union _MPI2_EVENT_HBD_DESCRIPTOR {
- MPI2_EVENT_HBD_PHY_SAS Sas;
-} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR,
- Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t;
-
-typedef struct _MPI2_EVENT_DATA_HBD_PHY {
- U8 DescriptorType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Reserved3; /* 0x04 */
- MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */
-} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY,
- Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t;
-
-/* values for the DescriptorType field */
-#define MPI2_EVENT_HBD_DT_SAS (0x01)
-
-
-
-/****************************************************************************
-* EventAck message
-****************************************************************************/
-
-/* EventAck Request message */
-typedef struct _MPI2_EVENT_ACK_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- 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 */
- U16 Event; /* 0x0C */
- U16 Reserved5; /* 0x0E */
- U32 EventContext; /* 0x10 */
-} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST,
- Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t;
-
-
-/* EventAck Reply message */
-typedef struct _MPI2_EVENT_ACK_REPLY
-{
- U16 Reserved1; /* 0x00 */
- 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 */
-} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY,
- Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t;
-
-
-/****************************************************************************
-* SendHostMessage message
-****************************************************************************/
-
-/* SendHostMessage Request message */
-typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST {
- U16 HostDataLength; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U8 Reserved4; /* 0x0C */
- U8 DestVF_ID; /* 0x0D */
- U16 Reserved5; /* 0x0E */
- U32 Reserved6; /* 0x10 */
- U32 Reserved7; /* 0x14 */
- U32 Reserved8; /* 0x18 */
- U32 Reserved9; /* 0x1C */
- U32 Reserved10; /* 0x20 */
- U32 HostData[1]; /* 0x24 */
-} MPI2_SEND_HOST_MESSAGE_REQUEST,
-MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST,
-Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t;
-
-
-/* SendHostMessage Reply message */
-typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY {
- U16 HostDataLength; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY,
-Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t;
-
-
-/****************************************************************************
-* FWDownload message
-****************************************************************************/
-
-/* FWDownload Request message */
-typedef struct _MPI2_FW_DOWNLOAD_REQUEST
-{
- U8 ImageType; /* 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 TotalImageSize; /* 0x0C */
- U32 Reserved5; /* 0x10 */
- MPI2_MPI_SGE_UNION SGL; /* 0x14 */
-} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST,
- Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest;
-
-#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01)
-
-#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01)
-#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02)
-#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06)
-#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07)
-#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08)
-#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09)
-#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A)
-#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
-#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C)
-#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
-
-/* FWDownload TransactionContext Element */
-typedef struct _MPI2_FW_DOWNLOAD_TCSGE
-{
- U8 Reserved1; /* 0x00 */
- U8 ContextSize; /* 0x01 */
- U8 DetailsLength; /* 0x02 */
- U8 Flags; /* 0x03 */
- U32 Reserved2; /* 0x04 */
- U32 ImageOffset; /* 0x08 */
- U32 ImageSize; /* 0x0C */
-} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE,
- Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t;
-
-/* FWDownload Reply message */
-typedef struct _MPI2_FW_DOWNLOAD_REPLY
-{
- U8 ImageType; /* 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 */
-} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY,
- Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t;
-
-
-/****************************************************************************
-* FWUpload message
-****************************************************************************/
-
-/* FWUpload Request message */
-typedef struct _MPI2_FW_UPLOAD_REQUEST
-{
- U8 ImageType; /* 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 */
- MPI2_MPI_SGE_UNION SGL; /* 0x14 */
-} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST,
- Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t;
-
-#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00)
-#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01)
-#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02)
-#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05)
-#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06)
-#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07)
-#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08)
-#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09)
-#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
-#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
-
-typedef struct _MPI2_FW_UPLOAD_TCSGE
-{
- U8 Reserved1; /* 0x00 */
- U8 ContextSize; /* 0x01 */
- U8 DetailsLength; /* 0x02 */
- U8 Flags; /* 0x03 */
- U32 Reserved2; /* 0x04 */
- U32 ImageOffset; /* 0x08 */
- U32 ImageSize; /* 0x0C */
-} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE,
- Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t;
-
-/* FWUpload Reply message */
-typedef struct _MPI2_FW_UPLOAD_REPLY
-{
- U8 ImageType; /* 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 ActualImageSize; /* 0x14 */
-} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY,
- Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t;
-
-
-/* FW Image Header */
-typedef struct _MPI2_FW_IMAGE_HEADER
-{
- U32 Signature; /* 0x00 */
- U32 Signature0; /* 0x04 */
- U32 Signature1; /* 0x08 */
- U32 Signature2; /* 0x0C */
- MPI2_VERSION_UNION MPIVersion; /* 0x10 */
- MPI2_VERSION_UNION FWVersion; /* 0x14 */
- MPI2_VERSION_UNION NVDATAVersion; /* 0x18 */
- MPI2_VERSION_UNION PackageVersion; /* 0x1C */
- U16 VendorID; /* 0x20 */
- U16 ProductID; /* 0x22 */
- U16 ProtocolFlags; /* 0x24 */
- U16 Reserved26; /* 0x26 */
- U32 IOCCapabilities; /* 0x28 */
- U32 ImageSize; /* 0x2C */
- U32 NextImageHeaderOffset; /* 0x30 */
- U32 Checksum; /* 0x34 */
- U32 Reserved38; /* 0x38 */
- U32 Reserved3C; /* 0x3C */
- U32 Reserved40; /* 0x40 */
- U32 Reserved44; /* 0x44 */
- U32 Reserved48; /* 0x48 */
- U32 Reserved4C; /* 0x4C */
- U32 Reserved50; /* 0x50 */
- U32 Reserved54; /* 0x54 */
- U32 Reserved58; /* 0x58 */
- U32 Reserved5C; /* 0x5C */
- U32 Reserved60; /* 0x60 */
- U32 FirmwareVersionNameWhat; /* 0x64 */
- U8 FirmwareVersionName[32]; /* 0x68 */
- U32 VendorNameWhat; /* 0x88 */
- U8 VendorName[32]; /* 0x8C */
- U32 PackageNameWhat; /* 0x88 */
- U8 PackageName[32]; /* 0x8C */
- U32 ReservedD0; /* 0xD0 */
- U32 ReservedD4; /* 0xD4 */
- U32 ReservedD8; /* 0xD8 */
- U32 ReservedDC; /* 0xDC */
- U32 ReservedE0; /* 0xE0 */
- U32 ReservedE4; /* 0xE4 */
- U32 ReservedE8; /* 0xE8 */
- U32 ReservedEC; /* 0xEC */
- U32 ReservedF0; /* 0xF0 */
- U32 ReservedF4; /* 0xF4 */
- U32 ReservedF8; /* 0xF8 */
- U32 ReservedFC; /* 0xFC */
-} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER,
- Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t;
-
-/* Signature field */
-#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00)
-#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000)
-#define MPI2_FW_HEADER_SIGNATURE (0xEA000000)
-
-/* Signature0 field */
-#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04)
-#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A)
-
-/* Signature1 field */
-#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08)
-#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5)
-
-/* Signature2 field */
-#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C)
-#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA)
-
-
-/* defines for using the ProductID field */
-#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000)
-#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000)
-
-#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
-#define MPI2_FW_HEADER_PID_PROD_A (0x0000)
-#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200)
-#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700)
-
-
-#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF)
-/* SAS */
-#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013)
-#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014)
-
-/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
-
-/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */
-
-
-#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C)
-#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30)
-#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64)
-
-#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840)
-
-#define MPI2_FW_HEADER_SIZE (0x100)
-
-
-/* Extended Image Header */
-typedef struct _MPI2_EXT_IMAGE_HEADER
-
-{
- U8 ImageType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Checksum; /* 0x04 */
- U32 ImageSize; /* 0x08 */
- U32 NextImageHeaderOffset; /* 0x0C */
- U32 PackageVersion; /* 0x10 */
- U32 Reserved3; /* 0x14 */
- U32 Reserved4; /* 0x18 */
- U32 Reserved5; /* 0x1C */
- U8 IdentifyString[32]; /* 0x20 */
-} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER,
- Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t;
-
-/* useful offsets */
-#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00)
-#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08)
-#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C)
-
-#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40)
-
-/* defines for the ImageType field */
-#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00)
-#define MPI2_EXT_IMAGE_TYPE_FW (0x01)
-#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03)
-#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04)
-#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05)
-#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06)
-#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07)
-#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08)
-#define MPI2_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09)
-#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80)
-#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF)
-#define MPI2_EXT_IMAGE_TYPE_MAX \
- (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */
-
-
-
-/* FLASH Layout Extended Image Data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check RegionsPerLayout at runtime.
- */
-#ifndef MPI2_FLASH_NUMBER_OF_REGIONS
-#define MPI2_FLASH_NUMBER_OF_REGIONS (1)
-#endif
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumberOfLayouts at runtime.
- */
-#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS
-#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1)
-#endif
-
-typedef struct _MPI2_FLASH_REGION
-{
- U8 RegionType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 RegionOffset; /* 0x04 */
- U32 RegionSize; /* 0x08 */
- U32 Reserved3; /* 0x0C */
-} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION,
- Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t;
-
-typedef struct _MPI2_FLASH_LAYOUT
-{
- U32 FlashSize; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U32 Reserved3; /* 0x0C */
- MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */
-} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT,
- Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t;
-
-typedef struct _MPI2_FLASH_LAYOUT_DATA
-{
- U8 ImageRevision; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 SizeOfRegion; /* 0x02 */
- U8 Reserved2; /* 0x03 */
- U16 NumberOfLayouts; /* 0x04 */
- U16 RegionsPerLayout; /* 0x06 */
- U16 MinimumSectorAlignment; /* 0x08 */
- U16 Reserved3; /* 0x0A */
- U32 Reserved4; /* 0x0C */
- MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */
-} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA,
- Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t;
-
-/* defines for the RegionType field */
-#define MPI2_FLASH_REGION_UNUSED (0x00)
-#define MPI2_FLASH_REGION_FIRMWARE (0x01)
-#define MPI2_FLASH_REGION_BIOS (0x02)
-#define MPI2_FLASH_REGION_NVDATA (0x03)
-#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05)
-#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06)
-#define MPI2_FLASH_REGION_CONFIG_1 (0x07)
-#define MPI2_FLASH_REGION_CONFIG_2 (0x08)
-#define MPI2_FLASH_REGION_MEGARAID (0x09)
-#define MPI2_FLASH_REGION_INIT (0x0A)
-
-/* ImageRevision */
-#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
-
-
-
-/* Supported Devices Extended Image Data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumberOfDevices at runtime.
- */
-#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES
-#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1)
-#endif
-
-typedef struct _MPI2_SUPPORTED_DEVICE
-{
- U16 DeviceID; /* 0x00 */
- U16 VendorID; /* 0x02 */
- U16 DeviceIDMask; /* 0x04 */
- U16 Reserved1; /* 0x06 */
- U8 LowPCIRev; /* 0x08 */
- U8 HighPCIRev; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 Reserved3; /* 0x0C */
-} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE,
- Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t;
-
-typedef struct _MPI2_SUPPORTED_DEVICES_DATA
-{
- U8 ImageRevision; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 NumberOfDevices; /* 0x02 */
- U8 Reserved2; /* 0x03 */
- U32 Reserved3; /* 0x04 */
- MPI2_SUPPORTED_DEVICE SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */
-} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA,
- Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t;
-
-/* ImageRevision */
-#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00)
-
-
-/* Init Extended Image Data */
-
-typedef struct _MPI2_INIT_IMAGE_FOOTER
-
-{
- U32 BootFlags; /* 0x00 */
- U32 ImageSize; /* 0x04 */
- U32 Signature0; /* 0x08 */
- U32 Signature1; /* 0x0C */
- U32 Signature2; /* 0x10 */
- U32 ResetVector; /* 0x14 */
-} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER,
- Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t;
-
-/* defines for the BootFlags field */
-#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00)
-
-/* defines for the ImageSize field */
-#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04)
-
-/* defines for the Signature0 field */
-#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08)
-#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA)
-
-/* defines for the Signature1 field */
-#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C)
-#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5)
-
-/* defines for the Signature2 field */
-#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10)
-#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A)
-
-/* Signature fields as individual bytes */
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A)
-
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5)
-
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A)
-
-/* defines for the ResetVector field */
-#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14)
-
-
-/* Encrypted Hash Extended Image Data */
-
-typedef struct _MPI25_ENCRYPTED_HASH_ENTRY {
- U8 HashImageType; /* 0x00 */
- U8 HashAlgorithm; /* 0x01 */
- U8 EncryptionAlgorithm; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 Reserved2; /* 0x04 */
- U32 EncryptedHash[1]; /* 0x08 */
-} MPI25_ENCRYPTED_HASH_ENTRY, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_ENTRY,
-Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t;
-
-/* values for HashImageType */
-#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00)
-#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01)
-#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02)
-
-/* values for HashAlgorithm */
-#define MPI25_HASH_ALGORITHM_UNUSED (0x00)
-#define MPI25_HASH_ALGORITHM_SHA256 (0x01)
-
-/* values for EncryptionAlgorithm */
-#define MPI25_ENCRYPTION_ALG_UNUSED (0x00)
-#define MPI25_ENCRYPTION_ALG_RSA256 (0x01)
-
-typedef struct _MPI25_ENCRYPTED_HASH_DATA {
- U8 ImageVersion; /* 0x00 */
- U8 NumHash; /* 0x01 */
- U16 Reserved1; /* 0x02 */
- U32 Reserved2; /* 0x04 */
- MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */
-} MPI25_ENCRYPTED_HASH_DATA, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_DATA,
-Mpi25EncryptedHashData_t, MPI2_POINTER pMpi25EncryptedHashData_t;
-
-/****************************************************************************
-* PowerManagementControl message
-****************************************************************************/
-
-/* PowerManagementControl Request message */
-typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST {
- U8 Feature; /* 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 Parameter1; /* 0x0C */
- U8 Parameter2; /* 0x0D */
- U8 Parameter3; /* 0x0E */
- U8 Parameter4; /* 0x0F */
- U32 Reserved5; /* 0x10 */
- U32 Reserved6; /* 0x14 */
-} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
- Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
-
-/* defines for the Feature field */
-#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01)
-#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02)
-#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */
-#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04)
-#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80)
-#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF)
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
-/* Parameter1 contains a PHY number */
-/* Parameter2 indicates power condition action using these defines */
-#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01)
-#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02)
-#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03)
-/* Parameter3 and Parameter4 are reserved */
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION
- * Feature */
-/* Parameter1 contains SAS port width modulation group number */
-/* Parameter2 indicates IOC action using these defines */
-#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01)
-#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02)
-#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03)
-/* Parameter3 indicates desired modulation level using these defines */
-#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00)
-#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01)
-#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02)
-#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03)
-/* Parameter4 is reserved */
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
-/* Parameter1 indicates desired PCIe link speed using these defines */
-#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */
-/* Parameter2 indicates desired PCIe link width using these defines */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */
-/* Parameter3 and Parameter4 are reserved */
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
-/* Parameter1 indicates desired IOC hardware clock speed using these defines */
-#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01)
-#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02)
-#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04)
-#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08)
-/* Parameter2, Parameter3, and Parameter4 are reserved */
-
-
-/* PowerManagementControl Reply message */
-typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY {
- U8 Feature; /* 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 */
-} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
- Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
deleted file mode 100644
index 7efa58f..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_raid.h
- * Title: MPI Integrated RAID messages and structures
- * Creation Date: April 26, 2007
- *
- * mpi2_raid.h Version: 02.00.10
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 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.
- * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
- * VolumeCreationFlags and marked the old one as obsolete.
- * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
- * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with
- * related structures and defines.
- * Added product-specific range to RAID Action values.
- * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN.
- * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
- * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
- * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_RAID_H
-#define MPI2_RAID_H
-
-/*****************************************************************************
-*
-* Integrated RAID Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* RAID Action messages
-****************************************************************************/
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */
-#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000)
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */
-#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000)
-#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001)
-
-/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */
-#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001)
-
-/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */
-typedef struct _MPI2_RAID_ACTION_RATE_DATA
-{
- U8 RateToChange; /* 0x00 */
- U8 RateOrMode; /* 0x01 */
- U16 DataScrubDuration; /* 0x02 */
-} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA,
- Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t;
-
-#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00)
-#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01)
-#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02)
-
-/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */
-typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION
-{
- U8 RAIDFunction; /* 0x00 */
- U8 Flags; /* 0x01 */
- U16 Reserved1; /* 0x02 */
-} MPI2_RAID_ACTION_START_RAID_FUNCTION,
- MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION,
- Mpi2RaidActionStartRaidFunction_t,
- MPI2_POINTER pMpi2RaidActionStartRaidFunction_t;
-
-/* defines for the RAIDFunction field */
-#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00)
-#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01)
-#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02)
-
-/* defines for the Flags field */
-#define MPI2_RAID_ACTION_START_NEW (0x00)
-#define MPI2_RAID_ACTION_START_RESUME (0x01)
-
-/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */
-typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION
-{
- U8 RAIDFunction; /* 0x00 */
- U8 Flags; /* 0x01 */
- U16 Reserved1; /* 0x02 */
-} MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
- MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
- Mpi2RaidActionStopRaidFunction_t,
- MPI2_POINTER pMpi2RaidActionStopRaidFunction_t;
-
-/* defines for the RAIDFunction field */
-#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00)
-#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01)
-#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02)
-
-/* defines for the Flags field */
-#define MPI2_RAID_ACTION_STOP_ABORT (0x00)
-#define MPI2_RAID_ACTION_STOP_PAUSE (0x01)
-
-/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */
-typedef struct _MPI2_RAID_ACTION_HOT_SPARE
-{
- U8 HotSparePool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 DevHandle; /* 0x02 */
-} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE,
- Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t;
-
-/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */
-typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE
-{
- U8 Flags; /* 0x00 */
- U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */
- U16 Reserved1; /* 0x02 */
-} MPI2_RAID_ACTION_FW_UPDATE_MODE,
- MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE,
- Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t;
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */
-#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00)
-#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01)
-
-typedef union _MPI2_RAID_ACTION_DATA
-{
- U32 Word;
- MPI2_RAID_ACTION_RATE_DATA Rates;
- MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction;
- MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction;
- MPI2_RAID_ACTION_HOT_SPARE HotSpare;
- MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode;
-} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA,
- Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t;
-
-
-/* RAID Action Request Message */
-typedef struct _MPI2_RAID_ACTION_REQUEST
-{
- U8 Action; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 VolDevHandle; /* 0x04 */
- U8 PhysDiskNum; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 Reserved3; /* 0x0C */
- MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */
- MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */
-} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST,
- Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t;
-
-/* RAID Action request Action values */
-
-#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01)
-#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02)
-#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03)
-#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04)
-#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05)
-#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A)
-#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B)
-#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F)
-#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11)
-#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15)
-#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17)
-#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18)
-#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19)
-#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C)
-#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D)
-#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E)
-#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20)
-#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21)
-#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22)
-#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23)
-#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24)
-#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80)
-#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF)
-
-/* RAID Volume Creation Structure */
-
-/*
- * The following define can be customized for the targeted product.
- */
-#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS
-#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1)
-#endif
-
-typedef struct _MPI2_RAID_VOLUME_PHYSDISK
-{
- U8 RAIDSetNum; /* 0x00 */
- U8 PhysDiskMap; /* 0x01 */
- U16 PhysDiskDevHandle; /* 0x02 */
-} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK,
- Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t;
-
-/* defines for the PhysDiskMap field */
-#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01)
-#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02)
-
-typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT
-{
- U8 NumPhysDisks; /* 0x00 */
- U8 VolumeType; /* 0x01 */
- U16 Reserved1; /* 0x02 */
- U32 VolumeCreationFlags; /* 0x04 */
- U32 VolumeSettings; /* 0x08 */
- U8 Reserved2; /* 0x0C */
- U8 ResyncRate; /* 0x0D */
- U16 DataScrubDuration; /* 0x0E */
- U64 VolumeMaxLBA; /* 0x10 */
- U32 StripeSize; /* 0x18 */
- U8 Name[16]; /* 0x1C */
- MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */
-} MPI2_RAID_VOLUME_CREATION_STRUCT,
- MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT,
- Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t;
-
-/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */
-
-/* defines for the VolumeCreationFlags field */
-#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000)
-#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004)
-#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002)
-#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001)
-/* The following is an obsolete define.
- * It must be shifted left 24 bits in order to set the proper bit.
- */
-#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
-
-
-/* RAID Online Capacity Expansion Structure */
-
-typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION
-{
- U32 Flags; /* 0x00 */
- U16 DevHandle0; /* 0x04 */
- U16 Reserved1; /* 0x06 */
- U16 DevHandle1; /* 0x08 */
- U16 Reserved2; /* 0x0A */
-} MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
- MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
- Mpi2RaidOnlineCapacityExpansion_t,
- MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t;
-
-/* RAID Compatibility Input Structure */
-
-typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT {
- U16 SourceDevHandle; /* 0x00 */
- U16 CandidateDevHandle; /* 0x02 */
- U32 Flags; /* 0x04 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
-} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT,
-MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT,
-Mpi2RaidCompatibilityInputStruct_t,
-MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t;
-
-/* defines for RAID Compatibility Structure Flags field */
-#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002)
-#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001)
-
-
-/* RAID Volume Indicator Structure */
-
-typedef struct _MPI2_RAID_VOL_INDICATOR
-{
- U64 TotalBlocks; /* 0x00 */
- U64 BlocksRemaining; /* 0x08 */
- U32 Flags; /* 0x10 */
- U32 ElapsedSeconds; /* 0x14 */
-} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR,
- Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t;
-
-/* defines for RAID Volume Indicator Flags field */
-#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID (0x80000000)
-
-#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F)
-#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000)
-#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
-#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002)
-#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003)
-#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004)
-
-/* RAID Compatibility Result Structure */
-
-typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT {
- U8 State; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 GenericAttributes; /* 0x04 */
- U32 OEMSpecificAttributes; /* 0x08 */
- U32 Reserved3; /* 0x0C */
- U32 Reserved4; /* 0x10 */
-} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT,
-MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT,
-Mpi2RaidCompatibilityResultStruct_t,
-MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t;
-
-/* defines for RAID Compatibility Result Structure State field */
-#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00)
-#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01)
-
-/* defines for RAID Compatibility Result Structure GenericAttributes field */
-#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010)
-
-#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C)
-#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008)
-#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004)
-
-#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003)
-#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002)
-#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001)
-
-/* RAID Action Reply ActionData union */
-typedef union _MPI2_RAID_ACTION_REPLY_DATA
-{
- U32 Word[6];
- MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
- U16 VolDevHandle;
- U8 VolumeState;
- U8 PhysDiskNum;
- MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult;
-} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA,
- Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t;
-
-/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
-
-
-/* RAID Action Reply Message */
-typedef struct _MPI2_RAID_ACTION_REPLY
-{
- U8 Action; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 VolDevHandle; /* 0x04 */
- U8 PhysDiskNum; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */
-} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY,
- Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t;
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
deleted file mode 100644
index 45b6fa1..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_sas.h
- * Title: MPI Serial Attached SCSI structures and definitions
- * Creation Date: February 9, 2007
- *
- * mpi2_sas.h Version: 02.00.05
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 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.
- * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
- * to MPI2_SGE_IO_UNION since it supports chained SGLs.
- * 05-12-10 02.00.04 Modified some comments.
- * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_SAS_H
-#define MPI2_SAS_H
-
-/*
- * Values for SASStatus.
- */
-#define MPI2_SASSTATUS_SUCCESS (0x00)
-#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01)
-#define MPI2_SASSTATUS_INVALID_FRAME (0x02)
-#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03)
-#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04)
-#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05)
-#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06)
-#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07)
-#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08)
-#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09)
-#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A)
-#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B)
-#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C)
-#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D)
-#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E)
-#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F)
-#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10)
-#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11)
-#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12)
-#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13)
-#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14)
-
-
-/*
- * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
- * data and SAS Configuration pages.
- */
-#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000)
-#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000)
-#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000)
-#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800)
-#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400)
-#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200)
-#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100)
-#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080)
-#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040)
-#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020)
-#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010)
-#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008)
-
-#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007)
-#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000)
-#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001)
-#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002)
-#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003)
-
-
-/*****************************************************************************
-*
-* SAS Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* SMP Passthrough messages
-****************************************************************************/
-
-/* SMP Passthrough Request Message */
-typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST
-{
- U8 PassthroughFlags; /* 0x00 */
- U8 PhysicalPort; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 RequestDataLength; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Reserved2; /* 0x0C */
- U64 SASAddress; /* 0x10 */
- U32 Reserved3; /* 0x18 */
- U32 Reserved4; /* 0x1C */
- MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */
-} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST,
- Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t;
-
-/* values for PassthroughFlags field */
-#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* SMP Passthrough Reply Message */
-typedef struct _MPI2_SMP_PASSTHROUGH_REPLY
-{
- U8 PassthroughFlags; /* 0x00 */
- U8 PhysicalPort; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 ResponseDataLength; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U8 Reserved2; /* 0x0C */
- U8 SASStatus; /* 0x0D */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 Reserved3; /* 0x14 */
- U8 ResponseData[4]; /* 0x18 */
-} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY,
- Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t;
-
-/* values for PassthroughFlags field */
-#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80)
-
-/* values for SASStatus field are at the top of this file */
-
-
-/****************************************************************************
-* SATA Passthrough messages
-****************************************************************************/
-
-/* SATA Passthrough Request Message */
-typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 PassthroughFlags; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Reserved2; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U32 Reserved4; /* 0x14 */
- U32 DataLength; /* 0x18 */
- U8 CommandFIS[20]; /* 0x1C */
- MPI2_SGE_IO_UNION SGL; /* 0x30 */
-} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
- Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
-
-/* values for PassthroughFlags field */
-#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* SATA Passthrough Reply Message */
-typedef struct _MPI2_SATA_PASSTHROUGH_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 PassthroughFlags; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U8 Reserved2; /* 0x0C */
- U8 SASStatus; /* 0x0D */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U8 StatusFIS[20]; /* 0x14 */
- U32 StatusControlRegisters; /* 0x28 */
- U32 TransferCount; /* 0x2C */
-} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY,
- Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t;
-
-/* values for SASStatus field are at the top of this file */
-
-
-/****************************************************************************
-* SAS IO Unit Control messages
-****************************************************************************/
-
-/* SAS IO Unit Control Request Message */
-typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST
-{
- U8 Operation; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 DevHandle; /* 0x04 */
- U8 IOCParameter; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U8 PhyNum; /* 0x0E */
- U8 PrimFlags; /* 0x0F */
- U32 Primitive; /* 0x10 */
- U8 LookupMethod; /* 0x14 */
- U8 Reserved5; /* 0x15 */
- U16 SlotNumber; /* 0x16 */
- U64 LookupAddress; /* 0x18 */
- U32 IOCParameterValue; /* 0x20 */
- U32 Reserved7; /* 0x24 */
- U32 Reserved8; /* 0x28 */
-} MPI2_SAS_IOUNIT_CONTROL_REQUEST,
- MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST,
- Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t;
-
-/* values for the Operation field */
-#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02)
-#define MPI2_SAS_OP_PHY_LINK_RESET (0x06)
-#define MPI2_SAS_OP_PHY_HARD_RESET (0x07)
-#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08)
-#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A)
-#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B)
-#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
-#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D)
-#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E)
-#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F)
-#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14)
-#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15)
-#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
-
-/* values for the PrimFlags field */
-#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08)
-#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02)
-#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01)
-
-/* values for the LookupMethod field */
-#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01)
-#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02)
-#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03)
-
-
-/* SAS IO Unit Control Reply Message */
-typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY
-{
- U8 Operation; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 DevHandle; /* 0x04 */
- U8 IOCParameter; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_SAS_IOUNIT_CONTROL_REPLY,
- MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY,
- Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t;
-
-
-#endif
-
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
deleted file mode 100644
index 659b8ac..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_tool.h
- * Title: MPI diagnostic tool structures and definitions
- * Creation Date: March 26, 2007
- *
- * mpi2_tool.h Version: 02.00.12
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 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.
- * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
- * and reply messages.
- * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
- * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
- * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
- * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer
- * Post Request.
- * 05-25-11 02.00.07 Added Flags field and related defines to
- * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST.
- * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
- * it uses MPI Chain SGE as well as MPI Simple SGE.
- * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
- * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_TOOL_H
-#define MPI2_TOOL_H
-
-/*****************************************************************************
-*
-* Toolbox Messages
-*
-*****************************************************************************/
-
-/* defines for the Tools */
-#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
-#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
-#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02)
-#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
-#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
-#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
-#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07)
-
-
-/****************************************************************************
-* Toolbox reply
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_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 */
-} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY,
- Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t;
-
-
-/****************************************************************************
-* Toolbox Clean Tool request
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_CLEAN_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 Flags; /* 0x0C */
- } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST,
- Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t;
-
-/* values for the Flags field */
-#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000)
-#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000)
-#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000)
-#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000)
-#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000)
-#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000)
-#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000)
-#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000)
-#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004)
-#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002)
-#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001)
-
-
-/****************************************************************************
-* Toolbox Memory Move request
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_MEM_MOVE_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 */
- MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */
-} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST,
- Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t;
-
-
-/****************************************************************************
-* Toolbox Diagnostic Data Upload request
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_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 Flags; /* 0x10 */
- U32 DataLength; /* 0x14 */
- MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */
-} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
-MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
-Mpi2ToolboxDiagDataUploadRequest_t,
-MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER {
- U32 DiagDataLength; /* 00h */
- U8 FormatCode; /* 04h */
- U8 Reserved1; /* 05h */
- U16 Reserved2; /* 06h */
-} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
-Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
-
-
-/****************************************************************************
-* 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 Flags; /* 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)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-/* values for the Flags field */
-#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80)
-#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07)
-
-/* 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
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_BEACON_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 Reserved5; /* 0x0C */
- U8 PhysicalPort; /* 0x0D */
- U8 Reserved6; /* 0x0E */
- U8 Flags; /* 0x0F */
-} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST,
- Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t;
-
-/* values for the Flags field */
-#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00)
-#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01)
-
-
-/****************************************************************************
-* Toolbox Diagnostic CLI Tool
-****************************************************************************/
-
-#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C)
-
-/* MPI v2.0 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_MPI_SGE_IO_UNION SGL; /* 0x70 */
-} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
- MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
- Mpi2ToolboxDiagnosticCliRequest_t,
- MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* 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;
-
-
-/****************************************************************************
-* Toolbox Console Text Display Tool
-****************************************************************************/
-
-/* Toolbox Console Text Display Tool request message */
-typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_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 Console; /* 0x0C */
- U8 Flags; /* 0x0D */
- U16 Reserved6; /* 0x0E */
- U8 TextToDisplay[4]; /* 0x10 */
-} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST,
-MPI2_POINTER PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST,
-Mpi2ToolboxTextDisplayRequest_t,
-MPI2_POINTER pMpi2ToolboxTextDisplayRequest_t;
-
-/* defines for the Console field */
-#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0)
-#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00)
-#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10)
-#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20)
-
-#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F)
-
-/* defines for the Flags field */
-#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01)
-
-
-
-/*****************************************************************************
-*
-* Diagnostic Buffer Messages
-*
-*****************************************************************************/
-
-
-/****************************************************************************
-* Diagnostic Buffer Post request
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
-{
- U8 ExtendedType; /* 0x00 */
- U8 BufferType; /* 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 */
- U64 BufferAddress; /* 0x0C */
- U32 BufferLength; /* 0x14 */
- U32 Reserved5; /* 0x18 */
- U32 Reserved6; /* 0x1C */
- U32 Flags; /* 0x20 */
- U32 ProductSpecific[23]; /* 0x24 */
-} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST,
- Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t;
-
-/* values for the ExtendedType field */
-#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02)
-
-/* values for the BufferType field */
-#define MPI2_DIAG_BUF_TYPE_TRACE (0x00)
-#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01)
-#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02)
-/* count of the number of buffer types */
-#define MPI2_DIAG_BUF_TYPE_COUNT (0x03)
-
-/* values for the Flags field */
-#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002)
-#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001)
-
-
-/****************************************************************************
-* Diagnostic Buffer Post reply
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_BUFFER_POST_REPLY
-{
- U8 ExtendedType; /* 0x00 */
- U8 BufferType; /* 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 TransferLength; /* 0x14 */
-} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY,
- Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t;
-
-
-/****************************************************************************
-* Diagnostic Release request
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_RELEASE_REQUEST
-{
- U8 Reserved1; /* 0x00 */
- U8 BufferType; /* 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 */
-} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST,
- Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t;
-
-
-/****************************************************************************
-* Diagnostic Buffer Post reply
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_RELEASE_REPLY
-{
- U8 Reserved1; /* 0x00 */
- U8 BufferType; /* 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 */
-} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY,
- Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t;
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h
deleted file mode 100644
index 6b0dcdd..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_type.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_type.h
- * Title: MPI basic type definitions
- * Creation Date: August 16, 2006
- *
- * mpi2_type.h Version: 02.00.00
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_TYPE_H
-#define MPI2_TYPE_H
-
-
-/*******************************************************************************
- * Define MPI2_POINTER if it hasn't already been defined. By default
- * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as
- * a far pointer by defining MPI2_POINTER as "far *" before this header file is
- * included.
- */
-#ifndef MPI2_POINTER
-#define MPI2_POINTER *
-#endif
-
-/* the basic types may have already been included by mpi_type.h */
-#ifndef MPI_TYPE_H
-/*****************************************************************************
-*
-* Basic Types
-*
-*****************************************************************************/
-
-typedef u8 U8;
-typedef __le16 U16;
-typedef __le32 U32;
-typedef __le64 U64 __attribute__((aligned(4)));
-
-/*****************************************************************************
-*
-* Pointer Types
-*
-*****************************************************************************/
-
-typedef U8 *PU8;
-typedef U16 *PU16;
-typedef U32 *PU32;
-typedef U64 *PU64;
-
-#endif
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
deleted file mode 100644
index c167911..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ /dev/null
@@ -1,4899 +0,0 @@
-/*
- * This is the Fusion MPT base driver providing common API layer interface
- * for access to MPT (Message Passing Technology) firmware.
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/sort.h>
-#include <linux/io.h>
-#include <linux/time.h>
-#include <linux/kthread.h>
-#include <linux/aer.h>
-
-#include "mpt2sas_base.h"
-
-static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
-
-#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
-
-#define MAX_HBA_QUEUE_DEPTH 30000
-#define MAX_CHAIN_DEPTH 100000
-static int max_queue_depth = -1;
-module_param(max_queue_depth, int, 0);
-MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
-
-static int max_sgl_entries = -1;
-module_param(max_sgl_entries, int, 0);
-MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
-
-static int msix_disable = -1;
-module_param(msix_disable, int, 0);
-MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
-
-static int max_msix_vectors = -1;
-module_param(max_msix_vectors, int, 0);
-MODULE_PARM_DESC(max_msix_vectors, " max msix vectors ");
-
-static int mpt2sas_fwfault_debug;
-MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
- "and halt firmware - (default=0)");
-
-static int disable_discovery = -1;
-module_param(disable_discovery, int, 0);
-MODULE_PARM_DESC(disable_discovery, " disable discovery ");
-
-static int
-_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
-
-static int
-_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
-
-/**
- * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
- *
- */
-static int
-_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
-{
- int ret = param_set_int(val, kp);
- struct MPT2SAS_ADAPTER *ioc;
-
- if (ret)
- return ret;
-
- /* global ioc spinlock to protect controller list on list operations */
- printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug);
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
- ioc->fwfault_debug = mpt2sas_fwfault_debug;
- spin_unlock(&gioc_lock);
- return 0;
-}
-
-module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug,
- param_get_int, &mpt2sas_fwfault_debug, 0644);
-
-/**
- * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc
- * @arg: input argument, used to derive ioc
- *
- * Return 0 if controller is removed from pci subsystem.
- * Return -1 for other case.
- */
-static int mpt2sas_remove_dead_ioc_func(void *arg)
-{
- struct MPT2SAS_ADAPTER *ioc = (struct MPT2SAS_ADAPTER *)arg;
- struct pci_dev *pdev;
-
- if ((ioc == NULL))
- return -1;
-
- pdev = ioc->pdev;
- if ((pdev == NULL))
- return -1;
- pci_stop_and_remove_bus_device_locked(pdev);
- return 0;
-}
-
-
-/**
- * _base_fault_reset_work - workq handling ioc fault conditions
- * @work: input argument, used to derive ioc
- * Context: sleep.
- *
- * Return nothing.
- */
-static void
-_base_fault_reset_work(struct work_struct *work)
-{
- struct MPT2SAS_ADAPTER *ioc =
- container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work);
- unsigned long flags;
- u32 doorbell;
- int rc;
- struct task_struct *p;
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->shost_recovery || ioc->pci_error_recovery)
- goto rearm_timer;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-
- doorbell = mpt2sas_base_get_iocstate(ioc, 0);
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) {
- printk(MPT2SAS_INFO_FMT "%s : SAS host is non-operational !!!!\n",
- ioc->name, __func__);
-
- /* It may be possible that EEH recovery can resolve some of
- * pci bus failure issues rather removing the dead ioc function
- * by considering controller is in a non-operational state. So
- * here priority is given to the EEH recovery. If it doesn't
- * not resolve this issue, mpt2sas driver will consider this
- * controller to non-operational state and remove the dead ioc
- * function.
- */
- if (ioc->non_operational_loop++ < 5) {
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock,
- flags);
- goto rearm_timer;
- }
-
- /*
- * Call _scsih_flush_pending_cmds callback so that we flush all
- * pending commands back to OS. This call is required to aovid
- * deadlock at block layer. Dead IOC will fail to do diag reset,
- * and this call is safe since dead ioc will never return any
- * command back from HW.
- */
- ioc->schedule_dead_ioc_flush_running_cmds(ioc);
- /*
- * Set remove_host flag early since kernel thread will
- * take some time to execute.
- */
- ioc->remove_host = 1;
- /*Remove the Dead Host */
- p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc,
- "mpt2sas_dead_ioc_%d", ioc->id);
- if (IS_ERR(p)) {
- printk(MPT2SAS_ERR_FMT
- "%s: Running mpt2sas_dead_ioc thread failed !!!!\n",
- ioc->name, __func__);
- } else {
- printk(MPT2SAS_ERR_FMT
- "%s: Running mpt2sas_dead_ioc thread success !!!!\n",
- ioc->name, __func__);
- }
-
- return; /* don't rearm timer */
- }
-
- ioc->non_operational_loop = 0;
-
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name,
- __func__, (rc == 0) ? "success" : "failed");
- doorbell = mpt2sas_base_get_iocstate(ioc, 0);
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
- mpt2sas_base_fault_info(ioc, doorbell &
- MPI2_DOORBELL_DATA_MASK);
- }
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- rearm_timer:
- if (ioc->fault_reset_work_q)
- queue_delayed_work(ioc->fault_reset_work_q,
- &ioc->fault_reset_work,
- msecs_to_jiffies(FAULT_POLLING_INTERVAL));
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-}
-
-/**
- * mpt2sas_base_start_watchdog - start the fault_reset_work_q
- * @ioc: per adapter object
- * Context: sleep.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned long flags;
-
- if (ioc->fault_reset_work_q)
- return;
-
- /* initialize fault polling */
- INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
- snprintf(ioc->fault_reset_work_q_name,
- sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
- ioc->fault_reset_work_q =
- create_singlethread_workqueue(ioc->fault_reset_work_q_name);
- if (!ioc->fault_reset_work_q) {
- printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n",
- ioc->name, __func__, __LINE__);
- return;
- }
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->fault_reset_work_q)
- queue_delayed_work(ioc->fault_reset_work_q,
- &ioc->fault_reset_work,
- msecs_to_jiffies(FAULT_POLLING_INTERVAL));
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-}
-
-/**
- * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q
- * @ioc: per adapter object
- * Context: sleep.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned long flags;
- struct workqueue_struct *wq;
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- wq = ioc->fault_reset_work_q;
- ioc->fault_reset_work_q = NULL;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
- if (wq) {
- if (!cancel_delayed_work_sync(&ioc->fault_reset_work))
- flush_workqueue(wq);
- destroy_workqueue(wq);
- }
-}
-
-/**
- * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
- * @ioc: per adapter object
- * @fault_code: fault code
- *
- * Return nothing.
- */
-void
-mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
-{
- printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
- ioc->name, fault_code);
-}
-
-/**
- * mpt2sas_halt_firmware - halt's mpt controller firmware
- * @ioc: per adapter object
- *
- * For debugging timeout related issues. Writing 0xCOFFEE00
- * to the doorbell register will halt controller firmware. With
- * the purpose to stop both driver and firmware, the enduser can
- * obtain a ring buffer from controller UART.
- */
-void
-mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc)
-{
- u32 doorbell;
-
- if (!ioc->fwfault_debug)
- return;
-
- dump_stack();
-
- doorbell = readl(&ioc->chip->Doorbell);
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
- mpt2sas_base_fault_info(ioc , doorbell);
- else {
- writel(0xC0FFEE00, &ioc->chip->Doorbell);
- printk(MPT2SAS_ERR_FMT "Firmware is halted due to command "
- "timeout\n", ioc->name);
- }
-
- panic("panic in %s\n", __func__);
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _base_sas_ioc_info - verbose translation of the ioc status
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @request_hdr: request mf
- *
- * Return nothing.
- */
-static void
-_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
- MPI2RequestHeader_t *request_hdr)
-{
- u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- char *desc = NULL;
- u16 frame_sz;
- char *func_str = NULL;
-
- /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */
- if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
- request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
- return;
-
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- return;
-
- switch (ioc_status) {
-
-/****************************************************************************
-* Common IOCStatus values for all replies
-****************************************************************************/
-
- case MPI2_IOCSTATUS_INVALID_FUNCTION:
- desc = "invalid function";
- break;
- case MPI2_IOCSTATUS_BUSY:
- desc = "busy";
- break;
- case MPI2_IOCSTATUS_INVALID_SGL:
- desc = "invalid sgl";
- break;
- case MPI2_IOCSTATUS_INTERNAL_ERROR:
- desc = "internal error";
- break;
- case MPI2_IOCSTATUS_INVALID_VPID:
- desc = "invalid vpid";
- break;
- case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
- desc = "insufficient resources";
- break;
- case MPI2_IOCSTATUS_INVALID_FIELD:
- desc = "invalid field";
- break;
- case MPI2_IOCSTATUS_INVALID_STATE:
- desc = "invalid state";
- break;
- case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
- desc = "op state not supported";
- break;
-
-/****************************************************************************
-* Config IOCStatus values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION:
- desc = "config invalid action";
- break;
- case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE:
- desc = "config invalid type";
- break;
- case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE:
- desc = "config invalid page";
- break;
- case MPI2_IOCSTATUS_CONFIG_INVALID_DATA:
- desc = "config invalid data";
- break;
- case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS:
- desc = "config no defaults";
- break;
- case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT:
- desc = "config cant commit";
- break;
-
-/****************************************************************************
-* SCSI IO Reply
-****************************************************************************/
-
- case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
- case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
- case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
- case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
- case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
- case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
- case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
- case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
- case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
- case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
- case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
- break;
-
-/****************************************************************************
-* For use by SCSI Initiator and SCSI Target end-to-end data protection
-****************************************************************************/
-
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- desc = "eedp guard error";
- break;
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- desc = "eedp ref tag error";
- break;
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- desc = "eedp app tag error";
- break;
-
-/****************************************************************************
-* SCSI Target values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX:
- desc = "target invalid io index";
- break;
- case MPI2_IOCSTATUS_TARGET_ABORTED:
- desc = "target aborted";
- break;
- case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE:
- desc = "target no conn retryable";
- break;
- case MPI2_IOCSTATUS_TARGET_NO_CONNECTION:
- desc = "target no connection";
- break;
- case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH:
- desc = "target xfer count mismatch";
- break;
- case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR:
- desc = "target data offset error";
- break;
- case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA:
- desc = "target too much write data";
- break;
- case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT:
- desc = "target iu too short";
- break;
- case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT:
- desc = "target ack nak timeout";
- break;
- case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED:
- desc = "target nak received";
- break;
-
-/****************************************************************************
-* Serial Attached SCSI values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED:
- desc = "smp request failed";
- break;
- case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN:
- desc = "smp data overrun";
- break;
-
-/****************************************************************************
-* Diagnostic Buffer Post / Diagnostic Release values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED:
- desc = "diagnostic released";
- break;
- default:
- break;
- }
-
- if (!desc)
- return;
-
- switch (request_hdr->Function) {
- case MPI2_FUNCTION_CONFIG:
- frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size;
- func_str = "config_page";
- break;
- case MPI2_FUNCTION_SCSI_TASK_MGMT:
- frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t);
- func_str = "task_mgmt";
- break;
- case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
- frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t);
- func_str = "sas_iounit_ctl";
- break;
- case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
- frame_sz = sizeof(Mpi2SepRequest_t);
- func_str = "enclosure";
- break;
- case MPI2_FUNCTION_IOC_INIT:
- frame_sz = sizeof(Mpi2IOCInitRequest_t);
- func_str = "ioc_init";
- break;
- case MPI2_FUNCTION_PORT_ENABLE:
- frame_sz = sizeof(Mpi2PortEnableRequest_t);
- func_str = "port_enable";
- break;
- case MPI2_FUNCTION_SMP_PASSTHROUGH:
- frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size;
- func_str = "smp_passthru";
- break;
- default:
- frame_sz = 32;
- func_str = "unknown";
- break;
- }
-
- printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p),"
- " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str);
-
- _debug_dump_mf(request_hdr, frame_sz/4);
-}
-
-/**
- * _base_display_event_data - verbose translation of firmware asyn events
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- *
- * Return nothing.
- */
-static void
-_base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventNotificationReply_t *mpi_reply)
-{
- char *desc = NULL;
- u16 event;
-
- if (!(ioc->logging_level & MPT_DEBUG_EVENTS))
- return;
-
- event = le16_to_cpu(mpi_reply->Event);
-
- switch (event) {
- case MPI2_EVENT_LOG_DATA:
- desc = "Log Data";
- break;
- case MPI2_EVENT_STATE_CHANGE:
- desc = "Status Change";
- break;
- case MPI2_EVENT_HARD_RESET_RECEIVED:
- desc = "Hard Reset Received";
- break;
- case MPI2_EVENT_EVENT_CHANGE:
- desc = "Event Change";
- break;
- case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
- desc = "Device Status Change";
- break;
- case MPI2_EVENT_IR_OPERATION_STATUS:
- if (!ioc->hide_ir_msg)
- desc = "IR Operation Status";
- break;
- case MPI2_EVENT_SAS_DISCOVERY:
- {
- Mpi2EventDataSasDiscovery_t *event_data =
- (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData;
- printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name,
- (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
- "start" : "stop");
- if (event_data->DiscoveryStatus)
- printk("discovery_status(0x%08x)",
- le32_to_cpu(event_data->DiscoveryStatus));
- printk("\n");
- return;
- }
- case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- desc = "SAS Broadcast Primitive";
- break;
- case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
- desc = "SAS Init Device Status Change";
- break;
- case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW:
- desc = "SAS Init Table Overflow";
- break;
- case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- desc = "SAS Topology Change List";
- break;
- case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- desc = "SAS Enclosure Device Status Change";
- break;
- case MPI2_EVENT_IR_VOLUME:
- if (!ioc->hide_ir_msg)
- desc = "IR Volume";
- break;
- case MPI2_EVENT_IR_PHYSICAL_DISK:
- if (!ioc->hide_ir_msg)
- desc = "IR Physical Disk";
- break;
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- if (!ioc->hide_ir_msg)
- desc = "IR Configuration Change List";
- break;
- case MPI2_EVENT_LOG_ENTRY_ADDED:
- if (!ioc->hide_ir_msg)
- desc = "Log Entry Added";
- break;
- case MPI2_EVENT_TEMP_THRESHOLD:
- desc = "Temperature Threshold";
- break;
- }
-
- if (!desc)
- return;
-
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc);
-}
-#endif
-
-/**
- * _base_sas_log_info - verbose translation of firmware log info
- * @ioc: per adapter object
- * @log_info: log info
- *
- * Return nothing.
- */
-static void
-_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
-{
- union loginfo_type {
- u32 loginfo;
- struct {
- u32 subcode:16;
- u32 code:8;
- u32 originator:4;
- u32 bus_type:4;
- } dw;
- };
- union loginfo_type sas_loginfo;
- char *originator_str = NULL;
-
- sas_loginfo.loginfo = log_info;
- if (sas_loginfo.dw.bus_type != 3 /*SAS*/)
- return;
-
- /* each nexus loss loginfo */
- if (log_info == 0x31170000)
- return;
-
- /* eat the loginfos associated with task aborts */
- if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info ==
- 0x31140000 || log_info == 0x31130000))
- return;
-
- switch (sas_loginfo.dw.originator) {
- case 0:
- originator_str = "IOP";
- break;
- case 1:
- originator_str = "PL";
- break;
- case 2:
- if (!ioc->hide_ir_msg)
- originator_str = "IR";
- else
- originator_str = "WarpDrive";
- break;
- }
-
- printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), "
- "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info,
- originator_str, sas_loginfo.dw.code,
- sas_loginfo.dw.subcode);
-}
-
-/**
- * _base_display_reply_info -
- * @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)
- *
- * Return nothing.
- */
-static void
-_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
- u16 ioc_status;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
- (ioc->logging_level & MPT_DEBUG_REPLY)) {
- _base_sas_ioc_info(ioc , mpi_reply,
- mpt2sas_base_get_msg_frame(ioc, smid));
- }
-#endif
- if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
- _base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo));
-}
-
-/**
- * mpt2sas_base_done - base internal command 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)
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-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 1;
-
- if (ioc->base_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
-
- ioc->base_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID;
- memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
- }
- 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: per adapter object
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Returns void.
- */
-static void
-_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
-{
- Mpi2EventNotificationReply_t *mpi_reply;
- Mpi2EventAckRequest_t *ack_request;
- u16 smid;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (!mpi_reply)
- return;
- if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
- return;
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _base_display_event_data(ioc, mpi_reply);
-#endif
- if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
- goto out;
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- goto out;
- }
-
- ack_request = mpt2sas_base_get_msg_frame(ioc, smid);
- memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
- ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
- ack_request->Event = mpi_reply->Event;
- ack_request->EventContext = mpi_reply->EventContext;
- 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, msix_index, reply);
-
- /* ctl callback handler */
- mpt2sas_ctl_event_callback(ioc, msix_index, reply);
-
- return;
-}
-
-/**
- * _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;
-
- if (smid < ioc->hi_priority_smid) {
- i = smid - 1;
- cb_idx = ioc->scsi_lookup[i].cb_idx;
- } else if (smid < ioc->internal_smid) {
- i = smid - ioc->hi_priority_smid;
- cb_idx = ioc->hpr_lookup[i].cb_idx;
- } else if (smid <= ioc->hba_queue_depth) {
- i = smid - ioc->internal_smid;
- cb_idx = ioc->internal_lookup[i].cb_idx;
- } else
- cb_idx = 0xFF;
- return cb_idx;
-}
-
-/**
- * _base_mask_interrupts - disable interrupts
- * @ioc: per adapter object
- *
- * Disabling ResetIRQ, Reply and Doorbell Interrupts
- *
- * Return nothing.
- */
-static void
-_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
-{
- u32 him_register;
-
- ioc->mask_interrupts = 1;
- him_register = readl(&ioc->chip->HostInterruptMask);
- him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK;
- writel(him_register, &ioc->chip->HostInterruptMask);
- readl(&ioc->chip->HostInterruptMask);
-}
-
-/**
- * _base_unmask_interrupts - enable interrupts
- * @ioc: per adapter object
- *
- * Enabling only Reply Interrupts
- *
- * Return nothing.
- */
-static void
-_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
-{
- u32 him_register;
-
- him_register = readl(&ioc->chip->HostInterruptMask);
- him_register &= ~MPI2_HIM_RIM;
- writel(him_register, &ioc->chip->HostInterruptMask);
- ioc->mask_interrupts = 0;
-}
-
-union reply_descriptor {
- u64 word;
- struct {
- u32 low;
- u32 high;
- } u;
-};
-
-/**
- * _base_interrupt - MPT adapter (IOC) specific interrupt handler.
- * @irq: irq number (not used)
- * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
- * @r: pt_regs pointer (not used)
- *
- * Return IRQ_HANDLE if processed, else IRQ_NONE.
- */
-static irqreturn_t
-_base_interrupt(int irq, void *bus_id)
-{
- struct adapter_reply_queue *reply_q = bus_id;
- union reply_descriptor rd;
- u32 completed_cmds;
- u8 request_desript_type;
- u16 smid;
- u8 cb_idx;
- u32 reply;
- u8 msix_index = reply_q->msix_index;
- struct MPT2SAS_ADAPTER *ioc = reply_q->ioc;
- Mpi2ReplyDescriptorsUnion_t *rpf;
- u8 rc;
-
- if (ioc->mask_interrupts)
- return IRQ_NONE;
-
- if (!atomic_add_unless(&reply_q->busy, 1, 1))
- return IRQ_NONE;
-
- rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index];
- request_desript_type = rpf->Default.ReplyFlags
- & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
- if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
- atomic_dec(&reply_q->busy);
- return IRQ_NONE;
- }
-
- completed_cmds = 0;
- cb_idx = 0xFF;
- do {
- rd.word = le64_to_cpu(rpf->Words);
- if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
- goto out;
- reply = 0;
- smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
- if (request_desript_type ==
- MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
- reply = le32_to_cpu
- (rpf->AddressReply.ReplyFrameAddress);
- if (reply > ioc->reply_dma_max_address ||
- reply < ioc->reply_dma_min_address)
- reply = 0;
- } else if (request_desript_type ==
- MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
- goto next;
- else if (request_desript_type ==
- MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
- goto next;
- if (smid) {
- cb_idx = _base_get_cb_idx(ioc, smid);
- if ((likely(cb_idx < MPT_MAX_CALLBACKS))
- && (likely(mpt_callbacks[cb_idx] != NULL))) {
- rc = mpt_callbacks[cb_idx](ioc, smid,
- msix_index, reply);
- if (reply)
- _base_display_reply_info(ioc, smid,
- msix_index, reply);
- if (rc)
- mpt2sas_base_free_smid(ioc, smid);
- }
- }
- if (!smid)
- _base_async_event(ioc, msix_index, reply);
-
- /* reply free queue handling */
- if (reply) {
- ioc->reply_free_host_index =
- (ioc->reply_free_host_index ==
- (ioc->reply_free_queue_depth - 1)) ?
- 0 : ioc->reply_free_host_index + 1;
- ioc->reply_free[ioc->reply_free_host_index] =
- cpu_to_le32(reply);
- wmb();
- writel(ioc->reply_free_host_index,
- &ioc->chip->ReplyFreeHostIndex);
- }
-
- next:
-
- rpf->Words = cpu_to_le64(ULLONG_MAX);
- reply_q->reply_post_host_index =
- (reply_q->reply_post_host_index ==
- (ioc->reply_post_queue_depth - 1)) ? 0 :
- reply_q->reply_post_host_index + 1;
- request_desript_type =
- reply_q->reply_post_free[reply_q->reply_post_host_index].
- Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
- completed_cmds++;
- if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
- goto out;
- if (!reply_q->reply_post_host_index)
- rpf = reply_q->reply_post_free;
- else
- rpf++;
- } while (1);
-
- out:
-
- if (!completed_cmds) {
- atomic_dec(&reply_q->busy);
- return IRQ_NONE;
- }
- wmb();
- if (ioc->is_warpdrive) {
- writel(reply_q->reply_post_host_index,
- ioc->reply_post_host_index[msix_index]);
- atomic_dec(&reply_q->busy);
- return IRQ_HANDLED;
- }
- writel(reply_q->reply_post_host_index | (msix_index <<
- MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex);
- atomic_dec(&reply_q->busy);
- return IRQ_HANDLED;
-}
-
-/**
- * _base_is_controller_msix_enabled - is controller support muli-reply queues
- * @ioc: per adapter object
- *
- */
-static inline int
-_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc)
-{
- return (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable;
-}
-
-/**
- * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues
- * @ioc: per adapter object
- * Context: ISR conext
- *
- * Called when a Task Management request has completed. We want
- * to flush the other reply queues so all the outstanding IO has been
- * completed back to OS before we process the TM completetion.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc)
-{
- struct adapter_reply_queue *reply_q;
-
- /* If MSIX capability is turned off
- * then multi-queues are not enabled
- */
- if (!_base_is_controller_msix_enabled(ioc))
- return;
-
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- if (ioc->shost_recovery)
- return;
- /* TMs are on msix_index == 0 */
- if (reply_q->msix_index == 0)
- continue;
- _base_interrupt(reply_q->vector, (void *)reply_q);
- }
-}
-
-/**
- * mpt2sas_base_release_callback_handler - clear interrupt callback handler
- * @cb_idx: callback index
- *
- * Return nothing.
- */
-void
-mpt2sas_base_release_callback_handler(u8 cb_idx)
-{
- mpt_callbacks[cb_idx] = NULL;
-}
-
-/**
- * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler
- * @cb_func: callback function
- *
- * Returns cb_func.
- */
-u8
-mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func)
-{
- u8 cb_idx;
-
- for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--)
- if (mpt_callbacks[cb_idx] == NULL)
- break;
-
- mpt_callbacks[cb_idx] = cb_func;
- return cb_idx;
-}
-
-/**
- * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler
- *
- * Return nothing.
- */
-void
-mpt2sas_base_initialize_callback_handler(void)
-{
- u8 cb_idx;
-
- for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++)
- mpt2sas_base_release_callback_handler(cb_idx);
-}
-
-/**
- * mpt2sas_base_build_zero_len_sge - build zero length sg entry
- * @ioc: per adapter object
- * @paddr: virtual address for SGE
- *
- * Create a zero length scatter gather entry to insure the IOCs hardware has
- * something to use if the target device goes brain dead and tries
- * to send data even when none is asked for.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr)
-{
- u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST |
- MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
- MPI2_SGE_FLAGS_SHIFT);
- ioc->base_add_sg_single(paddr, flags_length, -1);
-}
-
-/**
- * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr.
- * @paddr: virtual address for SGE
- * @flags_length: SGE flags and data transfer length
- * @dma_addr: Physical address
- *
- * Return nothing.
- */
-static void
-_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr)
-{
- Mpi2SGESimple32_t *sgel = paddr;
-
- flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
- MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
- sgel->FlagsLength = cpu_to_le32(flags_length);
- sgel->Address = cpu_to_le32(dma_addr);
-}
-
-
-/**
- * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr.
- * @paddr: virtual address for SGE
- * @flags_length: SGE flags and data transfer length
- * @dma_addr: Physical address
- *
- * Return nothing.
- */
-static void
-_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr)
-{
- Mpi2SGESimple64_t *sgel = paddr;
-
- flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
- MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
- sgel->FlagsLength = cpu_to_le32(flags_length);
- sgel->Address = cpu_to_le64(dma_addr);
-}
-
-#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10))
-
-/**
- * _base_config_dma_addressing - set dma addressing
- * @ioc: per adapter object
- * @pdev: PCI device struct
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
-{
- struct sysinfo s;
- u64 consistent_dma_mask;
-
- if (ioc->dma_mask)
- consistent_dma_mask = DMA_BIT_MASK(64);
- else
- consistent_dma_mask = DMA_BIT_MASK(32);
-
- if (sizeof(dma_addr_t) > 4) {
- const uint64_t required_mask =
- dma_get_required_mask(&pdev->dev);
- if ((required_mask > DMA_BIT_MASK(32)) &&
- !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
- !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {
- ioc->base_add_sg_single = &_base_add_sg_single_64;
- ioc->sge_size = sizeof(Mpi2SGESimple64_t);
- ioc->dma_mask = 64;
- goto out;
- }
- }
-
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
- && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- ioc->base_add_sg_single = &_base_add_sg_single_32;
- ioc->sge_size = sizeof(Mpi2SGESimple32_t);
- ioc->dma_mask = 32;
- } else
- return -ENODEV;
-
- out:
- si_meminfo(&s);
- printk(MPT2SAS_INFO_FMT
- "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
- ioc->name, ioc->dma_mask, convert_to_kb(s.totalram));
-
- return 0;
-}
-
-static int
-_base_change_consistent_dma_mask(struct MPT2SAS_ADAPTER *ioc,
- struct pci_dev *pdev)
-{
- if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
- if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
- return -ENODEV;
- }
- return 0;
-}
-/**
- * _base_check_enable_msix - checks MSIX capabable.
- * @ioc: per adapter object
- *
- * Check to see if card is capable of MSIX, and set number
- * of available msix vectors
- */
-static int
-_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
-{
- int base;
- u16 message_control;
-
-
- /* Check whether controller SAS2008 B0 controller,
- if it is SAS2008 B0 controller use IO-APIC instead of MSIX */
- if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 &&
- ioc->pdev->revision == 0x01) {
- return -EINVAL;
- }
-
- base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
- if (!base) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
- "supported\n", ioc->name));
- return -EINVAL;
- }
-
- /* get msix vector count */
- /* NUMA_IO not supported for older controllers */
- if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
- ioc->msix_vector_count = 1;
- else {
- pci_read_config_word(ioc->pdev, base + 2, &message_control);
- ioc->msix_vector_count = (message_control & 0x3FF) + 1;
- }
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
- "vector_count(%d)\n", ioc->name, ioc->msix_vector_count));
-
- return 0;
-}
-
-/**
- * _base_free_irq - free irq
- * @ioc: per adapter object
- *
- * Freeing respective reply_queue from the list.
- */
-static void
-_base_free_irq(struct MPT2SAS_ADAPTER *ioc)
-{
- struct adapter_reply_queue *reply_q, *next;
-
- if (list_empty(&ioc->reply_queue_list))
- return;
-
- list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
- list_del(&reply_q->list);
- irq_set_affinity_hint(reply_q->vector, NULL);
- free_cpumask_var(reply_q->affinity_hint);
- synchronize_irq(reply_q->vector);
- free_irq(reply_q->vector, reply_q);
- kfree(reply_q);
- }
-}
-
-/**
- * _base_request_irq - request irq
- * @ioc: per adapter object
- * @index: msix index into vector table
- * @vector: irq vector
- *
- * Inserting respective reply_queue into the list.
- */
-static int
-_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector)
-{
- struct adapter_reply_queue *reply_q;
- int r;
-
- reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL);
- if (!reply_q) {
- printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n",
- ioc->name, (int)sizeof(struct adapter_reply_queue));
- return -ENOMEM;
- }
- reply_q->ioc = ioc;
- reply_q->msix_index = index;
- reply_q->vector = vector;
-
- if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL))
- return -ENOMEM;
- cpumask_clear(reply_q->affinity_hint);
-
- atomic_set(&reply_q->busy, 0);
- if (ioc->msix_enable)
- snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
- MPT2SAS_DRIVER_NAME, ioc->id, index);
- else
- snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
- MPT2SAS_DRIVER_NAME, ioc->id);
- r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
- reply_q);
- if (r) {
- printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
- reply_q->name, vector);
- kfree(reply_q);
- return -EBUSY;
- }
-
- INIT_LIST_HEAD(&reply_q->list);
- list_add_tail(&reply_q->list, &ioc->reply_queue_list);
- return 0;
-}
-
-/**
- * _base_assign_reply_queues - assigning msix index for each cpu
- * @ioc: per adapter object
- *
- * The enduser would need to set the affinity via /proc/irq/#/smp_affinity
- *
- * It would nice if we could call irq_set_affinity, however it is not
- * an exported symbol
- */
-static void
-_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned int cpu, nr_cpus, nr_msix, index = 0;
- struct adapter_reply_queue *reply_q;
-
- if (!_base_is_controller_msix_enabled(ioc))
- return;
-
- memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
-
- nr_cpus = num_online_cpus();
- nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count,
- ioc->facts.MaxMSIxVectors);
- if (!nr_msix)
- return;
-
- cpu = cpumask_first(cpu_online_mask);
-
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-
- unsigned int i, group = nr_cpus / nr_msix;
-
- if (cpu >= nr_cpus)
- break;
-
- if (index < nr_cpus % nr_msix)
- group++;
-
- for (i = 0 ; i < group ; i++) {
- ioc->cpu_msix_table[cpu] = index;
- cpumask_or(reply_q->affinity_hint,
- reply_q->affinity_hint, get_cpu_mask(cpu));
- cpu = cpumask_next(cpu, cpu_online_mask);
- }
-
- if (irq_set_affinity_hint(reply_q->vector,
- reply_q->affinity_hint))
- dinitprintk(ioc, pr_info(MPT2SAS_FMT
- "error setting affinity hint for irq vector %d\n",
- ioc->name, reply_q->vector));
- index++;
- }
-}
-
-/**
- * _base_disable_msix - disables msix
- * @ioc: per adapter object
- *
- */
-static void
-_base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
-{
- if (ioc->msix_enable) {
- pci_disable_msix(ioc->pdev);
- ioc->msix_enable = 0;
- }
-}
-
-/**
- * _base_enable_msix - enables msix, failback to io_apic
- * @ioc: per adapter object
- *
- */
-static int
-_base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
-{
- struct msix_entry *entries, *a;
- int r;
- int i;
- u8 try_msix = 0;
-
- if (msix_disable == -1 || msix_disable == 0)
- try_msix = 1;
-
- if (!try_msix)
- goto try_ioapic;
-
- if (_base_check_enable_msix(ioc) != 0)
- goto try_ioapic;
-
- ioc->reply_queue_count = min_t(int, ioc->cpu_count,
- ioc->msix_vector_count);
-
- if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
- max_msix_vectors = 8;
-
- if (max_msix_vectors > 0) {
- ioc->reply_queue_count = min_t(int, max_msix_vectors,
- ioc->reply_queue_count);
- ioc->msix_vector_count = ioc->reply_queue_count;
- } else if (max_msix_vectors == 0)
- goto try_ioapic;
-
- printk(MPT2SAS_INFO_FMT
- "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n",
- ioc->name, ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors);
-
- entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
- GFP_KERNEL);
- if (!entries) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc "
- "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- goto try_ioapic;
- }
-
- for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++)
- a->entry = i;
-
- r = pci_enable_msix_exact(ioc->pdev, entries, ioc->reply_queue_count);
- if (r) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT
- "pci_enable_msix_exact failed (r=%d) !!!\n", ioc->name, r));
- kfree(entries);
- goto try_ioapic;
- }
-
- ioc->msix_enable = 1;
- for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) {
- r = _base_request_irq(ioc, i, a->vector);
- if (r) {
- _base_free_irq(ioc);
- _base_disable_msix(ioc);
- kfree(entries);
- goto try_ioapic;
- }
- }
-
- kfree(entries);
- return 0;
-
-/* failback to io_apic interrupt routing */
- try_ioapic:
-
- ioc->reply_queue_count = 1;
- r = _base_request_irq(ioc, 0, ioc->pdev->irq);
-
- return r;
-}
-
-/**
- * mpt2sas_base_map_resources - map in controller resources (io/irq/memap)
- * @ioc: per adapter object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
-{
- struct pci_dev *pdev = ioc->pdev;
- u32 memap_sz;
- u32 pio_sz;
- int i, r = 0;
- u64 pio_chip = 0;
- u64 chip_phys = 0;
- struct adapter_reply_queue *reply_q;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
- ioc->name, __func__));
-
- ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
- if (pci_enable_device_mem(pdev)) {
- printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
- "failed\n", ioc->name);
- ioc->bars = 0;
- return -ENODEV;
- }
-
-
- if (pci_request_selected_regions(pdev, ioc->bars,
- MPT2SAS_DRIVER_NAME)) {
- printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
- "failed\n", ioc->name);
- ioc->bars = 0;
- r = -ENODEV;
- goto out_fail;
- }
-
- /* AER (Advanced Error Reporting) hooks */
- pci_enable_pcie_error_reporting(pdev);
-
- pci_set_master(pdev);
-
- if (_base_config_dma_addressing(ioc, pdev) != 0) {
- printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n",
- ioc->name, pci_name(pdev));
- r = -ENODEV;
- goto out_fail;
- }
-
- for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) &&
- (!memap_sz || !pio_sz); i++) {
- if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
- if (pio_sz)
- continue;
- pio_chip = (u64)pci_resource_start(pdev, i);
- pio_sz = pci_resource_len(pdev, i);
- } else {
- if (memap_sz)
- continue;
- /* verify memory resource is valid before using */
- if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
- ioc->chip_phys = pci_resource_start(pdev, i);
- chip_phys = (u64)ioc->chip_phys;
- memap_sz = pci_resource_len(pdev, i);
- ioc->chip = ioremap(ioc->chip_phys, memap_sz);
- }
- }
- }
-
- if (ioc->chip == NULL) {
- printk(MPT2SAS_ERR_FMT "unable to map adapter memory! "
- "or resource not found\n", ioc->name);
- r = -EINVAL;
- goto out_fail;
- }
-
- _base_mask_interrupts(ioc);
-
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
- if (r)
- goto out_fail;
-
- if (!ioc->rdpq_array_enable_assigned) {
- ioc->rdpq_array_enable = ioc->rdpq_array_capable;
- ioc->rdpq_array_enable_assigned = 1;
- }
-
- r = _base_enable_msix(ioc);
- if (r)
- goto out_fail;
-
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
- printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
- reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
- "IO-APIC enabled"), reply_q->vector);
-
- printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
- ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz);
- printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
- ioc->name, (unsigned long long)pio_chip, pio_sz);
-
- /* Save PCI configuration state for recovery from PCI AER/EEH errors */
- pci_save_state(pdev);
-
- return 0;
-
- out_fail:
- if (ioc->chip_phys)
- iounmap(ioc->chip);
- ioc->chip_phys = 0;
- pci_release_selected_regions(ioc->pdev, ioc->bars);
- pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
- return r;
-}
-
-/**
- * mpt2sas_base_get_msg_frame - obtain request mf pointer
- * @ioc: per adapter object
- * @smid: system request message index(smid zero is invalid)
- *
- * Returns virt pointer to message frame.
- */
-void *
-mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return (void *)(ioc->request + (smid * ioc->request_sz));
-}
-
-/**
- * mpt2sas_base_get_sense_buffer - obtain a sense buffer assigned to a mf request
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns virt pointer to sense buffer.
- */
-void *
-mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
-}
-
-/**
- * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns phys pointer to the low 32bit address of the sense buffer.
- */
-__le32
-mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return cpu_to_le32(ioc->sense_dma +
- ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
-}
-
-/**
- * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address
- * @ioc: per adapter object
- * @phys_addr: lower 32 physical addr of the reply
- *
- * Converts 32bit lower physical addr into a virt address.
- */
-void *
-mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)
-{
- if (!phys_addr)
- return NULL;
- return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
-}
-
-/**
- * mpt2sas_base_get_smid - obtain a free smid from internal queue
- * @ioc: per adapter object
- * @cb_idx: callback index
- *
- * Returns smid (zero is invalid)
- */
-u16
-mpt2sas_base_get_smid(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->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 scsiio_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",
- ioc->name, __func__);
- return 0;
- }
-
- request = list_entry(ioc->free_list.next,
- struct scsiio_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);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return smid;
-}
-
-
-/**
- * mpt2sas_base_free_smid - put smid back on free_list
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return nothing.
- */
-void
-mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- unsigned long flags;
- int i;
- struct chain_tracker *chain_req, *next;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (smid < ioc->hi_priority_smid) {
- /* scsiio queue */
- i = smid - 1;
- if (!list_empty(&ioc->scsi_lookup[i].chain_list)) {
- list_for_each_entry_safe(chain_req, next,
- &ioc->scsi_lookup[i].chain_list, tracker_list) {
- list_del_init(&chain_req->tracker_list);
- list_add(&chain_req->tracker_list,
- &ioc->free_chain_list);
- }
- }
- ioc->scsi_lookup[i].cb_idx = 0xFF;
- ioc->scsi_lookup[i].scmd = NULL;
- ioc->scsi_lookup[i].direct_io = 0;
- list_add(&ioc->scsi_lookup[i].tracker_list,
- &ioc->free_list);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- /*
- * See _wait_for_commands_to_complete() call with regards
- * to this code.
- */
- if (ioc->shost_recovery && ioc->pending_io_count) {
- if (ioc->pending_io_count == 1)
- wake_up(&ioc->reset_wq);
- ioc->pending_io_count--;
- }
- return;
- } else if (smid < ioc->internal_smid) {
- /* hi-priority */
- i = smid - ioc->hi_priority_smid;
- ioc->hpr_lookup[i].cb_idx = 0xFF;
- list_add(&ioc->hpr_lookup[i].tracker_list,
- &ioc->hpr_free_list);
- } else if (smid <= ioc->hba_queue_depth) {
- /* internal queue */
- i = smid - ioc->internal_smid;
- ioc->internal_lookup[i].cb_idx = 0xFF;
- list_add(&ioc->internal_lookup[i].tracker_list,
- &ioc->internal_free_list);
- }
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-}
-
-/**
- * _base_writeq - 64 bit write to MMIO
- * @ioc: per adapter object
- * @b: data payload
- * @addr: address in MMIO space
- * @writeq_lock: spin lock
- *
- * Glue for handling an atomic 64 bit word to MMIO. This special handling takes
- * care of 32 bit environment where its not quarenteed to send the entire word
- * in one transfer.
- */
-#ifndef writeq
-static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
- spinlock_t *writeq_lock)
-{
- unsigned long flags;
- __u64 data_out = cpu_to_le64(b);
-
- spin_lock_irqsave(writeq_lock, flags);
- writel((u32)(data_out), addr);
- writel((u32)(data_out >> 32), (addr + 4));
- spin_unlock_irqrestore(writeq_lock, flags);
-}
-#else
-static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
- spinlock_t *writeq_lock)
-{
- writeq(cpu_to_le64(b), addr);
-}
-#endif
-
-static inline u8
-_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc)
-{
- return ioc->cpu_msix_table[raw_smp_processor_id()];
-}
-
-/**
- * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
- * @ioc: per adapter object
- * @smid: system request message index
- * @handle: device handle
- *
- * Return nothing.
- */
-void
-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.MSIxIndex = _base_get_msix_index(ioc);
- descriptor.SCSIIO.SMID = cpu_to_le16(smid);
- descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
- descriptor.SCSIIO.LMID = 0;
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-
-/**
- * mpt2sas_base_put_smid_hi_priority - send Task Management request to firmware
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return nothing.
- */
-void
-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.MSIxIndex = 0;
- descriptor.HighPriority.SMID = cpu_to_le16(smid);
- descriptor.HighPriority.LMID = 0;
- descriptor.HighPriority.Reserved1 = 0;
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-/**
- * mpt2sas_base_put_smid_default - Default, primarily used for config pages
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return nothing.
- */
-void
-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.MSIxIndex = _base_get_msix_index(ioc);
- descriptor.Default.SMID = cpu_to_le16(smid);
- descriptor.Default.LMID = 0;
- descriptor.Default.DescriptorTypeDependent = 0;
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-/**
- * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware
- * @ioc: per adapter object
- * @smid: system request message index
- * @io_index: value used to track the IO
- *
- * Return nothing.
- */
-void
-mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u16 io_index)
-{
- Mpi2RequestDescriptorUnion_t descriptor;
- u64 *request = (u64 *)&descriptor;
-
- descriptor.SCSITarget.RequestFlags =
- MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
- descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc);
- descriptor.SCSITarget.SMID = cpu_to_le16(smid);
- descriptor.SCSITarget.LMID = 0;
- descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-/**
- * _base_display_dell_branding - Disply branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc)
-{
- char dell_branding[MPT2SAS_DELL_BRANDING_SIZE];
-
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL)
- return;
-
- memset(dell_branding, 0, MPT2SAS_DELL_BRANDING_SIZE);
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID:
- strncpy(dell_branding,
- MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID:
- strncpy(dell_branding,
- MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID:
- strncpy(dell_branding,
- MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_6GBPS_SAS_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- default:
- sprintf(dell_branding, "0x%4X", ioc->pdev->subsystem_device);
- break;
- }
-
- printk(MPT2SAS_INFO_FMT "%s: Vendor(0x%04X), Device(0x%04X),"
- " SSVID(0x%04X), SSDID(0x%04X)\n", ioc->name, dell_branding,
- ioc->pdev->vendor, ioc->pdev->device, ioc->pdev->subsystem_vendor,
- ioc->pdev->subsystem_device);
-}
-
-/**
- * _base_display_intel_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL)
- return;
-
- switch (ioc->pdev->device) {
- case MPI2_MFGPAGE_DEVID_SAS2008:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_INTEL_RMS2LL080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS2LL080_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS2LL040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS2LL040_BRANDING);
- break;
- case MPT2SAS_INTEL_SSD910_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_SSD910_BRANDING);
- break;
- default:
- break;
- }
- case MPI2_MFGPAGE_DEVID_SAS2308_2:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_INTEL_RS25GB008_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RS25GB008_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25JB080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25JB080_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25JB040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25JB040_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25KB080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25KB080_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25KB040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25KB040_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25LB040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25LB040_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25LB080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25LB080_BRANDING);
- break;
- default:
- break;
- }
- default:
- break;
- }
-}
-
-/**
- * _base_display_hp_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID)
- return;
-
- switch (ioc->pdev->device) {
- case MPI2_MFGPAGE_DEVID_SAS2004:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING);
- break;
- default:
- break;
- }
- case MPI2_MFGPAGE_DEVID_SAS2308_2:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_HP_2_4_INTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_2_4_INTERNAL_BRANDING);
- break;
- case MPT2SAS_HP_2_4_EXTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_2_4_EXTERNAL_BRANDING);
- break;
- case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING);
- break;
- case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING);
- break;
- default:
- break;
- }
- default:
- break;
- }
-}
-
-/**
- * _base_display_ioc_capabilities - Disply IOC's capabilities.
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
-{
- int i = 0;
- char desc[16];
- u32 iounit_pg1_flags;
- u32 bios_version;
-
- bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
- strncpy(desc, ioc->manu_pg0.ChipName, 16);
- printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "
- "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
- ioc->name, desc,
- (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
- (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
- (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
- ioc->facts.FWVersion.Word & 0x000000FF,
- ioc->pdev->revision,
- (bios_version & 0xFF000000) >> 24,
- (bios_version & 0x00FF0000) >> 16,
- (bios_version & 0x0000FF00) >> 8,
- bios_version & 0x000000FF);
-
- _base_display_dell_branding(ioc);
- _base_display_intel_branding(ioc);
- _base_display_hp_branding(ioc);
-
- printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name);
-
- if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
- printk("Initiator");
- i++;
- }
-
- if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) {
- printk("%sTarget", i ? "," : "");
- i++;
- }
-
- i = 0;
- printk("), ");
- printk("Capabilities=(");
-
- if (!ioc->hide_ir_msg) {
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
- printk("Raid");
- i++;
- }
- }
-
- if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
- printk("%sTLR", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) {
- printk("%sMulticast", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) {
- printk("%sBIDI Target", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) {
- printk("%sEEDP", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
- printk("%sSnapshot Buffer", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
- printk("%sDiag Trace Buffer", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
- printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
- printk("%sTask Set Full", i ? "," : "");
- i++;
- }
-
- iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
- if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
- printk("%sNCQ", i ? "," : "");
- i++;
- }
-
- printk(")\n");
-}
-
-/**
- * mpt2sas_base_update_missing_delay - change the missing delay timers
- * @ioc: per adapter object
- * @device_missing_delay: amount of time till device is reported missing
- * @io_missing_delay: interval IO is returned when there is a missing device
- *
- * Return nothing.
- *
- * Passed on the command line, this function will modify the device missing
- * delay, as well as the io missing delay. This should be called at driver
- * load time.
- */
-void
-mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
- u16 device_missing_delay, u8 io_missing_delay)
-{
- u16 dmd, dmd_new, dmd_orignal;
- u8 io_missing_delay_original;
- u16 sz;
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2ConfigReply_t mpi_reply;
- u8 num_phys = 0;
- u16 ioc_status;
-
- mpt2sas_config_get_number_hba_phys(ioc, &num_phys);
- if (!num_phys)
- return;
-
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- /* device missing delay */
- dmd = sas_iounit_pg1->ReportDeviceMissingDelay;
- if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
- dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
- else
- dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
- dmd_orignal = dmd;
- if (device_missing_delay > 0x7F) {
- dmd = (device_missing_delay > 0x7F0) ? 0x7F0 :
- device_missing_delay;
- dmd = dmd / 16;
- dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16;
- } else
- dmd = device_missing_delay;
- sas_iounit_pg1->ReportDeviceMissingDelay = dmd;
-
- /* io missing delay */
- io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay;
- sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay;
-
- if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
- sz)) {
- if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
- dmd_new = (dmd &
- MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
- else
- dmd_new =
- dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
- printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), "
- "new(%d)\n", ioc->name, dmd_orignal, dmd_new);
- printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), "
- "new(%d)\n", ioc->name, io_missing_delay_original,
- io_missing_delay);
- ioc->device_missing_delay = dmd_new;
- ioc->io_missing_delay = io_missing_delay;
- }
-
-out:
- kfree(sas_iounit_pg1);
-}
-
-/**
- * _base_static_config_pages - static start of day config pages
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2ConfigReply_t mpi_reply;
- u32 iounit_pg1_flags;
-
- mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
- if (ioc->ir_firmware)
- mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply,
- &ioc->manu_pg10);
- mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
- mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
- mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
- mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
- mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
- mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8);
- _base_display_ioc_capabilities(ioc);
-
- /*
- * Enable task_set_full handling in iounit_pg1 when the
- * facts capabilities indicate that its supported.
- */
- iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
- if ((ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING))
- iounit_pg1_flags &=
- ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
- else
- iounit_pg1_flags |=
- MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
- ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
- mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
-
- if (ioc->iounit_pg8.NumSensors)
- ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
-}
-
-/**
- * _base_release_memory_pools - release memory
- * @ioc: per adapter object
- *
- * Free memory allocated from _base_allocate_memory_pools.
- *
- * Return nothing.
- */
-static void
-_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
-{
- int i = 0;
- struct reply_post_struct *rps;
-
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->request) {
- pci_free_consistent(ioc->pdev, ioc->request_dma_sz,
- ioc->request, ioc->request_dma);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)"
- ": free\n", ioc->name, ioc->request));
- ioc->request = NULL;
- }
-
- if (ioc->sense) {
- pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma);
- if (ioc->sense_dma_pool)
- pci_pool_destroy(ioc->sense_dma_pool);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)"
- ": free\n", ioc->name, ioc->sense));
- ioc->sense = NULL;
- }
-
- if (ioc->reply) {
- pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma);
- if (ioc->reply_dma_pool)
- pci_pool_destroy(ioc->reply_dma_pool);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)"
- ": free\n", ioc->name, ioc->reply));
- ioc->reply = NULL;
- }
-
- if (ioc->reply_free) {
- pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free,
- ioc->reply_free_dma);
- if (ioc->reply_free_dma_pool)
- pci_pool_destroy(ioc->reply_free_dma_pool);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool"
- "(0x%p): free\n", ioc->name, ioc->reply_free));
- ioc->reply_free = NULL;
- }
-
- if (ioc->reply_post) {
- do {
- rps = &ioc->reply_post[i];
- if (rps->reply_post_free) {
- pci_pool_free(
- ioc->reply_post_free_dma_pool,
- rps->reply_post_free,
- rps->reply_post_free_dma);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "reply_post_free_pool(0x%p): free\n",
- ioc->name, rps->reply_post_free));
- rps->reply_post_free = NULL;
- }
- } while (ioc->rdpq_array_enable &&
- (++i < ioc->reply_queue_count));
-
- if (ioc->reply_post_free_dma_pool)
- pci_pool_destroy(ioc->reply_post_free_dma_pool);
- kfree(ioc->reply_post);
- }
-
- if (ioc->config_page) {
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "config_page(0x%p): free\n", ioc->name,
- ioc->config_page));
- pci_free_consistent(ioc->pdev, ioc->config_page_sz,
- ioc->config_page, ioc->config_page_dma);
- }
-
- if (ioc->scsi_lookup) {
- free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages);
- ioc->scsi_lookup = NULL;
- }
- kfree(ioc->hpr_lookup);
- kfree(ioc->internal_lookup);
- if (ioc->chain_lookup) {
- for (i = 0; i < ioc->chain_depth; i++) {
- if (ioc->chain_lookup[i].chain_buffer)
- pci_pool_free(ioc->chain_dma_pool,
- ioc->chain_lookup[i].chain_buffer,
- ioc->chain_lookup[i].chain_buffer_dma);
- }
- if (ioc->chain_dma_pool)
- pci_pool_destroy(ioc->chain_dma_pool);
- free_pages((ulong)ioc->chain_lookup, ioc->chain_pages);
- ioc->chain_lookup = NULL;
- }
-}
-
-
-/**
- * _base_allocate_memory_pools - allocate start of day memory pools
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 success, anything else error
- */
-static int
-_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- struct mpt2sas_facts *facts;
- u16 max_sge_elements;
- u16 chains_needed_per_io;
- u32 sz, total_sz, reply_post_free_sz;
- u32 retry_sz;
- u16 max_request_credit;
- int i;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- retry_sz = 0;
- facts = &ioc->facts;
-
- /* command line tunables for max sgl entries */
- if (max_sgl_entries != -1) {
- ioc->shost->sg_tablesize = min_t(unsigned short,
- max_sgl_entries, SCSI_MAX_SG_CHAIN_SEGMENTS);
- if (ioc->shost->sg_tablesize > MPT2SAS_SG_DEPTH)
- printk(MPT2SAS_WARN_FMT
- "sg_tablesize(%u) is bigger than kernel defined"
- " SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name,
- ioc->shost->sg_tablesize, MPT2SAS_SG_DEPTH);
- } else {
- ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH;
- }
-
- /* command line tunables for max controller queue depth */
- if (max_queue_depth != -1 && max_queue_depth != 0) {
- max_request_credit = min_t(u16, max_queue_depth +
- ioc->hi_priority_depth + ioc->internal_depth,
- facts->RequestCredit);
- if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
- max_request_credit = MAX_HBA_QUEUE_DEPTH;
- } else
- max_request_credit = min_t(u16, facts->RequestCredit,
- MAX_HBA_QUEUE_DEPTH);
-
- 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;
-
- /* reply frame size */
- ioc->reply_sz = facts->ReplyFrameSize * 4;
-
- retry_allocation:
- total_sz = 0;
- /* calculate number of sg elements left over in the 1st frame */
- max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) -
- sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size);
- ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size;
-
- /* now do the same for a chain buffer */
- max_sge_elements = ioc->request_sz - ioc->sge_size;
- ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size;
-
- ioc->chain_offset_value_for_main_message =
- ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) +
- (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4;
-
- /*
- * MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE
- */
- chains_needed_per_io = ((ioc->shost->sg_tablesize -
- ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message)
- + 1;
- if (chains_needed_per_io > facts->MaxChainDepth) {
- chains_needed_per_io = facts->MaxChainDepth;
- ioc->shost->sg_tablesize = min_t(u16,
- ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message
- * chains_needed_per_io), ioc->shost->sg_tablesize);
- }
- ioc->chains_needed_per_io = chains_needed_per_io;
-
- /* reply free queue sizing - taking into account for 64 FW events */
- ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
-
- /* calculate reply descriptor post queue depth */
- ioc->reply_post_queue_depth = ioc->hba_queue_depth +
- ioc->reply_free_queue_depth + 1;
- /* align the reply post queue on the next 16 count boundary */
- if (ioc->reply_post_queue_depth % 16)
- ioc->reply_post_queue_depth += 16 -
- (ioc->reply_post_queue_depth % 16);
-
-
- if (ioc->reply_post_queue_depth >
- facts->MaxReplyDescriptorPostQueueDepth) {
- ioc->reply_post_queue_depth =
- facts->MaxReplyDescriptorPostQueueDepth -
- (facts->MaxReplyDescriptorPostQueueDepth % 16);
- ioc->hba_queue_depth =
- ((ioc->reply_post_queue_depth - 64) / 2) - 1;
- ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
- }
-
- 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));
-
- /* reply post queue, 16 byte align */
- reply_post_free_sz = ioc->reply_post_queue_depth *
- sizeof(Mpi2DefaultReplyDescriptor_t);
-
- sz = reply_post_free_sz;
- if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
- sz *= ioc->reply_queue_count;
-
- ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
- (ioc->reply_queue_count):1,
- sizeof(struct reply_post_struct), GFP_KERNEL);
-
- if (!ioc->reply_post) {
- printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
- ioc->name);
- goto out;
- }
- ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
- ioc->pdev, sz, 16, 0);
- if (!ioc->reply_post_free_dma_pool) {
- printk(MPT2SAS_ERR_FMT
- "reply_post_free pool: pci_pool_create failed\n",
- ioc->name);
- goto out;
- }
- i = 0;
- do {
- ioc->reply_post[i].reply_post_free =
- pci_pool_alloc(ioc->reply_post_free_dma_pool,
- GFP_KERNEL,
- &ioc->reply_post[i].reply_post_free_dma);
- if (!ioc->reply_post[i].reply_post_free) {
- printk(MPT2SAS_ERR_FMT
- "reply_post_free pool: pci_pool_alloc failed\n",
- ioc->name);
- goto out;
- }
- memset(ioc->reply_post[i].reply_post_free, 0, sz);
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "reply post free pool (0x%p): depth(%d),"
- "element_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->reply_post[i].reply_post_free,
- ioc->reply_post_queue_depth, 8, sz/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "reply_post_free_dma = (0x%llx)\n", ioc->name,
- (unsigned long long)
- ioc->reply_post[i].reply_post_free_dma));
- total_sz += sz;
- } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
-
- if (ioc->dma_mask == 64) {
- if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
- printk(MPT2SAS_WARN_FMT
- "no suitable consistent DMA mask for %s\n",
- ioc->name, pci_name(ioc->pdev));
- goto out;
- }
- }
-
- 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;
- 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->scsiio_depth;
- sz = ((ioc->scsiio_depth + 1) * 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: 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->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH)
- goto out;
- retry_sz += 64;
- 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: 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);
-
-
- /* 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);
-
-
- 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->hba_queue_depth, ioc->request_sz,
- (ioc->hba_queue_depth * ioc->request_sz)/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
- ioc->name, (unsigned long long) ioc->request_dma));
- total_sz += sz;
-
- sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker);
- ioc->scsi_lookup_pages = get_order(sz);
- ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages(
- GFP_KERNEL, ioc->scsi_lookup_pages);
- if (!ioc->scsi_lookup) {
- printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, "
- "sz(%d)\n", ioc->name, (int)sz);
- goto out;
- }
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): "
- "depth(%d)\n", ioc->name, ioc->request,
- ioc->scsiio_depth));
-
- ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH);
- sz = ioc->chain_depth * sizeof(struct chain_tracker);
- ioc->chain_pages = get_order(sz);
-
- ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
- GFP_KERNEL, ioc->chain_pages);
- if (!ioc->chain_lookup) {
- printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, "
- "sz(%d)\n", ioc->name, (int)sz);
- goto out;
- }
- ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
- ioc->request_sz, 16, 0);
- if (!ioc->chain_dma_pool) {
- printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create "
- "failed\n", ioc->name);
- goto out;
- }
- for (i = 0; i < ioc->chain_depth; i++) {
- ioc->chain_lookup[i].chain_buffer = pci_pool_alloc(
- ioc->chain_dma_pool , GFP_KERNEL,
- &ioc->chain_lookup[i].chain_buffer_dma);
- if (!ioc->chain_lookup[i].chain_buffer) {
- ioc->chain_depth = i;
- goto chain_done;
- }
- total_sz += ioc->request_sz;
- }
-chain_done:
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth"
- "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
- ioc->request_sz))/1024));
-
- /* 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->scsiio_depth * SCSI_SENSE_BUFFERSIZE;
- ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,
- 0);
- if (!ioc->sense_dma_pool) {
- printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n",
- ioc->name);
- goto out;
- }
- ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL,
- &ioc->sense_dma);
- if (!ioc->sense) {
- printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n",
- ioc->name);
- goto out;
- }
- 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->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));
- total_sz += sz;
-
- /* reply pool, 4 byte align */
- sz = ioc->reply_free_queue_depth * ioc->reply_sz;
- ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4,
- 0);
- if (!ioc->reply_dma_pool) {
- printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n",
- ioc->name);
- goto out;
- }
- ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL,
- &ioc->reply_dma);
- if (!ioc->reply) {
- printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n",
- ioc->name);
- goto out;
- }
- ioc->reply_dma_min_address = (u32)(ioc->reply_dma);
- ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz;
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth"
- "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply,
- ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n",
- ioc->name, (unsigned long long)ioc->reply_dma));
- total_sz += sz;
-
- /* reply free queue, 16 byte align */
- sz = ioc->reply_free_queue_depth * 4;
- ioc->reply_free_dma_pool = pci_pool_create("reply_free pool",
- ioc->pdev, sz, 16, 0);
- if (!ioc->reply_free_dma_pool) {
- printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create "
- "failed\n", ioc->name);
- goto out;
- }
- ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL,
- &ioc->reply_free_dma);
- if (!ioc->reply_free) {
- printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc "
- "failed\n", ioc->name);
- goto out;
- }
- memset(ioc->reply_free, 0, sz);
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): "
- "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma"
- "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
- total_sz += sz;
-
- ioc->config_page_sz = 512;
- ioc->config_page = pci_alloc_consistent(ioc->pdev,
- ioc->config_page_sz, &ioc->config_page_dma);
- if (!ioc->config_page) {
- printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc "
- "failed\n", ioc->name);
- goto out;
- }
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
- "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
- "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
- total_sz += ioc->config_page_sz;
-
- printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
- ioc->name, total_sz/1024);
- printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
- "Max Controller Queue Depth(%d)\n",
- ioc->name, ioc->shost->can_queue, facts->RequestCredit);
- printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
- ioc->name, ioc->shost->sg_tablesize);
- return 0;
-
- out:
- return -ENOMEM;
-}
-
-
-/**
- * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter.
- * @ioc: Pointer to MPT_ADAPTER structure
- * @cooked: Request raw or cooked IOC state
- *
- * Returns all IOC Doorbell register bits if cooked==0, else just the
- * Doorbell bits in MPI_IOC_STATE_MASK.
- */
-u32
-mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked)
-{
- u32 s, sc;
-
- s = readl(&ioc->chip->Doorbell);
- sc = s & MPI2_IOC_STATE_MASK;
- return cooked ? sc : s;
-}
-
-/**
- * _base_wait_on_iocstate - waiting on a particular ioc state
- * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
- int sleep_flag)
-{
- u32 count, cntdn;
- u32 current_state;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- current_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (current_state == ioc_state)
- return 0;
- if (count && current_state == MPI2_IOC_STATE_FAULT)
- break;
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- return current_state;
-}
-
-/**
- * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
- * a write to the doorbell)
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
- */
-static int
-_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 cntdn, count;
- u32 int_status;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- int_status = readl(&ioc->chip->HostInterruptStatus);
- if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "successful count(%d), timeout(%d)\n", ioc->name,
- __func__, count, timeout));
- return 0;
- }
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
- "int_status(%x)!\n", ioc->name, __func__, count, int_status);
- return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
- * doorbell.
- */
-static int
-_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 cntdn, count;
- u32 int_status;
- u32 doorbell;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- int_status = readl(&ioc->chip->HostInterruptStatus);
- if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "successful count(%d), timeout(%d)\n", ioc->name,
- __func__, count, timeout));
- return 0;
- } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- doorbell = readl(&ioc->chip->Doorbell);
- if ((doorbell & MPI2_IOC_STATE_MASK) ==
- MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc , doorbell);
- return -EFAULT;
- }
- } else if (int_status == 0xFFFFFFFF)
- goto out;
-
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- out:
- printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
- "int_status(%x)!\n", ioc->name, __func__, count, int_status);
- return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 cntdn, count;
- u32 doorbell_reg;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- doorbell_reg = readl(&ioc->chip->Doorbell);
- if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "successful count(%d), timeout(%d)\n", ioc->name,
- __func__, count, timeout));
- return 0;
- }
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
- "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg);
- return -EFAULT;
-}
-
-/**
- * _base_send_ioc_reset - send doorbell reset
- * @ioc: per adapter object
- * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout,
- int sleep_flag)
-{
- u32 ioc_state;
- int r = 0;
-
- if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
- printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n",
- ioc->name, __func__);
- return -EFAULT;
- }
-
- if (!(ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY))
- return -EFAULT;
-
- printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name);
-
- writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
- &ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) {
- r = -EFAULT;
- goto out;
- }
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
- timeout, sleep_flag);
- if (ioc_state) {
- printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
- " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
- r = -EFAULT;
- goto out;
- }
- out:
- printk(MPT2SAS_INFO_FMT "message unit reset: %s\n",
- ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
- return r;
-}
-
-/**
- * _base_handshake_req_reply_wait - send request thru doorbell interface
- * @ioc: per adapter object
- * @request_bytes: request length
- * @request: pointer having request payload
- * @reply_bytes: reply length
- * @reply: pointer to reply payload
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
- u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
-{
- MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
- int i;
- u8 failed;
- u16 dummy;
- __le32 *mfp;
-
- /* make sure doorbell is not in use */
- if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
- printk(MPT2SAS_ERR_FMT "doorbell is in use "
- " (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* clear pending doorbell interrupts from previous state changes */
- if (readl(&ioc->chip->HostInterruptStatus) &
- MPI2_HIS_IOC2SYS_DB_STATUS)
- writel(0, &ioc->chip->HostInterruptStatus);
-
- /* send message to ioc */
- writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
- ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
- &ioc->chip->Doorbell);
-
- 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;
- }
- writel(0, &ioc->chip->HostInterruptStatus);
-
- if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "ack failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* send message 32-bits at a time */
- for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
- writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
- failed = 1;
- }
-
- if (failed) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "sending request failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* now wait for the reply */
- if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "int failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* read the first two 16-bits, it gives the total length of the reply */
- reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
- writel(0, &ioc->chip->HostInterruptStatus);
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "int failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
- reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
- writel(0, &ioc->chip->HostInterruptStatus);
-
- for (i = 2; i < default_reply->MsgLength * 2; i++) {
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell "
- "handshake int failed (line=%d)\n", ioc->name,
- __LINE__);
- return -EFAULT;
- }
- if (i >= reply_bytes/2) /* overflow case */
- dummy = readl(&ioc->chip->Doorbell);
- else
- reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
- writel(0, &ioc->chip->HostInterruptStatus);
- }
-
- _base_wait_for_doorbell_int(ioc, 5, sleep_flag);
- if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use "
- " (line=%d)\n", ioc->name, __LINE__));
- }
- writel(0, &ioc->chip->HostInterruptStatus);
-
- if (ioc->logging_level & MPT_DEBUG_INIT) {
- mfp = (__le32 *)reply;
- printk(KERN_INFO "\toffset:data\n");
- for (i = 0; i < reply_bytes/4; i++)
- printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
- le32_to_cpu(mfp[i]));
- }
- return 0;
-}
-
-/**
- * mpt2sas_base_sas_iounit_control - send sas iounit control to FW
- * @ioc: per adapter object
- * @mpi_reply: the reply payload from FW
- * @mpi_request: the request payload sent to FW
- *
- * The SAS IO Unit Control Request message allows the host to perform low-level
- * operations, such as resets on the PHYs of the IO Unit, also allows the host
- * to obtain the IOC assigned device handles for a device if it has other
- * identifying information about the device, in addition allows the host to
- * remove IOC resources associated with the device.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SasIoUnitControlReply_t *mpi_reply,
- Mpi2SasIoUnitControlRequest_t *mpi_request)
-{
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- bool issue_reset = false;
- int rc;
- void *request;
- u16 wait_state_count;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mutex_lock(&ioc->base_cmds.mutex);
-
- if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->base_cmds.status = MPT2_CMD_PENDING;
- request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->base_cmds.smid = smid;
- memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t));
- 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;
- init_completion(&ioc->base_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
- msecs_to_jiffies(10000));
- 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)
- ioc->ioc_link_reset_in_progress = 0;
- if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SasIoUnitControlRequest_t)/4);
- if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
- issue_reset = true;
- goto issue_host_reset;
- }
- if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
- memcpy(mpi_reply, ioc->base_cmds.reply,
- sizeof(Mpi2SasIoUnitControlReply_t));
- else
- memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t));
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- goto out;
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- rc = -EFAULT;
- out:
- mutex_unlock(&ioc->base_cmds.mutex);
- return rc;
-}
-
-
-/**
- * mpt2sas_base_scsi_enclosure_processor - sending request to sep device
- * @ioc: per adapter object
- * @mpi_reply: the reply payload from FW
- * @mpi_request: the request payload sent to FW
- *
- * The SCSI Enclosure Processor request message causes the IOC to
- * communicate with SES devices to control LED status signals.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request)
-{
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- bool issue_reset = false;
- int rc;
- void *request;
- u16 wait_state_count;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mutex_lock(&ioc->base_cmds.mutex);
-
- if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->base_cmds.status = MPT2_CMD_PENDING;
- request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->base_cmds.smid = smid;
- memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
- init_completion(&ioc->base_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
- msecs_to_jiffies(10000));
- if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SepRequest_t)/4);
- if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
- issue_reset = true;
- goto issue_host_reset;
- }
- if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
- memcpy(mpi_reply, ioc->base_cmds.reply,
- sizeof(Mpi2SepReply_t));
- else
- memset(mpi_reply, 0, sizeof(Mpi2SepReply_t));
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- goto out;
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- rc = -EFAULT;
- out:
- mutex_unlock(&ioc->base_cmds.mutex);
- return rc;
-}
-
-/**
- * _base_get_port_facts - obtain port facts reply and save in ioc
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
-{
- Mpi2PortFactsRequest_t mpi_request;
- Mpi2PortFactsReply_t mpi_reply;
- struct mpt2sas_port_facts *pfacts;
- int mpi_reply_sz, mpi_request_sz, r;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
- mpi_request_sz = sizeof(Mpi2PortFactsRequest_t);
- memset(&mpi_request, 0, mpi_request_sz);
- mpi_request.Function = MPI2_FUNCTION_PORT_FACTS;
- mpi_request.PortNumber = port;
- r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
- (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
-
- if (r != 0) {
- printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
- return r;
- }
-
- pfacts = &ioc->pfacts[port];
- memset(pfacts, 0, sizeof(struct mpt2sas_port_facts));
- pfacts->PortNumber = mpi_reply.PortNumber;
- pfacts->VP_ID = mpi_reply.VP_ID;
- pfacts->VF_ID = mpi_reply.VF_ID;
- pfacts->MaxPostedCmdBuffers =
- le16_to_cpu(mpi_reply.MaxPostedCmdBuffers);
-
- return 0;
-}
-
-/**
- * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL
- * @ioc: per adapter object
- * @timeout:
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_wait_for_iocstate(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 ioc_state, doorbell;
- int rc;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->pci_error_recovery)
- return 0;
-
- doorbell = mpt2sas_base_get_iocstate(ioc, 0);
- ioc_state = doorbell & MPI2_IOC_STATE_MASK;
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n",
- ioc->name, __func__, ioc_state));
-
- switch (ioc_state) {
- case MPI2_IOC_STATE_READY:
- case MPI2_IOC_STATE_OPERATIONAL:
- return 0;
- }
-
- if (doorbell & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
- "unexpected doorbell activ!e\n", ioc->name));
- goto issue_diag_reset;
- }
-
- if (ioc_state == MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc, doorbell &
- MPI2_DOORBELL_DATA_MASK);
- goto issue_diag_reset;
- }
-
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
- timeout, sleep_flag);
- if (ioc_state) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed going to ready state (ioc_state=0x%x)\n",
- ioc->name, __func__, ioc_state);
- return -EFAULT;
- }
-
- issue_diag_reset:
- rc = _base_diag_reset(ioc, sleep_flag);
- return rc;
-}
-
-/**
- * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- Mpi2IOCFactsRequest_t mpi_request;
- Mpi2IOCFactsReply_t mpi_reply;
- struct mpt2sas_facts *facts;
- int mpi_reply_sz, mpi_request_sz, r;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- r = _base_wait_for_iocstate(ioc, 10, sleep_flag);
- if (r) {
- printk(MPT2SAS_ERR_FMT "%s: failed getting to correct state\n",
- ioc->name, __func__);
- return r;
- }
-
- mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
- mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
- memset(&mpi_request, 0, mpi_request_sz);
- mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
- r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
- (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
-
- if (r != 0) {
- printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
- return r;
- }
-
- facts = &ioc->facts;
- memset(facts, 0, sizeof(struct mpt2sas_facts));
- facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
- facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
- facts->VP_ID = mpi_reply.VP_ID;
- facts->VF_ID = mpi_reply.VF_ID;
- facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
- facts->MaxChainDepth = mpi_reply.MaxChainDepth;
- facts->WhoInit = mpi_reply.WhoInit;
- facts->NumberOfPorts = mpi_reply.NumberOfPorts;
- facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
- facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
- facts->MaxReplyDescriptorPostQueueDepth =
- le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
- facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
- facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
- if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
- ioc->ir_firmware = 1;
- if ((facts->IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
- ioc->rdpq_array_capable = 1;
- facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
- facts->IOCRequestFrameSize =
- le16_to_cpu(mpi_reply.IOCRequestFrameSize);
- facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
- facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
- ioc->shost->max_id = -1;
- facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
- facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
- facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
- facts->HighPriorityCredit =
- le16_to_cpu(mpi_reply.HighPriorityCredit);
- facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
- facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), "
- "max chains per io(%d)\n", ioc->name, facts->RequestCredit,
- facts->MaxChainDepth));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), "
- "reply frame size(%d)\n", ioc->name,
- facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
- return 0;
-}
-
-/**
- * _base_send_ioc_init - send ioc_init to firmware
- * @ioc: per adapter object
- * @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, int sleep_flag)
-{
- Mpi2IOCInitRequest_t mpi_request;
- Mpi2IOCInitReply_t mpi_reply;
- int i, r = 0;
- struct timeval current_time;
- u16 ioc_status;
- u32 reply_post_free_array_sz = 0;
- Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
- dma_addr_t reply_post_free_array_dma;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- 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 = 0; /* TODO */
- mpi_request.VP_ID = 0;
- mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
- mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
-
- if (_base_is_controller_msix_enabled(ioc))
- mpi_request.HostMSIxVectors = ioc->reply_queue_count;
- mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
- mpi_request.ReplyDescriptorPostQueueDepth =
- cpu_to_le16(ioc->reply_post_queue_depth);
- mpi_request.ReplyFreeQueueDepth =
- cpu_to_le16(ioc->reply_free_queue_depth);
-
- mpi_request.SenseBufferAddressHigh =
- cpu_to_le32((u64)ioc->sense_dma >> 32);
- mpi_request.SystemReplyAddressHigh =
- cpu_to_le32((u64)ioc->reply_dma >> 32);
- mpi_request.SystemRequestFrameBaseAddress =
- cpu_to_le64((u64)ioc->request_dma);
- mpi_request.ReplyFreeQueueAddress =
- cpu_to_le64((u64)ioc->reply_free_dma);
-
- if (ioc->rdpq_array_enable) {
- reply_post_free_array_sz = ioc->reply_queue_count *
- sizeof(Mpi2IOCInitRDPQArrayEntry);
- reply_post_free_array = pci_alloc_consistent(ioc->pdev,
- reply_post_free_array_sz, &reply_post_free_array_dma);
- if (!reply_post_free_array) {
- printk(MPT2SAS_ERR_FMT
- "reply_post_free_array: pci_alloc_consistent failed\n",
- ioc->name);
- r = -ENOMEM;
- goto out;
- }
- memset(reply_post_free_array, 0, reply_post_free_array_sz);
- for (i = 0; i < ioc->reply_queue_count; i++)
- reply_post_free_array[i].RDPQBaseAddress =
- cpu_to_le64(
- (u64)ioc->reply_post[i].reply_post_free_dma);
- mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
- mpi_request.ReplyDescriptorPostQueueAddress =
- cpu_to_le64((u64)reply_post_free_array_dma);
- } else {
- mpi_request.ReplyDescriptorPostQueueAddress =
- cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
- }
-
- /* This time stamp specifies number of milliseconds
- * since epoch ~ midnight January 1, 1970.
- */
- do_gettimeofday(&current_time);
- mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 +
- (current_time.tv_usec / 1000));
-
- if (ioc->logging_level & MPT_DEBUG_INIT) {
- __le32 *mfp;
- int i;
-
- mfp = (__le32 *)&mpi_request;
- printk(KERN_INFO "\toffset:data\n");
- for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
- printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
- le32_to_cpu(mfp[i]));
- }
-
- r = _base_handshake_req_reply_wait(ioc,
- sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
- sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10,
- sleep_flag);
-
- if (r != 0) {
- printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
- goto out;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS ||
- mpi_reply.IOCLogInfo) {
- printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__);
- r = -EIO;
- }
-
-out:
- if (reply_post_free_array)
- pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
- reply_post_free_array,
- reply_post_free_array_dma);
- return r;
-}
-
-/**
- * mpt2sas_port_enable_done - command completion routine for port enable
- * @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)
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-u8
-mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
- u16 ioc_status;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
- return 1;
-
- if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
-
- ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID;
- memcpy(ioc->port_enable_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- }
- ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING;
-
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- ioc->port_enable_failed = 1;
-
- if (ioc->is_driver_loading) {
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- mpt2sas_port_enable_complete(ioc);
- return 1;
- } else {
- ioc->start_scan_failed = ioc_status;
- ioc->start_scan = 0;
- return 1;
- }
- }
- complete(&ioc->port_enable_cmds.done);
- return 1;
-}
-
-
-/**
- * _base_send_port_enable - send port_enable(discovery stuff) to firmware
- * @ioc: per adapter object
- * @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, int sleep_flag)
-{
- Mpi2PortEnableRequest_t *mpi_request;
- Mpi2PortEnableReply_t *mpi_reply;
- unsigned long timeleft;
- int r = 0;
- u16 smid;
- u16 ioc_status;
-
- printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name);
-
- if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {
- printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- ioc->port_enable_cmds.status = MPT2_CMD_PENDING;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->port_enable_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
- mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
-
- init_completion(&ioc->port_enable_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done,
- 300*HZ);
- if (!(ioc->port_enable_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2PortEnableRequest_t)/4);
- if (ioc->port_enable_cmds.status & MPT2_CMD_RESET)
- r = -EFAULT;
- else
- r = -ETIME;
- goto out;
- }
- mpi_reply = ioc->port_enable_cmds.reply;
-
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n",
- ioc->name, __func__, ioc_status);
- r = -EFAULT;
- goto out;
- }
- out:
- ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED;
- printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ?
- "SUCCESS" : "FAILED"));
- return r;
-}
-
-/**
- * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply)
- * @ioc: per adapter object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2PortEnableRequest_t *mpi_request;
- u16 smid;
-
- printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name);
-
- if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {
- printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- ioc->port_enable_cmds.status = MPT2_CMD_PENDING;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->port_enable_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
- mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
-
- mpt2sas_base_put_smid_default(ioc, smid);
- return 0;
-}
-
-/**
- * _base_determine_wait_on_discovery - desposition
- * @ioc: per adapter object
- *
- * Decide whether to wait on discovery to complete. Used to either
- * locate boot device, or report volumes ahead of physical devices.
- *
- * Returns 1 for wait, 0 for don't wait
- */
-static int
-_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc)
-{
- /* We wait for discovery to complete if IR firmware is loaded.
- * The sas topology events arrive before PD events, so we need time to
- * turn on the bit in ioc->pd_handles to indicate PD
- * Also, it maybe required to report Volumes ahead of physical
- * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set.
- */
- if (ioc->ir_firmware)
- return 1;
-
- /* if no Bios, then we don't need to wait */
- if (!ioc->bios_pg3.BiosVersion)
- return 0;
-
- /* Bios is present, then we drop down here.
- *
- * If there any entries in the Bios Page 2, then we wait
- * for discovery to complete.
- */
-
- /* Current Boot Device */
- if ((ioc->bios_pg2.CurrentBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK) ==
- MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED &&
- /* Request Boot Device */
- (ioc->bios_pg2.ReqBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK) ==
- MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED &&
- /* Alternate Request Boot Device */
- (ioc->bios_pg2.ReqAltBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK) ==
- MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED)
- return 0;
-
- return 1;
-}
-
-
-/**
- * _base_unmask_events - turn on notification for this event
- * @ioc: per adapter object
- * @event: firmware event
- *
- * The mask is stored in ioc->event_masks.
- */
-static void
-_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)
-{
- u32 desired_event;
-
- if (event >= 128)
- return;
-
- desired_event = (1 << (event % 32));
-
- if (event < 32)
- ioc->event_masks[0] &= ~desired_event;
- else if (event < 64)
- ioc->event_masks[1] &= ~desired_event;
- else if (event < 96)
- ioc->event_masks[2] &= ~desired_event;
- else if (event < 128)
- ioc->event_masks[3] &= ~desired_event;
-}
-
-/**
- * _base_event_notification - send event notification
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- Mpi2EventNotificationRequest_t *mpi_request;
- unsigned long timeleft;
- u16 smid;
- int r = 0;
- int i;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
- printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
- ioc->base_cmds.status = MPT2_CMD_PENDING;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->base_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
- mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
- 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] =
- cpu_to_le32(ioc->event_masks[i]);
- init_completion(&ioc->base_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- 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",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2EventNotificationRequest_t)/4);
- if (ioc->base_cmds.status & MPT2_CMD_RESET)
- r = -EFAULT;
- else
- r = -ETIME;
- } else
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
- ioc->name, __func__));
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- return r;
-}
-
-/**
- * mpt2sas_base_validate_event_type - validating event types
- * @ioc: per adapter object
- * @event: firmware event
- *
- * This will turn on firmware event notification when application
- * ask for that event. We don't mask events that are already enabled.
- */
-void
-mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)
-{
- int i, j;
- u32 event_mask, desired_event;
- u8 send_update_to_fw;
-
- for (i = 0, send_update_to_fw = 0; i <
- MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) {
- event_mask = ~event_type[i];
- desired_event = 1;
- for (j = 0; j < 32; j++) {
- if (!(event_mask & desired_event) &&
- (ioc->event_masks[i] & desired_event)) {
- ioc->event_masks[i] &= ~desired_event;
- send_update_to_fw = 1;
- }
- desired_event = (desired_event << 1);
- }
- }
-
- if (!send_update_to_fw)
- return;
-
- mutex_lock(&ioc->base_cmds.mutex);
- _base_event_notification(ioc, CAN_SLEEP);
- mutex_unlock(&ioc->base_cmds.mutex);
-}
-
-/**
- * _base_diag_reset - the "big hammer" start of day reset
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- u32 host_diagnostic;
- u32 ioc_state;
- u32 count;
- u32 hcb_size;
-
- printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
- ioc->name));
-
- count = 0;
- do {
- /* Write magic sequence to WriteSequence register
- * Loop until in diagnostic mode
- */
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic "
- "sequence\n", ioc->name));
- writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence);
-
- /* wait 100 msec */
- if (sleep_flag == CAN_SLEEP)
- msleep(100);
- else
- mdelay(100);
-
- if (count++ > 20)
- goto out;
-
- host_diagnostic = readl(&ioc->chip->HostDiagnostic);
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic "
- "sequence: count(%d), host_diagnostic(0x%08x)\n",
- ioc->name, count, host_diagnostic));
-
- } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
-
- hcb_size = readl(&ioc->chip->HCBSize);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n",
- ioc->name));
- writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
- &ioc->chip->HostDiagnostic);
-
- /* This delay allows the chip PCIe hardware time to finish reset tasks*/
- if (sleep_flag == CAN_SLEEP)
- msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
- else
- mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
-
- /* Approximately 300 second max wait */
- for (count = 0; count < (300000000 /
- MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {
-
- host_diagnostic = readl(&ioc->chip->HostDiagnostic);
-
- if (host_diagnostic == 0xFFFFFFFF)
- goto out;
- if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
- break;
-
- /* Wait to pass the second read delay window */
- if (sleep_flag == CAN_SLEEP)
- msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
- /1000);
- else
- mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
- /1000);
- }
-
- if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter "
- "assuming the HCB Address points to good F/W\n",
- ioc->name));
- host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
- host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
- writel(host_diagnostic, &ioc->chip->HostDiagnostic);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT
- "re-enable the HCDW\n", ioc->name));
- writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
- &ioc->chip->HCBSize);
- }
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n",
- ioc->name));
- writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
- &ioc->chip->HostDiagnostic);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the "
- "diagnostic register\n", ioc->name));
- writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the "
- "READY state\n", ioc->name));
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
- sleep_flag);
- if (ioc_state) {
- printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
- " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
- goto out;
- }
-
- printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
- return 0;
-
- out:
- printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name);
- return -EFAULT;
-}
-
-/**
- * _base_make_ioc_ready - put controller in READY state
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- * @type: FORCE_BIG_HAMMER or SOFT_RESET
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
- enum reset_type type)
-{
- u32 ioc_state;
- int rc;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->pci_error_recovery)
- return 0;
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n",
- ioc->name, __func__, ioc_state));
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
- return 0;
-
- if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
- "active!\n", ioc->name));
- goto issue_diag_reset;
- }
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc, ioc_state &
- MPI2_DOORBELL_DATA_MASK);
- goto issue_diag_reset;
- }
-
- if (type == FORCE_BIG_HAMMER)
- goto issue_diag_reset;
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
- if (!(_base_send_ioc_reset(ioc,
- MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) {
- ioc->ioc_reset_count++;
- return 0;
- }
-
- issue_diag_reset:
- rc = _base_diag_reset(ioc, CAN_SLEEP);
- ioc->ioc_reset_count++;
- return rc;
-}
-
-/**
- * _base_make_ioc_operational - put controller in OPERATIONAL state
- * @ioc: per adapter object
- * @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, int sleep_flag)
-{
- int r, i;
- unsigned long flags;
- u32 reply_address;
- u16 smid;
- struct _tr_list *delayed_tr, *delayed_tr_next;
- u8 hide_flag;
- struct adapter_reply_queue *reply_q;
- long reply_post_free;
- u32 reply_post_free_sz, index = 0;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_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);
- }
-
- list_for_each_entry_safe(delayed_tr, delayed_tr_next,
- &ioc->delayed_tr_volume_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);
- smid = 1;
- for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
- INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list);
- ioc->scsi_lookup[i].cb_idx = 0xFF;
- ioc->scsi_lookup[i].smid = smid;
- ioc->scsi_lookup[i].scmd = NULL;
- ioc->scsi_lookup[i].direct_io = 0;
- 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);
- }
-
- /* chain pool */
- INIT_LIST_HEAD(&ioc->free_chain_list);
- for (i = 0; i < ioc->chain_depth; i++)
- list_add_tail(&ioc->chain_lookup[i].tracker_list,
- &ioc->free_chain_list);
-
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- /* initialize Reply Free Queue */
- for (i = 0, reply_address = (u32)ioc->reply_dma ;
- i < ioc->reply_free_queue_depth ; i++, reply_address +=
- ioc->reply_sz)
- ioc->reply_free[i] = cpu_to_le32(reply_address);
-
- /* initialize reply queues */
- if (ioc->is_driver_loading)
- _base_assign_reply_queues(ioc);
-
- /* initialize Reply Post Free Queue */
- reply_post_free_sz = ioc->reply_post_queue_depth *
- sizeof(Mpi2DefaultReplyDescriptor_t);
- reply_post_free = (long)ioc->reply_post[index].reply_post_free;
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- reply_q->reply_post_host_index = 0;
- reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
- reply_post_free;
- for (i = 0; i < ioc->reply_post_queue_depth; i++)
- reply_q->reply_post_free[i].Words =
- cpu_to_le64(ULLONG_MAX);
- if (!_base_is_controller_msix_enabled(ioc))
- goto skip_init_reply_post_free_queue;
- /*
- * If RDPQ is enabled, switch to the next allocation.
- * Otherwise advance within the contiguous region.
- */
- if (ioc->rdpq_array_enable)
- reply_post_free = (long)
- ioc->reply_post[++index].reply_post_free;
- else
- reply_post_free += reply_post_free_sz;
- }
- skip_init_reply_post_free_queue:
-
- r = _base_send_ioc_init(ioc, sleep_flag);
- if (r)
- return r;
-
- /* initialize reply free host index */
- ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
- writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
-
- /* initialize reply post host index */
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT,
- &ioc->chip->ReplyPostHostIndex);
- if (!_base_is_controller_msix_enabled(ioc))
- goto skip_init_reply_post_host_index;
- }
-
- skip_init_reply_post_host_index:
-
- _base_unmask_interrupts(ioc);
-
- r = _base_event_notification(ioc, sleep_flag);
- if (r)
- return r;
-
- if (sleep_flag == CAN_SLEEP)
- _base_static_config_pages(ioc);
-
-
- if (ioc->is_driver_loading) {
- if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
- == 0x80) {
- hide_flag = (u8) (
- le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) &
- MFG_PAGE10_HIDE_SSDS_MASK);
- if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK)
- ioc->mfg_pg10_hide_flag = hide_flag;
- }
- ioc->wait_for_discovery_to_complete =
- _base_determine_wait_on_discovery(ioc);
- return r; /* scan_start and scan_finished support */
- }
- r = _base_send_port_enable(ioc, sleep_flag);
- if (r)
- return r;
-
- return r;
-}
-
-/**
- * mpt2sas_base_free_resources - free resources controller resources (io/irq/memap)
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-void
-mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
-{
- struct pci_dev *pdev = ioc->pdev;
-
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- /* synchronizing freeing resource with pci_access_mutex lock */
- mutex_lock(&ioc->pci_access_mutex);
- if (ioc->chip_phys && ioc->chip) {
- _base_mask_interrupts(ioc);
- ioc->shost_recovery = 1;
- _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
- ioc->shost_recovery = 0;
- }
-
- _base_free_irq(ioc);
- _base_disable_msix(ioc);
-
- if (ioc->chip_phys && ioc->chip)
- iounmap(ioc->chip);
- ioc->chip_phys = 0;
-
- if (pci_is_enabled(pdev)) {
- pci_release_selected_regions(ioc->pdev, ioc->bars);
- pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
- }
- mutex_unlock(&ioc->pci_access_mutex);
- return;
-}
-
-/**
- * mpt2sas_base_attach - attach controller instance
- * @ioc: per adapter object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
-{
- int r, i;
- int cpu_id, last_cpu_id = 0;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- /* setup cpu_msix_table */
- ioc->cpu_count = num_online_cpus();
- for_each_online_cpu(cpu_id)
- last_cpu_id = cpu_id;
- ioc->cpu_msix_table_sz = last_cpu_id + 1;
- ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
- ioc->reply_queue_count = 1;
- if (!ioc->cpu_msix_table) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
- "cpu_msix_table failed!!!\n", ioc->name));
- r = -ENOMEM;
- goto out_free_resources;
- }
-
- if (ioc->is_warpdrive) {
- ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
- sizeof(resource_size_t *), GFP_KERNEL);
- if (!ioc->reply_post_host_index) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation "
- "for cpu_msix_table failed!!!\n", ioc->name));
- r = -ENOMEM;
- goto out_free_resources;
- }
- }
-
- ioc->rdpq_array_enable_assigned = 0;
- ioc->dma_mask = 0;
- r = mpt2sas_base_map_resources(ioc);
- if (r)
- goto out_free_resources;
-
- if (ioc->is_warpdrive) {
- ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
- &ioc->chip->ReplyPostHostIndex;
-
- for (i = 1; i < ioc->cpu_msix_table_sz; i++)
- ioc->reply_post_host_index[i] =
- (resource_size_t __iomem *)
- ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
- * 4)));
- }
-
- pci_set_drvdata(ioc->pdev, ioc->shost);
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
- if (r)
- goto out_free_resources;
-
- r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
- if (r)
- goto out_free_resources;
-
- ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
- sizeof(struct mpt2sas_port_facts), GFP_KERNEL);
- if (!ioc->pfacts) {
- r = -ENOMEM;
- 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;
-
- init_waitqueue_head(&ioc->reset_wq);
- /* allocate memory pd handle bitmask list */
- ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
- if (ioc->facts.MaxDevHandle % 8)
- ioc->pd_handles_sz++;
- ioc->pd_handles = kzalloc(ioc->pd_handles_sz,
- GFP_KERNEL);
- if (!ioc->pd_handles) {
- r = -ENOMEM;
- goto out_free_resources;
- }
- ioc->blocking_handles = kzalloc(ioc->pd_handles_sz,
- GFP_KERNEL);
- if (!ioc->blocking_handles) {
- r = -ENOMEM;
- goto out_free_resources;
- }
- ioc->fwfault_debug = mpt2sas_fwfault_debug;
-
- /* base internal command bits */
- mutex_init(&ioc->base_cmds.mutex);
- ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
-
- /* port_enable command bits */
- ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED;
-
- /* transport internal command bits */
- ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->transport_cmds.mutex);
-
- /* scsih internal command bits */
- ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->scsih_cmds.mutex);
-
- /* task management internal command bits */
- ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->tm_cmds.mutex);
-
- /* config page internal command bits */
- ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->config_cmds.mutex);
-
- /* ctl module internal command bits */
- ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->ctl_cmds.mutex);
-
- if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
- !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
- !ioc->config_cmds.reply || !ioc->ctl_cmds.reply ||
- !ioc->ctl_cmds.sense) {
- r = -ENOMEM;
- goto out_free_resources;
- }
-
- if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
- !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
- !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) {
- r = -ENOMEM;
- goto out_free_resources;
- }
-
- for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
- ioc->event_masks[i] = -1;
-
- /* here we enable the events we care about */
- _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
- _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
- _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME);
- _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
- _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
- _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
- _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD);
- r = _base_make_ioc_operational(ioc, CAN_SLEEP);
- if (r)
- goto out_free_resources;
-
- ioc->non_operational_loop = 0;
-
- return 0;
-
- out_free_resources:
-
- ioc->remove_host = 1;
- mpt2sas_base_free_resources(ioc);
- _base_release_memory_pools(ioc);
- pci_set_drvdata(ioc->pdev, NULL);
- kfree(ioc->cpu_msix_table);
- if (ioc->is_warpdrive)
- kfree(ioc->reply_post_host_index);
- kfree(ioc->pd_handles);
- kfree(ioc->blocking_handles);
- kfree(ioc->tm_cmds.reply);
- kfree(ioc->transport_cmds.reply);
- kfree(ioc->scsih_cmds.reply);
- kfree(ioc->config_cmds.reply);
- kfree(ioc->base_cmds.reply);
- kfree(ioc->port_enable_cmds.reply);
- kfree(ioc->ctl_cmds.reply);
- kfree(ioc->ctl_cmds.sense);
- kfree(ioc->pfacts);
- ioc->ctl_cmds.reply = NULL;
- ioc->base_cmds.reply = NULL;
- ioc->tm_cmds.reply = NULL;
- ioc->scsih_cmds.reply = NULL;
- ioc->transport_cmds.reply = NULL;
- ioc->config_cmds.reply = NULL;
- ioc->pfacts = NULL;
- return r;
-}
-
-
-/**
- * mpt2sas_base_detach - remove controller instance
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-void
-mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
-{
-
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mpt2sas_base_stop_watchdog(ioc);
- mpt2sas_base_free_resources(ioc);
- _base_release_memory_pools(ioc);
- pci_set_drvdata(ioc->pdev, NULL);
- kfree(ioc->cpu_msix_table);
- if (ioc->is_warpdrive)
- kfree(ioc->reply_post_host_index);
- kfree(ioc->pd_handles);
- kfree(ioc->blocking_handles);
- kfree(ioc->pfacts);
- kfree(ioc->ctl_cmds.reply);
- kfree(ioc->ctl_cmds.sense);
- kfree(ioc->base_cmds.reply);
- kfree(ioc->port_enable_cmds.reply);
- kfree(ioc->tm_cmds.reply);
- kfree(ioc->transport_cmds.reply);
- kfree(ioc->scsih_cmds.reply);
- kfree(ioc->config_cmds.reply);
-}
-
-/**
- * _base_reset_handler - reset callback handler (for base)
- * @ioc: per adapter object
- * @reset_phase: phase
- *
- * The handler for doing any required cleanup or initialization.
- *
- * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
- * MPT2_IOC_DONE_RESET
- *
- * Return nothing.
- */
-static void
-_base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
-{
- mpt2sas_scsih_reset_handler(ioc, reset_phase);
- mpt2sas_ctl_reset_handler(ioc, reset_phase);
- switch (reset_phase) {
- case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
- break;
- case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
- if (ioc->transport_cmds.status & MPT2_CMD_PENDING) {
- ioc->transport_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid);
- complete(&ioc->transport_cmds.done);
- }
- if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
- ioc->base_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid);
- complete(&ioc->base_cmds.done);
- }
- if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {
- ioc->port_enable_failed = 1;
- ioc->port_enable_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid);
- if (ioc->is_driver_loading) {
- ioc->start_scan_failed =
- MPI2_IOCSTATUS_INTERNAL_ERROR;
- ioc->start_scan = 0;
- ioc->port_enable_cmds.status =
- MPT2_CMD_NOT_USED;
- } else
- complete(&ioc->port_enable_cmds.done);
-
- }
- if (ioc->config_cmds.status & MPT2_CMD_PENDING) {
- ioc->config_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid);
- ioc->config_cmds.smid = USHRT_MAX;
- complete(&ioc->config_cmds.done);
- }
- break;
- case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
- break;
- }
-}
-
-/**
- * _wait_for_commands_to_complete - reset controller
- * @ioc: Pointer to MPT_ADAPTER structure
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * This function waiting(3s) for all pending commands to complete
- * prior to putting controller in reset.
- */
-static void
-_wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- u32 ioc_state;
- unsigned long flags;
- u16 i;
-
- ioc->pending_io_count = 0;
- if (sleep_flag != CAN_SLEEP)
- return;
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL)
- return;
-
- /* pending command count */
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- 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);
-
- if (!ioc->pending_io_count)
- return;
-
- /* wait for pending commands to complete */
- wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ);
-}
-
-/**
- * mpt2sas_base_hard_reset_handler - reset controller
- * @ioc: Pointer to MPT_ADAPTER structure
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- * @type: FORCE_BIG_HAMMER or SOFT_RESET
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
- enum reset_type type)
-{
- int r;
- unsigned long flags;
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- if (ioc->pci_error_recovery) {
- printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n",
- ioc->name, __func__);
- r = 0;
- goto out_unlocked;
- }
-
- if (mpt2sas_fwfault_debug)
- mpt2sas_halt_firmware(ioc);
-
- /* TODO - What we really should be doing is pulling
- * out all the code associated with NO_SLEEP; its never used.
- * That is legacy code from mpt fusion driver, ported over.
- * I will leave this BUG_ON here for now till its been resolved.
- */
- BUG_ON(sleep_flag == NO_SLEEP);
-
- /* wait for an active reset in progress to complete */
- if (!mutex_trylock(&ioc->reset_in_progress_mutex)) {
- do {
- ssleep(1);
- } while (ioc->shost_recovery == 1);
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
- __func__));
- return ioc->ioc_reset_in_progress_status;
- }
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- ioc->shost_recovery = 1;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-
- _base_reset_handler(ioc, MPT2_IOC_PRE_RESET);
- _wait_for_commands_to_complete(ioc, sleep_flag);
- _base_mask_interrupts(ioc);
- r = _base_make_ioc_ready(ioc, sleep_flag, type);
- if (r)
- goto out;
- _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET);
-
- /* If this hard reset is called while port enable is active, then
- * there is no reason to call make_ioc_operational
- */
- if (ioc->is_driver_loading && ioc->port_enable_failed) {
- ioc->remove_host = 1;
- r = -EFAULT;
- goto out;
- }
-
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
- if (r)
- goto out;
-
- if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
- panic("%s: Issue occurred with flashing controller firmware."
- "Please reboot the system and ensure that the correct"
- " firmware version is running\n", ioc->name);
-
- r = _base_make_ioc_operational(ioc, sleep_flag);
- if (!r)
- _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
- out:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n",
- ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- ioc->ioc_reset_in_progress_status = r;
- ioc->shost_recovery = 0;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
- mutex_unlock(&ioc->reset_in_progress_mutex);
-
- out_unlocked:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
- __func__));
- return r;
-}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
deleted file mode 100644
index 97ea360..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
- * This is the Fusion MPT base driver providing common API layer interface
- * for access to MPT (Message Passing Technology) firmware.
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef MPT2SAS_BASE_H_INCLUDED
-#define MPT2SAS_BASE_H_INCLUDED
-
-#include "mpi/mpi2_type.h"
-#include "mpi/mpi2.h"
-#include "mpi/mpi2_ioc.h"
-#include "mpi/mpi2_cnfg.h"
-#include "mpi/mpi2_init.h"
-#include "mpi/mpi2_raid.h"
-#include "mpi/mpi2_tool.h"
-#include "mpi/mpi2_sas.h"
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_transport_sas.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_eh.h>
-
-#include "mpt2sas_debug.h"
-
-/* driver versioning info */
-#define MPT2SAS_DRIVER_NAME "mpt2sas"
-#define MPT2SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
-#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "20.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 20
-#define MPT2SAS_MINOR_VERSION 100
-#define MPT2SAS_BUILD_VERSION 00
-#define MPT2SAS_RELEASE_VERSION 00
-
-/*
- * Set MPT2SAS_SG_DEPTH value based on user input.
- */
-#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE
-#if CONFIG_SCSI_MPT2SAS_MAX_SGE < 16
-#define MPT2SAS_SG_DEPTH 16
-#elif CONFIG_SCSI_MPT2SAS_MAX_SGE > 128
-#define MPT2SAS_SG_DEPTH 128
-#else
-#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE
-#endif
-#else
-#define MPT2SAS_SG_DEPTH 128 /* MAX_HW_SEGMENTS */
-#endif
-
-
-/*
- * Generic Defines
- */
-#define MPT2SAS_SATA_QUEUE_DEPTH 32
-#define MPT2SAS_SAS_QUEUE_DEPTH 254
-#define MPT2SAS_RAID_QUEUE_DEPTH 128
-
-#define MPT_NAME_LENGTH 32 /* generic length of strings */
-#define MPT_STRING_LENGTH 64
-
-#define MPT_MAX_CALLBACKS 16
-
-
-#define CAN_SLEEP 1
-#define NO_SLEEP 0
-
-#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
-
-#define MPI2_HIM_MASK 0xFFFFFFFF /* mask every bit*/
-
-#define MPT2SAS_INVALID_DEVICE_HANDLE 0xFFFF
-
-
-/*
- * reset phases
- */
-#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */
-#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */
-#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */
-
-/*
- * logging format
- */
-#define MPT2SAS_FMT "%s: "
-#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT
-#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT
-#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT
-#define MPT2SAS_ERR_FMT KERN_ERR MPT2SAS_FMT
-
-/*
- * Dell HBA branding
- */
-#define MPT2SAS_DELL_BRANDING_SIZE 32
-
-#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA"
-#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter"
-#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated"
-#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular"
-#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded"
-#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200"
-#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS"
-
-/*
- * Dell HBA SSDIDs
- */
-#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C
-#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D
-#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E
-#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F
-#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20
-#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21
-#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22
-
-/*
- * Intel HBA branding
- */
-#define MPT2SAS_INTEL_RMS25JB080_BRANDING \
- "Intel(R) Integrated RAID Module RMS25JB080"
-#define MPT2SAS_INTEL_RMS25JB040_BRANDING \
- "Intel(R) Integrated RAID Module RMS25JB040"
-#define MPT2SAS_INTEL_RMS25KB080_BRANDING \
- "Intel(R) Integrated RAID Module RMS25KB080"
-#define MPT2SAS_INTEL_RMS25KB040_BRANDING \
- "Intel(R) Integrated RAID Module RMS25KB040"
-#define MPT2SAS_INTEL_RMS25LB040_BRANDING \
- "Intel(R) Integrated RAID Module RMS25LB040"
-#define MPT2SAS_INTEL_RMS25LB080_BRANDING \
- "Intel(R) Integrated RAID Module RMS25LB080"
-#define MPT2SAS_INTEL_RMS2LL080_BRANDING \
- "Intel Integrated RAID Module RMS2LL080"
-#define MPT2SAS_INTEL_RMS2LL040_BRANDING \
- "Intel Integrated RAID Module RMS2LL040"
-#define MPT2SAS_INTEL_RS25GB008_BRANDING \
- "Intel(R) RAID Controller RS25GB008"
-#define MPT2SAS_INTEL_SSD910_BRANDING \
- "Intel(R) SSD 910 Series"
-/*
- * Intel HBA SSDIDs
- */
-#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516
-#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517
-#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518
-#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519
-#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A
-#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B
-#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E
-#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F
-#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000
-#define MPT2SAS_INTEL_SSD910_SSDID 0x3700
-
-/*
- * HP HBA branding
- */
-#define MPT2SAS_HP_3PAR_SSVID 0x1590
-#define MPT2SAS_HP_2_4_INTERNAL_BRANDING "HP H220 Host Bus Adapter"
-#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING "HP H221 Host Bus Adapter"
-#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter"
-#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING "HP H220i Host Bus Adapter"
-#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING "HP H210i Host Bus Adapter"
-
-/*
- * HO HBA SSDIDs
- */
-#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041
-#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042
-#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043
-#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044
-#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046
-
-/*
- * WarpDrive Specific Log codes
- */
-
-#define MPT2_WARPDRIVE_LOGENTRY (0x8002)
-#define MPT2_WARPDRIVE_LC_SSDT (0x41)
-#define MPT2_WARPDRIVE_LC_SSDLW (0x43)
-#define MPT2_WARPDRIVE_LC_SSDLF (0x44)
-#define MPT2_WARPDRIVE_LC_BRMF (0x4D)
-
-/*
- * per target private data
- */
-#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01
-#define MPT_TARGET_FLAGS_VOLUME 0x02
-#define MPT_TARGET_FLAGS_DELETED 0x04
-
-/**
- * struct MPT2SAS_TARGET - starget private hostdata
- * @starget: starget object
- * @sas_address: target sas address
- * @raid_device: raid_device pointer to access volume data
- * @handle: device handle
- * @num_luns: number luns
- * @flags: MPT_TARGET_FLAGS_XXX flags
- * @deleted: target flaged for deletion
- * @tm_busy: target is busy with TM request.
- * @sdev: The sas_device associated with this target
- */
-struct MPT2SAS_TARGET {
- struct scsi_target *starget;
- u64 sas_address;
- struct _raid_device *raid_device;
- u16 handle;
- int num_luns;
- u32 flags;
- u8 deleted;
- u8 tm_busy;
- struct _sas_device *sdev;
-};
-
-
-/*
- * per device private data
- */
-#define MPT_DEVICE_FLAGS_INIT 0x01
-#define MPT_DEVICE_TLR_ON 0x02
-
-/**
- * struct MPT2SAS_DEVICE - sdev private hostdata
- * @sas_target: starget private hostdata
- * @lun: lun number
- * @flags: MPT_DEVICE_XXX flags
- * @configured_lun: lun is configured
- * @block: device is in SDEV_BLOCK state
- * @tlr_snoop_check: flag used in determining whether to disable TLR
- */
-
-/* OEM Identifiers */
-#define MFG10_OEM_ID_INVALID (0x00000000)
-#define MFG10_OEM_ID_DELL (0x00000001)
-#define MFG10_OEM_ID_FSC (0x00000002)
-#define MFG10_OEM_ID_SUN (0x00000003)
-#define MFG10_OEM_ID_IBM (0x00000004)
-
-/* GENERIC Flags 0*/
-#define MFG10_GF0_OCE_DISABLED (0x00000001)
-#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002)
-#define MFG10_GF0_R10_DISPLAY (0x00000004)
-#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008)
-#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010)
-
-/* OEM Specific Flags will come from OEM specific header files */
-typedef struct _MPI2_CONFIG_PAGE_MAN_10 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 00h */
- U8 OEMIdentifier; /* 04h */
- U8 Reserved1; /* 05h */
- U16 Reserved2; /* 08h */
- U32 Reserved3; /* 0Ch */
- U32 GenericFlags0; /* 10h */
- U32 GenericFlags1; /* 14h */
- U32 Reserved4; /* 18h */
- U32 OEMSpecificFlags0; /* 1Ch */
- U32 OEMSpecificFlags1; /* 20h */
- U32 Reserved5[18]; /* 24h-60h*/
-} MPI2_CONFIG_PAGE_MAN_10,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10,
- Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t;
-
-#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003)
-#define MFG_PAGE10_HIDE_ALL_DISKS (0x00)
-#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01)
-#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02)
-
-
-struct MPT2SAS_DEVICE {
- struct MPT2SAS_TARGET *sas_target;
- unsigned int lun;
- u32 flags;
- u8 configured_lun;
- u8 block;
- u8 tlr_snoop_check;
-};
-
-#define MPT2_CMD_NOT_USED 0x8000 /* free */
-#define MPT2_CMD_COMPLETE 0x0001 /* completed */
-#define MPT2_CMD_PENDING 0x0002 /* pending */
-#define MPT2_CMD_REPLY_VALID 0x0004 /* reply is valid */
-#define MPT2_CMD_RESET 0x0008 /* host reset dropped the command */
-
-/**
- * struct _internal_cmd - internal commands struct
- * @mutex: mutex
- * @done: completion
- * @reply: reply message pointer
- * @sense: sense data
- * @status: MPT2_CMD_XXX status
- * @smid: system message id
- */
-struct _internal_cmd {
- struct mutex mutex;
- struct completion done;
- void *reply;
- void *sense;
- u16 status;
- u16 smid;
-};
-
-
-/**
- * struct _sas_device - attached device information
- * @list: sas device list
- * @starget: starget object
- * @sas_address: device sas address
- * @device_name: retrieved from the SAS IDENTIFY frame.
- * @handle: device handle
- * @sas_address_parent: sas address of parent expander or sas host
- * @enclosure_handle: enclosure handle
- * @enclosure_logical_id: enclosure logical identifier
- * @volume_handle: volume handle (valid when hidden raid member)
- * @volume_wwid: volume unique identifier
- * @device_info: bitfield provides detailed info about the device
- * @id: target id
- * @channel: target channel
- * @slot: number number
- * @phy: phy identifier provided in sas device page 0
- * @responding: used in _scsih_sas_device_mark_responding
- * @pfa_led_on: flag for PFA LED status
- */
-struct _sas_device {
- struct list_head list;
- struct scsi_target *starget;
- u64 sas_address;
- u64 device_name;
- u16 handle;
- u64 sas_address_parent;
- u16 enclosure_handle;
- u64 enclosure_logical_id;
- u16 volume_handle;
- u64 volume_wwid;
- u32 device_info;
- int id;
- int channel;
- u16 slot;
- u8 phy;
- u8 responding;
- u8 pfa_led_on;
- struct kref refcount;
-};
-
-static inline void sas_device_get(struct _sas_device *s)
-{
- kref_get(&s->refcount);
-}
-
-static inline void sas_device_free(struct kref *r)
-{
- kfree(container_of(r, struct _sas_device, refcount));
-}
-
-static inline void sas_device_put(struct _sas_device *s)
-{
- kref_put(&s->refcount, sas_device_free);
-}
-
-/**
- * struct _raid_device - raid volume link list
- * @list: sas device list
- * @starget: starget object
- * @sdev: scsi device struct (volumes are single lun)
- * @wwid: unique identifier for the volume
- * @handle: device handle
- * @block_size: Block size of the volume
- * @id: target id
- * @channel: target channel
- * @volume_type: the raid level
- * @device_info: bitfield provides detailed info about the hidden components
- * @num_pds: number of hidden raid components
- * @responding: used in _scsih_raid_device_mark_responding
- * @percent_complete: resync percent complete
- * @direct_io_enabled: Whether direct io to PDs are allowed or not
- * @stripe_exponent: X where 2powX is the stripe sz in blocks
- * @block_exponent: X where 2powX is the block sz in bytes
- * @max_lba: Maximum number of LBA in the volume
- * @stripe_sz: Stripe Size of the volume
- * @device_info: Device info of the volume member disk
- * @pd_handle: Array of handles of the physical drives for direct I/O in le16
- */
-#define MPT_MAX_WARPDRIVE_PDS 8
-struct _raid_device {
- struct list_head list;
- struct scsi_target *starget;
- struct scsi_device *sdev;
- u64 wwid;
- u16 handle;
- u16 block_sz;
- int id;
- int channel;
- u8 volume_type;
- u8 num_pds;
- u8 responding;
- u8 percent_complete;
- u8 direct_io_enabled;
- u8 stripe_exponent;
- u8 block_exponent;
- u64 max_lba;
- u32 stripe_sz;
- u32 device_info;
- u16 pd_handle[MPT_MAX_WARPDRIVE_PDS];
-};
-
-/**
- * struct _boot_device - boot device info
- * @is_raid: flag to indicate whether this is volume
- * @device: holds pointer for either struct _sas_device or
- * struct _raid_device
- */
-struct _boot_device {
- u8 is_raid;
- void *device;
-};
-
-/**
- * struct _sas_port - wide/narrow sas port information
- * @port_list: list of ports belonging to expander
- * @num_phys: number of phys belonging to this port
- * @remote_identify: attached device identification
- * @rphy: sas transport rphy object
- * @port: sas transport wide/narrow port object
- * @phy_list: _sas_phy list objects belonging to this port
- */
-struct _sas_port {
- struct list_head port_list;
- u8 num_phys;
- struct sas_identify remote_identify;
- struct sas_rphy *rphy;
- struct sas_port *port;
- struct list_head phy_list;
-};
-
-/**
- * struct _sas_phy - phy information
- * @port_siblings: list of phys belonging to a port
- * @identify: phy identification
- * @remote_identify: attached device identification
- * @phy: sas transport phy object
- * @phy_id: unique phy id
- * @handle: device handle for this phy
- * @attached_handle: device handle for attached device
- * @phy_belongs_to_port: port has been created for this phy
- */
-struct _sas_phy {
- struct list_head port_siblings;
- struct sas_identify identify;
- struct sas_identify remote_identify;
- struct sas_phy *phy;
- u8 phy_id;
- u16 handle;
- u16 attached_handle;
- u8 phy_belongs_to_port;
-};
-
-/**
- * struct _sas_node - sas_host/expander information
- * @list: list of expanders
- * @parent_dev: parent device class
- * @num_phys: number phys belonging to this sas_host/expander
- * @sas_address: sas address of this sas_host/expander
- * @handle: handle for this sas_host/expander
- * @sas_address_parent: sas address of parent expander or sas host
- * @enclosure_handle: handle for this a member of an enclosure
- * @device_info: bitwise defining capabilities of this sas_host/expander
- * @responding: used in _scsih_expander_device_mark_responding
- * @phy: a list of phys that make up this sas_host/expander
- * @sas_port_list: list of ports attached to this sas_host/expander
- */
-struct _sas_node {
- struct list_head list;
- struct device *parent_dev;
- u8 num_phys;
- u64 sas_address;
- u16 handle;
- u64 sas_address_parent;
- u16 enclosure_handle;
- u64 enclosure_logical_id;
- u8 responding;
- struct _sas_phy *phy;
- struct list_head sas_port_list;
-};
-
-/**
- * enum reset_type - reset state
- * @FORCE_BIG_HAMMER: issue diagnostic reset
- * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer
- */
-enum reset_type {
- FORCE_BIG_HAMMER,
- SOFT_RESET,
-};
-
-/**
- * struct chain_tracker - firmware chain tracker
- * @chain_buffer: chain buffer
- * @chain_buffer_dma: physical address
- * @tracker_list: list of free request (ioc->free_chain_list)
- */
-struct chain_tracker {
- void *chain_buffer;
- dma_addr_t chain_buffer_dma;
- struct list_head tracker_list;
-};
-
-/**
- * struct scsiio_tracker - scsi mf request tracker
- * @smid: system message id
- * @scmd: scsi request pointer
- * @cb_idx: callback index
- * @direct_io: To indicate whether I/O is direct (WARPDRIVE)
- * @chain_list: list of chains associated to this IO
- * @tracker_list: list of free request (ioc->free_list)
- */
-struct scsiio_tracker {
- u16 smid;
- struct scsi_cmnd *scmd;
- u8 cb_idx;
- u8 direct_io;
- struct list_head chain_list;
- struct list_head tracker_list;
-};
-
-/**
- * struct request_tracker - firmware request tracker
- * @smid: system message id
- * @cb_idx: callback index
- * @tracker_list: list of free request (ioc->free_list)
- */
-struct request_tracker {
- u16 smid;
- u8 cb_idx;
- 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);
-
-/**
- * struct adapter_reply_queue - the reply queue struct
- * @ioc: per adapter object
- * @msix_index: msix index into vector table
- * @vector: irq vector
- * @reply_post_host_index: head index in the pool where FW completes IO
- * @reply_post_free: reply post base virt address
- * @name: the name registered to request_irq()
- * @busy: isr is actively processing replies on another cpu
- * @list: this list
-*/
-struct adapter_reply_queue {
- struct MPT2SAS_ADAPTER *ioc;
- u8 msix_index;
- unsigned int vector;
- u32 reply_post_host_index;
- Mpi2ReplyDescriptorsUnion_t *reply_post_free;
- char name[MPT_NAME_LENGTH];
- atomic_t busy;
- cpumask_var_t affinity_hint;
- struct list_head list;
-};
-
-/* IOC Facts and Port Facts converted from little endian to cpu */
-union mpi2_version_union {
- MPI2_VERSION_STRUCT Struct;
- u32 Word;
-};
-
-struct mpt2sas_facts {
- u16 MsgVersion;
- u16 HeaderVersion;
- u8 IOCNumber;
- u8 VP_ID;
- u8 VF_ID;
- u16 IOCExceptions;
- u16 IOCStatus;
- u32 IOCLogInfo;
- u8 MaxChainDepth;
- u8 WhoInit;
- u8 NumberOfPorts;
- u8 MaxMSIxVectors;
- u16 RequestCredit;
- u16 ProductID;
- u32 IOCCapabilities;
- union mpi2_version_union FWVersion;
- u16 IOCRequestFrameSize;
- u16 Reserved3;
- u16 MaxInitiators;
- u16 MaxTargets;
- u16 MaxSasExpanders;
- u16 MaxEnclosures;
- u16 ProtocolFlags;
- u16 HighPriorityCredit;
- u16 MaxReplyDescriptorPostQueueDepth;
- u8 ReplyFrameSize;
- u8 MaxVolumes;
- u16 MaxDevHandle;
- u16 MaxPersistentEntries;
- u16 MinDevHandle;
-};
-
-struct mpt2sas_port_facts {
- u8 PortNumber;
- u8 VP_ID;
- u8 VF_ID;
- u8 PortType;
- u16 MaxPostedCmdBuffers;
-};
-
-struct reply_post_struct {
- Mpi2ReplyDescriptorsUnion_t *reply_post_free;
- dma_addr_t reply_post_free_dma;
-};
-
-/**
- * enum mutex_type - task management mutex type
- * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
- * @TM_MUTEX_ON: mutex is required
- */
-enum mutex_type {
- TM_MUTEX_OFF = 0,
- TM_MUTEX_ON = 1,
-};
-
-typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
-/**
- * struct MPT2SAS_ADAPTER - per adapter struct
- * @list: ioc_list
- * @shost: shost object
- * @id: unique adapter id
- * @cpu_count: number online cpus
- * @name: generic ioc string
- * @tmp_string: tmp string used for logging
- * @pdev: pci pdev object
- * @chip: memory mapped register space
- * @chip_phys: physical addrss prior to mapping
- * @logging_level: see mpt2sas_debug.h
- * @fwfault_debug: debuging FW timeouts
- * @ir_firmware: IR firmware present
- * @bars: bitmask of BAR's that must be configured
- * @mask_interrupts: ignore interrupt
- * @dma_mask: used to set the consistent dma mask
- * @fault_reset_work_q_name: fw fault work queue
- * @fault_reset_work_q: ""
- * @fault_reset_work: ""
- * @firmware_event_name: fw event work queue
- * @firmware_event_thread: ""
- * @fw_events_off: flag to turn off fw event handling
- * @fw_event_lock:
- * @fw_event_list: list of fw events
- * @aen_event_read_flag: event log was read
- * @broadcast_aen_busy: broadcast aen waiting to be serviced
- * @shost_recovery: host reset in progress
- * @ioc_reset_in_progress_lock:
- * @ioc_link_reset_in_progress: phy/hard reset in progress
- * @ignore_loginfos: ignore loginfos during task management
- * @remove_host: flag for when driver unloads, to avoid sending dev resets
- * @pci_error_recovery: flag to prevent ioc access until slot reset completes
- * @wait_for_discovery_to_complete: flag set at driver load time when
- * waiting on reporting devices
- * @is_driver_loading: flag set at driver load time
- * @port_enable_failed: flag set when port enable has failed
- * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work
- * @start_scan_failed: means port enable failed, return's the ioc_status
- * @msix_enable: flag indicating msix is enabled
- * @msix_vector_count: number msix vectors
- * @cpu_msix_table: table for mapping cpus to msix index
- * @cpu_msix_table_sz: table size
- * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands
- * @scsi_io_cb_idx: shost generated commands
- * @tm_cb_idx: task management commands
- * @scsih_cb_idx: scsih internal commands
- * @transport_cb_idx: transport internal commands
- * @ctl_cb_idx: clt internal commands
- * @base_cb_idx: base internal commands
- * @config_cb_idx: base internal commands
- * @tm_tr_cb_idx : device removal target reset handshake
- * @tm_tr_volume_cb_idx : volume removal target reset
- * @base_cmds:
- * @transport_cmds:
- * @scsih_cmds:
- * @tm_cmds:
- * @ctl_cmds:
- * @config_cmds:
- * @base_add_sg_single: handler for either 32/64 bit sgl's
- * @event_type: bits indicating which events to log
- * @event_context: unique id for each logged event
- * @event_log: event log pointer
- * @event_masks: events that are masked
- * @facts: static facts data
- * @pfacts: static port facts data
- * @manu_pg0: static manufacturing page 0
- * @manu_pg10: static manufacturing page 10
- * @bios_pg2: static bios page 2
- * @bios_pg3: static bios page 3
- * @ioc_pg8: static ioc page 8
- * @iounit_pg0: static iounit page 0
- * @iounit_pg1: static iounit page 1
- * @iounit_pg8: static iounit page 8
- * @sas_hba: sas host object
- * @sas_expander_list: expander object list
- * @sas_node_lock:
- * @sas_device_list: sas device object list
- * @sas_device_init_list: sas device object list (used only at init time)
- * @sas_device_lock:
- * @io_missing_delay: time for IO completed by fw when PDR enabled
- * @device_missing_delay: time for device missing by fw when PDR enabled
- * @sas_id : used for setting volume target IDs
- * @blocking_handles: bitmask used to identify which devices need blocking
- * @pd_handles : bitmask for PD handles
- * @pd_handles_sz : size of pd_handle bitmask
- * @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
- * @scsiio_depth: SCSI_IO queue depth
- * @request_sz: per request frame size
- * @request: pool of request frames
- * @request_dma:
- * @request_dma_sz:
- * @scsi_lookup: firmware request tracker list
- * @scsi_lookup_lock:
- * @free_list: free list of request
- * @chain: pool of chains
- * @pending_io_count:
- * @reset_wq:
- * @chain_dma:
- * @max_sges_in_main_message: number sg elements in main message
- * @max_sges_in_chain_message: number sg elements per chain
- * @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:
- * @reply_depth: hba reply queue depth:
- * @reply_sz: per reply frame size:
- * @reply: pool of replys:
- * @reply_dma:
- * @reply_dma_pool:
- * @reply_free_queue_depth: reply free depth
- * @reply_free: pool for reply free queue (32 bit addr)
- * @reply_free_dma:
- * @reply_free_dma_pool:
- * @reply_free_host_index: tail index in pool to insert free replys
- * @reply_post_queue_depth: reply post queue depth
- * @reply_post_struct: struct for reply_post_free physical & virt address
- * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
- * @rdpq_array_enable: rdpq_array support is enabled in the driver
- * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
- * is assigned only ones
- * @reply_queue_count: number of reply queue's
- * @reply_queue_list: link list contaning the reply queue info
- * @reply_post_host_index: head index in the pool where FW completes IO
- * @delayed_tr_list: target reset link list
- * @delayed_tr_volume_list: volume target reset link list
- * @@temp_sensors_count: flag to carry the number of temperature sensors
- * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
- * pci resource handling. PCI resource freeing will lead to free
- * vital hardware/memory resource, which might be in use by cli/sysfs
- * path functions resulting in Null pointer reference followed by kernel
- * crash. To avoid the above race condition we use mutex syncrhonization
- * which ensures the syncrhonization between cli/sysfs_show path
- */
-struct MPT2SAS_ADAPTER {
- struct list_head list;
- struct Scsi_Host *shost;
- u8 id;
- int cpu_count;
- char name[MPT_NAME_LENGTH];
- char tmp_string[MPT_STRING_LENGTH];
- struct pci_dev *pdev;
- Mpi2SystemInterfaceRegs_t __iomem *chip;
- resource_size_t chip_phys;
- int logging_level;
- int fwfault_debug;
- u8 ir_firmware;
- int bars;
- u8 mask_interrupts;
- int dma_mask;
-
- /* fw fault handler */
- char fault_reset_work_q_name[20];
- struct workqueue_struct *fault_reset_work_q;
- struct delayed_work fault_reset_work;
-
- /* fw event handler */
- char firmware_event_name[20];
- struct workqueue_struct *firmware_event_thread;
- spinlock_t fw_event_lock;
- struct list_head fw_event_list;
-
- /* misc flags */
- int aen_event_read_flag;
- u8 broadcast_aen_busy;
- u16 broadcast_aen_pending;
- u8 shost_recovery;
-
- struct mutex reset_in_progress_mutex;
- spinlock_t ioc_reset_in_progress_lock;
- u8 ioc_link_reset_in_progress;
- u8 ioc_reset_in_progress_status;
-
- u8 ignore_loginfos;
- u8 remove_host;
- u8 pci_error_recovery;
- u8 wait_for_discovery_to_complete;
- struct completion port_enable_done;
- u8 is_driver_loading;
- u8 port_enable_failed;
-
- u8 start_scan;
- u16 start_scan_failed;
-
- u8 msix_enable;
- u16 msix_vector_count;
- u8 *cpu_msix_table;
- resource_size_t __iomem **reply_post_host_index;
- u16 cpu_msix_table_sz;
- u32 ioc_reset_count;
- MPT2SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
- u32 non_operational_loop;
-
- /* internal commands, callback index */
- u8 scsi_io_cb_idx;
- u8 tm_cb_idx;
- u8 transport_cb_idx;
- u8 scsih_cb_idx;
- u8 ctl_cb_idx;
- u8 base_cb_idx;
- u8 port_enable_cb_idx;
- u8 config_cb_idx;
- u8 tm_tr_cb_idx;
- u8 tm_tr_volume_cb_idx;
- u8 tm_sas_control_cb_idx;
- struct _internal_cmd base_cmds;
- struct _internal_cmd port_enable_cmds;
- struct _internal_cmd transport_cmds;
- struct _internal_cmd scsih_cmds;
- struct _internal_cmd tm_cmds;
- struct _internal_cmd ctl_cmds;
- struct _internal_cmd config_cmds;
-
- MPT_ADD_SGE base_add_sg_single;
-
- /* event log */
- u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
- u32 event_context;
- void *event_log;
- u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
-
- /* static config pages */
- struct mpt2sas_facts facts;
- struct mpt2sas_port_facts *pfacts;
- Mpi2ManufacturingPage0_t manu_pg0;
- Mpi2BiosPage2_t bios_pg2;
- Mpi2BiosPage3_t bios_pg3;
- Mpi2IOCPage8_t ioc_pg8;
- Mpi2IOUnitPage0_t iounit_pg0;
- Mpi2IOUnitPage1_t iounit_pg1;
- Mpi2IOUnitPage8_t iounit_pg8;
-
- struct _boot_device req_boot_device;
- struct _boot_device req_alt_boot_device;
- struct _boot_device current_boot_device;
-
- /* sas hba, expander, and device list */
- struct _sas_node sas_hba;
- struct list_head sas_expander_list;
- spinlock_t sas_node_lock;
- struct list_head sas_device_list;
- struct list_head sas_device_init_list;
- spinlock_t sas_device_lock;
- struct list_head raid_device_list;
- spinlock_t raid_device_lock;
- u8 io_missing_delay;
- u16 device_missing_delay;
- int sas_id;
- void *blocking_handles;
- void *pd_handles;
- u16 pd_handles_sz;
-
- /* config page */
- u16 config_page_sz;
- void *config_page;
- dma_addr_t config_page_dma;
-
- /* scsiio request */
- u16 hba_queue_depth;
- u16 sge_size;
- u16 scsiio_depth;
- u16 request_sz;
- u8 *request;
- dma_addr_t request_dma;
- u32 request_dma_sz;
- struct scsiio_tracker *scsi_lookup;
- ulong scsi_lookup_pages;
- spinlock_t scsi_lookup_lock;
- struct list_head free_list;
- int pending_io_count;
- wait_queue_head_t reset_wq;
-
- /* chain */
- struct chain_tracker *chain_lookup;
- struct list_head free_chain_list;
- struct dma_pool *chain_dma_pool;
- ulong chain_pages;
- u16 max_sges_in_main_message;
- u16 max_sges_in_chain_message;
- u16 chains_needed_per_io;
- u16 chain_offset_value_for_main_message;
- u32 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;
- struct dma_pool *sense_dma_pool;
-
- /* reply */
- u16 reply_sz;
- u8 *reply;
- dma_addr_t reply_dma;
- u32 reply_dma_max_address;
- u32 reply_dma_min_address;
- struct dma_pool *reply_dma_pool;
-
- /* reply free queue */
- u16 reply_free_queue_depth;
- __le32 *reply_free;
- dma_addr_t reply_free_dma;
- struct dma_pool *reply_free_dma_pool;
- u32 reply_free_host_index;
-
- /* reply post queue */
- u16 reply_post_queue_depth;
- struct reply_post_struct *reply_post;
- u8 rdpq_array_capable;
- u8 rdpq_array_enable;
- u8 rdpq_array_enable_assigned;
- struct dma_pool *reply_post_free_dma_pool;
- u8 reply_queue_count;
- struct list_head reply_queue_list;
-
- struct list_head delayed_tr_list;
- struct list_head delayed_tr_volume_list;
- u8 temp_sensors_count;
-
- /* diag buffer support */
- u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
- u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT];
- dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT];
- u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT];
- u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT];
- Mpi2ManufacturingPage10_t manu_pg10;
- u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
- u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
- u32 ring_buffer_offset;
- u32 ring_buffer_sz;
- u8 is_warpdrive;
- u8 hide_ir_msg;
- u8 mfg_pg10_hide_flag;
- u8 hide_drives;
-
- struct mutex pci_access_mutex;
-};
-
-typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply);
-
-
-/* base shared API */
-extern struct list_head mpt2sas_ioc_list;
-/* spinlock on list operations over IOCs
- * Case: when multiple warpdrive cards(IOCs) are in use
- * Each IOC will added to the ioc list stucture on initialization.
- * Watchdog threads run at regular intervals to check IOC for any
- * fault conditions which will trigger the dead_ioc thread to
- * deallocate pci resource, resulting deleting the IOC netry from list,
- * this deletion need to protected by spinlock to enusre that
- * ioc removal is syncrhonized, if not synchronized it might lead to
- * list_del corruption as the ioc list is traversed in cli path
- */
-extern spinlock_t gioc_lock;
-void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc);
-
-int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc);
-int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc);
-int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
- enum reset_type type);
-
-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);
-__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
- u16 smid);
-void mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc);
-
-/* 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,
- u16 handle);
-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,
- 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);
-
-u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply);
-u8 mpt2sas_port_enable_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);
-
-void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code);
-int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t
- *mpi_request);
-int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request);
-void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
-
-void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
-
-void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
- u16 device_missing_delay, u8 io_missing_delay);
-
-int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc);
-
-/* scsih shared API */
-void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
- u32 reply);
-int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- uint channel, uint id, uint lun, u8 type, u16 smid_task,
- ulong timeout, enum mutex_type m_type);
-void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
-void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
-void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address);
-struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
- u16 handle);
-struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
- *ioc, u64 sas_address);
-struct _sas_device *mpt2sas_get_sdev_by_addr(
- struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-struct _sas_device *__mpt2sas_get_sdev_by_addr(
- struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-
-void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
-
-/* config shared API */
-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);
-int mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page);
-int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2BiosPage2_t *config_page);
-int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2BiosPage3_t *config_page);
-int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOUnitPage0_t *config_page);
-int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz);
-int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOUnitPage1_t *config_page);
-int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOUnitPage1_t *config_page);
-int mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page);
-int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
-int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
-int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
-int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOCPage8_t *config_page);
-int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle);
-int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number);
-int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number);
-int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds);
-int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz);
-int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
- u32 form_specific);
-int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
- u16 *volume_handle);
-int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
- u64 *wwid);
-/* ctl shared API */
-extern struct device_attribute *mpt2sas_host_attrs[];
-extern struct device_attribute *mpt2sas_dev_attrs[];
-void mpt2sas_ctl_init(void);
-void mpt2sas_ctl_exit(void);
-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 msix_index,
- u32 reply);
-void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventNotificationReply_t *mpi_reply);
-
-void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc,
- u8 bits_to_regsiter);
-
-/* transport shared API */
-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, u64 sas_address);
-void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u64 sas_address_parent);
-int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
-int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
-void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address, u16 handle, u8 phy_number, u8 link_rate);
-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,
- enum scsi_device_state new_state);
-
-#endif /* MPT2SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
deleted file mode 100644
index c43815b..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ /dev/null
@@ -1,1527 +0,0 @@
-/*
- * This module provides common API for accessing firmware configuration pages
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/blkdev.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include "mpt2sas_base.h"
-
-/* local definitions */
-
-/* Timeout for config page request (in seconds) */
-#define MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT 15
-
-/* Common sgl flags for READING a config page. */
-#define MPT2_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
- | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT)
-
-/* Common sgl flags for WRITING a config page. */
-#define MPT2_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
- | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \
- << MPI2_SGE_FLAGS_SHIFT)
-
-/**
- * struct config_request - obtain dma memory via routine
- * @sz: size
- * @page: virt pointer
- * @page_dma: phys pointer
- *
- */
-struct config_request{
- u16 sz;
- void *page;
- dma_addr_t page_dma;
-};
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _config_display_some_debug - debug routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @calling_function_name: string pass from calling function
- * @mpi_reply: reply message frame
- * Context: none.
- *
- * Function for displaying debug info helpful when debugging issues
- * in this module.
- */
-static void
-_config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
-{
- Mpi2ConfigRequest_t *mpi_request;
- char *desc = NULL;
-
- if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
- return;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
- case MPI2_CONFIG_PAGETYPE_IO_UNIT:
- desc = "io_unit";
- break;
- case MPI2_CONFIG_PAGETYPE_IOC:
- desc = "ioc";
- break;
- case MPI2_CONFIG_PAGETYPE_BIOS:
- desc = "bios";
- break;
- case MPI2_CONFIG_PAGETYPE_RAID_VOLUME:
- desc = "raid_volume";
- break;
- case MPI2_CONFIG_PAGETYPE_MANUFACTURING:
- desc = "manufaucturing";
- break;
- case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK:
- desc = "physdisk";
- break;
- case MPI2_CONFIG_PAGETYPE_EXTENDED:
- switch (mpi_request->ExtPageType) {
- case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT:
- desc = "sas_io_unit";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER:
- desc = "sas_expander";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE:
- desc = "sas_device";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY:
- desc = "sas_phy";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_LOG:
- desc = "log";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE:
- desc = "enclosure";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG:
- desc = "raid_config";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING:
- desc = "driver_mapping";
- break;
- }
- break;
- }
-
- if (!desc)
- return;
-
- printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), "
- "smid(%d)\n", ioc->name, calling_function_name, desc,
- mpi_request->Header.PageNumber, mpi_request->Action,
- le32_to_cpu(mpi_request->PageAddress), smid);
-
- if (!mpi_reply)
- return;
-
- if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- printk(MPT2SAS_INFO_FMT
- "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
-}
-#endif
-
-/**
- * _config_alloc_config_dma_memory - obtain physical memory
- * @ioc: per adapter object
- * @mem: struct config_request
- *
- * A wrapper for obtaining dma-able memory for config page request.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
- struct config_request *mem)
-{
- int r = 0;
-
- if (mem->sz > ioc->config_page_sz) {
- mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz,
- &mem->page_dma, GFP_KERNEL);
- if (!mem->page) {
- printk(MPT2SAS_ERR_FMT "%s: dma_alloc_coherent"
- " failed asking for (%d) bytes!!\n",
- ioc->name, __func__, mem->sz);
- r = -ENOMEM;
- }
- } else { /* use tmp buffer if less than 512 bytes */
- mem->page = ioc->config_page;
- mem->page_dma = ioc->config_page_dma;
- }
- return r;
-}
-
-/**
- * _config_free_config_dma_memory - wrapper to free the memory
- * @ioc: per adapter object
- * @mem: struct config_request
- *
- * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static void
-_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
- struct config_request *mem)
-{
- if (mem->sz > ioc->config_page_sz)
- dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page,
- mem->page_dma);
-}
-
-/**
- * mpt2sas_config_done - config page 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: none.
- *
- * The callback handler when using _config_request.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-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 1;
- if (ioc->config_cmds.smid != smid)
- return 1;
- ioc->config_cmds.status |= MPT2_CMD_COMPLETE;
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply) {
- ioc->config_cmds.status |= MPT2_CMD_REPLY_VALID;
- memcpy(ioc->config_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- }
- ioc->config_cmds.status &= ~MPT2_CMD_PENDING;
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _config_display_some_debug(ioc, smid, "config_done", mpi_reply);
-#endif
- ioc->config_cmds.smid = USHRT_MAX;
- complete(&ioc->config_cmds.done);
- return 1;
-}
-
-/**
- * _config_request - main routine for sending config page requests
- * @ioc: per adapter object
- * @mpi_request: request message frame
- * @mpi_reply: reply mf payload returned from firmware
- * @timeout: timeout in seconds
- * @config_page: contents of the config page
- * @config_page_sz: size of config page
- * Context: sleep
- *
- * A generic API for config page requests to firmware.
- *
- * The ioc->config_cmds.status flag should be MPT2_CMD_NOT_USED before calling
- * this API.
- *
- * The callback index is set inside `ioc->config_cb_idx.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
- *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout,
- void *config_page, u16 config_page_sz)
-{
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- Mpi2ConfigRequest_t *config_request;
- int r;
- u8 retry_count, issue_host_reset = 0;
- u16 wait_state_count;
- struct config_request mem;
-
- mutex_lock(&ioc->config_cmds.mutex);
- if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n",
- ioc->name, __func__);
- mutex_unlock(&ioc->config_cmds.mutex);
- return -EAGAIN;
- }
-
- 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;
- mpi_request->Header.PageType = mpi_reply->Header.PageType;
- mpi_request->Header.PageLength = mpi_reply->Header.PageLength;
- mpi_request->ExtPageLength = mpi_reply->ExtPageLength;
- mpi_request->ExtPageType = mpi_reply->ExtPageType;
- if (mpi_request->Header.PageLength)
- mem.sz = mpi_request->Header.PageLength * 4;
- else
- mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
- r = _config_alloc_config_dma_memory(ioc, &mem);
- if (r != 0)
- goto out;
- if (mpi_request->Action ==
- MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
- mpi_request->Action ==
- MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
- ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
- MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz,
- mem.page_dma);
- memcpy(mem.page, config_page, min_t(u16, mem.sz,
- config_page_sz));
- } else {
- memset(config_page, 0, config_page_sz);
- ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
- MPT2_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma);
- }
- }
-
- retry_config:
- if (retry_count) {
- if (retry_count > 2) { /* attempt only 2 retries */
- r = -EFAULT;
- goto free_mem;
- }
- printk(MPT2SAS_INFO_FMT "%s: attempting retry (%d)\n",
- ioc->name, __func__, retry_count);
- }
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- r = -EFAULT;
- goto free_mem;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- r = -EAGAIN;
- goto free_mem;
- }
-
- r = 0;
- memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t));
- ioc->config_cmds.status = MPT2_CMD_PENDING;
- config_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->config_cmds.smid = smid;
- memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _config_display_some_debug(ioc, smid, "config_request", NULL);
-#endif
- init_completion(&ioc->config_cmds.done);
- 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)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2ConfigRequest_t)/4);
- retry_count++;
- if (ioc->config_cmds.smid == smid)
- mpt2sas_base_free_smid(ioc, smid);
- if ((ioc->shost_recovery) || (ioc->config_cmds.status &
- MPT2_CMD_RESET) || ioc->pci_error_recovery)
- goto retry_config;
- issue_host_reset = 1;
- r = -EFAULT;
- goto free_mem;
- }
-
- if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID)
- memcpy(mpi_reply, ioc->config_cmds.reply,
- sizeof(Mpi2ConfigReply_t));
- if (retry_count)
- printk(MPT2SAS_INFO_FMT "%s: retry (%d) completed!!\n",
- ioc->name, __func__, retry_count);
- if (config_page && mpi_request->Action ==
- MPI2_CONFIG_ACTION_PAGE_READ_CURRENT)
- memcpy(config_page, mem.page, min_t(u16, mem.sz,
- config_page_sz));
- free_mem:
- if (config_page)
- _config_free_config_dma_memory(ioc, &mem);
- out:
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->config_cmds.mutex);
-
- if (issue_host_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- return r;
-}
-
-/**
- * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
- mpi_request.Header.PageNumber = 10;
- mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_bios_pg2 - obtain bios page 2
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
- mpi_request.Header.PageNumber = 2;
- mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_bios_pg3 - obtain bios page 3
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2BiosPage3_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
- mpi_request.Header.PageNumber = 3;
- mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_set_iounit_pg1 - set iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 3;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg8 - obtain iounit page 8
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 8;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
- mpi_request.Header.PageNumber = 8;
- mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: device handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
- mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
- mpi_request.Header.PageNumber = 0;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: device handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
- mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION;
- mpi_request.Header.PageNumber = 1;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host
- * @ioc: per adapter object
- * @num_phys: pointer returned with the number of phys
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
- u16 ioc_status;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasIOUnitPage0_t config_page;
-
- *num_phys = 0;
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page,
- sizeof(Mpi2SasIOUnitPage0_t));
- if (!r) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS)
- *num_phys = config_page.NumPhys;
- }
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Calling function should call config_get_number_hba_phys prior to
- * this function, so enough memory is allocated for config_page.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Calling function should call config_get_number_hba_phys prior to
- * this function, so enough memory is allocated for config_page.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Calling function should call config_get_number_hba_phys prior to
- * this function, so enough memory is allocated for config_page.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
- _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_expander_pg0 - obtain expander page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: expander handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_expander_pg1 - obtain expander page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @phy_number: phy number
- * @handle: expander handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number,
- u16 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
- (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: expander handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_phy_pg0 - obtain phy page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @phy_number: phy number
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_phy_pg1 - obtain phy page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @phy_number: phy number
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: volume handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form,
- u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume
- * @ioc: per adapter object
- * @handle: volume handle
- * @num_pds: returns pds count
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u8 *num_pds)
-{
- Mpi2ConfigRequest_t mpi_request;
- Mpi2RaidVolPage0_t config_page;
- Mpi2ConfigReply_t mpi_reply;
- int r;
- u16 ioc_status;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- *num_pds = 0;
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page,
- sizeof(Mpi2RaidVolPage0_t));
- if (!r) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS)
- *num_pds = config_page.NumPhysDisks;
- }
-
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: volume handle
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form,
- u32 handle, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE
- * @form_specific: specific to the form
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
- u32 form_specific)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | form_specific);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_volume_handle - returns volume handle for give hidden raid components
- * @ioc: per adapter object
- * @pd_handle: phys disk handle
- * @volume_handle: volume handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
- u16 *volume_handle)
-{
- Mpi2RaidConfigurationPage0_t *config_page = NULL;
- Mpi2ConfigRequest_t mpi_request;
- Mpi2ConfigReply_t mpi_reply;
- int r, i, config_page_sz;
- u16 ioc_status;
- int config_num;
- u16 element_type;
- u16 phys_disk_dev_handle;
-
- *volume_handle = 0;
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG;
- mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION;
- mpi_request.Header.PageNumber = 0;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4);
- config_page = kmalloc(config_page_sz, GFP_KERNEL);
- if (!config_page) {
- r = -1;
- goto out;
- }
- config_num = 0xff;
- while (1) {
- mpi_request.PageAddress = cpu_to_le32(config_num +
- MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- config_page_sz);
- if (r)
- goto out;
- r = -1;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- goto out;
- for (i = 0; i < config_page->NumElements; i++) {
- element_type = le16_to_cpu(config_page->
- ConfigElement[i].ElementFlags) &
- MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
- if (element_type ==
- MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT ||
- element_type ==
- MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) {
- phys_disk_dev_handle =
- le16_to_cpu(config_page->ConfigElement[i].
- PhysDiskDevHandle);
- if (phys_disk_dev_handle == pd_handle) {
- *volume_handle =
- le16_to_cpu(config_page->
- ConfigElement[i].VolDevHandle);
- r = 0;
- goto out;
- }
- } else if (element_type ==
- MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) {
- *volume_handle = 0;
- r = 0;
- goto out;
- }
- }
- config_num = config_page->ConfigNum;
- }
- out:
- kfree(config_page);
- return r;
-}
-
-/**
- * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle
- * @ioc: per adapter object
- * @volume_handle: volume handle
- * @wwid: volume wwid
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
- u64 *wwid)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2RaidVolPage1_t raid_vol_pg1;
-
- *wwid = 0;
- if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE,
- volume_handle))) {
- *wwid = le64_to_cpu(raid_vol_pg1.WWID);
- return 0;
- } else
- return -1;
-}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
deleted file mode 100644
index 3694b63..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ /dev/null
@@ -1,3101 +0,0 @@
-/*
- * Management Module Support for MPT (Message Passing Technology) based
- * controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/compat.h>
-#include <linux/poll.h>
-
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-#include "mpt2sas_base.h"
-#include "mpt2sas_ctl.h"
-
-static DEFINE_MUTEX(_ctl_mutex);
-static struct fasync_struct *async_queue;
-static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait);
-
-static int _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type,
- u8 *issue_reset);
-
-/**
- * enum block_state - blocking state
- * @NON_BLOCKING: non blocking
- * @BLOCKING: blocking
- *
- * These states are for ioctls that need to wait for a response
- * from firmware, so they probably require sleep.
- */
-enum block_state {
- NON_BLOCKING,
- BLOCKING,
-};
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _ctl_sas_device_find_by_handle - sas device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for sas_device based on sas_address, then return sas_device
- * object.
- */
-static struct _sas_device *
-_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device, *r;
-
- r = NULL;
- list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
- if (sas_device->handle != handle)
- continue;
- r = sas_device;
- goto out;
- }
-
- out:
- return r;
-}
-
-/**
- * _ctl_display_some_debug - debug routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @calling_function_name: string pass from calling function
- * @mpi_reply: reply message frame
- * Context: none.
- *
- * Function for displaying debug info helpful when debugging issues
- * in this module.
- */
-static void
-_ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
-{
- Mpi2ConfigRequest_t *mpi_request;
- char *desc = NULL;
-
- if (!(ioc->logging_level & MPT_DEBUG_IOCTL))
- return;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- switch (mpi_request->Function) {
- case MPI2_FUNCTION_SCSI_IO_REQUEST:
- {
- Mpi2SCSIIORequest_t *scsi_request =
- (Mpi2SCSIIORequest_t *)mpi_request;
-
- snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
- "scsi_io, cmd(0x%02x), cdb_len(%d)",
- scsi_request->CDB.CDB32[0],
- le16_to_cpu(scsi_request->IoFlags) & 0xF);
- desc = ioc->tmp_string;
- break;
- }
- case MPI2_FUNCTION_SCSI_TASK_MGMT:
- desc = "task_mgmt";
- break;
- case MPI2_FUNCTION_IOC_INIT:
- desc = "ioc_init";
- break;
- case MPI2_FUNCTION_IOC_FACTS:
- desc = "ioc_facts";
- break;
- case MPI2_FUNCTION_CONFIG:
- {
- Mpi2ConfigRequest_t *config_request =
- (Mpi2ConfigRequest_t *)mpi_request;
-
- snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
- "config, type(0x%02x), ext_type(0x%02x), number(%d)",
- (config_request->Header.PageType &
- MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType,
- config_request->Header.PageNumber);
- desc = ioc->tmp_string;
- break;
- }
- case MPI2_FUNCTION_PORT_FACTS:
- desc = "port_facts";
- break;
- case MPI2_FUNCTION_PORT_ENABLE:
- desc = "port_enable";
- break;
- case MPI2_FUNCTION_EVENT_NOTIFICATION:
- desc = "event_notification";
- break;
- case MPI2_FUNCTION_FW_DOWNLOAD:
- desc = "fw_download";
- break;
- case MPI2_FUNCTION_FW_UPLOAD:
- desc = "fw_upload";
- break;
- case MPI2_FUNCTION_RAID_ACTION:
- desc = "raid_action";
- break;
- case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
- {
- Mpi2SCSIIORequest_t *scsi_request =
- (Mpi2SCSIIORequest_t *)mpi_request;
-
- snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
- "raid_pass, cmd(0x%02x), cdb_len(%d)",
- scsi_request->CDB.CDB32[0],
- le16_to_cpu(scsi_request->IoFlags) & 0xF);
- desc = ioc->tmp_string;
- break;
- }
- case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
- desc = "sas_iounit_cntl";
- break;
- case MPI2_FUNCTION_SATA_PASSTHROUGH:
- desc = "sata_pass";
- break;
- case MPI2_FUNCTION_DIAG_BUFFER_POST:
- desc = "diag_buffer_post";
- break;
- case MPI2_FUNCTION_DIAG_RELEASE:
- desc = "diag_release";
- break;
- case MPI2_FUNCTION_SMP_PASSTHROUGH:
- desc = "smp_passthrough";
- break;
- }
-
- if (!desc)
- return;
-
- printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n",
- ioc->name, calling_function_name, desc, smid);
-
- if (!mpi_reply)
- return;
-
- if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- printk(MPT2SAS_INFO_FMT
- "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
-
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
- Mpi2SCSIIOReply_t *scsi_reply =
- (Mpi2SCSIIOReply_t *)mpi_reply;
- struct _sas_device *sas_device = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _ctl_sas_device_find_by_handle(ioc,
- le16_to_cpu(scsi_reply->DevHandle));
- if (sas_device) {
- printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
- "phy(%d)\n", ioc->name, (unsigned long long)
- sas_device->sas_address, sas_device->phy);
- printk(MPT2SAS_WARN_FMT
- "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
- ioc->name, sas_device->enclosure_logical_id,
- sas_device->slot);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
- printk(MPT2SAS_INFO_FMT
- "\tscsi_state(0x%02x), scsi_status"
- "(0x%02x)\n", ioc->name,
- scsi_reply->SCSIState,
- scsi_reply->SCSIStatus);
- }
-}
-#endif
-
-/**
- * mpt2sas_ctl_done - ctl module 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: none.
- *
- * The callback handler when using ioc->ctl_cb_idx.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-u8
-mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
- Mpi2SCSIIOReply_t *scsiio_reply;
- const void *sense_data;
- u32 sz;
-
- if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
- if (ioc->ctl_cmds.smid != smid)
- return 1;
- ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE;
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply) {
- memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
- ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID;
- /* get sense data */
- if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_reply->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
- scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply;
- if (scsiio_reply->SCSIState &
- MPI2_SCSI_STATE_AUTOSENSE_VALID) {
- sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
- le32_to_cpu(scsiio_reply->SenseCount));
- sense_data = mpt2sas_base_get_sense_buffer(ioc,
- smid);
- memcpy(ioc->ctl_cmds.sense, sense_data, sz);
- }
- }
- }
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
-#endif
- ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->ctl_cmds.done);
- return 1;
-}
-
-/**
- * _ctl_check_event_type - determines when an event needs logging
- * @ioc: per adapter object
- * @event: firmware event
- *
- * The bitmask in ioc->event_type[] indicates which events should be
- * be saved in the driver event_log. This bitmask is set by application.
- *
- * Returns 1 when event should be captured, or zero means no match.
- */
-static int
-_ctl_check_event_type(struct MPT2SAS_ADAPTER *ioc, u16 event)
-{
- u16 i;
- u32 desired_event;
-
- if (event >= 128 || !event || !ioc->event_log)
- return 0;
-
- desired_event = (1 << (event % 32));
- if (!desired_event)
- desired_event = 1;
- i = event / 32;
- return desired_event & ioc->event_type[i];
-}
-
-/**
- * mpt2sas_ctl_add_to_event_log - add event
- * @ioc: per adapter object
- * @mpi_reply: reply message frame
- *
- * Return nothing.
- */
-void
-mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventNotificationReply_t *mpi_reply)
-{
- struct MPT2_IOCTL_EVENTS *event_log;
- u16 event;
- int i;
- u32 sz, event_data_sz;
- u8 send_aen = 0;
-
- if (!ioc->event_log)
- return;
-
- event = le16_to_cpu(mpi_reply->Event);
-
- if (_ctl_check_event_type(ioc, event)) {
-
- /* insert entry into circular event_log */
- i = ioc->event_context % MPT2SAS_CTL_EVENT_LOG_SIZE;
- event_log = ioc->event_log;
- event_log[i].event = event;
- event_log[i].context = ioc->event_context++;
-
- event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4;
- sz = min_t(u32, event_data_sz, MPT2_EVENT_DATA_SIZE);
- memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE);
- memcpy(event_log[i].data, mpi_reply->EventData, sz);
- send_aen = 1;
- }
-
- /* This aen_event_read_flag flag is set until the
- * application has read the event log.
- * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify.
- */
- if (event == MPI2_EVENT_LOG_ENTRY_ADDED ||
- (send_aen && !ioc->aen_event_read_flag)) {
- ioc->aen_event_read_flag = 1;
- wake_up_interruptible(&ctl_poll_wait);
- if (async_queue)
- kill_fasync(&async_queue, SIGIO, POLL_IN);
- }
-}
-
-/**
- * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time)
- * @ioc: per adapter object
- * @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.
- *
- * Returns void.
- */
-void
-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);
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
- mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
- return;
-}
-
-/**
- * _ctl_verify_adapter - validates ioc_number passed from application
- * @ioc: per adapter object
- * @iocpp: The ioc pointer is returned in this.
- *
- * Return (-1) means error, else ioc_number.
- */
-static int
-_ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp)
-{
- struct MPT2SAS_ADAPTER *ioc;
- /* global ioc lock to protect controller on list operations */
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
- if (ioc->id != ioc_number)
- continue;
- spin_unlock(&gioc_lock);
- *iocpp = ioc;
- return ioc_number;
- }
- spin_unlock(&gioc_lock);
- *iocpp = NULL;
- return -1;
-}
-
-/**
- * mpt2sas_ctl_reset_handler - reset callback handler (for ctl)
- * @ioc: per adapter object
- * @reset_phase: phase
- *
- * The handler for doing any required cleanup or initialization.
- *
- * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
- * MPT2_IOC_DONE_RESET
- */
-void
-mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
-{
- int i;
- u8 issue_reset;
-
- switch (reset_phase) {
- case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
- for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
- if (!(ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_REGISTERED))
- continue;
- if ((ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- continue;
- _ctl_send_release(ioc, i, &issue_reset);
- }
- break;
- case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
- if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) {
- ioc->ctl_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
- complete(&ioc->ctl_cmds.done);
- }
- break;
- case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
-
- for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
- if (!(ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_REGISTERED))
- continue;
- if ((ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- continue;
- ioc->diag_buffer_status[i] |=
- MPT2_DIAG_BUFFER_IS_DIAG_RESET;
- }
- break;
- }
-}
-
-/**
- * _ctl_fasync -
- * @fd -
- * @filep -
- * @mode -
- *
- * Called when application request fasyn callback handler.
- */
-static int
-_ctl_fasync(int fd, struct file *filep, int mode)
-{
- return fasync_helper(fd, filep, mode, &async_queue);
-}
-
-/**
- * _ctl_poll -
- * @file -
- * @wait -
- *
- */
-static unsigned int
-_ctl_poll(struct file *filep, poll_table *wait)
-{
- struct MPT2SAS_ADAPTER *ioc;
-
- poll_wait(filep, &ctl_poll_wait, wait);
-
- /* global ioc lock to protect controller on list operations */
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
- if (ioc->aen_event_read_flag) {
- spin_unlock(&gioc_lock);
- return POLLIN | POLLRDNORM;
- }
- }
- spin_unlock(&gioc_lock);
- return 0;
-}
-
-/**
- * _ctl_set_task_mid - assign an active smid to tm request
- * @ioc: per adapter object
- * @karg - (struct mpt2_ioctl_command)
- * @tm_request - pointer to mf from user space
- *
- * Returns 0 when an smid if found, else fail.
- * during failure, the reply frame is filled.
- */
-static int
-_ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
- Mpi2SCSITaskManagementRequest_t *tm_request)
-{
- u8 found = 0;
- u16 i;
- u16 handle;
- struct scsi_cmnd *scmd;
- struct MPT2SAS_DEVICE *priv_data;
- unsigned long flags;
- Mpi2SCSITaskManagementReply_t *tm_reply;
- u32 sz;
- u32 lun;
- char *desc = NULL;
-
- if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
- desc = "abort_task";
- else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
- desc = "query_task";
- else
- return 0;
-
- lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN);
-
- handle = le16_to_cpu(tm_request->DevHandle);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- 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)
- continue;
- if (lun != scmd->device->lun)
- continue;
- priv_data = scmd->device->hostdata;
- if (priv_data->sas_target == NULL)
- continue;
- if (priv_data->sas_target->handle != handle)
- continue;
- tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid);
- found = 1;
- }
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- if (!found) {
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
- desc, le16_to_cpu(tm_request->DevHandle), lun));
- tm_reply = ioc->ctl_cmds.reply;
- tm_reply->DevHandle = tm_request->DevHandle;
- tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- tm_reply->TaskType = tm_request->TaskType;
- tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4;
- tm_reply->VP_ID = tm_request->VP_ID;
- tm_reply->VF_ID = tm_request->VF_ID;
- sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz);
- if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply,
- sz))
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- return 1;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
- desc, le16_to_cpu(tm_request->DevHandle), lun,
- le16_to_cpu(tm_request->TaskMID)));
- return 0;
-}
-
-/**
- * _ctl_do_mpt_command - main handler for MPT2COMMAND opcode
- * @ioc: per adapter object
- * @karg - (struct mpt2_ioctl_command)
- * @mf - pointer to mf in user space
- */
-static long
-_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg,
- void __user *mf)
-{
- MPI2RequestHeader_t *mpi_request = NULL, *request;
- MPI2DefaultReply_t *mpi_reply;
- u32 ioc_state;
- u16 ioc_status;
- u16 smid;
- unsigned long timeout, timeleft;
- u8 issue_reset;
- u32 sz;
- void *psge;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- size_t data_out_sz = 0;
- void *data_in = NULL;
- dma_addr_t data_in_dma;
- size_t data_in_sz = 0;
- u32 sgl_flags;
- long ret;
- u16 wait_state_count;
-
- issue_reset = 0;
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- ret = -EAGAIN;
- goto out;
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- ret = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL);
- if (!mpi_request) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for "
- "mpi_request\n", ioc->name, __func__);
- ret = -ENOMEM;
- goto out;
- }
-
- /* Check for overflow and wraparound */
- if (karg.data_sge_offset * 4 > ioc->request_sz ||
- karg.data_sge_offset > (UINT_MAX / 4)) {
- ret = -EINVAL;
- goto out;
- }
-
- /* copy in request message frame from user */
- if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,
- __func__);
- ret = -EFAULT;
- goto out;
- }
-
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
- smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ret = -EAGAIN;
- goto out;
- }
- } else {
-
- 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__);
- ret = -EAGAIN;
- goto out;
- }
- }
-
- ret = 0;
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- request = mpt2sas_base_get_msg_frame(ioc, smid);
- memcpy(request, mpi_request, karg.data_sge_offset*4);
- ioc->ctl_cmds.smid = smid;
- data_out_sz = karg.data_out_size;
- data_in_sz = karg.data_in_size;
-
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
- if (!le16_to_cpu(mpi_request->FunctionDependent1) ||
- le16_to_cpu(mpi_request->FunctionDependent1) >
- ioc->facts.MaxDevHandle) {
- ret = -EINVAL;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- /* obtain dma-able memory for data transfer */
- if (data_out_sz) /* WRITE */ {
- data_out = pci_alloc_consistent(ioc->pdev, data_out_sz,
- &data_out_dma);
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- if (copy_from_user(data_out, karg.data_out_buf_ptr,
- data_out_sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -EFAULT;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- if (data_in_sz) /* READ */ {
- data_in = pci_alloc_consistent(ioc->pdev, data_in_sz,
- &data_in_dma);
- if (!data_in) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- /* add scatter gather elements */
- psge = (void *)request + (karg.data_sge_offset*4);
-
- if (!data_out_sz && !data_in_sz) {
- mpt2sas_base_build_zero_len_sge(ioc, psge);
- } else if (data_out_sz && data_in_sz) {
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_out_sz, data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_in_sz, data_in_dma);
- } else if (data_out_sz) /* WRITE */ {
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_out_sz, data_out_dma);
- } else if (data_in_sz) /* READ */ {
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_in_sz, data_in_dma);
- }
-
- /* send command to firmware */
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _ctl_display_some_debug(ioc, smid, "ctl_request", NULL);
-#endif
-
- init_completion(&ioc->ctl_cmds.done);
- switch (mpi_request->Function) {
- case MPI2_FUNCTION_SCSI_IO_REQUEST:
- case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
- {
- Mpi2SCSIIORequest_t *scsiio_request =
- (Mpi2SCSIIORequest_t *)request;
- scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
- scsiio_request->SenseBufferLowAddress =
- mpt2sas_base_get_sense_buffer_dma(ioc, smid);
- memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE);
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
- mpt2sas_base_put_smid_scsi_io(ioc, smid,
- le16_to_cpu(mpi_request->FunctionDependent1));
- else
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
- case MPI2_FUNCTION_SCSI_TASK_MGMT:
- {
- Mpi2SCSITaskManagementRequest_t *tm_request =
- (Mpi2SCSITaskManagementRequest_t *)request;
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
- "handle(0x%04x), task_type(0x%02x)\n", ioc->name,
- le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
-
- if (tm_request->TaskType ==
- MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
- tm_request->TaskType ==
- MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) {
- if (_ctl_set_task_mid(ioc, &karg, tm_request)) {
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
- tm_request->DevHandle));
- mpt2sas_base_put_smid_hi_priority(ioc, smid);
- break;
- }
- case MPI2_FUNCTION_SMP_PASSTHROUGH:
- {
- Mpi2SmpPassthroughRequest_t *smp_request =
- (Mpi2SmpPassthroughRequest_t *)mpi_request;
- u8 *data;
-
- /* ioc determines which port to use */
- smp_request->PhysicalPort = 0xFF;
- if (smp_request->PassthroughFlags &
- MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)
- data = (u8 *)&smp_request->SGL;
- else {
- if (unlikely(data_out == NULL)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- mpt2sas_base_free_smid(ioc, smid);
- ret = -EINVAL;
- goto out;
- }
- data = data_out;
- }
-
- if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {
- ioc->ioc_link_reset_in_progress = 1;
- ioc->ignore_loginfos = 1;
- }
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
- case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
- {
- Mpi2SasIoUnitControlRequest_t *sasiounit_request =
- (Mpi2SasIoUnitControlRequest_t *)mpi_request;
-
- if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET
- || sasiounit_request->Operation ==
- MPI2_SAS_OP_PHY_LINK_RESET) {
- ioc->ioc_link_reset_in_progress = 1;
- ioc->ignore_loginfos = 1;
- }
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
- default:
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
-
- if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT)
- timeout = MPT2_IOCTL_DEFAULT_TIMEOUT;
- else
- timeout = karg.timeout;
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- timeout*HZ);
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
- Mpi2SCSITaskManagementRequest_t *tm_request =
- (Mpi2SCSITaskManagementRequest_t *)mpi_request;
- mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
- tm_request->DevHandle));
- } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
- mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) &&
- ioc->ioc_link_reset_in_progress) {
- ioc->ioc_link_reset_in_progress = 0;
- ioc->ignore_loginfos = 0;
- }
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request, karg.data_sge_offset);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
- (ioc->logging_level & MPT_DEBUG_TM)) {
- Mpi2SCSITaskManagementReply_t *tm_reply =
- (Mpi2SCSITaskManagementReply_t *)mpi_reply;
-
- printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
- "IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
- "TerminationCount(0x%08x)\n", ioc->name,
- le16_to_cpu(tm_reply->IOCStatus),
- le32_to_cpu(tm_reply->IOCLogInfo),
- le32_to_cpu(tm_reply->TerminationCount));
- }
-#endif
- /* copy out xdata to user */
- if (data_in_sz) {
- if (copy_to_user(karg.data_in_buf_ptr, data_in,
- data_in_sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENODATA;
- goto out;
- }
- }
-
- /* copy out reply message frame to user */
- if (karg.max_reply_bytes) {
- sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz);
- if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply,
- sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENODATA;
- goto out;
- }
- }
-
- /* copy out sense to user */
- if (karg.max_sense_bytes && (mpi_request->Function ==
- MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
- sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE);
- if (copy_to_user(karg.sense_data_ptr,
- ioc->ctl_cmds.sense, sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENODATA;
- goto out;
- }
- }
-
- issue_host_reset:
- if (issue_reset) {
- ret = -ENODATA;
- if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
- mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) {
- printk(MPT2SAS_INFO_FMT "issue target reset: handle "
- "= (0x%04x)\n", ioc->name,
- le16_to_cpu(mpi_request->FunctionDependent1));
- mpt2sas_halt_firmware(ioc);
- mpt2sas_scsih_issue_tm(ioc,
- le16_to_cpu(mpi_request->FunctionDependent1), 0, 0,
- 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10,
- TM_MUTEX_ON);
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- } else
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- }
-
- out:
-
- /* free memory associated with sg buffers */
- if (data_in)
- pci_free_consistent(ioc->pdev, data_in_sz, data_in,
- data_in_dma);
-
- if (data_out)
- pci_free_consistent(ioc->pdev, data_out_sz, data_out,
- data_out_dma);
-
- kfree(mpi_request);
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return ret;
-}
-
-/**
- * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_iocinfo karg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- memset(&karg, 0 , sizeof(karg));
- if (ioc->is_warpdrive)
- karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200;
- else
- karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
- if (ioc->pfacts)
- karg.port_number = ioc->pfacts[0].PortNumber;
- karg.hw_rev = ioc->pdev->revision;
- karg.pci_id = ioc->pdev->device;
- karg.subsystem_device = ioc->pdev->subsystem_device;
- karg.subsystem_vendor = ioc->pdev->subsystem_vendor;
- karg.pci_information.u.bits.bus = ioc->pdev->bus->number;
- karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn);
- karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);
- karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);
- karg.firmware_version = ioc->facts.FWVersion.Word;
- strcpy(karg.driver_version, MPT2SAS_DRIVER_NAME);
- strcat(karg.driver_version, "-");
- strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
- karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
-
- if (copy_to_user(arg, &karg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_eventquery karg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE;
- memcpy(karg.event_types, ioc->event_type,
- MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
-
- if (copy_to_user(arg, &karg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_eventenable karg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- if (ioc->event_log)
- return 0;
- memcpy(ioc->event_type, karg.event_types,
- MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
- mpt2sas_base_validate_event_type(ioc, ioc->event_type);
-
- /* initialize event_log */
- ioc->event_context = 0;
- ioc->aen_event_read_flag = 0;
- ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE,
- sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL);
- if (!ioc->event_log) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -ENOMEM;
- }
- return 0;
-}
-
-/**
- * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_eventreport karg;
- u32 number_bytes, max_events, max;
- struct mpt2_ioctl_eventreport __user *uarg = arg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- number_bytes = karg.hdr.max_data_size -
- sizeof(struct mpt2_ioctl_header);
- max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS);
- max = min_t(u32, MPT2SAS_CTL_EVENT_LOG_SIZE, max_events);
-
- /* If fewer than 1 event is requested, there must have
- * been some type of error.
- */
- if (!max || !ioc->event_log)
- return -ENODATA;
-
- number_bytes = max * sizeof(struct MPT2_IOCTL_EVENTS);
- if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- /* reset flag so SIGIO can restart */
- ioc->aen_event_read_flag = 0;
- return 0;
-}
-
-/**
- * _ctl_do_reset - main handler for MPT2HARDRESET opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_diag_reset karg;
- int retval;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- printk(MPT2SAS_INFO_FMT "host reset: %s\n",
- ioc->name, ((!retval) ? "SUCCESS" : "FAILED"));
- return 0;
-}
-
-/**
- * _ctl_btdh_search_sas_device - searching for sas device
- * @ioc: per adapter object
- * @btdh: btdh ioctl payload
- */
-static int
-_ctl_btdh_search_sas_device(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_ioctl_btdh_mapping *btdh)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
- int rc = 0;
-
- if (list_empty(&ioc->sas_device_list))
- return rc;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
- if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
- btdh->handle == sas_device->handle) {
- btdh->bus = sas_device->channel;
- btdh->id = sas_device->id;
- rc = 1;
- goto out;
- } else if (btdh->bus == sas_device->channel && btdh->id ==
- sas_device->id && btdh->handle == 0xFFFF) {
- btdh->handle = sas_device->handle;
- rc = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return rc;
-}
-
-/**
- * _ctl_btdh_search_raid_device - searching for raid device
- * @ioc: per adapter object
- * @btdh: btdh ioctl payload
- */
-static int
-_ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_ioctl_btdh_mapping *btdh)
-{
- struct _raid_device *raid_device;
- unsigned long flags;
- int rc = 0;
-
- if (list_empty(&ioc->raid_device_list))
- return rc;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
- btdh->handle == raid_device->handle) {
- btdh->bus = raid_device->channel;
- btdh->id = raid_device->id;
- rc = 1;
- goto out;
- } else if (btdh->bus == raid_device->channel && btdh->id ==
- raid_device->id && btdh->handle == 0xFFFF) {
- btdh->handle = raid_device->handle;
- rc = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- return rc;
-}
-
-/**
- * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_btdh_mapping karg;
- int rc;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- rc = _ctl_btdh_search_sas_device(ioc, &karg);
- if (!rc)
- _ctl_btdh_search_raid_device(ioc, &karg);
-
- if (copy_to_user(arg, &karg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_diag_capability - return diag buffer capability
- * @ioc: per adapter object
- * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED
- *
- * returns 1 when diag buffer support is enabled in firmware
- */
-static u8
-_ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type)
-{
- u8 rc = 0;
-
- switch (buffer_type) {
- case MPI2_DIAG_BUF_TYPE_TRACE:
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
- rc = 1;
- break;
- case MPI2_DIAG_BUF_TYPE_SNAPSHOT:
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
- rc = 1;
- break;
- case MPI2_DIAG_BUF_TYPE_EXTENDED:
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
- rc = 1;
- }
-
- return rc;
-}
-
-/**
- * _ctl_diag_register_2 - wrapper for registering diag buffer support
- * @ioc: per adapter object
- * @diag_register: the diag_register struct passed in from user space
- *
- */
-static long
-_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_diag_register *diag_register)
-{
- int rc, i;
- void *request_data = NULL;
- dma_addr_t request_data_dma;
- u32 request_data_sz = 0;
- Mpi2DiagBufferPostRequest_t *mpi_request;
- Mpi2DiagBufferPostReply_t *mpi_reply;
- u8 buffer_type;
- unsigned long timeleft;
- u16 smid;
- u16 ioc_status;
- u8 issue_reset = 0;
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- buffer_type = diag_register->buffer_type;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if (ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) {
- printk(MPT2SAS_ERR_FMT "%s: already has a registered "
- "buffer for buffer_type(0x%02x)\n", ioc->name, __func__,
- buffer_type);
- return -EINVAL;
- }
-
- if (diag_register->requested_buffer_size % 4) {
- printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size "
- "is not 4 byte aligned\n", ioc->name, __func__);
- return -EINVAL;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->ctl_cmds.smid = smid;
-
- request_data = ioc->diag_buffer[buffer_type];
- request_data_sz = diag_register->requested_buffer_size;
- ioc->unique_id[buffer_type] = diag_register->unique_id;
- ioc->diag_buffer_status[buffer_type] = 0;
- memcpy(ioc->product_specific[buffer_type],
- diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS);
- ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags;
-
- if (request_data) {
- request_data_dma = ioc->diag_buffer_dma[buffer_type];
- if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) {
- pci_free_consistent(ioc->pdev,
- ioc->diag_buffer_sz[buffer_type],
- request_data, request_data_dma);
- request_data = NULL;
- }
- }
-
- if (request_data == NULL) {
- ioc->diag_buffer_sz[buffer_type] = 0;
- ioc->diag_buffer_dma[buffer_type] = 0;
- request_data = pci_alloc_consistent(
- ioc->pdev, request_data_sz, &request_data_dma);
- if (request_data == NULL) {
- printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"
- " for diag buffers, requested size(%d)\n",
- ioc->name, __func__, request_data_sz);
- mpt2sas_base_free_smid(ioc, smid);
- return -ENOMEM;
- }
- ioc->diag_buffer[buffer_type] = request_data;
- ioc->diag_buffer_sz[buffer_type] = request_data_sz;
- ioc->diag_buffer_dma[buffer_type] = request_data_dma;
- }
-
- mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
- mpi_request->BufferType = diag_register->buffer_type;
- mpi_request->Flags = cpu_to_le32(diag_register->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_INFO_FMT "%s: diag_buffer(0x%p), "
- "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
- (unsigned long long)request_data_dma,
- le32_to_cpu(mpi_request->BufferLength)));
-
- for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
- mpi_request->ProductSpecific[i] =
- cpu_to_le32(ioc->product_specific[buffer_type][i]);
-
- init_completion(&ioc->ctl_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
-
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2DiagBufferPostRequest_t)/4);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- /* process the completed Reply Message Frame */
- if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
- ioc->name, __func__));
- } else {
- printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
- "log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
- rc = -EFAULT;
- }
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- out:
-
- if (rc && request_data)
- pci_free_consistent(ioc->pdev, request_data_sz,
- request_data, request_data_dma);
-
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return rc;
-}
-
-/**
- * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time
- * @ioc: per adapter object
- * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1
- *
- * This is called when command line option diag_buffer_enable is enabled
- * at driver load time.
- */
-void
-mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register)
-{
- struct mpt2_diag_register diag_register;
-
- memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
-
- if (bits_to_register & 1) {
- printk(MPT2SAS_INFO_FMT "registering trace buffer support\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
- /* register for 1MB buffers */
- diag_register.requested_buffer_size = (1024 * 1024);
- diag_register.unique_id = 0x7075900;
- _ctl_diag_register_2(ioc, &diag_register);
- }
-
- if (bits_to_register & 2) {
- printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT;
- /* register for 2MB buffers */
- diag_register.requested_buffer_size = 2 * (1024 * 1024);
- diag_register.unique_id = 0x7075901;
- _ctl_diag_register_2(ioc, &diag_register);
- }
-
- if (bits_to_register & 4) {
- printk(MPT2SAS_INFO_FMT "registering extended buffer support\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED;
- /* register for 2MB buffers */
- diag_register.requested_buffer_size = 2 * (1024 * 1024);
- diag_register.unique_id = 0x7075901;
- _ctl_diag_register_2(ioc, &diag_register);
- }
-}
-
-/**
- * _ctl_diag_register - application register with driver
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- *
- * This will allow the driver to setup any required buffers that will be
- * needed by firmware to communicate with the driver.
- */
-static long
-_ctl_diag_register(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_register karg;
- long rc;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- rc = _ctl_diag_register_2(ioc, &karg);
- return rc;
-}
-
-/**
- * _ctl_diag_unregister - application unregister with driver
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- *
- * This will allow the driver to cleanup any memory allocated for diag
- * messages and to free up any resources.
- */
-static long
-_ctl_diag_unregister(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_unregister karg;
- void *request_data;
- dma_addr_t request_data_dma;
- u32 request_data_sz;
- u8 buffer_type;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- buffer_type = karg.unique_id & 0x000000ff;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
- "registered\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) has not been "
- "released\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
-
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__, karg.unique_id);
- return -EINVAL;
- }
-
- request_data = ioc->diag_buffer[buffer_type];
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- request_data_sz = ioc->diag_buffer_sz[buffer_type];
- request_data_dma = ioc->diag_buffer_dma[buffer_type];
- pci_free_consistent(ioc->pdev, request_data_sz,
- request_data, request_data_dma);
- ioc->diag_buffer[buffer_type] = NULL;
- ioc->diag_buffer_status[buffer_type] = 0;
- return 0;
-}
-
-/**
- * _ctl_diag_query - query relevant info associated with diag buffers
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- *
- * The application will send only buffer_type and unique_id. Driver will
- * inspect unique_id first, if valid, fill in all the info. If unique_id is
- * 0x00, the driver will return info specified by Buffer Type.
- */
-static long
-_ctl_diag_query(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_query karg;
- void *request_data;
- int i;
- u8 buffer_type;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- karg.application_flags = 0;
- buffer_type = karg.buffer_type;
-
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
- "registered\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
-
- if (karg.unique_id & 0xffffff00) {
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__,
- karg.unique_id);
- return -EINVAL;
- }
- }
-
- request_data = ioc->diag_buffer[buffer_type];
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- if (ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED)
- karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
- MPT2_APP_FLAGS_BUFFER_VALID);
- else
- karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
- MPT2_APP_FLAGS_BUFFER_VALID |
- MPT2_APP_FLAGS_FW_BUFFER_ACCESS);
-
- for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
- karg.product_specific[i] =
- ioc->product_specific[buffer_type][i];
-
- karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type];
- karg.driver_added_buffer_size = 0;
- karg.unique_id = ioc->unique_id[buffer_type];
- karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type];
-
- if (copy_to_user(arg, &karg, sizeof(struct mpt2_diag_query))) {
- printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query "
- "data @ %p\n", ioc->name, __func__, arg);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_send_release - Diag Release Message
- * @ioc: per adapter object
- * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
- * @issue_reset - specifies whether host reset is required.
- *
- */
-static int
-_ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
-{
- Mpi2DiagReleaseRequest_t *mpi_request;
- Mpi2DiagReleaseReply_t *mpi_reply;
- u16 smid;
- u16 ioc_status;
- u32 ioc_state;
- int rc;
- unsigned long timeleft;
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- rc = 0;
- *issue_reset = 0;
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "skipping due to FAULT state\n", ioc->name,
- __func__));
- rc = -EAGAIN;
- goto out;
- }
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->ctl_cmds.smid = smid;
-
- mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;
- mpi_request->BufferType = buffer_type;
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
-
- init_completion(&ioc->ctl_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
-
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2DiagReleaseRequest_t)/4);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- *issue_reset = 1;
- rc = -EFAULT;
- goto out;
- }
-
- /* process the completed Reply Message Frame */
- if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_RELEASED;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
- ioc->name, __func__));
- } else {
- printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
- "log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
- rc = -EFAULT;
- }
-
- out:
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return rc;
-}
-
-/**
- * _ctl_diag_release - request to send Diag Release Message to firmware
- * @arg - user space buffer containing ioctl content
- *
- * This allows ownership of the specified buffer to returned to the driver,
- * allowing an application to read the buffer without fear that firmware is
- * overwritting information in the buffer.
- */
-static long
-_ctl_diag_release(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_release karg;
- void *request_data;
- int rc;
- u8 buffer_type;
- u8 issue_reset = 0;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- buffer_type = karg.unique_id & 0x000000ff;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
- "registered\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
-
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__, karg.unique_id);
- return -EINVAL;
- }
-
- if (ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_RELEASED) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) "
- "is already released\n", ioc->name, __func__,
- buffer_type);
- return 0;
- }
-
- request_data = ioc->diag_buffer[buffer_type];
-
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- /* buffers were released by due to host reset */
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_DIAG_RESET)) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_RELEASED;
- ioc->diag_buffer_status[buffer_type] &=
- ~MPT2_DIAG_BUFFER_IS_DIAG_RESET;
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) "
- "was released due to host reset\n", ioc->name, __func__,
- buffer_type);
- return 0;
- }
-
- rc = _ctl_send_release(ioc, buffer_type, &issue_reset);
-
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- return rc;
-}
-
-/**
- * _ctl_diag_read_buffer - request for copy of the diag buffer
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_read_buffer karg;
- struct mpt2_diag_read_buffer __user *uarg = arg;
- void *request_data, *diag_data;
- Mpi2DiagBufferPostRequest_t *mpi_request;
- Mpi2DiagBufferPostReply_t *mpi_reply;
- int rc, i;
- u8 buffer_type;
- unsigned long timeleft, request_size, copy_size;
- u16 smid;
- u16 ioc_status;
- u8 issue_reset = 0;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- buffer_type = karg.unique_id & 0x000000ff;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__, karg.unique_id);
- return -EINVAL;
- }
-
- request_data = ioc->diag_buffer[buffer_type];
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- request_size = ioc->diag_buffer_sz[buffer_type];
-
- if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {
- printk(MPT2SAS_ERR_FMT "%s: either the starting_offset "
- "or bytes_to_read are not 4 byte aligned\n", ioc->name,
- __func__);
- return -EINVAL;
- }
-
- if (karg.starting_offset > request_size)
- return -EINVAL;
-
- diag_data = (void *)(request_data + karg.starting_offset);
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), "
- "offset(%d), sz(%d)\n", ioc->name, __func__,
- diag_data, karg.starting_offset, karg.bytes_to_read));
-
- /* Truncate data on requests that are too large */
- if ((diag_data + karg.bytes_to_read < diag_data) ||
- (diag_data + karg.bytes_to_read > request_data + request_size))
- copy_size = request_size - karg.starting_offset;
- else
- copy_size = karg.bytes_to_read;
-
- if (copy_to_user((void __user *)uarg->diagnostic_data,
- diag_data, copy_size)) {
- printk(MPT2SAS_ERR_FMT "%s: Unable to write "
- "mpt_diag_read_buffer_t data @ %p\n", ioc->name,
- __func__, diag_data);
- return -EFAULT;
- }
-
- if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)
- return 0;
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type));
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "buffer_type(0x%02x) is still registered\n", ioc->name,
- __func__, buffer_type));
- return 0;
- }
- /* Get a free request frame and save the message context.
- */
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->ctl_cmds.smid = smid;
-
- mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
- mpi_request->BufferType = buffer_type;
- mpi_request->BufferLength =
- cpu_to_le32(ioc->diag_buffer_sz[buffer_type]);
- mpi_request->BufferAddress =
- cpu_to_le64(ioc->diag_buffer_dma[buffer_type]);
- 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;
-
- init_completion(&ioc->ctl_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
-
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2DiagBufferPostRequest_t)/4);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- /* process the completed Reply Message Frame */
- if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
- ioc->name, __func__));
- } else {
- printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
- "log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
- rc = -EFAULT;
- }
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- out:
-
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return rc;
-}
-
-
-#ifdef CONFIG_COMPAT
-/**
- * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
- * @ioc: per adapter object
- * @cmd - ioctl opcode
- * @arg - (struct mpt2_ioctl_command32)
- *
- * MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
- */
-static long
-_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd,
- void __user *arg)
-{
- struct mpt2_ioctl_command32 karg32;
- struct mpt2_ioctl_command32 __user *uarg;
- struct mpt2_ioctl_command karg;
-
- if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
- return -EINVAL;
-
- uarg = (struct mpt2_ioctl_command32 __user *) arg;
-
- if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
- karg.hdr.ioc_number = karg32.hdr.ioc_number;
- karg.hdr.port_number = karg32.hdr.port_number;
- karg.hdr.max_data_size = karg32.hdr.max_data_size;
- karg.timeout = karg32.timeout;
- karg.max_reply_bytes = karg32.max_reply_bytes;
- karg.data_in_size = karg32.data_in_size;
- karg.data_out_size = karg32.data_out_size;
- karg.max_sense_bytes = karg32.max_sense_bytes;
- karg.data_sge_offset = karg32.data_sge_offset;
- karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
- karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
- karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
- karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
- return _ctl_do_mpt_command(ioc, karg, &uarg->mf);
-}
-#endif
-
-/**
- * _ctl_ioctl_main - main ioctl entry point
- * @file - (struct file)
- * @cmd - ioctl opcode
- * @arg -
- * compat - handles 32 bit applications in 64bit os
- */
-static long
-_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
- u8 compat)
-{
- struct MPT2SAS_ADAPTER *ioc;
- struct mpt2_ioctl_header ioctl_header;
- enum block_state state;
- long ret = -EINVAL;
-
- /* get IOCTL header */
- if (copy_from_user(&ioctl_header, (char __user *)arg,
- sizeof(struct mpt2_ioctl_header))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
- /* pci_access_mutex lock acquired by ioctl path */
- mutex_lock(&ioc->pci_access_mutex);
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading || ioc->remove_host) {
- ret = -EAGAIN;
- goto out_unlock_pciaccess;
- }
-
- state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
- if (state == NON_BLOCKING) {
- if (!mutex_trylock(&ioc->ctl_cmds.mutex)) {
- ret = -EAGAIN;
- goto out_unlock_pciaccess;
- }
- } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) {
- ret = -ERESTARTSYS;
- goto out_unlock_pciaccess;
- }
-
- switch (cmd) {
- case MPT2IOCINFO:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo))
- ret = _ctl_getiocinfo(ioc, arg);
- break;
-#ifdef CONFIG_COMPAT
- case MPT2COMMAND32:
-#endif
- case MPT2COMMAND:
- {
- struct mpt2_ioctl_command __user *uarg;
- struct mpt2_ioctl_command karg;
-#ifdef CONFIG_COMPAT
- if (compat) {
- ret = _ctl_compat_mpt_command(ioc, cmd, arg);
- break;
- }
-#endif
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- ret = -EFAULT;
- break;
- }
-
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
- uarg = arg;
- ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
- }
- break;
- }
- case MPT2EVENTQUERY:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery))
- ret = _ctl_eventquery(ioc, arg);
- break;
- case MPT2EVENTENABLE:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable))
- ret = _ctl_eventenable(ioc, arg);
- break;
- case MPT2EVENTREPORT:
- ret = _ctl_eventreport(ioc, arg);
- break;
- case MPT2HARDRESET:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset))
- ret = _ctl_do_reset(ioc, arg);
- break;
- case MPT2BTDHMAPPING:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping))
- ret = _ctl_btdh_mapping(ioc, arg);
- break;
- case MPT2DIAGREGISTER:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register))
- ret = _ctl_diag_register(ioc, arg);
- break;
- case MPT2DIAGUNREGISTER:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister))
- ret = _ctl_diag_unregister(ioc, arg);
- break;
- case MPT2DIAGQUERY:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query))
- ret = _ctl_diag_query(ioc, arg);
- break;
- case MPT2DIAGRELEASE:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release))
- ret = _ctl_diag_release(ioc, arg);
- break;
- case MPT2DIAGREADBUFFER:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer))
- ret = _ctl_diag_read_buffer(ioc, arg);
- break;
- default:
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT
- "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
- break;
- }
-
- mutex_unlock(&ioc->ctl_cmds.mutex);
-out_unlock_pciaccess:
- mutex_unlock(&ioc->pci_access_mutex);
- return ret;
-}
-
-/**
- * _ctl_ioctl - main ioctl entry point (unlocked)
- * @file - (struct file)
- * @cmd - ioctl opcode
- * @arg -
- */
-static long
-_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- long ret;
-
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);
- return ret;
-}
-#ifdef CONFIG_COMPAT
-/**
- * _ctl_ioctl_compat - main ioctl entry point (compat)
- * @file -
- * @cmd -
- * @arg -
- *
- * This routine handles 32 bit applications in 64bit os.
- */
-static long
-_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
-{
- long ret;
-
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);
- return ret;
-}
-#endif
-
-/* scsi host attributes */
-
-/**
- * _ctl_version_fw_show - firmware version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
- (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
- (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
- (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
- ioc->facts.FWVersion.Word & 0x000000FF);
-}
-static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
-
-/**
- * _ctl_version_bios_show - bios version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
-
- return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
- (version & 0xFF000000) >> 24,
- (version & 0x00FF0000) >> 16,
- (version & 0x0000FF00) >> 8,
- version & 0x000000FF);
-}
-static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
-
-/**
- * _ctl_version_mpi_show - MPI (message passing interface) version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
- ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
-}
-static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
-
-/**
- * _ctl_version_product_show - product name
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName);
-}
-static DEVICE_ATTR(version_product, S_IRUGO,
- _ctl_version_product_show, NULL);
-
-/**
- * _ctl_version_nvdata_persistent_show - ndvata persistent version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_nvdata_persistent_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08xh\n",
- le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
-}
-static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
- _ctl_version_nvdata_persistent_show, NULL);
-
-/**
- * _ctl_version_nvdata_default_show - nvdata default version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_nvdata_default_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08xh\n",
- le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
-}
-static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
- _ctl_version_nvdata_default_show, NULL);
-
-/**
- * _ctl_board_name_show - board name
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName);
-}
-static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
-
-/**
- * _ctl_board_assembly_show - board assembly name
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly);
-}
-static DEVICE_ATTR(board_assembly, S_IRUGO,
- _ctl_board_assembly_show, NULL);
-
-/**
- * _ctl_board_tracer_show - board tracer number
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber);
-}
-static DEVICE_ATTR(board_tracer, S_IRUGO,
- _ctl_board_tracer_show, NULL);
-
-/**
- * _ctl_io_delay_show - io missing delay
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is for firmware implemention for deboucing device
- * removal events.
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
-}
-static DEVICE_ATTR(io_delay, S_IRUGO,
- _ctl_io_delay_show, NULL);
-
-/**
- * _ctl_device_delay_show - device missing delay
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is for firmware implemention for deboucing device
- * removal events.
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
-}
-static DEVICE_ATTR(device_delay, S_IRUGO,
- _ctl_device_delay_show, NULL);
-
-/**
- * _ctl_fw_queue_depth_show - global credits
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is firmware queue depth limit
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit);
-}
-static DEVICE_ATTR(fw_queue_depth, S_IRUGO,
- _ctl_fw_queue_depth_show, NULL);
-
-/**
- * _ctl_sas_address_show - sas address
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is the controller sas address
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
- (unsigned long long)ioc->sas_hba.sas_address);
-}
-static DEVICE_ATTR(host_sas_address, S_IRUGO,
- _ctl_host_sas_address_show, NULL);
-
-/**
- * _ctl_logging_level_show - logging level
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read/write' shost attribute.
- */
-static ssize_t
-_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level);
-}
-static ssize_t
-_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int val = 0;
-
- if (sscanf(buf, "%x", &val) != 1)
- return -EINVAL;
-
- ioc->logging_level = val;
- printk(MPT2SAS_INFO_FMT "logging_level=%08xh\n", ioc->name,
- ioc->logging_level);
- return strlen(buf);
-}
-static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
- _ctl_logging_level_show, _ctl_logging_level_store);
-
-/* device attributes */
-/*
- * _ctl_fwfault_debug_show - show/store fwfault_debug
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * mpt2sas_fwfault_debug is command line option
- * A sysfs 'read/write' shost attribute.
- */
-static ssize_t
-_ctl_fwfault_debug_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
-}
-static ssize_t
-_ctl_fwfault_debug_store(struct device *cdev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int val = 0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- ioc->fwfault_debug = val;
- printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name,
- ioc->fwfault_debug);
- return strlen(buf);
-}
-static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
- _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
-
-
-/**
- * _ctl_ioc_reset_count_show - ioc reset count
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is firmware queue depth limit
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count);
-}
-static DEVICE_ATTR(ioc_reset_count, S_IRUGO,
- _ctl_ioc_reset_count_show, NULL);
-
-/**
- * _ctl_ioc_reply_queue_count_show - number of reply queues
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is number of reply queues
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_ioc_reply_queue_count_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- u8 reply_queue_count;
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- if ((ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable)
- reply_queue_count = ioc->reply_queue_count;
- else
- reply_queue_count = 1;
- return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count);
-}
-static DEVICE_ATTR(reply_queue_count, S_IRUGO,
- _ctl_ioc_reply_queue_count_show, NULL);
-
-/**
- * _ctl_BRM_status_show - Backup Rail Monitor Status
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is number of reply queues
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- Mpi2IOUnitPage3_t *io_unit_pg3 = NULL;
- Mpi2ConfigReply_t mpi_reply;
- u16 backup_rail_monitor_status = 0;
- u16 ioc_status;
- int sz;
- ssize_t rc = 0;
-
- if (!ioc->is_warpdrive) {
- printk(MPT2SAS_ERR_FMT "%s: BRM attribute is only for"\
- "warpdrive\n", ioc->name, __func__);
- goto out;
- }
- /* pci_access_mutex lock acquired by sysfs show path */
- mutex_lock(&ioc->pci_access_mutex);
- if (ioc->pci_error_recovery || ioc->remove_host) {
- mutex_unlock(&ioc->pci_access_mutex);
- return 0;
- }
-
- /* allocate upto GPIOVal 36 entries */
- sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
- io_unit_pg3 = kzalloc(sz, GFP_KERNEL);
- if (!io_unit_pg3) {
- printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"\
- "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz);
- goto out;
- }
-
- if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) !=
- 0) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed reading iounit_pg3\n", ioc->name,
- __func__);
- goto out;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "%s: iounit_pg3 failed with"\
- "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status);
- goto out;
- }
-
- if (io_unit_pg3->GPIOCount < 25) {
- printk(MPT2SAS_ERR_FMT "%s: iounit_pg3->GPIOCount less than"\
- "25 entries, detected (%d) entries\n", ioc->name, __func__,
- io_unit_pg3->GPIOCount);
- goto out;
- }
-
- /* BRM status is in bit zero of GPIOVal[24] */
- backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]);
- rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1));
-
- out:
- kfree(io_unit_pg3);
- mutex_unlock(&ioc->pci_access_mutex);
- return rc;
-}
-static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
-
-struct DIAG_BUFFER_START {
- __le32 Size;
- __le32 DiagVersion;
- u8 BufferType;
- u8 Reserved[3];
- __le32 Reserved1;
- __le32 Reserved2;
- __le32 Reserved3;
-};
-/**
- * _ctl_host_trace_buffer_size_show - host buffer size (trace only)
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_host_trace_buffer_size_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- u32 size = 0;
- struct DIAG_BUFFER_START *request_data;
-
- if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- request_data = (struct DIAG_BUFFER_START *)
- ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE];
- if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 ||
- le32_to_cpu(request_data->DiagVersion) == 0x01000000) &&
- le32_to_cpu(request_data->Reserved3) == 0x4742444c)
- size = le32_to_cpu(request_data->Size);
-
- ioc->ring_buffer_sz = size;
- return snprintf(buf, PAGE_SIZE, "%d\n", size);
-}
-static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
- _ctl_host_trace_buffer_size_show, NULL);
-
-/**
- * _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read/write' shost attribute.
- *
- * You will only be able to read 4k bytes of ring buffer at a time.
- * In order to read beyond 4k bytes, you will have to write out the
- * offset to the same attribute, it will move the pointer.
- */
-static ssize_t
-_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- void *request_data;
- u32 size;
-
- if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- if (ioc->ring_buffer_offset > ioc->ring_buffer_sz)
- return 0;
-
- size = ioc->ring_buffer_sz - ioc->ring_buffer_offset;
- size = (size > PAGE_SIZE) ? PAGE_SIZE : size;
- request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset;
- memcpy(buf, request_data, size);
- return size;
-}
-
-static ssize_t
-_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int val = 0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- ioc->ring_buffer_offset = val;
- return strlen(buf);
-}
-static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
- _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store);
-
-/*****************************************/
-
-/**
- * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read/write' shost attribute.
- *
- * This is a mechnism to post/release host_trace_buffers
- */
-static ssize_t
-_ctl_host_trace_buffer_enable_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) ||
- ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0))
- return snprintf(buf, PAGE_SIZE, "off\n");
- else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- return snprintf(buf, PAGE_SIZE, "release\n");
- else
- return snprintf(buf, PAGE_SIZE, "post\n");
-}
-
-static ssize_t
-_ctl_host_trace_buffer_enable_store(struct device *cdev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- char str[10] = "";
- struct mpt2_diag_register diag_register;
- u8 issue_reset = 0;
-
- if (sscanf(buf, "%9s", str) != 1)
- return -EINVAL;
-
- if (!strcmp(str, "post")) {
- /* exit out if host buffers are already posted */
- if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) &&
- (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) &&
- ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_RELEASED) == 0))
- goto out;
- memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
- printk(MPT2SAS_INFO_FMT "posting host trace buffers\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
- diag_register.requested_buffer_size = (1024 * 1024);
- diag_register.unique_id = 0x7075900;
- ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0;
- _ctl_diag_register_2(ioc, &diag_register);
- } else if (!strcmp(str, "release")) {
- /* exit out if host buffers are already released */
- if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE])
- goto out;
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)
- goto out;
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- goto out;
- printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n",
- ioc->name);
- _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset);
- }
-
- out:
- return strlen(buf);
-}
-static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
- _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store);
-
-struct device_attribute *mpt2sas_host_attrs[] = {
- &dev_attr_version_fw,
- &dev_attr_version_bios,
- &dev_attr_version_mpi,
- &dev_attr_version_product,
- &dev_attr_version_nvdata_persistent,
- &dev_attr_version_nvdata_default,
- &dev_attr_board_name,
- &dev_attr_board_assembly,
- &dev_attr_board_tracer,
- &dev_attr_io_delay,
- &dev_attr_device_delay,
- &dev_attr_logging_level,
- &dev_attr_fwfault_debug,
- &dev_attr_fw_queue_depth,
- &dev_attr_host_sas_address,
- &dev_attr_ioc_reset_count,
- &dev_attr_host_trace_buffer_size,
- &dev_attr_host_trace_buffer,
- &dev_attr_host_trace_buffer_enable,
- &dev_attr_reply_queue_count,
- &dev_attr_BRM_status,
- NULL,
-};
-
-/**
- * _ctl_device_sas_address_show - sas address
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is the sas address for the target
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
-
- return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
- (unsigned long long)sas_device_priv_data->sas_target->sas_address);
-}
-static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
-
-/**
- * _ctl_device_handle_show - device handle
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is the firmware assigned device handle
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
-
- return snprintf(buf, PAGE_SIZE, "0x%04x\n",
- sas_device_priv_data->sas_target->handle);
-}
-static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
-
-struct device_attribute *mpt2sas_dev_attrs[] = {
- &dev_attr_sas_address,
- &dev_attr_sas_device_handle,
- NULL,
-};
-
-static const struct file_operations ctl_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = _ctl_ioctl,
- .poll = _ctl_poll,
- .fasync = _ctl_fasync,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = _ctl_ioctl_compat,
-#endif
- .llseek = noop_llseek,
-};
-
-static struct miscdevice ctl_dev = {
- .minor = MPT2SAS_MINOR,
- .name = MPT2SAS_DEV_NAME,
- .fops = &ctl_fops,
-};
-
-/**
- * mpt2sas_ctl_init - main entry point for ctl.
- *
- */
-void
-mpt2sas_ctl_init(void)
-{
- async_queue = NULL;
- if (misc_register(&ctl_dev) < 0)
- printk(KERN_ERR "%s can't register misc device [minor=%d]\n",
- MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
-
- init_waitqueue_head(&ctl_poll_wait);
-}
-
-/**
- * mpt2sas_ctl_exit - exit point for ctl
- *
- */
-void
-mpt2sas_ctl_exit(void)
-{
- struct MPT2SAS_ADAPTER *ioc;
- int i;
-
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
-
- /* free memory associated to diag buffers */
- for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
- if (!ioc->diag_buffer[i])
- continue;
- pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i],
- ioc->diag_buffer[i], ioc->diag_buffer_dma[i]);
- ioc->diag_buffer[i] = NULL;
- ioc->diag_buffer_status[i] = 0;
- }
-
- kfree(ioc->event_log);
- }
- misc_deregister(&ctl_dev);
-}
-
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
deleted file mode 100644
index 46b2fc5..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Management Module Support for MPT (Message Passing Technology) based
- * controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef MPT2SAS_CTL_H_INCLUDED
-#define MPT2SAS_CTL_H_INCLUDED
-
-#ifdef __KERNEL__
-#include <linux/miscdevice.h>
-#endif
-
-#define MPT2SAS_DEV_NAME "mpt2ctl"
-#define MPT2_MAGIC_NUMBER 'L'
-#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */
-
-/**
- * IOCTL opcodes
- */
-#define MPT2IOCINFO _IOWR(MPT2_MAGIC_NUMBER, 17, \
- struct mpt2_ioctl_iocinfo)
-#define MPT2COMMAND _IOWR(MPT2_MAGIC_NUMBER, 20, \
- struct mpt2_ioctl_command)
-#ifdef CONFIG_COMPAT
-#define MPT2COMMAND32 _IOWR(MPT2_MAGIC_NUMBER, 20, \
- struct mpt2_ioctl_command32)
-#endif
-#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \
- struct mpt2_ioctl_eventquery)
-#define MPT2EVENTENABLE _IOWR(MPT2_MAGIC_NUMBER, 22, \
- struct mpt2_ioctl_eventenable)
-#define MPT2EVENTREPORT _IOWR(MPT2_MAGIC_NUMBER, 23, \
- struct mpt2_ioctl_eventreport)
-#define MPT2HARDRESET _IOWR(MPT2_MAGIC_NUMBER, 24, \
- struct mpt2_ioctl_diag_reset)
-#define MPT2BTDHMAPPING _IOWR(MPT2_MAGIC_NUMBER, 31, \
- struct mpt2_ioctl_btdh_mapping)
-
-/* diag buffer support */
-#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \
- struct mpt2_diag_register)
-#define MPT2DIAGRELEASE _IOWR(MPT2_MAGIC_NUMBER, 27, \
- struct mpt2_diag_release)
-#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \
- struct mpt2_diag_unregister)
-#define MPT2DIAGQUERY _IOWR(MPT2_MAGIC_NUMBER, 29, \
- struct mpt2_diag_query)
-#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \
- struct mpt2_diag_read_buffer)
-
-/**
- * struct mpt2_ioctl_header - main header structure
- * @ioc_number - IOC unit number
- * @port_number - IOC port number
- * @max_data_size - maximum number bytes to transfer on read
- */
-struct mpt2_ioctl_header {
- uint32_t ioc_number;
- uint32_t port_number;
- uint32_t max_data_size;
-};
-
-/**
- * struct mpt2_ioctl_diag_reset - diagnostic reset
- * @hdr - generic header
- */
-struct mpt2_ioctl_diag_reset {
- struct mpt2_ioctl_header hdr;
-};
-
-
-/**
- * struct mpt2_ioctl_pci_info - pci device info
- * @device - pci device id
- * @function - pci function id
- * @bus - pci bus id
- * @segment_id - pci segment id
- */
-struct mpt2_ioctl_pci_info {
- union {
- struct {
- uint32_t device:5;
- uint32_t function:3;
- uint32_t bus:24;
- } bits;
- uint32_t word;
- } u;
- uint32_t segment_id;
-};
-
-
-#define MPT2_IOCTL_INTERFACE_SCSI (0x00)
-#define MPT2_IOCTL_INTERFACE_FC (0x01)
-#define MPT2_IOCTL_INTERFACE_FC_IP (0x02)
-#define MPT2_IOCTL_INTERFACE_SAS (0x03)
-#define MPT2_IOCTL_INTERFACE_SAS2 (0x04)
-#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05)
-#define MPT2_IOCTL_VERSION_LENGTH (32)
-
-/**
- * struct mpt2_ioctl_iocinfo - generic controller info
- * @hdr - generic header
- * @adapter_type - type of adapter (spi, fc, sas)
- * @port_number - port number
- * @pci_id - PCI Id
- * @hw_rev - hardware revision
- * @sub_system_device - PCI subsystem Device ID
- * @sub_system_vendor - PCI subsystem Vendor ID
- * @rsvd0 - reserved
- * @firmware_version - firmware version
- * @bios_version - BIOS version
- * @driver_version - driver version - 32 ASCII characters
- * @rsvd1 - reserved
- * @scsi_id - scsi id of adapter 0
- * @rsvd2 - reserved
- * @pci_information - pci info (2nd revision)
- */
-struct mpt2_ioctl_iocinfo {
- struct mpt2_ioctl_header hdr;
- uint32_t adapter_type;
- uint32_t port_number;
- uint32_t pci_id;
- uint32_t hw_rev;
- uint32_t subsystem_device;
- uint32_t subsystem_vendor;
- uint32_t rsvd0;
- uint32_t firmware_version;
- uint32_t bios_version;
- uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH];
- uint8_t rsvd1;
- uint8_t scsi_id;
- uint16_t rsvd2;
- struct mpt2_ioctl_pci_info pci_information;
-};
-
-
-/* number of event log entries */
-#define MPT2SAS_CTL_EVENT_LOG_SIZE (50)
-
-/**
- * struct mpt2_ioctl_eventquery - query event count and type
- * @hdr - generic header
- * @event_entries - number of events returned by get_event_report
- * @rsvd - reserved
- * @event_types - type of events currently being captured
- */
-struct mpt2_ioctl_eventquery {
- struct mpt2_ioctl_header hdr;
- uint16_t event_entries;
- uint16_t rsvd;
- uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
-};
-
-/**
- * struct mpt2_ioctl_eventenable - enable/disable event capturing
- * @hdr - generic header
- * @event_types - toggle off/on type of events to be captured
- */
-struct mpt2_ioctl_eventenable {
- struct mpt2_ioctl_header hdr;
- uint32_t event_types[4];
-};
-
-#define MPT2_EVENT_DATA_SIZE (192)
-/**
- * struct MPT2_IOCTL_EVENTS -
- * @event - the event that was reported
- * @context - unique value for each event assigned by driver
- * @data - event data returned in fw reply message
- */
-struct MPT2_IOCTL_EVENTS {
- uint32_t event;
- uint32_t context;
- uint8_t data[MPT2_EVENT_DATA_SIZE];
-};
-
-/**
- * struct mpt2_ioctl_eventreport - returing event log
- * @hdr - generic header
- * @event_data - (see struct MPT2_IOCTL_EVENTS)
- */
-struct mpt2_ioctl_eventreport {
- struct mpt2_ioctl_header hdr;
- struct MPT2_IOCTL_EVENTS event_data[1];
-};
-
-/**
- * struct mpt2_ioctl_command - generic mpt firmware passthru ioctl
- * @hdr - generic header
- * @timeout - command timeout in seconds. (if zero then use driver default
- * value).
- * @reply_frame_buf_ptr - reply location
- * @data_in_buf_ptr - destination for read
- * @data_out_buf_ptr - data source for write
- * @sense_data_ptr - sense data location
- * @max_reply_bytes - maximum number of reply bytes to be sent to app.
- * @data_in_size - number bytes for data transfer in (read)
- * @data_out_size - number bytes for data transfer out (write)
- * @max_sense_bytes - maximum number of bytes for auto sense buffers
- * @data_sge_offset - offset in words from the start of the request message to
- * the first SGL
- * @mf[1];
- */
-struct mpt2_ioctl_command {
- struct mpt2_ioctl_header hdr;
- uint32_t timeout;
- void __user *reply_frame_buf_ptr;
- void __user *data_in_buf_ptr;
- void __user *data_out_buf_ptr;
- void __user *sense_data_ptr;
- uint32_t max_reply_bytes;
- uint32_t data_in_size;
- uint32_t data_out_size;
- uint32_t max_sense_bytes;
- uint32_t data_sge_offset;
- uint8_t mf[1];
-};
-
-#ifdef CONFIG_COMPAT
-struct mpt2_ioctl_command32 {
- struct mpt2_ioctl_header hdr;
- uint32_t timeout;
- uint32_t reply_frame_buf_ptr;
- uint32_t data_in_buf_ptr;
- uint32_t data_out_buf_ptr;
- uint32_t sense_data_ptr;
- uint32_t max_reply_bytes;
- uint32_t data_in_size;
- uint32_t data_out_size;
- uint32_t max_sense_bytes;
- uint32_t data_sge_offset;
- uint8_t mf[1];
-};
-#endif
-
-/**
- * struct mpt2_ioctl_btdh_mapping - mapping info
- * @hdr - generic header
- * @id - target device identification number
- * @bus - SCSI bus number that the target device exists on
- * @handle - device handle for the target device
- * @rsvd - reserved
- *
- * To obtain a bus/id the application sets
- * handle to valid handle, and bus/id to 0xFFFF.
- *
- * To obtain the device handle the application sets
- * bus/id valid value, and the handle to 0xFFFF.
- */
-struct mpt2_ioctl_btdh_mapping {
- struct mpt2_ioctl_header hdr;
- uint32_t id;
- uint32_t bus;
- uint16_t handle;
- uint16_t rsvd;
-};
-
-
-/* status bits for ioc->diag_buffer_status */
-#define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01)
-#define MPT2_DIAG_BUFFER_IS_RELEASED (0x02)
-#define MPT2_DIAG_BUFFER_IS_DIAG_RESET (0x04)
-
-/* application flags for mpt2_diag_register, mpt2_diag_query */
-#define MPT2_APP_FLAGS_APP_OWNED (0x0001)
-#define MPT2_APP_FLAGS_BUFFER_VALID (0x0002)
-#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS (0x0004)
-
-/* flags for mpt2_diag_read_buffer */
-#define MPT2_FLAGS_REREGISTER (0x0001)
-
-#define MPT2_PRODUCT_SPECIFIC_DWORDS 23
-
-/**
- * struct mpt2_diag_register - application register with driver
- * @hdr - generic header
- * @reserved -
- * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
- * @application_flags - misc flags
- * @diagnostic_flags - specifies flags affecting command processing
- * @product_specific - product specific information
- * @requested_buffer_size - buffers size in bytes
- * @unique_id - tag specified by application that is used to signal ownership
- * of the buffer.
- *
- * This will allow the driver to setup any required buffers that will be
- * needed by firmware to communicate with the driver.
- */
-struct mpt2_diag_register {
- struct mpt2_ioctl_header hdr;
- uint8_t reserved;
- uint8_t buffer_type;
- uint16_t application_flags;
- uint32_t diagnostic_flags;
- uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
- uint32_t requested_buffer_size;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_unregister - application unregister with driver
- * @hdr - generic header
- * @unique_id - tag uniquely identifies the buffer to be unregistered
- *
- * This will allow the driver to cleanup any memory allocated for diag
- * messages and to free up any resources.
- */
-struct mpt2_diag_unregister {
- struct mpt2_ioctl_header hdr;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_query - query relevant info associated with diag buffers
- * @hdr - generic header
- * @reserved -
- * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
- * @application_flags - misc flags
- * @diagnostic_flags - specifies flags affecting command processing
- * @product_specific - product specific information
- * @total_buffer_size - diag buffer size in bytes
- * @driver_added_buffer_size - size of extra space appended to end of buffer
- * @unique_id - unique id associated with this buffer.
- *
- * The application will send only buffer_type and unique_id. Driver will
- * inspect unique_id first, if valid, fill in all the info. If unique_id is
- * 0x00, the driver will return info specified by Buffer Type.
- */
-struct mpt2_diag_query {
- struct mpt2_ioctl_header hdr;
- uint8_t reserved;
- uint8_t buffer_type;
- uint16_t application_flags;
- uint32_t diagnostic_flags;
- uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
- uint32_t total_buffer_size;
- uint32_t driver_added_buffer_size;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_release - request to send Diag Release Message to firmware
- * @hdr - generic header
- * @unique_id - tag uniquely identifies the buffer to be released
- *
- * This allows ownership of the specified buffer to returned to the driver,
- * allowing an application to read the buffer without fear that firmware is
- * overwritting information in the buffer.
- */
-struct mpt2_diag_release {
- struct mpt2_ioctl_header hdr;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_read_buffer - request for copy of the diag buffer
- * @hdr - generic header
- * @status -
- * @reserved -
- * @flags - misc flags
- * @starting_offset - starting offset within drivers buffer where to start
- * reading data at into the specified application buffer
- * @bytes_to_read - number of bytes to copy from the drivers buffer into the
- * application buffer starting at starting_offset.
- * @unique_id - unique id associated with this buffer.
- * @diagnostic_data - data payload
- */
-struct mpt2_diag_read_buffer {
- struct mpt2_ioctl_header hdr;
- uint8_t status;
- uint8_t reserved;
- uint16_t flags;
- uint32_t starting_offset;
- uint32_t bytes_to_read;
- uint32_t unique_id;
- uint32_t diagnostic_data[1];
-};
-
-#endif /* MPT2SAS_CTL_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
deleted file mode 100644
index 277120d..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Logging Support for MPT (Message Passing Technology) based controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef MPT2SAS_DEBUG_H_INCLUDED
-#define MPT2SAS_DEBUG_H_INCLUDED
-
-#define MPT_DEBUG 0x00000001
-#define MPT_DEBUG_MSG_FRAME 0x00000002
-#define MPT_DEBUG_SG 0x00000004
-#define MPT_DEBUG_EVENTS 0x00000008
-#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010
-#define MPT_DEBUG_INIT 0x00000020
-#define MPT_DEBUG_EXIT 0x00000040
-#define MPT_DEBUG_FAIL 0x00000080
-#define MPT_DEBUG_TM 0x00000100
-#define MPT_DEBUG_REPLY 0x00000200
-#define MPT_DEBUG_HANDSHAKE 0x00000400
-#define MPT_DEBUG_CONFIG 0x00000800
-#define MPT_DEBUG_DL 0x00001000
-#define MPT_DEBUG_RESET 0x00002000
-#define MPT_DEBUG_SCSI 0x00004000
-#define MPT_DEBUG_IOCTL 0x00008000
-#define MPT_DEBUG_CSMISAS 0x00010000
-#define MPT_DEBUG_SAS 0x00020000
-#define MPT_DEBUG_TRANSPORT 0x00040000
-#define MPT_DEBUG_TASK_SET_FULL 0x00080000
-
-#define MPT_DEBUG_TARGET_MODE 0x00100000
-
-
-/*
- * CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig
- */
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \
-{ \
- if (IOC->logging_level & BITS) \
- CMD; \
-}
-#else
-#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
-#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
-
-
-/*
- * debug macros
- */
-
-#define dprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG)
-
-#define dsgprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG)
-
-#define devtprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS)
-
-#define dewtprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK)
-
-#define dinitprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT)
-
-#define dexitprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT)
-
-#define dfailprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL)
-
-#define dtmprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM)
-
-#define dreplyprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY)
-
-#define dhsprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE)
-
-#define dcprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG)
-
-#define ddlprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL)
-
-#define drsprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET)
-
-#define dsprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI)
-
-#define dctlprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
-
-#define dcsmisasprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS)
-
-#define dsasprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS)
-
-#define dsastransport(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
-
-#define dmfprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
-
-#define dtsfprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL)
-
-#define dtransportprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT)
-
-#define dTMprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE)
-
-/* inline functions for dumping debug data*/
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _debug_dump_mf - print message frame contents
- * @mpi_request: pointer to message frame
- * @sz: number of dwords
- */
-static inline void
-_debug_dump_mf(void *mpi_request, int sz)
-{
- int i;
- __le32 *mfp = (__le32 *)mpi_request;
-
- printk(KERN_INFO "mf:\n\t");
- for (i = 0; i < sz; i++) {
- if (i && ((i % 8) == 0))
- printk("\n\t");
- printk("%08x ", le32_to_cpu(mfp[i]));
- }
- printk("\n");
-}
-#else
-#define _debug_dump_mf(mpi_request, sz)
-#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
-
-#endif /* MPT2SAS_DEBUG_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
deleted file mode 100644
index 0ad09b2..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ /dev/null
@@ -1,8855 +0,0 @@
-/*
- * Scsi Host Layer for MPT (Message Passing Technology) based controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/blkdev.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/aer.h>
-#include <linux/raid_class.h>
-#include <linux/slab.h>
-
-#include <asm/unaligned.h>
-
-#include "mpt2sas_base.h"
-
-MODULE_AUTHOR(MPT2SAS_AUTHOR);
-MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
-
-#define RAID_CHANNEL 1
-
-/* forward proto's */
-static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander);
-static void _firmware_event_work(struct work_struct *work);
-
-static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-
-static void _scsih_scan_start(struct Scsi_Host *shost);
-static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time);
-
-/* global parameters */
-LIST_HEAD(mpt2sas_ioc_list);
-/* global ioc lock for list operations */
-DEFINE_SPINLOCK(gioc_lock);
-/* local parameters */
-static u8 scsi_io_cb_idx = -1;
-static u8 tm_cb_idx = -1;
-static u8 ctl_cb_idx = -1;
-static u8 base_cb_idx = -1;
-static u8 port_enable_cb_idx = -1;
-static u8 transport_cb_idx = -1;
-static u8 scsih_cb_idx = -1;
-static u8 config_cb_idx = -1;
-static int mpt_ids;
-
-static u8 tm_tr_cb_idx = -1 ;
-static u8 tm_tr_volume_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 "
- "(default=0)");
-
-static ushort max_sectors = 0xFFFF;
-module_param(max_sectors, ushort, 0);
-MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767");
-
-static int missing_delay[2] = {-1, -1};
-module_param_array(missing_delay, int, NULL, 0);
-MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
-
-/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
-#define MPT2SAS_MAX_LUN (16895)
-static int max_lun = MPT2SAS_MAX_LUN;
-module_param(max_lun, int, 0);
-MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-
-/* diag_buffer_enable is bitwise
- * bit 0 set = TRACE
- * bit 1 set = SNAPSHOT
- * bit 2 set = EXTENDED
- *
- * Either bit can be set, or both
- */
-static int diag_buffer_enable = -1;
-module_param(diag_buffer_enable, int, 0);
-MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "
- "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
-
-static int disable_discovery = -1;
-module_param(disable_discovery, int, 0);
-MODULE_PARM_DESC(disable_discovery, " disable discovery ");
-
-/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */
-static int prot_mask = 0;
-module_param(prot_mask, int, 0);
-MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
-
-/**
- * struct sense_info - common structure for obtaining sense keys
- * @skey: sense key
- * @asc: additional sense code
- * @ascq: additional sense code qualifier
- */
-struct sense_info {
- u8 skey;
- u8 asc;
- u8 ascq;
-};
-
-
-#define MPT2SAS_TURN_ON_PFA_LED (0xFFFC)
-#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD)
-#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF)
-/**
- * struct fw_event_work - firmware event struct
- * @list: link list framework
- * @work: work object (ioc->fault_reset_work_q)
- * @cancel_pending_work: flag set during reset handling
- * @ioc: per adapter object
- * @device_handle: device handle
- * @VF_ID: virtual function id
- * @VP_ID: virtual port id
- * @ignore: flag meaning this event has been marked to ignore
- * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
- * @event_data: reply event data payload follows
- *
- * This object stored on ioc->fw_event_list.
- */
-struct fw_event_work {
- struct list_head list;
- u8 cancel_pending_work;
- struct delayed_work delayed_work;
- struct MPT2SAS_ADAPTER *ioc;
- u16 device_handle;
- u8 VF_ID;
- u8 VP_ID;
- u8 ignore;
- u16 event;
- struct kref refcount;
- char event_data[0] __aligned(4);
-};
-
-static void fw_event_work_free(struct kref *r)
-{
- kfree(container_of(r, struct fw_event_work, refcount));
-}
-
-static void fw_event_work_get(struct fw_event_work *fw_work)
-{
- kref_get(&fw_work->refcount);
-}
-
-static void fw_event_work_put(struct fw_event_work *fw_work)
-{
- kref_put(&fw_work->refcount, fw_event_work_free);
-}
-
-static struct fw_event_work *alloc_fw_event_work(int len)
-{
- struct fw_event_work *fw_event;
-
- fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC);
- if (!fw_event)
- return NULL;
-
- kref_init(&fw_event->refcount);
- return fw_event;
-}
-
-/* raid transport support */
-static struct raid_template *mpt2sas_raid_template;
-
-/**
- * struct _scsi_io_transfer - scsi io transfer
- * @handle: sas device handle (assigned by firmware)
- * @is_raid: flag set for hidden raid components
- * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
- * @data_length: data transfer length
- * @data_dma: dma pointer to data
- * @sense: sense data
- * @lun: lun number
- * @cdb_length: cdb length
- * @cdb: cdb contents
- * @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
- * @scsi_status: scsi staus
- * @log_info: log information
- * @transfer_length: data length transfer when there is a reply message
- *
- * Used for sending internal scsi commands to devices within this module.
- * Refer to _scsi_send_scsi_io().
- */
-struct _scsi_io_transfer {
- u16 handle;
- u8 is_raid;
- enum dma_data_direction dir;
- u32 data_length;
- dma_addr_t data_dma;
- u8 sense[SCSI_SENSE_BUFFERSIZE];
- u32 lun;
- 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;
- u16 ioc_status;
- u8 scsi_state;
- u8 scsi_status;
- u32 log_info;
- u32 transfer_length;
-};
-
-/*
- * The pci device ids are defined in mpi/mpi2_cnfg.h.
- */
-static struct pci_device_id scsih_pci_table[] = {
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Falcon ~ 2008*/
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Liberator ~ 2108 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Meteor ~ 2116 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Thunderbolt ~ 2208 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Mustang ~ 2308 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
- PCI_ANY_ID, PCI_ANY_ID },
- /* SSS6200 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
- PCI_ANY_ID, PCI_ANY_ID },
- {0} /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, scsih_pci_table);
-
-/**
- * _scsih_set_debug_level - global setting of ioc->logging_level.
- *
- * Note: The logging levels are defined in mpt2sas_debug.h.
- */
-static int
-_scsih_set_debug_level(const char *val, struct kernel_param *kp)
-{
- int ret = param_set_int(val, kp);
- struct MPT2SAS_ADAPTER *ioc;
-
- if (ret)
- return ret;
-
- printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
- ioc->logging_level = logging_level;
- spin_unlock(&gioc_lock);
- return 0;
-}
-module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
- &logging_level, 0644);
-
-/**
- * _scsih_srch_boot_sas_address - search based on sas_address
- * @sas_address: sas address
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static inline int
-_scsih_srch_boot_sas_address(u64 sas_address,
- Mpi2BootDeviceSasWwid_t *boot_device)
-{
- return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
-}
-
-/**
- * _scsih_srch_boot_device_name - search based on device name
- * @device_name: device name specified in INDENTIFY fram
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static inline int
-_scsih_srch_boot_device_name(u64 device_name,
- Mpi2BootDeviceDeviceName_t *boot_device)
-{
- return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
-}
-
-/**
- * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
- * @enclosure_logical_id: enclosure logical id
- * @slot_number: slot number
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static inline int
-_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
- Mpi2BootDeviceEnclosureSlot_t *boot_device)
-{
- return (enclosure_logical_id == le64_to_cpu(boot_device->
- EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
- SlotNumber)) ? 1 : 0;
-}
-
-/**
- * _scsih_is_boot_device - search for matching boot device.
- * @sas_address: sas address
- * @device_name: device name specified in INDENTIFY fram
- * @enclosure_logical_id: enclosure logical id
- * @slot_number: slot number
- * @form: specifies boot device form
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static int
-_scsih_is_boot_device(u64 sas_address, u64 device_name,
- u64 enclosure_logical_id, u16 slot, u8 form,
- Mpi2BiosPage2BootDevice_t *boot_device)
-{
- int rc = 0;
-
- switch (form) {
- case MPI2_BIOSPAGE2_FORM_SAS_WWID:
- if (!sas_address)
- break;
- rc = _scsih_srch_boot_sas_address(
- sas_address, &boot_device->SasWwid);
- break;
- case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
- if (!enclosure_logical_id)
- break;
- rc = _scsih_srch_boot_encl_slot(
- enclosure_logical_id,
- slot, &boot_device->EnclosureSlot);
- break;
- case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
- if (!device_name)
- break;
- rc = _scsih_srch_boot_device_name(
- device_name, &boot_device->DeviceName);
- break;
- case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
- break;
- }
-
- return rc;
-}
-
-/**
- * _scsih_get_sas_address - set the sas_address for given device handle
- * @handle: device handle
- * @sas_address: sas address
- *
- * Returns 0 success, non-zero when failure
- */
-static int
-_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u64 *sas_address)
-{
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 ioc_status;
- *sas_address = 0;
-
- if (handle <= ioc->sas_hba.num_phys) {
- *sas_address = ioc->sas_hba.sas_address;
- return 0;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- return 0;
- }
-
- /* we hit this becuase the given parent handle doesn't exist */
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- return -ENXIO;
- /* else error case */
- printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), "
- "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
- __FILE__, __LINE__, __func__);
- return -EIO;
-}
-
-/**
- * _scsih_determine_boot_device - determine boot device.
- * @ioc: per adapter object
- * @device: either sas_device or raid_device object
- * @is_raid: [flag] 1 = raid object, 0 = sas object
- *
- * Determines whether this device should be first reported device to
- * to scsi-ml or sas transport, this purpose is for persistent boot device.
- * There are primary, alternate, and current entries in bios page 2. The order
- * priority is primary, alternate, then current. This routine saves
- * the corresponding device object and is_raid flag in the ioc object.
- * The saved data to be used later in _scsih_probe_boot_devices().
- */
-static void
-_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
- void *device, u8 is_raid)
-{
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- u64 sas_address;
- u64 device_name;
- u64 enclosure_logical_id;
- u16 slot;
-
- /* only process this function when driver loads */
- if (!ioc->is_driver_loading)
- return;
-
- /* no Bios, return immediately */
- if (!ioc->bios_pg3.BiosVersion)
- return;
-
- if (!is_raid) {
- sas_device = device;
- sas_address = sas_device->sas_address;
- device_name = sas_device->device_name;
- enclosure_logical_id = sas_device->enclosure_logical_id;
- slot = sas_device->slot;
- } else {
- raid_device = device;
- sas_address = raid_device->wwid;
- device_name = 0;
- enclosure_logical_id = 0;
- slot = 0;
- }
-
- if (!ioc->req_boot_device.device) {
- if (_scsih_is_boot_device(sas_address, device_name,
- enclosure_logical_id, slot,
- (ioc->bios_pg2.ReqBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK),
- &ioc->bios_pg2.RequestedBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: req_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
- ioc->req_boot_device.device = device;
- ioc->req_boot_device.is_raid = is_raid;
- }
- }
-
- if (!ioc->req_alt_boot_device.device) {
- if (_scsih_is_boot_device(sas_address, device_name,
- enclosure_logical_id, slot,
- (ioc->bios_pg2.ReqAltBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK),
- &ioc->bios_pg2.RequestedAltBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: req_alt_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
- ioc->req_alt_boot_device.device = device;
- ioc->req_alt_boot_device.is_raid = is_raid;
- }
- }
-
- if (!ioc->current_boot_device.device) {
- if (_scsih_is_boot_device(sas_address, device_name,
- enclosure_logical_id, slot,
- (ioc->bios_pg2.CurrentBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK),
- &ioc->bios_pg2.CurrentBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: current_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
- ioc->current_boot_device.device = device;
- ioc->current_boot_device.is_raid = is_raid;
- }
- }
-}
-
-static struct _sas_device *
-__mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc,
- struct MPT2SAS_TARGET *tgt_priv)
-{
- struct _sas_device *ret;
-
- assert_spin_locked(&ioc->sas_device_lock);
-
- ret = tgt_priv->sdev;
- if (ret)
- sas_device_get(ret);
-
- return ret;
-}
-
-static struct _sas_device *
-mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc,
- struct MPT2SAS_TARGET *tgt_priv)
-{
- struct _sas_device *ret;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- ret = __mpt2sas_get_sdev_from_target(ioc, tgt_priv);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return ret;
-}
-
-
-struct _sas_device *
-__mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_device *sas_device;
-
- assert_spin_locked(&ioc->sas_device_lock);
-
- list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->sas_address == sas_address)
- goto found_device;
-
- list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->sas_address == sas_address)
- goto found_device;
-
- return NULL;
-
-found_device:
- sas_device_get(sas_device);
- return sas_device;
-}
-
-/**
- * mpt2sas_get_sdev_by_addr - sas device search
- * @ioc: per adapter object
- * @sas_address: sas address
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for sas_device based on sas_address, then return sas_device
- * object.
- */
-struct _sas_device *
-mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return sas_device;
-}
-
-static struct _sas_device *
-__mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device;
-
- assert_spin_locked(&ioc->sas_device_lock);
-
- list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->handle == handle)
- goto found_device;
-
- list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->handle == handle)
- goto found_device;
-
- return NULL;
-
-found_device:
- sas_device_get(sas_device);
- return sas_device;
-}
-
-/**
- * mpt2sas_get_sdev_by_handle - sas device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for sas_device based on sas_address, then return sas_device
- * object.
- */
-static struct _sas_device *
-mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return sas_device;
-}
-
-/**
- * _scsih_sas_device_remove - remove sas_device from list.
- * @ioc: per adapter object
- * @sas_device: the sas_device object
- * Context: This function will acquire ioc->sas_device_lock.
- *
- * If sas_device is on the list, remove it and decrement its reference count.
- */
-static void
-_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- if (!sas_device)
- return;
-
- /*
- * The lock serializes access to the list, but we still need to verify
- * that nobody removed the entry while we were waiting on the lock.
- */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- if (!list_empty(&sas_device->list)) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-
-/**
- * _scsih_sas_device_add - insert sas_device to the list.
- * @ioc: per adapter object
- * @sas_device: the sas_device object
- * Context: This function will acquire ioc->sas_device_lock.
- *
- * Adding new object to the ioc->sas_device_list.
- */
-static void
-_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
- "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)sas_device->sas_address));
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device_get(sas_device);
- list_add_tail(&sas_device->list, &ioc->sas_device_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->sas_address_parent)) {
- _scsih_sas_device_remove(ioc, sas_device);
- } else if (!sas_device->starget) {
- /* When asyn scanning is enabled, its not possible to remove
- * devices while scanning is turned on due to an oops in
- * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
- */
- if (!ioc->is_driver_loading) {
- mpt2sas_transport_port_remove(ioc,
- sas_device->sas_address,
- sas_device->sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
- }
- }
-}
-
-/**
- * _scsih_sas_device_init_add - insert sas_device to the list.
- * @ioc: per adapter object
- * @sas_device: the sas_device object
- * Context: This function will acquire ioc->sas_device_lock.
- *
- * Adding new object at driver load time to the ioc->sas_device_init_list.
- */
-static void
-_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
- "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)sas_device->sas_address));
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device_get(sas_device);
- list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
- _scsih_determine_boot_device(ioc, sas_device, 0);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-/**
- * _scsih_raid_device_find_by_id - raid device search
- * @ioc: per adapter object
- * @id: sas device target id
- * @channel: sas device channel
- * Context: Calling function should acquire ioc->raid_device_lock
- *
- * This searches for raid_device based on target id, then return raid_device
- * object.
- */
-static struct _raid_device *
-_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
-{
- struct _raid_device *raid_device, *r;
-
- r = NULL;
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->id == id && raid_device->channel == channel) {
- r = raid_device;
- goto out;
- }
- }
-
- out:
- return r;
-}
-
-/**
- * _scsih_raid_device_find_by_handle - raid device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->raid_device_lock
- *
- * This searches for raid_device based on handle, then return raid_device
- * object.
- */
-static struct _raid_device *
-_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _raid_device *raid_device, *r;
-
- r = NULL;
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->handle != handle)
- continue;
- r = raid_device;
- goto out;
- }
-
- out:
- return r;
-}
-
-/**
- * _scsih_raid_device_find_by_wwid - raid device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->raid_device_lock
- *
- * This searches for raid_device based on wwid, then return raid_device
- * object.
- */
-static struct _raid_device *
-_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
-{
- struct _raid_device *raid_device, *r;
-
- r = NULL;
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->wwid != wwid)
- continue;
- r = raid_device;
- goto out;
- }
-
- out:
- return r;
-}
-
-/**
- * _scsih_raid_device_add - add raid_device object
- * @ioc: per adapter object
- * @raid_device: raid_device object
- *
- * This is added to the raid_device_list link list.
- */
-static void
-_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- unsigned long flags;
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
- "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
- raid_device->handle, (unsigned long long)raid_device->wwid));
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_add_tail(&raid_device->list, &ioc->raid_device_list);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * _scsih_raid_device_remove - delete raid_device object
- * @ioc: per adapter object
- * @raid_device: raid_device object
- *
- */
-static void
-_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_del(&raid_device->list);
- kfree(raid_device);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * mpt2sas_scsih_expander_find_by_handle - expander device search
- * @ioc: per adapter object
- * @handle: expander handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for expander device based on handle, then returns the
- * sas_node object.
- */
-struct _sas_node *
-mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_node *sas_expander, *r;
-
- r = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->handle != handle)
- continue;
- r = sas_expander;
- goto out;
- }
- out:
- return r;
-}
-
-/**
- * mpt2sas_scsih_expander_find_by_sas_address - expander device search
- * @ioc: per adapter object
- * @sas_address: sas address
- * Context: Calling function should acquire ioc->sas_node_lock.
- *
- * This searches for expander device based on sas_address, then returns the
- * sas_node object.
- */
-struct _sas_node *
-mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_node *sas_expander, *r;
-
- r = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->sas_address != sas_address)
- continue;
- r = sas_expander;
- goto out;
- }
- out:
- return r;
-}
-
-/**
- * _scsih_expander_node_add - insert expander device to the list.
- * @ioc: per adapter object
- * @sas_expander: the sas_device object
- * Context: This function will acquire ioc->sas_node_lock.
- *
- * Adding new object to the ioc->sas_expander_list.
- *
- * Return nothing.
- */
-static void
-_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-}
-
-/**
- * _scsih_is_end_device - determines if device is an end device
- * @device_info: bitfield providing information about the device.
- * Context: none
- *
- * Returns 1 if end device.
- */
-static int
-_scsih_is_end_device(u32 device_info)
-{
- if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
- ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
- (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
- (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
- return 1;
- else
- return 0;
-}
-
-/**
- * _scsih_scsi_lookup_get - returns scmd entry
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns the smid stored scmd pointer.
- */
-static struct scsi_cmnd *
-_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return ioc->scsi_lookup[smid - 1].scmd;
-}
-
-/**
- * _scsih_scsi_lookup_get_clear - returns scmd entry
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns the smid stored scmd pointer.
- * Then will derefrence the stored scmd pointer.
- */
-static inline struct scsi_cmnd *
-_scsih_scsi_lookup_get_clear(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_find_by_scmd - scmd 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 search for a scmd pointer in the scsi_lookup array,
- * returning the revelent smid. A returned value of zero means invalid.
- */
-static u16
-_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
- *scmd)
-{
- u16 smid;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- smid = 0;
- for (i = 0; i < ioc->scsiio_depth; i++) {
- if (ioc->scsi_lookup[i].scmd == scmd) {
- smid = ioc->scsi_lookup[i].smid;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return smid;
-}
-
-/**
- * _scsih_scsi_lookup_find_by_target - search for matching channel:id
- * @ioc: per adapter object
- * @id: target id
- * @channel: channel
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * This will search for a matching channel:id in the scsi_lookup array,
- * returning 1 if found.
- */
-static u8
-_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
- int channel)
-{
- u8 found;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- found = 0;
- 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)) {
- found = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return found;
-}
-
-/**
- * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
- * @ioc: per adapter object
- * @id: target id
- * @lun: lun number
- * @channel: channel
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * This will search for a matching channel:id:lun in the scsi_lookup array,
- * returning 1 if found.
- */
-static u8
-_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
- unsigned int lun, int channel)
-{
- u8 found;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- found = 0;
- 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 &&
- ioc->scsi_lookup[i].scmd->device->lun == lun)) {
- found = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return found;
-}
-
-/**
- * _scsih_get_chain_buffer_tracker - obtain chain tracker
- * @ioc: per adapter object
- * @smid: smid associated to an IO request
- *
- * Returns chain tracker(from ioc->free_chain_list)
- */
-static struct chain_tracker *
-_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- struct chain_tracker *chain_req;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (list_empty(&ioc->free_chain_list)) {
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not "
- "available\n", ioc->name));
- return NULL;
- }
- chain_req = list_entry(ioc->free_chain_list.next,
- struct chain_tracker, tracker_list);
- list_del_init(&chain_req->tracker_list);
- list_add_tail(&chain_req->tracker_list,
- &ioc->scsi_lookup[smid - 1].chain_list);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return chain_req;
-}
-
-/**
- * _scsih_build_scatter_gather - main sg creation routine
- * @ioc: per adapter object
- * @scmd: scsi command
- * @smid: system request message index
- * Context: none.
- *
- * The main routine that builds scatter gather table from a given
- * scsi request sent via the .queuecommand main handler.
- *
- * Returns 0 success, anything else error
- */
-static int
-_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
- struct scsi_cmnd *scmd, u16 smid)
-{
- Mpi2SCSIIORequest_t *mpi_request;
- dma_addr_t chain_dma;
- struct scatterlist *sg_scmd;
- void *sg_local, *chain;
- u32 chain_offset;
- u32 chain_length;
- u32 chain_flags;
- int sges_left;
- u32 sges_in_segment;
- u32 sgl_flags;
- u32 sgl_flags_last_element;
- u32 sgl_flags_end_buffer;
- struct chain_tracker *chain_req;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
-
- /* init scatter gather flags */
- sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
- if (scmd->sc_data_direction == DMA_TO_DEVICE)
- sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
- sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
- << MPI2_SGE_FLAGS_SHIFT;
- sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
- << MPI2_SGE_FLAGS_SHIFT;
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-
- sg_scmd = scsi_sglist(scmd);
- sges_left = scsi_dma_map(scmd);
- if (sges_left < 0) {
- sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
- " failed: request for %d bytes!\n", scsi_bufflen(scmd));
- return -ENOMEM;
- }
-
- sg_local = &mpi_request->SGL;
- sges_in_segment = ioc->max_sges_in_main_message;
- if (sges_left <= sges_in_segment)
- goto fill_in_last_segment;
-
- mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
- (sges_in_segment * ioc->sge_size))/4;
-
- /* fill in main message segment when there is a chain following */
- while (sges_in_segment) {
- if (sges_in_segment == 1)
- ioc->base_add_sg_single(sg_local,
- sgl_flags_last_element | sg_dma_len(sg_scmd),
- sg_dma_address(sg_scmd));
- else
- ioc->base_add_sg_single(sg_local, sgl_flags |
- sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
- sg_scmd = sg_next(sg_scmd);
- sg_local += ioc->sge_size;
- sges_left--;
- sges_in_segment--;
- }
-
- /* initializing the chain flags and pointers */
- chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
- chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
- if (!chain_req)
- return -1;
- chain = chain_req->chain_buffer;
- chain_dma = chain_req->chain_buffer_dma;
- do {
- sges_in_segment = (sges_left <=
- ioc->max_sges_in_chain_message) ? sges_left :
- ioc->max_sges_in_chain_message;
- chain_offset = (sges_left == sges_in_segment) ?
- 0 : (sges_in_segment * ioc->sge_size)/4;
- chain_length = sges_in_segment * ioc->sge_size;
- if (chain_offset) {
- chain_offset = chain_offset <<
- MPI2_SGE_CHAIN_OFFSET_SHIFT;
- chain_length += ioc->sge_size;
- }
- ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
- chain_length, chain_dma);
- sg_local = chain;
- if (!chain_offset)
- goto fill_in_last_segment;
-
- /* fill in chain segments */
- while (sges_in_segment) {
- if (sges_in_segment == 1)
- ioc->base_add_sg_single(sg_local,
- sgl_flags_last_element |
- sg_dma_len(sg_scmd),
- sg_dma_address(sg_scmd));
- else
- ioc->base_add_sg_single(sg_local, sgl_flags |
- sg_dma_len(sg_scmd),
- sg_dma_address(sg_scmd));
- sg_scmd = sg_next(sg_scmd);
- sg_local += ioc->sge_size;
- sges_left--;
- sges_in_segment--;
- }
-
- chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
- if (!chain_req)
- return -1;
- chain = chain_req->chain_buffer;
- chain_dma = chain_req->chain_buffer_dma;
- } while (1);
-
-
- fill_in_last_segment:
-
- /* fill the last segment */
- while (sges_left) {
- if (sges_left == 1)
- ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
- sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
- else
- ioc->base_add_sg_single(sg_local, sgl_flags |
- sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
- sg_scmd = sg_next(sg_scmd);
- sg_local += ioc->sge_size;
- sges_left--;
- }
-
- return 0;
-}
-
-/**
- * _scsih_change_queue_depth - setting device queue depth
- * @sdev: scsi device struct
- * @qdepth: requested queue depth
- *
- * Returns queue depth.
- */
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
-{
- struct Scsi_Host *shost = sdev->host;
- int max_depth;
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- max_depth = shost->can_queue;
-
- /* limit max device queue for SATA to 32 */
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- goto not_sata;
- sas_target_priv_data = sas_device_priv_data->sas_target;
- if (!sas_target_priv_data)
- goto not_sata;
- if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
- goto not_sata;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data);
- if (sas_device) {
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
-
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- not_sata:
- if (!sdev->tagged_supported)
- max_depth = 1;
- if (qdepth > max_depth)
- qdepth = max_depth;
- return scsi_change_queue_depth(sdev, qdepth);
-}
-
-/**
- * _scsih_target_alloc - target add routine
- * @starget: scsi target struct
- *
- * Returns 0 if ok. Any other return is assumed to be an error and
- * the device is ignored.
- */
-static int
-_scsih_target_alloc(struct scsi_target *starget)
-{
- struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- unsigned long flags;
- struct sas_rphy *rphy;
-
- sas_target_priv_data = kzalloc(sizeof(*sas_target_priv_data),
- GFP_KERNEL);
- if (!sas_target_priv_data)
- return -ENOMEM;
-
- starget->hostdata = sas_target_priv_data;
- sas_target_priv_data->starget = starget;
- sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
-
- /* RAID volumes */
- if (starget->channel == RAID_CHANNEL) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
- starget->channel);
- if (raid_device) {
- sas_target_priv_data->handle = raid_device->handle;
- sas_target_priv_data->sas_address = raid_device->wwid;
- sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
- if (ioc->is_warpdrive)
- sas_target_priv_data->raid_device = raid_device;
- raid_device->starget = starget;
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- return 0;
- }
-
- /* sas/sata devices */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- rphy = dev_to_rphy(starget->dev.parent);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- rphy->identify.sas_address);
-
- if (sas_device) {
- sas_target_priv_data->handle = sas_device->handle;
- sas_target_priv_data->sas_address = sas_device->sas_address;
- sas_target_priv_data->sdev = sas_device;
- sas_device->starget = starget;
- sas_device->id = starget->id;
- sas_device->channel = starget->channel;
- if (test_bit(sas_device->handle, ioc->pd_handles))
- sas_target_priv_data->flags |=
- MPT_TARGET_FLAGS_RAID_COMPONENT;
-
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return 0;
-}
-
-/**
- * _scsih_target_destroy - target destroy routine
- * @starget: scsi target struct
- *
- * Returns nothing.
- */
-static void
-_scsih_target_destroy(struct scsi_target *starget)
-{
- struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- unsigned long flags;
- struct sas_rphy *rphy;
-
- sas_target_priv_data = starget->hostdata;
- if (!sas_target_priv_data)
- return;
-
- if (starget->channel == RAID_CHANNEL) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
- starget->channel);
- if (raid_device) {
- raid_device->starget = NULL;
- raid_device->sdev = NULL;
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- goto out;
- }
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- rphy = dev_to_rphy(starget->dev.parent);
- sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data);
- if (sas_device && (sas_device->starget == starget) &&
- (sas_device->id == starget->id) &&
- (sas_device->channel == starget->channel))
- sas_device->starget = NULL;
-
- if (sas_device) {
- /*
- * Corresponding get() is in _scsih_target_alloc()
- */
- sas_target_priv_data->sdev = NULL;
- sas_device_put(sas_device);
-
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- out:
- kfree(sas_target_priv_data);
- starget->hostdata = NULL;
-}
-
-/**
- * _scsih_slave_alloc - device add routine
- * @sdev: scsi device struct
- *
- * Returns 0 if ok. Any other return is assumed to be an error and
- * the device is ignored.
- */
-static int
-_scsih_slave_alloc(struct scsi_device *sdev)
-{
- struct Scsi_Host *shost;
- struct MPT2SAS_ADAPTER *ioc;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_target *starget;
- struct _raid_device *raid_device;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data),
- GFP_KERNEL);
- if (!sas_device_priv_data)
- return -ENOMEM;
-
- sas_device_priv_data->lun = sdev->lun;
- sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
-
- starget = scsi_target(sdev);
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->num_luns++;
- sas_device_priv_data->sas_target = sas_target_priv_data;
- sdev->hostdata = sas_device_priv_data;
- if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
- sdev->no_uld_attach = 1;
-
- shost = dev_to_shost(&starget->dev);
- ioc = shost_priv(shost);
- if (starget->channel == RAID_CHANNEL) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc,
- starget->id, starget->channel);
- if (raid_device)
- raid_device->sdev = sdev; /* raid is single lun */
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
-
- if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_target_priv_data->sas_address);
- if (sas_device && (sas_device->starget == NULL)) {
- sdev_printk(KERN_INFO, sdev,
- "%s : sas_device->starget set to starget @ %d\n",
- __func__, __LINE__);
- sas_device->starget = starget;
- }
-
- if (sas_device)
- sas_device_put(sas_device);
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
-
- return 0;
-}
-
-/**
- * _scsih_slave_destroy - device destroy routine
- * @sdev: scsi device struct
- *
- * Returns nothing.
- */
-static void
-_scsih_slave_destroy(struct scsi_device *sdev)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct scsi_target *starget;
- struct Scsi_Host *shost;
- struct MPT2SAS_ADAPTER *ioc;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- if (!sdev->hostdata)
- return;
-
- starget = scsi_target(sdev);
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->num_luns--;
-
- shost = dev_to_shost(&starget->dev);
- ioc = shost_priv(shost);
-
- if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_from_target(ioc,
- sas_target_priv_data);
- if (sas_device && !sas_target_priv_data->num_luns)
- sas_device->starget = NULL;
-
- if (sas_device)
- sas_device_put(sas_device);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
-
- kfree(sdev->hostdata);
- sdev->hostdata = NULL;
-}
-
-/**
- * _scsih_display_sata_capabilities - sata capabilities
- * @ioc: per adapter object
- * @handle: device handle
- * @sdev: scsi device struct
- */
-static void
-_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
- u16 handle, struct scsi_device *sdev)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- u32 ioc_status;
- u16 flags;
- u32 device_info;
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- flags = le16_to_cpu(sas_device_pg0.Flags);
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
-
- sdev_printk(KERN_INFO, sdev,
- "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
- "sw_preserve(%s)\n",
- (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
- "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
-}
-
-/**
- * _scsih_is_raid - return boolean indicating device is raid volume
- * @dev the device struct object
- */
-static int
-_scsih_is_raid(struct device *dev)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
-
- if (ioc->is_warpdrive)
- return 0;
- return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
-}
-
-/**
- * _scsih_get_resync - get raid volume resync percent complete
- * @dev the device struct object
- */
-static void
-_scsih_get_resync(struct device *dev)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
- static struct _raid_device *raid_device;
- unsigned long flags;
- Mpi2RaidVolPage0_t vol_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 volume_status_flags;
- u8 percent_complete;
- u16 handle;
-
- percent_complete = 0;
- handle = 0;
- if (ioc->is_warpdrive)
- goto out;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
- sdev->channel);
- if (raid_device) {
- handle = raid_device->handle;
- percent_complete = raid_device->percent_complete;
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (!handle)
- goto out;
-
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- percent_complete = 0;
- goto out;
- }
-
- volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
- if (!(volume_status_flags &
- MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS))
- percent_complete = 0;
-
- out:
- raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
-}
-
-/**
- * _scsih_get_state - get raid volume level
- * @dev the device struct object
- */
-static void
-_scsih_get_state(struct device *dev)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
- static struct _raid_device *raid_device;
- unsigned long flags;
- Mpi2RaidVolPage0_t vol_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 volstate;
- enum raid_state state = RAID_STATE_UNKNOWN;
- u16 handle = 0;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
- sdev->channel);
- if (raid_device)
- handle = raid_device->handle;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (!raid_device)
- goto out;
-
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
- if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
- state = RAID_STATE_RESYNCING;
- goto out;
- }
-
- switch (vol_pg0.VolumeState) {
- case MPI2_RAID_VOL_STATE_OPTIMAL:
- case MPI2_RAID_VOL_STATE_ONLINE:
- state = RAID_STATE_ACTIVE;
- break;
- case MPI2_RAID_VOL_STATE_DEGRADED:
- state = RAID_STATE_DEGRADED;
- break;
- case MPI2_RAID_VOL_STATE_FAILED:
- case MPI2_RAID_VOL_STATE_MISSING:
- state = RAID_STATE_OFFLINE;
- break;
- }
- out:
- raid_set_state(mpt2sas_raid_template, dev, state);
-}
-
-/**
- * _scsih_set_level - set raid level
- * @sdev: scsi device struct
- * @volume_type: volume type
- */
-static void
-_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
-{
- enum raid_level level = RAID_LEVEL_UNKNOWN;
-
- switch (volume_type) {
- case MPI2_RAID_VOL_TYPE_RAID0:
- level = RAID_LEVEL_0;
- break;
- case MPI2_RAID_VOL_TYPE_RAID10:
- level = RAID_LEVEL_10;
- break;
- case MPI2_RAID_VOL_TYPE_RAID1E:
- level = RAID_LEVEL_1E;
- break;
- case MPI2_RAID_VOL_TYPE_RAID1:
- level = RAID_LEVEL_1;
- break;
- }
-
- raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
-}
-
-/**
- * _scsih_get_volume_capabilities - volume capabilities
- * @ioc: per adapter object
- * @sas_device: the raid_device object
- *
- * Returns 0 for success, else 1
- */
-static int
-_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- Mpi2RaidVolPage0_t *vol_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 sz;
- u8 num_pds;
-
- if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
- &num_pds)) || !num_pds) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
- return 1;
- }
-
- raid_device->num_pds = num_pds;
- sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
- sizeof(Mpi2RaidVol0PhysDisk_t));
- vol_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!vol_pg0) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
- return 1;
- }
-
- if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
- kfree(vol_pg0);
- return 1;
- }
-
- raid_device->volume_type = vol_pg0->VolumeType;
-
- /* figure out what the underlying devices are by
- * obtaining the device_info bits for the 1st device
- */
- if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
- vol_pg0->PhysDisk[0].PhysDiskNum))) {
- if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
- le16_to_cpu(pd_pg0.DevHandle)))) {
- raid_device->device_info =
- le32_to_cpu(sas_device_pg0.DeviceInfo);
- }
- }
-
- kfree(vol_pg0);
- return 0;
-}
-/**
- * _scsih_disable_ddio - Disable direct I/O for all the volumes
- * @ioc: per adapter object
- */
-static void
-_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidVolPage1_t vol_pg1;
- Mpi2ConfigReply_t mpi_reply;
- struct _raid_device *raid_device;
- u16 handle;
- u16 ioc_status;
- unsigned long flags;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
- handle = le16_to_cpu(vol_pg1.DevHandle);
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device)
- raid_device->direct_io_enabled = 0;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
- return;
-}
-
-
-/**
- * _scsih_get_num_volumes - Get number of volumes in the ioc
- * @ioc: per adapter object
- */
-static u8
-_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidVolPage1_t vol_pg1;
- Mpi2ConfigReply_t mpi_reply;
- u16 handle;
- u8 vol_cnt = 0;
- u16 ioc_status;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
- vol_cnt++;
- handle = le16_to_cpu(vol_pg1.DevHandle);
- }
- return vol_cnt;
-}
-
-
-/**
- * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O.
- * @ioc: per adapter object
- * @raid_device: the raid_device object
- */
-static void
-_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- Mpi2RaidVolPage0_t *vol_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 sz;
- u8 num_pds, count;
- unsigned long stripe_sz, block_sz;
- u8 stripe_exp, block_exp;
- u64 dev_max_lba;
-
- if (!ioc->is_warpdrive)
- return;
-
- if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "globally as drives are exposed\n", ioc->name);
- return;
- }
- if (_scsih_get_num_volumes(ioc) > 1) {
- _scsih_disable_ddio(ioc);
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "globally as number of drives > 1\n", ioc->name);
- return;
- }
- if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
- &num_pds)) || !num_pds) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "Failure in computing number of drives\n", ioc->name);
- return;
- }
-
- sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
- sizeof(Mpi2RaidVol0PhysDisk_t));
- vol_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!vol_pg0) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "Memory allocation failure for RVPG0\n", ioc->name);
- return;
- }
-
- if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "Failure in retrieving RVPG0\n", ioc->name);
- kfree(vol_pg0);
- return;
- }
-
- /*
- * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
- * assumed for WARPDRIVE, disable direct I/O
- */
- if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
- printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x): num_mem=%d, "
- "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
- num_pds, MPT_MAX_WARPDRIVE_PDS);
- kfree(vol_pg0);
- return;
- }
- for (count = 0; count < num_pds; count++) {
- if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
- vol_pg0->PhysDisk[count].PhysDiskNum) ||
- le16_to_cpu(pd_pg0.DevHandle) ==
- MPT2SAS_INVALID_DEVICE_HANDLE) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
- "disabled for the drive with handle(0x%04x) member"
- "handle retrieval failed for member number=%d\n",
- ioc->name, raid_device->handle,
- vol_pg0->PhysDisk[count].PhysDiskNum);
- goto out_error;
- }
- /* Disable direct I/O if member drive lba exceeds 4 bytes */
- dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
- if (dev_max_lba >> 32) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
- "disabled for the drive with handle(0x%04x) member"
- "handle (0x%04x) unsupported max lba 0x%016llx\n",
- ioc->name, raid_device->handle,
- le16_to_cpu(pd_pg0.DevHandle),
- (unsigned long long)dev_max_lba);
- goto out_error;
- }
-
- raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
- }
-
- /*
- * Assumption for WD: Direct I/O is not supported if the volume is
- * not RAID0
- */
- if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x): type=%d, "
- "s_sz=%uK, blk_size=%u\n", ioc->name,
- raid_device->handle, raid_device->volume_type,
- (le32_to_cpu(vol_pg0->StripeSize) *
- le16_to_cpu(vol_pg0->BlockSize)) / 1024,
- le16_to_cpu(vol_pg0->BlockSize));
- goto out_error;
- }
-
- stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
- stripe_exp = find_first_bit(&stripe_sz, 32);
- if (stripe_exp == 32) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
- ioc->name, raid_device->handle,
- (le32_to_cpu(vol_pg0->StripeSize) *
- le16_to_cpu(vol_pg0->BlockSize)) / 1024);
- goto out_error;
- }
- raid_device->stripe_exponent = stripe_exp;
- block_sz = le16_to_cpu(vol_pg0->BlockSize);
- block_exp = find_first_bit(&block_sz, 16);
- if (block_exp == 16) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x) invalid block sz %u\n",
- ioc->name, raid_device->handle,
- le16_to_cpu(vol_pg0->BlockSize));
- goto out_error;
- }
- raid_device->block_exponent = block_exp;
- raid_device->direct_io_enabled = 1;
-
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive"
- " with handle(0x%04x)\n", ioc->name, raid_device->handle);
- /*
- * WARPDRIVE: Though the following fields are not used for direct IO,
- * stored for future purpose:
- */
- raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
- raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
- raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
-
-
- kfree(vol_pg0);
- return;
-
-out_error:
- raid_device->direct_io_enabled = 0;
- for (count = 0; count < num_pds; count++)
- raid_device->pd_handle[count] = 0;
- kfree(vol_pg0);
- return;
-}
-
-/**
- * _scsih_enable_tlr - setting TLR flags
- * @ioc: per adapter object
- * @sdev: scsi device struct
- *
- * Enabling Transaction Layer Retries for tape devices when
- * vpd page 0x90 is present
- *
- */
-static void
-_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
-{
- /* only for TAPE */
- if (sdev->type != TYPE_TAPE)
- return;
-
- if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
- return;
-
- sas_enable_tlr(sdev);
- sdev_printk(KERN_INFO, sdev, "TLR %s\n",
- sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
- return;
-
-}
-
-/**
- * _scsih_slave_configure - device configure routine.
- * @sdev: scsi device struct
- *
- * Returns 0 if ok. Any other return is assumed to be an error and
- * the device is ignored.
- */
-static int
-_scsih_slave_configure(struct scsi_device *sdev)
-{
- struct Scsi_Host *shost = sdev->host;
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- unsigned long flags;
- int qdepth;
- u8 ssp_target = 0;
- char *ds = "";
- char *r_level = "";
- u16 handle, volume_handle = 0;
- u64 volume_wwid = 0;
-
- qdepth = 1;
- sas_device_priv_data = sdev->hostdata;
- sas_device_priv_data->configured_lun = 1;
- sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
- sas_target_priv_data = sas_device_priv_data->sas_target;
- handle = sas_target_priv_data->handle;
-
- /* raid volume handling */
- if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (!raid_device) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- return 1;
- }
-
- if (_scsih_get_volume_capabilities(ioc, raid_device)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- return 1;
- }
- /*
- * WARPDRIVE: Initialize the required data for Direct IO
- */
- _scsih_init_warpdrive_properties(ioc, raid_device);
-
- /* RAID Queue Depth Support
- * IS volume = underlying qdepth of drive type, either
- * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
- * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
- */
- if (raid_device->device_info &
- MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
- qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
- ds = "SSP";
- } else {
- qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
- if (raid_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- ds = "SATA";
- else
- ds = "STP";
- }
-
- switch (raid_device->volume_type) {
- case MPI2_RAID_VOL_TYPE_RAID0:
- r_level = "RAID0";
- break;
- case MPI2_RAID_VOL_TYPE_RAID1E:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- if (ioc->manu_pg10.OEMIdentifier &&
- (le32_to_cpu(ioc->manu_pg10.GenericFlags0) &
- MFG10_GF0_R10_DISPLAY) &&
- !(raid_device->num_pds % 2))
- r_level = "RAID10";
- else
- r_level = "RAID1E";
- break;
- case MPI2_RAID_VOL_TYPE_RAID1:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- r_level = "RAID1";
- break;
- case MPI2_RAID_VOL_TYPE_RAID10:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- r_level = "RAID10";
- break;
- case MPI2_RAID_VOL_TYPE_UNKNOWN:
- default:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- r_level = "RAIDX";
- break;
- }
-
- if (!ioc->hide_ir_msg)
- sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "wwid(0x%016llx), pd_count(%d), type(%s)\n",
- r_level, raid_device->handle,
- (unsigned long long)raid_device->wwid,
- raid_device->num_pds, ds);
- _scsih_change_queue_depth(sdev, qdepth);
- /* raid transport support */
- if (!ioc->is_warpdrive)
- _scsih_set_level(sdev, raid_device->volume_type);
- return 0;
- }
-
- /* non-raid handling */
- if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
- if (mpt2sas_config_get_volume_handle(ioc, handle,
- &volume_handle)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
- if (volume_handle && mpt2sas_config_get_volume_wwid(ioc,
- volume_handle, &volume_wwid)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
- }
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_device_priv_data->sas_target->sas_address);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- return 1;
- }
- sas_device->volume_handle = volume_handle;
- sas_device->volume_wwid = volume_wwid;
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
- qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
- ssp_target = 1;
- ds = "SSP";
- } else {
- qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
- ds = "STP";
- else if (sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- ds = "SATA";
- }
- sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
- ds, sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- sas_device->phy,
- (unsigned long long)sas_device->device_name);
- sdev_printk(KERN_INFO, sdev, "%s: "
- "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
- (unsigned long long) sas_device->enclosure_logical_id,
- sas_device->slot);
-
- sas_device_put(sas_device);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!ssp_target)
- _scsih_display_sata_capabilities(ioc, handle, sdev);
-
- _scsih_change_queue_depth(sdev, qdepth);
-
- if (ssp_target) {
- sas_read_port_mode_page(sdev);
- _scsih_enable_tlr(ioc, sdev);
- }
-
- return 0;
-}
-
-/**
- * _scsih_bios_param - fetch head, sector, cylinder info for a disk
- * @sdev: scsi device struct
- * @bdev: pointer to block device context
- * @capacity: device size (in 512 byte sectors)
- * @params: three element array to place output:
- * params[0] number of heads (max 255)
- * params[1] number of sectors (max 63)
- * params[2] number of cylinders
- *
- * Return nothing.
- */
-static int
-_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int params[])
-{
- int heads;
- int sectors;
- sector_t cylinders;
- ulong dummy;
-
- heads = 64;
- sectors = 32;
-
- dummy = heads * sectors;
- cylinders = capacity;
- sector_div(cylinders, dummy);
-
- /*
- * Handle extended translation size for logical drives
- * > 1Gb
- */
- if ((ulong)capacity >= 0x200000) {
- heads = 255;
- sectors = 63;
- dummy = heads * sectors;
- cylinders = capacity;
- sector_div(cylinders, dummy);
- }
-
- /* return result */
- params[0] = heads;
- params[1] = sectors;
- params[2] = cylinders;
-
- return 0;
-}
-
-/**
- * _scsih_response_code - translation of device response code
- * @ioc: per adapter object
- * @response_code: response code returned by the device
- *
- * Return nothing.
- */
-static void
-_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
-{
- char *desc;
-
- switch (response_code) {
- case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
- desc = "task management request completed";
- break;
- case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
- desc = "invalid frame";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
- desc = "task management request not supported";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
- desc = "task management request failed";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
- desc = "task management request succeeded";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
- desc = "invalid lun";
- break;
- case 0xA:
- desc = "overlapped tag attempted";
- break;
- case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
- desc = "task queued, however not sent to target";
- break;
- default:
- desc = "unknown";
- break;
- }
- printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
- ioc->name, response_code, desc);
-}
-
-/**
- * _scsih_tm_done - tm 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: none.
- *
- * The callback handler when using scsih_issue_tm.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-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 1;
- if (ioc->tm_cmds.smid != smid)
- return 1;
- mpt2sas_base_flush_reply_queues(ioc);
- ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply) {
- memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
- ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
- }
- ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->tm_cmds.done);
- return 1;
-}
-
-/**
- * mpt2sas_scsih_set_tm_flag - set per target tm_busy
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During taskmangement request, we need to freeze the device queue.
- */
-void
-mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
- u8 skip = 0;
-
- shost_for_each_device(sdev, ioc->shost) {
- if (skip)
- continue;
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
- sas_device_priv_data->sas_target->tm_busy = 1;
- skip = 1;
- ioc->ignore_loginfos = 1;
- }
- }
-}
-
-/**
- * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During taskmangement request, we need to freeze the device queue.
- */
-void
-mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
- u8 skip = 0;
-
- shost_for_each_device(sdev, ioc->shost) {
- if (skip)
- continue;
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
- sas_device_priv_data->sas_target->tm_busy = 0;
- skip = 1;
- ioc->ignore_loginfos = 0;
- }
- }
-}
-
-
-/**
- * mpt2sas_scsih_issue_tm - main routine for sending tm requests
- * @ioc: per adapter struct
- * @device_handle: device handle
- * @channel: the channel assigned by the OS
- * @id: the id assigned by the OS
- * @lun: lun number
- * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
- * @smid_task: smid assigned to the task
- * @timeout: timeout in seconds
- * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
- * Context: user
- *
- * A generic API for sending task management requests to firmware.
- *
- * The callback index is set inside `ioc->tm_cb_idx`.
- *
- * Return SUCCESS or FAILED.
- */
-int
-mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
- uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
- enum mutex_type m_type)
-{
- Mpi2SCSITaskManagementRequest_t *mpi_request;
- Mpi2SCSITaskManagementReply_t *mpi_reply;
- u16 smid = 0;
- u32 ioc_state;
- unsigned long timeleft;
- struct scsiio_tracker *scsi_lookup = NULL;
- int rc;
-
- if (m_type == TM_MUTEX_ON)
- mutex_lock(&ioc->tm_cmds.mutex);
- if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
- __func__, ioc->name);
- rc = FAILED;
- goto err_out;
- }
-
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- rc = FAILED;
- goto err_out;
- }
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
- "active!\n", ioc->name));
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- goto err_out;
- }
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc, ioc_state &
- MPI2_DOORBELL_DATA_MASK);
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- goto err_out;
- }
-
- 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__);
- rc = FAILED;
- goto err_out;
- }
-
- if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
- scsi_lookup = &ioc->scsi_lookup[smid_task - 1];
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
- " 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;
- memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
- memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t));
- mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- mpi_request->DevHandle = cpu_to_le16(handle);
- mpi_request->TaskType = type;
- mpi_request->TaskMID = cpu_to_le16(smid_task);
- 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);
- timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
- if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SCSITaskManagementRequest_t)/4);
- if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- mpt2sas_scsih_clear_tm_flag(ioc, handle);
- goto err_out;
- }
- }
-
- if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
- mpi_reply = ioc->tm_cmds.reply;
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
- "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
- if (ioc->logging_level & MPT_DEBUG_TM) {
- _scsih_response_code(ioc, mpi_reply->ResponseCode);
- if (mpi_reply->IOCStatus)
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SCSITaskManagementRequest_t)/4);
- }
- }
-
- switch (type) {
- case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
- rc = SUCCESS;
- if (scsi_lookup->scmd == NULL)
- break;
- rc = FAILED;
- break;
-
- case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
- if (_scsih_scsi_lookup_find_by_target(ioc, id, channel))
- rc = FAILED;
- else
- rc = SUCCESS;
- break;
-
- case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
- case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
- if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
- rc = FAILED;
- else
- rc = SUCCESS;
- break;
- case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
- rc = SUCCESS;
- break;
- default:
- rc = FAILED;
- break;
- }
-
- mpt2sas_scsih_clear_tm_flag(ioc, handle);
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- if (m_type == TM_MUTEX_ON)
- mutex_unlock(&ioc->tm_cmds.mutex);
-
- return rc;
-
- err_out:
- if (m_type == TM_MUTEX_ON)
- mutex_unlock(&ioc->tm_cmds.mutex);
- return rc;
-}
-
-/**
- * _scsih_tm_display_info - displays info about the device
- * @ioc: per adapter struct
- * @scmd: pointer to scsi command object
- *
- * Called by task management callback handlers.
- */
-static void
-_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
-{
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *priv_target = starget->hostdata;
- struct _sas_device *sas_device = NULL;
- unsigned long flags;
- char *device_str = NULL;
-
- if (!priv_target)
- return;
- if (ioc->hide_ir_msg)
- device_str = "WarpDrive";
- else
- device_str = "volume";
-
- scsi_print_command(scmd);
- if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- starget_printk(KERN_INFO, starget, "%s handle(0x%04x), "
- "%s wwid(0x%016llx)\n", device_str, priv_target->handle,
- device_str, (unsigned long long)priv_target->sas_address);
- } else {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_from_target(ioc, priv_target);
- if (sas_device) {
- if (priv_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- starget_printk(KERN_INFO, starget,
- "volume handle(0x%04x), "
- "volume wwid(0x%016llx)\n",
- sas_device->volume_handle,
- (unsigned long long)sas_device->volume_wwid);
- }
- starget_printk(KERN_INFO, starget,
- "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
- sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- sas_device->phy);
- starget_printk(KERN_INFO, starget,
- "enclosure_logical_id(0x%016llx), slot(%d)\n",
- (unsigned long long)sas_device->enclosure_logical_id,
- sas_device->slot);
-
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
-}
-
-/**
- * _scsih_abort - eh threads main abort routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_abort(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- u16 smid;
- u16 handle;
- int r;
-
- sdev_printk(KERN_INFO, scmd->device, "attempting task abort! "
- "scmd(%p)\n", scmd);
- _scsih_tm_display_info(ioc, scmd);
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
- "scmd(%p)\n", scmd);
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- r = SUCCESS;
- goto out;
- }
-
- /* search for the command */
- smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
- if (!smid) {
- scmd->result = DID_RESET << 16;
- r = SUCCESS;
- goto out;
- }
-
- /* for hidden raid components and volumes this is not supported */
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT ||
- sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- scmd->result = DID_RESET << 16;
- r = FAILED;
- goto out;
- }
-
- mpt2sas_halt_firmware(ioc);
-
- handle = sas_device_priv_data->sas_target->handle;
- r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
- scmd->device->id, scmd->device->lun,
- MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON);
-
- out:
- sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
- ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
- return r;
-}
-
-/**
- * _scsih_dev_reset - eh threads main device reset routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_dev_reset(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device = NULL;
- u16 handle;
- int r;
-
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *target_priv_data = starget->hostdata;
-
- starget_printk(KERN_INFO, starget, "attempting device reset! "
- "scmd(%p)\n", scmd);
- _scsih_tm_display_info(ioc, scmd);
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- starget_printk(KERN_INFO, starget, "device been deleted! "
- "scmd(%p)\n", scmd);
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- r = SUCCESS;
- goto out;
- }
-
- /* for hidden raid components obtain the volume_handle */
- handle = 0;
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- sas_device = mpt2sas_get_sdev_from_target(ioc,
- target_priv_data);
- if (sas_device)
- handle = sas_device->volume_handle;
- } else
- handle = sas_device_priv_data->sas_target->handle;
-
- if (!handle) {
- scmd->result = DID_RESET << 16;
- r = FAILED;
- goto out;
- }
-
- r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
- scmd->device->id, scmd->device->lun,
- MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON);
-
- out:
- sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
- ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
-
- if (sas_device)
- sas_device_put(sas_device);
-
- return r;
-}
-
-/**
- * _scsih_target_reset - eh threads main target reset routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_target_reset(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device = NULL;
- u16 handle;
- int r;
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *target_priv_data = starget->hostdata;
-
- starget_printk(KERN_INFO, starget, "attempting target reset! "
- "scmd(%p)\n", scmd);
- _scsih_tm_display_info(ioc, scmd);
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- starget_printk(KERN_INFO, starget, "target been deleted! "
- "scmd(%p)\n", scmd);
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- r = SUCCESS;
- goto out;
- }
-
- /* for hidden raid components obtain the volume_handle */
- handle = 0;
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- sas_device = mpt2sas_get_sdev_from_target(ioc,
- target_priv_data);
- if (sas_device)
- handle = sas_device->volume_handle;
- } else
- handle = sas_device_priv_data->sas_target->handle;
-
- if (!handle) {
- scmd->result = DID_RESET << 16;
- r = FAILED;
- goto out;
- }
-
- r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
- scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
- 30, TM_MUTEX_ON);
-
- out:
- starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
- ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
-
- if (sas_device)
- sas_device_put(sas_device);
-
- return r;
-}
-
-/**
- * _scsih_host_reset - eh threads main host reset routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_host_reset(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- int r, retval;
-
- printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
-
- if (ioc->is_driver_loading) {
- printk(MPT2SAS_INFO_FMT "Blocking the host reset\n",
- ioc->name);
- r = FAILED;
- goto out;
- }
-
- retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- r = (retval < 0) ? FAILED : SUCCESS;
-
- out:
- printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
-
- return r;
-}
-
-/**
- * _scsih_fw_event_add - insert and queue up fw_event
- * @ioc: per adapter object
- * @fw_event: object describing the event
- * Context: This function will acquire ioc->fw_event_lock.
- *
- * This adds the firmware event object into link list, then queues it up to
- * be processed from user context.
- *
- * Return nothing.
- */
-static void
-_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
-{
- unsigned long flags;
-
- if (ioc->firmware_event_thread == NULL)
- return;
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- fw_event_work_get(fw_event);
- list_add_tail(&fw_event->list, &ioc->fw_event_list);
- INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
- fw_event_work_get(fw_event);
- queue_delayed_work(ioc->firmware_event_thread,
- &fw_event->delayed_work, 0);
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-}
-
-/**
- * _scsih_fw_event_del_from_list - delete fw_event from the list
- * @ioc: per adapter object
- * @fw_event: object describing the event
- * Context: This function will acquire ioc->fw_event_lock.
- *
- * If the fw_event is on the fw_event_list, remove it and do a put.
- *
- * Return nothing.
- */
-static void
-_scsih_fw_event_del_from_list(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
- *fw_event)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- if (!list_empty(&fw_event->list)) {
- list_del_init(&fw_event->list);
- fw_event_work_put(fw_event);
- }
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-}
-
-/**
- * _scsih_error_recovery_delete_devices - remove devices not responding
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- struct fw_event_work *fw_event;
-
- if (ioc->is_driver_loading)
- return;
-
- fw_event = alloc_fw_event_work(0);
- if (!fw_event)
- return;
-
- fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES;
- fw_event->ioc = ioc;
- _scsih_fw_event_add(ioc, fw_event);
- fw_event_work_put(fw_event);
-}
-
-/**
- * mpt2sas_port_enable_complete - port enable completed (fake event)
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-void
-mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc)
-{
- struct fw_event_work *fw_event;
-
- fw_event = alloc_fw_event_work(0);
- if (!fw_event)
- return;
- fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE;
- fw_event->ioc = ioc;
- _scsih_fw_event_add(ioc, fw_event);
- fw_event_work_put(fw_event);
-}
-
-static struct fw_event_work *dequeue_next_fw_event(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned long flags;
- struct fw_event_work *fw_event = NULL;
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- if (!list_empty(&ioc->fw_event_list)) {
- fw_event = list_first_entry(&ioc->fw_event_list,
- struct fw_event_work, list);
- list_del_init(&fw_event->list);
- }
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-
- return fw_event;
-}
-
-/**
- * _scsih_fw_event_cleanup_queue - cleanup event queue
- * @ioc: per adapter object
- *
- * Walk the firmware event queue, either killing timers, or waiting
- * for outstanding events to complete
- *
- * Return nothing.
- */
-static void
-_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
-{
- struct fw_event_work *fw_event;
-
- if (list_empty(&ioc->fw_event_list) ||
- !ioc->firmware_event_thread || in_interrupt())
- return;
-
- while ((fw_event = dequeue_next_fw_event(ioc))) {
- /*
- * Wait on the fw_event to complete. If this returns 1, then
- * the event was never executed, and we need a put for the
- * reference the delayed_work had on the fw_event.
- *
- * If it did execute, we wait for it to finish, and the put will
- * happen from _firmware_event_work()
- */
- if (cancel_delayed_work_sync(&fw_event->delayed_work))
- fw_event_work_put(fw_event);
-
- fw_event_work_put(fw_event);
- }
-}
-
-/**
- * _scsih_ublock_io_all_device - unblock every device
- * @ioc: per adapter object
- *
- * change the device state from block to running
- */
-static void
-_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (!sas_device_priv_data->block)
- continue;
- sas_device_priv_data->block = 0;
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, "
- "handle(0x%04x)\n",
- sas_device_priv_data->sas_target->handle));
- scsi_internal_device_unblock(sdev, SDEV_RUNNING);
- }
-}
-/**
- * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During device pull we need to appropiately set the sdev state.
- */
-static void
-_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (!sas_device_priv_data->block)
- continue;
- if (sas_device_priv_data->sas_target->sas_address ==
- sas_address) {
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
- MPT2SAS_INFO_FMT "SDEV_RUNNING: "
- "sas address(0x%016llx)\n", ioc->name,
- (unsigned long long)sas_address));
- sas_device_priv_data->block = 0;
- scsi_internal_device_unblock(sdev, SDEV_RUNNING);
- }
- }
-}
-
-/**
- * _scsih_block_io_all_device - set the device state to SDEV_BLOCK
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During device pull we need to appropiately set the sdev state.
- */
-static void
-_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->block)
- continue;
- sas_device_priv_data->block = 1;
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, "
- "handle(0x%04x)\n",
- sas_device_priv_data->sas_target->handle));
- scsi_internal_device_block(sdev);
- }
-}
-
-
-/**
- * _scsih_block_io_device - set the device state to SDEV_BLOCK
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During device pull we need to appropiately set the sdev state.
- */
-static void
-_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->block)
- continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
- MPT2SAS_INFO_FMT "SDEV_BLOCK: "
- "handle(0x%04x)\n", ioc->name, handle));
- sas_device_priv_data->block = 1;
- scsi_internal_device_block(sdev);
- }
- }
-}
-
-/**
- * _scsih_block_io_to_children_attached_to_ex
- * @ioc: per adapter object
- * @sas_expander: the sas_device object
- *
- * This routine set sdev state to SDEV_BLOCK for all devices
- * attached to this expander. This function called when expander is
- * pulled.
- */
-static void
-_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander)
-{
- struct _sas_port *mpt2sas_port;
- struct _sas_device *sas_device;
- struct _sas_node *expander_sibling;
- unsigned long flags;
-
- if (!sas_expander)
- return;
-
- list_for_each_entry(mpt2sas_port,
- &sas_expander->sas_port_list, port_list) {
- if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- mpt2sas_port->remote_identify.sas_address);
- if (sas_device) {
- set_bit(sas_device->handle,
- ioc->blocking_handles);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
- }
-
- list_for_each_entry(mpt2sas_port,
- &sas_expander->sas_port_list, port_list) {
-
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_EDGE_EXPANDER_DEVICE ||
- mpt2sas_port->remote_identify.device_type ==
- SAS_FANOUT_EXPANDER_DEVICE) {
- expander_sibling =
- mpt2sas_scsih_expander_find_by_sas_address(
- ioc, mpt2sas_port->remote_identify.sas_address);
- _scsih_block_io_to_children_attached_to_ex(ioc,
- expander_sibling);
- }
- }
-}
-
-/**
- * _scsih_block_io_to_children_attached_directly
- * @ioc: per adapter object
- * @event_data: topology change event data
- *
- * This routine set sdev state to SDEV_BLOCK for all devices
- * direct attached during device pull.
- */
-static void
-_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasTopologyChangeList_t *event_data)
-{
- int i;
- u16 handle;
- u16 reason_code;
- u8 phy_number;
-
- for (i = 0; i < event_data->NumEntries; i++) {
- 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;
- if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
- _scsih_block_io_device(ioc, handle);
- }
-}
-
-/**
- * _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 protocol
- * with controller firmware. This function will issue target reset
- * using high priority request queue. It will send a sas iounit
- * control 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;
- u16 smid;
- struct _sas_device *sas_device = NULL;
- struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
- u64 sas_address = 0;
- unsigned long flags;
- struct _tr_list *delayed_tr;
- u32 ioc_state;
-
- if (ioc->remove_host) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been "
- "removed: handle(0x%04x)\n", __func__, ioc->name, handle));
- return;
- } else if (ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci "
- "error recovery: handle(0x%04x)\n", __func__, ioc->name,
- handle));
- return;
- }
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not "
- "operational: handle(0x%04x)\n", __func__, ioc->name,
- handle));
- return;
- }
-
- /* if PD, then return */
- if (test_bit(handle, ioc->pd_handles))
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device && sas_device->starget &&
- sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- sas_address = sas_device->sas_address;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_target_priv_data) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: "
- "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle,
- (unsigned long long)sas_address));
- _scsih_ublock_io_device(ioc, sas_address);
- sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
- }
-
- 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)
- goto out;
- INIT_LIST_HEAD(&delayed_tr->list);
- delayed_tr->handle = handle;
- list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n",
- ioc->name, handle));
- goto out;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
- "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
- ioc->tm_tr_cb_idx));
- 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;
- mpt2sas_base_put_smid_hi_priority(ioc, smid);
-out:
- if (sas_device)
- sas_device_put(sas_device);
-}
-
-
-
-/**
- * _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 control completion routine.
- * This code is part of the code to initiate the device removal
- * handshake protocol 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)
-{
- Mpi2SasIoUnitControlReply_t *mpi_reply =
- mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (likely(mpi_reply)) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "sc_complete:handle(0x%04x), (open) "
- "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
- le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo)));
- } else {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- }
- return 1;
-}
-
-/**
- * _scsih_tm_tr_volume_send - send target reset request for volumes
- * @ioc: per adapter object
- * @handle: device handle
- * Context: interrupt time.
- *
- * 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_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- Mpi2SCSITaskManagementRequest_t *mpi_request;
- u16 smid;
- struct _tr_list *delayed_tr;
-
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
- "progress!\n", __func__, ioc->name));
- return;
- }
-
- smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_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;
- list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n",
- ioc->name, handle));
- return;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
- "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
- ioc->tm_tr_volume_cb_idx));
- 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;
- mpt2sas_base_put_smid_hi_priority(ioc, smid);
-}
-
-/**
- * _scsih_tm_volume_tr_complete - target reset completion
- * @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.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 msix_index, u32 reply)
-{
- u16 handle;
- Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
- Mpi2SCSITaskManagementReply_t *mpi_reply =
- mpt2sas_base_get_reply_virt_addr(ioc, reply);
-
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
- "progress!\n", __func__, ioc->name));
- return 1;
- }
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return 1;
- }
- mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
- handle = le16_to_cpu(mpi_request_tm->DevHandle);
- if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
- dewtprintk(ioc, printk("spurious interrupt: "
- "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle,
- le16_to_cpu(mpi_reply->DevHandle), smid));
- return 0;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n", ioc->name,
- handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
-
- return _scsih_check_for_pending_tm(ioc, smid);
-}
-
-/**
- * _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 protocol with controller firmware.
- * It will send a sas iounit control 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)
-{
- u16 handle;
- Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
- Mpi2SCSITaskManagementReply_t *mpi_reply =
- mpt2sas_base_get_reply_virt_addr(ioc, reply);
- Mpi2SasIoUnitControlRequest_t *mpi_request;
- u16 smid_sas_ctrl;
- u32 ioc_state;
-
- if (ioc->remove_host) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been "
- "removed\n", __func__, ioc->name));
- return 1;
- } else if (ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci "
- "error recovery\n", __func__, ioc->name));
- return 1;
- }
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not "
- "operational\n", __func__, ioc->name));
- return 1;
- }
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return 1;
- }
- mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
- handle = le16_to_cpu(mpi_request_tm->DevHandle);
- if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
- "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
- le16_to_cpu(mpi_reply->DevHandle), smid));
- return 0;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n", ioc->name,
- handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
-
- 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 1;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
- "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
- ioc->tm_sas_control_cb_idx));
- 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_request_tm->DevHandle;
- mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
-
- return _scsih_check_for_pending_tm(ioc, smid);
-}
-
-/**
- * _scsih_check_for_pending_tm - check for pending task management
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * This will check delayed target reset list, and feed the
- * next reqeust.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- struct _tr_list *delayed_tr;
-
- if (!list_empty(&ioc->delayed_tr_volume_list)) {
- delayed_tr = list_entry(ioc->delayed_tr_volume_list.next,
- struct _tr_list, list);
- mpt2sas_base_free_smid(ioc, smid);
- _scsih_tm_tr_volume_send(ioc, delayed_tr->handle);
- list_del(&delayed_tr->list);
- kfree(delayed_tr);
- return 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);
- _scsih_tm_tr_send(ioc, delayed_tr->handle);
- list_del(&delayed_tr->list);
- kfree(delayed_tr);
- return 0;
- }
-
- return 1;
-}
-
-/**
- * _scsih_check_topo_delete_events - sanity check on topo events
- * @ioc: per adapter object
- * @event_data: the event data payload
- *
- * This routine added to better handle cable breaker.
- *
- * This handles the case where driver receives multiple expander
- * add and delete events in a single shot. When there is a delete event
- * the routine will void any pending add events waiting in the event queue.
- *
- * Return nothing.
- */
-static void
-_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasTopologyChangeList_t *event_data)
-{
- struct fw_event_work *fw_event;
- Mpi2EventDataSasTopologyChangeList_t *local_event_data;
- 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++) {
- 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) {
- _scsih_block_io_to_children_attached_directly(ioc, event_data);
- return;
- }
- if (event_data->ExpStatus ==
- MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) {
- /* put expander attached devices into blocking state */
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
- expander_handle);
- _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- do {
- handle = find_first_bit(ioc->blocking_handles,
- ioc->facts.MaxDevHandle);
- if (handle < ioc->facts.MaxDevHandle)
- _scsih_block_io_device(ioc, handle);
- } while (test_and_clear_bit(handle, ioc->blocking_handles));
- } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
- _scsih_block_io_to_children_attached_directly(ioc, event_data);
-
- if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
- return;
-
- /* mark ignore flag for pending events */
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
- if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
- fw_event->ignore)
- continue;
- local_event_data = (Mpi2EventDataSasTopologyChangeList_t *)
- fw_event->event_data;
- if (local_event_data->ExpStatus ==
- MPI2_EVENT_SAS_TOPO_ES_ADDED ||
- local_event_data->ExpStatus ==
- MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
- if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
- expander_handle) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "setting ignoring flag\n", ioc->name));
- fw_event->ignore = 1;
- }
- }
- }
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-}
-
-/**
- * _scsih_set_volume_delete_flag - setting volume delete flag
- * @ioc: per adapter object
- * @handle: device handle
- *
- * This
- * Return nothing.
- */
-static void
-_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _raid_device *raid_device;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device && raid_device->starget &&
- raid_device->starget->hostdata) {
- sas_target_priv_data =
- raid_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "setting delete flag: handle(0x%04x), "
- "wwid(0x%016llx)\n", ioc->name, handle,
- (unsigned long long) raid_device->wwid));
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * _scsih_set_volume_handle_for_tr - set handle for target reset to volume
- * @handle: input handle
- * @a: handle for volume a
- * @b: handle for volume b
- *
- * IR firmware only supports two raid volumes. The purpose of this
- * routine is to set the volume handle in either a or b. When the given
- * input handle is non-zero, or when a and b have not been set before.
- */
-static void
-_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b)
-{
- if (!handle || handle == *a || handle == *b)
- return;
- if (!*a)
- *a = handle;
- else if (!*b)
- *b = handle;
-}
-
-/**
- * _scsih_check_ir_config_unhide_events - check for UNHIDE events
- * @ioc: per adapter object
- * @event_data: the event data payload
- * Context: interrupt time.
- *
- * This routine will send target reset to volume, followed by target
- * resets to the PDs. This is called when a PD has been removed, or
- * volume has been deleted or removed. When the target reset is sent
- * to volume, the PD target resets need to be queued to start upon
- * completion of the volume target reset.
- *
- * Return nothing.
- */
-static void
-_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrConfigChangeList_t *event_data)
-{
- Mpi2EventIrConfigElement_t *element;
- int i;
- u16 handle, volume_handle, a, b;
- struct _tr_list *delayed_tr;
-
- a = 0;
- b = 0;
-
- if (ioc->is_warpdrive)
- return;
-
- /* Volume Resets for Deleted or Removed */
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
- if (element->ReasonCode ==
- MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED ||
- element->ReasonCode ==
- MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
- volume_handle = le16_to_cpu(element->VolDevHandle);
- _scsih_set_volume_delete_flag(ioc, volume_handle);
- _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
- }
- }
-
- /* Volume Resets for UNHIDE events */
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
- if (le32_to_cpu(event_data->Flags) &
- MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
- continue;
- if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) {
- volume_handle = le16_to_cpu(element->VolDevHandle);
- _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
- }
- }
-
- if (a)
- _scsih_tm_tr_volume_send(ioc, a);
- if (b)
- _scsih_tm_tr_volume_send(ioc, b);
-
- /* PD target resets */
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
- if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE)
- continue;
- handle = le16_to_cpu(element->PhysDiskDevHandle);
- volume_handle = le16_to_cpu(element->VolDevHandle);
- clear_bit(handle, ioc->pd_handles);
- if (!volume_handle)
- _scsih_tm_tr_send(ioc, handle);
- else if (volume_handle == a || volume_handle == b) {
- delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
- BUG_ON(!delayed_tr);
- INIT_LIST_HEAD(&delayed_tr->list);
- delayed_tr->handle = handle;
- list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
- handle));
- } else
- _scsih_tm_tr_send(ioc, handle);
- }
-}
-
-
-/**
- * _scsih_check_volume_delete_events - set delete flag for volumes
- * @ioc: per adapter object
- * @event_data: the event data payload
- * Context: interrupt time.
- *
- * This will handle the case when the cable connected to entire volume is
- * pulled. We will take care of setting the deleted flag so normal IO will
- * not be sent.
- *
- * Return nothing.
- */
-static void
-_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrVolume_t *event_data)
-{
- u32 state;
-
- if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
- return;
- state = le32_to_cpu(event_data->NewValue);
- if (state == MPI2_RAID_VOL_STATE_MISSING || state ==
- MPI2_RAID_VOL_STATE_FAILED)
- _scsih_set_volume_delete_flag(ioc,
- le16_to_cpu(event_data->VolDevHandle));
-}
-
-/**
- * _scsih_temp_threshold_events - display temperature threshold exceeded events
- * @ioc: per adapter object
- * @event_data: the temp threshold event data
- * Context: interrupt time.
- *
- * Return nothing.
- */
-static void
-_scsih_temp_threshold_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataTemperature_t *event_data)
-{
- if (ioc->temp_sensors_count >= event_data->SensorNum) {
- printk(MPT2SAS_ERR_FMT "Temperature Threshold flags %s%s%s%s"
- " exceeded for Sensor: %d !!!\n", ioc->name,
- ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ",
- event_data->SensorNum);
- printk(MPT2SAS_ERR_FMT "Current Temp In Celsius: %d\n",
- ioc->name, event_data->CurrentTemperature);
- }
-}
-
-/**
- * _scsih_flush_running_cmds - completing outstanding commands.
- * @ioc: per adapter object
- *
- * The flushing out of all pending scmd commands following host reset,
- * where all IO is dropped to the floor.
- *
- * Return nothing.
- */
-static void
-_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
-{
- struct scsi_cmnd *scmd;
- u16 smid;
- u16 count = 0;
-
- for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
- scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
- if (!scmd)
- continue;
- count++;
- mpt2sas_base_free_smid(ioc, smid);
- scsi_dma_unmap(scmd);
- if (ioc->pci_error_recovery)
- scmd->result = DID_NO_CONNECT << 16;
- else
- scmd->result = DID_RESET << 16;
- scmd->scsi_done(scmd);
- }
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
- ioc->name, count));
-}
-
-/**
- * _scsih_setup_eedp - setup MPI request for EEDP transfer
- * @scmd: pointer to scsi command object
- * @mpi_request: pointer to the SCSI_IO reqest message frame
- *
- * Supporting protection 1 and 3.
- *
- * Returns nothing
- */
-static void
-_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
-{
- u16 eedp_flags;
- unsigned char prot_op = scsi_get_prot_op(scmd);
- unsigned char prot_type = scsi_get_prot_type(scmd);
-
- if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
- return;
-
- if (prot_op == SCSI_PROT_READ_STRIP)
- eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
- else if (prot_op == SCSI_PROT_WRITE_INSERT)
- eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
- else
- return;
-
- switch (prot_type) {
- case SCSI_PROT_DIF_TYPE1:
- case SCSI_PROT_DIF_TYPE2:
-
- /*
- * enable ref/guard checking
- * auto increment ref tag
- */
- eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
- MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
- MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
- mpi_request->CDB.EEDP32.PrimaryReferenceTag =
- cpu_to_be32(scsi_get_lba(scmd));
- break;
-
- case SCSI_PROT_DIF_TYPE3:
-
- /*
- * enable guard checking
- */
- eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
- break;
- }
- mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
- mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
-}
-
-/**
- * _scsih_eedp_error_handling - return sense code for EEDP errors
- * @scmd: pointer to scsi command object
- * @ioc_status: ioc status
- *
- * Returns nothing
- */
-static void
-_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
-{
- u8 ascq;
-
- switch (ioc_status) {
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- ascq = 0x01;
- break;
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- ascq = 0x02;
- break;
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- ascq = 0x03;
- break;
- default:
- ascq = 0x00;
- break;
- }
-
- scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10, ascq);
- scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) |
- SAM_STAT_CHECK_CONDITION;
-}
-
-/**
- * _scsih_scsi_direct_io_get - returns direct io flag
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns the smid stored scmd pointer.
- */
-static inline u8
-_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return ioc->scsi_lookup[smid - 1].direct_io;
-}
-
-/**
- * _scsih_scsi_direct_io_set - sets direct io flag
- * @ioc: per adapter object
- * @smid: system request message index
- * @direct_io: Zero or non-zero value to set in the direct_io flag
- *
- * Returns Nothing.
- */
-static inline void
-_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
-{
- ioc->scsi_lookup[smid - 1].direct_io = direct_io;
-}
-
-
-/**
- * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
- * @ioc: per adapter object
- * @scmd: pointer to scsi command object
- * @raid_device: pointer to raid device data structure
- * @mpi_request: pointer to the SCSI_IO reqest message frame
- * @smid: system request message index
- *
- * Returns nothing
- */
-static void
-_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
- struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
- u16 smid)
-{
- sector_t v_lba, p_lba, stripe_off, column, io_size;
- u32 stripe_sz, stripe_exp;
- u8 num_pds, cmd = scmd->cmnd[0];
-
- if (cmd != READ_10 && cmd != WRITE_10 &&
- cmd != READ_16 && cmd != WRITE_16)
- return;
-
- if (cmd == READ_10 || cmd == WRITE_10)
- v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]);
- else
- v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]);
-
- io_size = scsi_bufflen(scmd) >> raid_device->block_exponent;
-
- if (v_lba + io_size - 1 > raid_device->max_lba)
- return;
-
- stripe_sz = raid_device->stripe_sz;
- stripe_exp = raid_device->stripe_exponent;
- stripe_off = v_lba & (stripe_sz - 1);
-
- /* Return unless IO falls within a stripe */
- if (stripe_off + io_size > stripe_sz)
- return;
-
- num_pds = raid_device->num_pds;
- p_lba = v_lba >> stripe_exp;
- column = sector_div(p_lba, num_pds);
- p_lba = (p_lba << stripe_exp) + stripe_off;
-
- mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]);
-
- if (cmd == READ_10 || cmd == WRITE_10)
- put_unaligned_be32(lower_32_bits(p_lba),
- &mpi_request->CDB.CDB32[2]);
- else
- put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]);
-
- _scsih_scsi_direct_io_set(ioc, smid, 1);
-}
-
-/**
- * _scsih_qcmd - main scsi request entry point
- * @scmd: pointer to scsi command object
- * @done: function pointer to be invoked on completion
- *
- * The callback index is set inside `ioc->scsi_io_cb_idx`.
- *
- * Returns 0 on success. If there's a failure, return either:
- * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
- * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
- */
-static int
-_scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _raid_device *raid_device;
- Mpi2SCSIIORequest_t *mpi_request;
- u32 mpi_control;
- u16 smid;
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- if (ioc->pci_error_recovery || ioc->remove_host) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- sas_target_priv_data = sas_device_priv_data->sas_target;
- /* invalid device handle */
- if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- /* host recovery or link resets sent via IOCTLs */
- if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
- return SCSI_MLQUEUE_HOST_BUSY;
- /* device busy with task management */
- else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
- return SCSI_MLQUEUE_DEVICE_BUSY;
- /* device has been deleted */
- else if (sas_target_priv_data->deleted) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- if (scmd->sc_data_direction == DMA_FROM_DEVICE)
- mpi_control = MPI2_SCSIIO_CONTROL_READ;
- else if (scmd->sc_data_direction == DMA_TO_DEVICE)
- mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
- else
- mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
-
- /* set tags */
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
-
- /* Make sure Device is not raid volume.
- * We do not expose raid functionality to upper layer for warpdrive.
- */
- if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
- sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
- mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
-
- 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__);
- goto out;
- }
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
- _scsih_setup_eedp(scmd, mpi_request);
- if (scmd->cmd_len == 32)
- mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
- mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT)
- mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
- else
- mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
- mpi_request->DevHandle =
- cpu_to_le16(sas_device_priv_data->sas_target->handle);
- mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
- mpi_request->Control = cpu_to_le32(mpi_control);
- mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
- mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
- mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
- mpi_request->SenseBufferLowAddress =
- mpt2sas_base_get_sense_buffer_dma(ioc, smid);
- 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);
-
- if (!mpi_request->DataLength) {
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
- } else {
- if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- raid_device = sas_target_priv_data->raid_device;
- if (raid_device && raid_device->direct_io_enabled)
- _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request,
- smid);
-
- if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
- mpt2sas_base_put_smid_scsi_io(ioc, smid,
- le16_to_cpu(mpi_request->DevHandle));
- else
- mpt2sas_base_put_smid_default(ioc, smid);
- return 0;
-
- out:
- return SCSI_MLQUEUE_HOST_BUSY;
-}
-
-/**
- * _scsih_normalize_sense - normalize descriptor and fixed format sense data
- * @sense_buffer: sense data returned by target
- * @data: normalized skey/asc/ascq
- *
- * Return nothing.
- */
-static void
-_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
-{
- if ((sense_buffer[0] & 0x7F) >= 0x72) {
- /* descriptor format */
- data->skey = sense_buffer[1] & 0x0F;
- data->asc = sense_buffer[2];
- data->ascq = sense_buffer[3];
- } else {
- /* fixed format */
- data->skey = sense_buffer[2] & 0x0F;
- data->asc = sense_buffer[12];
- data->ascq = sense_buffer[13];
- }
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request
- * @ioc: per adapter object
- * @scmd: pointer to scsi command object
- * @mpi_reply: reply mf payload returned from firmware
- *
- * scsi_status - SCSI Status code returned from target device
- * scsi_state - state info associated with SCSI_IO determined by ioc
- * ioc_status - ioc supplied status info
- *
- * Return nothing.
- */
-static void
-_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
- Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
-{
- u32 response_info;
- u8 *response_bytes;
- u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- u8 scsi_state = mpi_reply->SCSIState;
- u8 scsi_status = mpi_reply->SCSIStatus;
- char *desc_ioc_state = NULL;
- char *desc_scsi_status = NULL;
- char *desc_scsi_state = ioc->tmp_string;
- u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
- struct _sas_device *sas_device = NULL;
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *priv_target = starget->hostdata;
- char *device_str = NULL;
-
- if (!priv_target)
- return;
-
- if (ioc->hide_ir_msg)
- device_str = "WarpDrive";
- else
- device_str = "volume";
-
- if (log_info == 0x31170000)
- return;
-
- switch (ioc_status) {
- case MPI2_IOCSTATUS_SUCCESS:
- desc_ioc_state = "success";
- break;
- case MPI2_IOCSTATUS_INVALID_FUNCTION:
- desc_ioc_state = "invalid function";
- break;
- case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
- desc_ioc_state = "scsi recovered error";
- break;
- case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
- desc_ioc_state = "scsi invalid dev handle";
- break;
- case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
- desc_ioc_state = "scsi device not there";
- break;
- case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
- desc_ioc_state = "scsi data overrun";
- break;
- case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
- desc_ioc_state = "scsi data underrun";
- break;
- case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
- desc_ioc_state = "scsi io data error";
- break;
- case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
- desc_ioc_state = "scsi protocol error";
- break;
- case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
- desc_ioc_state = "scsi task terminated";
- break;
- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
- desc_ioc_state = "scsi residual mismatch";
- break;
- case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
- desc_ioc_state = "scsi task mgmt failed";
- break;
- case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
- desc_ioc_state = "scsi ioc terminated";
- break;
- case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
- desc_ioc_state = "scsi ext terminated";
- break;
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- desc_ioc_state = "eedp guard error";
- break;
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- desc_ioc_state = "eedp ref tag error";
- break;
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- desc_ioc_state = "eedp app tag error";
- break;
- default:
- desc_ioc_state = "unknown";
- break;
- }
-
- switch (scsi_status) {
- case MPI2_SCSI_STATUS_GOOD:
- desc_scsi_status = "good";
- break;
- case MPI2_SCSI_STATUS_CHECK_CONDITION:
- desc_scsi_status = "check condition";
- break;
- case MPI2_SCSI_STATUS_CONDITION_MET:
- desc_scsi_status = "condition met";
- break;
- case MPI2_SCSI_STATUS_BUSY:
- desc_scsi_status = "busy";
- break;
- case MPI2_SCSI_STATUS_INTERMEDIATE:
- desc_scsi_status = "intermediate";
- break;
- case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
- desc_scsi_status = "intermediate condmet";
- break;
- case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
- desc_scsi_status = "reservation conflict";
- break;
- case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
- desc_scsi_status = "command terminated";
- break;
- case MPI2_SCSI_STATUS_TASK_SET_FULL:
- desc_scsi_status = "task set full";
- break;
- case MPI2_SCSI_STATUS_ACA_ACTIVE:
- desc_scsi_status = "aca active";
- break;
- case MPI2_SCSI_STATUS_TASK_ABORTED:
- desc_scsi_status = "task aborted";
- break;
- default:
- desc_scsi_status = "unknown";
- break;
- }
-
- desc_scsi_state[0] = '\0';
- if (!scsi_state)
- desc_scsi_state = " ";
- if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
- strcat(desc_scsi_state, "response info ");
- if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
- strcat(desc_scsi_state, "state terminated ");
- if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
- strcat(desc_scsi_state, "no status ");
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
- strcat(desc_scsi_state, "autosense failed ");
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
- strcat(desc_scsi_state, "autosense valid ");
-
- scsi_print_command(scmd);
-
- if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
- device_str, (unsigned long long)priv_target->sas_address);
- } else {
- sas_device = mpt2sas_get_sdev_from_target(ioc, priv_target);
- if (sas_device) {
- printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
- "phy(%d)\n", ioc->name, sas_device->sas_address,
- sas_device->phy);
- printk(MPT2SAS_WARN_FMT
- "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
- ioc->name, sas_device->enclosure_logical_id,
- sas_device->slot);
-
- sas_device_put(sas_device);
- }
- }
-
- printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), "
- "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle),
- desc_ioc_state, ioc_status, smid);
- printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
- "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
- scsi_get_resid(scmd));
- printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
- "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
- le32_to_cpu(mpi_reply->TransferCount), scmd->result);
- printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
- "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
- scsi_status, desc_scsi_state, scsi_state);
-
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
- struct sense_info data;
- _scsih_normalize_sense(scmd->sense_buffer, &data);
- printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
- "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
- data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
- }
-
- if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
- response_info = le32_to_cpu(mpi_reply->ResponseInfo);
- response_bytes = (u8 *)&response_info;
- _scsih_response_code(ioc, response_bytes[0]);
- }
-}
-#endif
-
-/**
- * _scsih_turn_on_pfa_led - illuminate PFA LED
- * @ioc: per adapter object
- * @handle: device handle
- * Context: process
- *
- * Return nothing.
- */
-static void
-_scsih_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- Mpi2SepReply_t mpi_reply;
- Mpi2SepRequest_t mpi_request;
- struct _sas_device *sas_device;
-
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (!sas_device)
- return;
-
- memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
- mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
- mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
- mpi_request.SlotStatus =
- cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
- mpi_request.DevHandle = cpu_to_le16(handle);
- mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
- if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
- &mpi_request)) != 0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- goto out;
- }
- sas_device->pfa_led_on = 1;
-
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
- goto out;
- }
-out:
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_turn_off_pfa_led - turn off PFA LED
- * @ioc: per adapter object
- * @sas_device: sas device whose PFA LED has to turned off
- * Context: process
- *
- * Return nothing.
- */
-static void
-_scsih_turn_off_pfa_led(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- Mpi2SepReply_t mpi_reply;
- Mpi2SepRequest_t mpi_request;
-
- memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
- mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
- mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
- mpi_request.SlotStatus = 0;
- mpi_request.Slot = cpu_to_le16(sas_device->slot);
- mpi_request.DevHandle = 0;
- mpi_request.EnclosureHandle = cpu_to_le16(sas_device->enclosure_handle);
- mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
- if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
- &mpi_request)) != 0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return;
- }
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: "
- "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name,
- le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
- return;
- }
-}
-
-/**
- * _scsih_send_event_to_turn_on_pfa_led - fire delayed event
- * @ioc: per adapter object
- * @handle: device handle
- * Context: interrupt.
- *
- * Return nothing.
- */
-static void
-_scsih_send_event_to_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct fw_event_work *fw_event;
-
- fw_event = alloc_fw_event_work(0);
- if (!fw_event)
- return;
- fw_event->event = MPT2SAS_TURN_ON_PFA_LED;
- fw_event->device_handle = handle;
- fw_event->ioc = ioc;
- _scsih_fw_event_add(ioc, fw_event);
- fw_event_work_put(fw_event);
-}
-
-/**
- * _scsih_smart_predicted_fault - process smart errors
- * @ioc: per adapter object
- * @handle: device handle
- * Context: interrupt.
- *
- * Return nothing.
- */
-static void
-_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct scsi_target *starget;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- Mpi2EventNotificationReply_t *event_reply;
- Mpi2EventDataSasDeviceStatusChange_t *event_data;
- struct _sas_device *sas_device;
- ssize_t sz;
- unsigned long flags;
-
- /* only handle non-raid devices */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (!sas_device) {
- goto out_unlock;
- }
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
-
- if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
- ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)))
- goto out_unlock;
-
- starget_printk(KERN_WARNING, starget, "predicted fault\n");
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
- _scsih_send_event_to_turn_on_pfa_led(ioc, handle);
-
- /* insert into event log */
- sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
- sizeof(Mpi2EventDataSasDeviceStatusChange_t);
- event_reply = kzalloc(sz, GFP_ATOMIC);
- if (!event_reply) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
- event_reply->Event =
- cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
- event_reply->MsgLength = sz/4;
- event_reply->EventDataLength =
- cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
- event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
- event_reply->EventData;
- event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
- event_data->ASC = 0x5D;
- event_data->DevHandle = cpu_to_le16(handle);
- event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
- mpt2sas_ctl_add_to_event_log(ioc, event_reply);
- kfree(event_reply);
-out:
- if (sas_device)
- sas_device_put(sas_device);
- return;
-
-out_unlock:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- goto out;
-}
-
-/**
- * _scsih_io_done - scsi request callback
- * @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)
- *
- * Callback handler when using _scsih_qcmd.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
-{
- Mpi2SCSIIORequest_t *mpi_request;
- Mpi2SCSIIOReply_t *mpi_reply;
- struct scsi_cmnd *scmd;
- u16 ioc_status;
- u32 xfer_cnt;
- u8 scsi_state;
- u8 scsi_status;
- u32 log_info;
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- u32 response_code = 0;
- unsigned long flags;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
- if (scmd == NULL)
- return 1;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
-
- if (mpi_reply == NULL) {
- scmd->result = DID_OK << 16;
- goto out;
- }
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
- sas_device_priv_data->sas_target->deleted) {
- scmd->result = DID_NO_CONNECT << 16;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
- /*
- * WARPDRIVE: If direct_io is set then it is directIO,
- * the failed direct I/O should be redirected to volume
- */
- if (_scsih_scsi_direct_io_get(ioc, smid) &&
- ((ioc_status & MPI2_IOCSTATUS_MASK)
- != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- ioc->scsi_lookup[smid - 1].scmd = scmd;
- _scsih_scsi_direct_io_set(ioc, smid, 0);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
- mpi_request->DevHandle =
- cpu_to_le16(sas_device_priv_data->sas_target->handle);
- mpt2sas_base_put_smid_scsi_io(ioc, smid,
- sas_device_priv_data->sas_target->handle);
- return 0;
- }
-
-
- /* turning off TLR */
- scsi_state = mpi_reply->SCSIState;
- if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
- response_code =
- le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
- if (!sas_device_priv_data->tlr_snoop_check) {
- sas_device_priv_data->tlr_snoop_check++;
- /* Make sure Device is not raid volume.
- * We do not expose raid functionality to upper layer for warpdrive.
- */
- if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
- sas_is_tlr_enabled(scmd->device) &&
- response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
- sas_disable_tlr(scmd->device);
- sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
- }
- }
-
- xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
- scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
- if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
- log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
- else
- log_info = 0;
- ioc_status &= MPI2_IOCSTATUS_MASK;
- scsi_status = mpi_reply->SCSIStatus;
-
- if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
- (scsi_status == MPI2_SCSI_STATUS_BUSY ||
- scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
- scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
- ioc_status = MPI2_IOCSTATUS_SUCCESS;
- }
-
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
- struct sense_info data;
- const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
- smid);
- u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
- le32_to_cpu(mpi_reply->SenseCount));
- memcpy(scmd->sense_buffer, sense_data, sz);
- _scsih_normalize_sense(scmd->sense_buffer, &data);
- /* failure prediction threshold exceeded */
- if (data.asc == 0x5D)
- _scsih_smart_predicted_fault(ioc,
- le16_to_cpu(mpi_reply->DevHandle));
- }
-
- switch (ioc_status) {
- case MPI2_IOCSTATUS_BUSY:
- case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
- scmd->result = SAM_STAT_BUSY;
- break;
-
- case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
- scmd->result = DID_NO_CONNECT << 16;
- break;
-
- case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
- if (sas_device_priv_data->block) {
- scmd->result = DID_TRANSPORT_DISRUPTED << 16;
- goto out;
- }
- if (log_info == 0x32010081) {
- scmd->result = DID_RESET << 16;
- break;
- }
- scmd->result = DID_SOFT_ERROR << 16;
- break;
- case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
- case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
- scmd->result = DID_RESET << 16;
- break;
-
- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
- if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
- scmd->result = DID_SOFT_ERROR << 16;
- else
- scmd->result = (DID_OK << 16) | scsi_status;
- break;
-
- case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
- scmd->result = (DID_OK << 16) | scsi_status;
-
- if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
- break;
-
- if (xfer_cnt < scmd->underflow) {
- if (scsi_status == SAM_STAT_BUSY)
- scmd->result = SAM_STAT_BUSY;
- else
- scmd->result = DID_SOFT_ERROR << 16;
- } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
- MPI2_SCSI_STATE_NO_SCSI_STATUS))
- scmd->result = DID_SOFT_ERROR << 16;
- else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
- scmd->result = DID_RESET << 16;
- else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
- mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
- mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
- scmd->sense_buffer[0] = 0x70;
- scmd->sense_buffer[2] = ILLEGAL_REQUEST;
- scmd->sense_buffer[12] = 0x20;
- scmd->sense_buffer[13] = 0;
- }
- break;
-
- case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
- scsi_set_resid(scmd, 0);
- case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
- case MPI2_IOCSTATUS_SUCCESS:
- scmd->result = (DID_OK << 16) | scsi_status;
- if (response_code ==
- MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
- (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
- MPI2_SCSI_STATE_NO_SCSI_STATUS)))
- scmd->result = DID_SOFT_ERROR << 16;
- else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
- scmd->result = DID_RESET << 16;
- break;
-
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- _scsih_eedp_error_handling(scmd, ioc_status);
- break;
- case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
- case MPI2_IOCSTATUS_INVALID_FUNCTION:
- case MPI2_IOCSTATUS_INVALID_SGL:
- case MPI2_IOCSTATUS_INTERNAL_ERROR:
- case MPI2_IOCSTATUS_INVALID_FIELD:
- case MPI2_IOCSTATUS_INVALID_STATE:
- case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
- case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
- default:
- scmd->result = DID_SOFT_ERROR << 16;
- break;
-
- }
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
- _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
-#endif
-
- out:
- scsi_dma_unmap(scmd);
- scmd->scsi_done(scmd);
- return 1;
-}
-
-/**
- * _scsih_sas_host_refresh - refreshing sas host object contents
- * @ioc: per adapter object
- * Context: user
- *
- * During port enable, fw will send topology events for every device. Its
- * possible that the handles may change from the previous setting, so this
- * code keeping handles updating if changed.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
-{
- u16 sz;
- u16 ioc_status;
- int i;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
- u16 attached_handle;
- u8 link_rate;
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
- "updating handles for sas_host(0x%016llx)\n",
- ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
-
- sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
- * sizeof(Mpi2SasIOUnit0PhyData_t));
- sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz)) != 0)
- goto out;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- goto out;
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4;
- if (i == 0)
- ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
- PhyData[0].ControllerDevHandle);
- ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
- attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
- AttachedDevHandle);
- if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
- link_rate = MPI2_SAS_NEG_LINK_RATE_1_5;
- mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
- attached_handle, i, link_rate);
- }
- out:
- kfree(sas_iounit_pg0);
-}
-
-/**
- * _scsih_sas_host_add - create sas host object
- * @ioc: per adapter object
- *
- * Creating host side data object, stored in ioc->sas_hba
- *
- * Return nothing.
- */
-static void
-_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
-{
- int i;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2SasPhyPage0_t phy_pg0;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2SasEnclosurePage0_t enclosure_pg0;
- u16 ioc_status;
- u16 sz;
- u16 device_missing_delay;
-
- mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
- if (!ioc->sas_hba.num_phys) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- /* sas_iounit page 0 */
- sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit0PhyData_t));
- sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
- if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- /* sas_iounit page 1 */
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- ioc->io_missing_delay =
- le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
- device_missing_delay =
- le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
- if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
- ioc->device_missing_delay = (device_missing_delay &
- MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
- else
- ioc->device_missing_delay = device_missing_delay &
- MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
-
- ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
- ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
- sizeof(struct _sas_phy), GFP_KERNEL);
- if (!ioc->sas_hba.phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
- i))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- if (i == 0)
- ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
- PhyData[0].ControllerDevHandle);
- ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
- ioc->sas_hba.phy[i].phy_id = i;
- mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
- phy_pg0, ioc->sas_hba.parent_dev);
- }
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc->sas_hba.enclosure_handle =
- le16_to_cpu(sas_device_pg0.EnclosureHandle);
- ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
- "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
- (unsigned long long) ioc->sas_hba.sas_address,
- ioc->sas_hba.num_phys) ;
-
- if (ioc->sas_hba.enclosure_handle) {
- if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
- &enclosure_pg0,
- MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
- ioc->sas_hba.enclosure_handle))) {
- ioc->sas_hba.enclosure_logical_id =
- le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
- }
- }
-
- out:
- kfree(sas_iounit_pg1);
- kfree(sas_iounit_pg0);
-}
-
-/**
- * _scsih_expander_add - creating expander object
- * @ioc: per adapter object
- * @handle: expander handle
- *
- * Creating expander object, stored in ioc->sas_expander_list.
- *
- * Return 0 for success, else error.
- */
-static int
-_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_node *sas_expander;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2ExpanderPage0_t expander_pg0;
- Mpi2ExpanderPage1_t expander_pg1;
- Mpi2SasEnclosurePage0_t enclosure_pg0;
- u32 ioc_status;
- u16 parent_handle;
- u64 sas_address, sas_address_parent = 0;
- int i;
- unsigned long flags;
- struct _sas_port *mpt2sas_port = NULL;
- int rc = 0;
-
- if (!handle)
- return -1;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery)
- return -1;
-
- if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
- MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- /* handle out of order topology events */
- parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
- if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
- != 0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- if (sas_address_parent != ioc->sas_hba.sas_address) {
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
- sas_address_parent);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!sas_expander) {
- rc = _scsih_expander_add(ioc, parent_handle);
- if (rc != 0)
- return rc;
- }
- }
-
- 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);
-
- if (sas_expander)
- return 0;
-
- sas_expander = kzalloc(sizeof(struct _sas_node),
- GFP_KERNEL);
- if (!sas_expander) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- sas_expander->handle = handle;
- sas_expander->num_phys = expander_pg0.NumPhys;
- sas_expander->sas_address_parent = sas_address_parent;
- sas_expander->sas_address = sas_address;
-
- printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
- " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
- handle, parent_handle, (unsigned long long)
- sas_expander->sas_address, sas_expander->num_phys);
-
- if (!sas_expander->num_phys)
- goto out_fail;
- sas_expander->phy = kcalloc(sas_expander->num_phys,
- sizeof(struct _sas_phy), GFP_KERNEL);
- if (!sas_expander->phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
-
- INIT_LIST_HEAD(&sas_expander->sas_port_list);
- mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
- sas_address_parent);
- if (!mpt2sas_port) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
- sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
-
- for (i = 0 ; i < sas_expander->num_phys ; i++) {
- if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
- &expander_pg1, i, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
- sas_expander->phy[i].handle = handle;
- sas_expander->phy[i].phy_id = i;
-
- if ((mpt2sas_transport_add_expander_phy(ioc,
- &sas_expander->phy[i], expander_pg1,
- sas_expander->parent_dev))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
- }
-
- if (sas_expander->enclosure_handle) {
- if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
- &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
- sas_expander->enclosure_handle))) {
- sas_expander->enclosure_logical_id =
- le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
- }
- }
-
- _scsih_expander_node_add(ioc, sas_expander);
- return 0;
-
- out_fail:
-
- if (mpt2sas_port)
- mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_address_parent);
- kfree(sas_expander);
- return rc;
-}
-
-/**
- * _scsih_done - scsih callback handler.
- * @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)
- *
- * Callback handler when sending internal generated message frames.
- * The callback index passed is `ioc->scsih_cb_idx`
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_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->scsih_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
- if (ioc->scsih_cmds.smid != smid)
- return 1;
- ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- memcpy(ioc->scsih_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
- }
- ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->scsih_cmds.done);
- return 1;
-}
-
-/**
- * mpt2sas_expander_remove - removing expander object
- * @ioc: per adapter object
- * @sas_address: expander sas_address
- *
- * Return nothing.
- */
-void
-mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
-{
- struct _sas_node *sas_expander;
- unsigned long flags;
-
- if (ioc->shost_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
- sas_address);
- if (sas_expander)
- list_del(&sas_expander->list);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (sas_expander)
- _scsih_expander_node_remove(ioc, sas_expander);
-}
-
-/**
- * _scsih_check_access_status - check access flags
- * @ioc: per adapter object
- * @sas_address: sas address
- * @handle: sas device handle
- * @access_flags: errors returned during discovery of the device
- *
- * Return 0 for success, else failure
- */
-static u8
-_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 handle, u8 access_status)
-{
- u8 rc = 1;
- char *desc = NULL;
-
- switch (access_status) {
- case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
- rc = 0;
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
- desc = "sata capability failed";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
- desc = "sata affiliation conflict";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
- desc = "route not addressable";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
- desc = "smp error not addressable";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
- desc = "device blocked";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
- desc = "sata initialization failed";
- break;
- default:
- desc = "unknown";
- break;
- }
-
- if (!rc)
- return 0;
-
- printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
- "handle(0x%04x)\n", ioc->name, desc,
- (unsigned long long)sas_address, handle);
- return rc;
-}
-
-static void
-_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- struct _sas_device *sas_device;
- u32 ioc_status;
- unsigned long flags;
- u64 sas_address;
- struct scsi_target *starget;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- u32 device_info;
-
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
- return;
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- return;
-
- /* check if this is end device */
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
- if (!(_scsih_is_end_device(device_info)))
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
-
- if (!sas_device) {
- printk(MPT2SAS_ERR_FMT "device is not present "
- "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
- goto out_unlock;
- }
-
- if (unlikely(sas_device->handle != handle)) {
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
- starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
- " to (0x%04x)!!!\n", sas_device->handle, handle);
- sas_target_priv_data->handle = handle;
- sas_device->handle = handle;
- }
-
- /* check if device is present */
- if (!(le16_to_cpu(sas_device_pg0.Flags) &
- MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
- printk(MPT2SAS_ERR_FMT "device is not present "
- "handle(0x%04x), flags!!!\n", ioc->name, handle);
- goto out_unlock;
- }
-
- /* check if there were any issues with discovery */
- if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus))
- goto out_unlock;
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- _scsih_ublock_io_device(ioc, sas_address);
- if (sas_device)
- sas_device_put(sas_device);
- return;
-
-out_unlock:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_add_device - creating sas device object
- * @ioc: per adapter object
- * @handle: sas device handle
- * @phy_num: phy number end device attached to
- * @is_pd: is this hidden raid component
- *
- * Creating end device object, stored in ioc->sas_device_list.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2SasEnclosurePage0_t enclosure_pg0;
- struct _sas_device *sas_device;
- u32 ioc_status;
- __le64 sas_address;
- u32 device_info;
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
-
- /* check if device is present */
- if (!(le16_to_cpu(sas_device_pg0.Flags) &
- MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
- ioc->name, le16_to_cpu(sas_device_pg0.Flags));
- return -1;
- }
-
- /* check if there were any issues with discovery */
- if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus))
- return -1;
-
- /* check if this is end device */
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
- if (!(_scsih_is_end_device(device_info))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- sas_device = mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
-
- if (sas_device) {
- sas_device_put(sas_device);
- return 0;
- }
-
- sas_device = kzalloc(sizeof(struct _sas_device),
- GFP_KERNEL);
- if (!sas_device) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- kref_init(&sas_device->refcount);
- sas_device->handle = handle;
- if (_scsih_get_sas_address(ioc, le16_to_cpu
- (sas_device_pg0.ParentDevHandle),
- &sas_device->sas_address_parent) != 0)
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- sas_device->enclosure_handle =
- le16_to_cpu(sas_device_pg0.EnclosureHandle);
- sas_device->slot =
- le16_to_cpu(sas_device_pg0.Slot);
- sas_device->device_info = device_info;
- sas_device->sas_address = sas_address;
- sas_device->phy = sas_device_pg0.PhyNum;
-
- /* get enclosure_logical_id */
- if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
- ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
- sas_device->enclosure_handle)))
- sas_device->enclosure_logical_id =
- le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
-
- /* get device name */
- sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
-
- if (ioc->wait_for_discovery_to_complete)
- _scsih_sas_device_init_add(ioc, sas_device);
- else
- _scsih_sas_device_add(ioc, sas_device);
-
- sas_device_put(sas_device);
- return 0;
-}
-
-/**
- * _scsih_remove_device - removing sas device object
- * @ioc: per adapter object
- * @sas_device_delete: the sas_device object
- *
- * Return nothing.
- */
-static void
-_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
-
- if ((ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) &&
- (sas_device->pfa_led_on)) {
- _scsih_turn_off_pfa_led(ioc, sas_device);
- sas_device->pfa_led_on = 0;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
- "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)
- sas_device->sas_address));
-
- if (sas_device->starget && sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- _scsih_ublock_io_device(ioc, sas_device->sas_address);
- sas_target_priv_data->handle =
- MPT2SAS_INVALID_DEVICE_HANDLE;
- }
-
- if (!ioc->hide_drives)
- mpt2sas_transport_port_remove(ioc,
- sas_device->sas_address,
- sas_device->sas_address_parent);
-
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
- "(0x%016llx)\n", ioc->name, sas_device->handle,
- (unsigned long long) sas_device->sas_address);
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
- "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)
- sas_device->sas_address));
-}
-/**
- * _scsih_device_remove_by_handle - removing device object by handle
- * @ioc: per adapter object
- * @handle: device handle
- *
- * Return nothing.
- */
-static void
-_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- if (ioc->shost_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_device) {
- _scsih_remove_device(ioc, sas_device);
- sas_device_put(sas_device);
- }
-}
-
-/**
- * mpt2sas_device_remove_by_sas_address - removing device object by sas address
- * @ioc: per adapter object
- * @sas_address: device sas_address
- *
- * Return nothing.
- */
-void
-mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- if (ioc->shost_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address);
- if (sas_device) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_device) {
- _scsih_remove_device(ioc, sas_device);
- sas_device_put(sas_device);
- }
-}
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_topology_change_event_debug - debug for topology event
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- */
-static void
-_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasTopologyChangeList_t *event_data)
-{
- int i;
- u16 handle;
- u16 reason_code;
- u8 phy_number;
- char *status_str = NULL;
- u8 link_rate, prev_link_rate;
-
- switch (event_data->ExpStatus) {
- case MPI2_EVENT_SAS_TOPO_ES_ADDED:
- status_str = "add";
- break;
- case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
- status_str = "remove";
- break;
- case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
- case 0:
- status_str = "responding";
- break;
- case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
- status_str = "remove delay";
- break;
- default:
- status_str = "unknown status";
- break;
- }
- printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
- ioc->name, status_str);
- printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) "
- "start_phy(%02d), count(%d)\n",
- le16_to_cpu(event_data->ExpanderDevHandle),
- le16_to_cpu(event_data->EnclosureHandle),
- event_data->StartPhyNum, event_data->NumEntries);
- for (i = 0; i < event_data->NumEntries; i++) {
- 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;
- switch (reason_code) {
- case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
- status_str = "target add";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- status_str = "target remove";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
- status_str = "delay target remove";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
- status_str = "link rate change";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
- status_str = "target responding";
- break;
- default:
- status_str = "unknown";
- break;
- }
- link_rate = event_data->PHY[i].LinkRate >> 4;
- prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
- printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:"
- " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
- handle, status_str, link_rate, prev_link_rate);
-
- }
-}
-#endif
-
-/**
- * _scsih_sas_topology_change_event - handle topology changes
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- */
-static void
-_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- int i;
- u16 parent_handle, handle;
- u16 reason_code;
- u8 phy_number, max_phys;
- struct _sas_node *sas_expander;
- u64 sas_address;
- unsigned long flags;
- u8 link_rate, prev_link_rate;
- Mpi2EventDataSasTopologyChangeList_t *event_data =
- (Mpi2EventDataSasTopologyChangeList_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_topology_change_event_debug(ioc, event_data);
-#endif
-
- if (ioc->remove_host || ioc->pci_error_recovery)
- return;
-
- if (!ioc->sas_hba.num_phys)
- _scsih_sas_host_add(ioc);
- else
- _scsih_sas_host_refresh(ioc);
-
- if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
- "event\n", ioc->name));
- return;
- }
-
- parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
-
- /* handle expander add */
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
- if (_scsih_expander_add(ioc, parent_handle) != 0)
- return;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
- parent_handle);
- if (sas_expander) {
- sas_address = sas_expander->sas_address;
- max_phys = sas_expander->num_phys;
- } else if (parent_handle < ioc->sas_hba.num_phys) {
- sas_address = ioc->sas_hba.sas_address;
- max_phys = ioc->sas_hba.num_phys;
- } else {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* handle siblings events */
- for (i = 0; i < event_data->NumEntries; i++) {
- if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
- "expander event\n", ioc->name));
- return;
- }
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery)
- return;
- phy_number = event_data->StartPhyNum + i;
- if (phy_number >= max_phys)
- continue;
- 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;
- link_rate = event_data->PHY[i].LinkRate >> 4;
- prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
- switch (reason_code) {
- case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
-
- if (ioc->shost_recovery)
- break;
-
- if (link_rate == prev_link_rate)
- break;
-
- mpt2sas_transport_update_links(ioc, sas_address,
- handle, phy_number, link_rate);
-
- if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
- break;
-
- _scsih_check_device(ioc, handle);
- break;
- case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
-
- if (ioc->shost_recovery)
- break;
-
- mpt2sas_transport_update_links(ioc, sas_address,
- handle, phy_number, link_rate);
-
- _scsih_add_device(ioc, handle, phy_number, 0);
- break;
- case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
-
- _scsih_device_remove_by_handle(ioc, handle);
- break;
- }
- }
-
- /* handle expander removal */
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
- sas_expander)
- mpt2sas_expander_remove(ioc, sas_address);
-
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_device_status_change_event_debug - debug for device event
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasDeviceStatusChange_t *event_data)
-{
- char *reason_str = NULL;
-
- switch (event_data->ReasonCode) {
- case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
- reason_str = "smart data";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
- reason_str = "unsupported device discovered";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
- reason_str = "internal device reset";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
- reason_str = "internal task abort";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
- reason_str = "internal task abort set";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
- reason_str = "internal clear task set";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
- reason_str = "internal query task";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
- reason_str = "sata init failure";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
- reason_str = "internal device reset complete";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
- reason_str = "internal task abort complete";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
- reason_str = "internal async notification";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
- reason_str = "expander reduced functionality";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
- reason_str = "expander reduced functionality complete";
- break;
- default:
- reason_str = "unknown reason";
- break;
- }
- printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
- "\thandle(0x%04x), sas address(0x%016llx), tag(%d)",
- ioc->name, reason_str, le16_to_cpu(event_data->DevHandle),
- (unsigned long long)le64_to_cpu(event_data->SASAddress),
- le16_to_cpu(event_data->TaskTag));
- if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
- printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
- event_data->ASC, event_data->ASCQ);
- printk(KERN_INFO "\n");
-}
-#endif
-
-/**
- * _scsih_sas_device_status_change_event - handle device status change
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- struct MPT2SAS_TARGET *target_priv_data;
- struct _sas_device *sas_device;
- u64 sas_address;
- unsigned long flags;
- Mpi2EventDataSasDeviceStatusChange_t *event_data =
- (Mpi2EventDataSasDeviceStatusChange_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_device_status_change_event_debug(ioc,
- event_data);
-#endif
-
- /* In MPI Revision K (0xC), the internal device reset complete was
- * implemented, so avoid setting tm_busy flag for older firmware.
- */
- if ((ioc->facts.HeaderVersion >> 8) < 0xC)
- return;
-
- if (event_data->ReasonCode !=
- MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
- event_data->ReasonCode !=
- MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_address = le64_to_cpu(event_data->SASAddress);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
-
- if (!sas_device || !sas_device->starget)
- goto out;
-
- target_priv_data = sas_device->starget->hostdata;
- if (!target_priv_data)
- goto out;
-
- if (event_data->ReasonCode ==
- MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
- target_priv_data->tm_busy = 1;
- else
- target_priv_data->tm_busy = 0;
-
-out:
- if (sas_device)
- sas_device_put(sas_device);
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasEnclDevStatusChange_t *event_data)
-{
- char *reason_str = NULL;
-
- switch (event_data->ReasonCode) {
- case MPI2_EVENT_SAS_ENCL_RC_ADDED:
- reason_str = "enclosure add";
- break;
- case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
- reason_str = "enclosure remove";
- break;
- default:
- reason_str = "unknown reason";
- break;
- }
-
- printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n"
- "\thandle(0x%04x), enclosure logical id(0x%016llx)"
- " number slots(%d)\n", ioc->name, reason_str,
- le16_to_cpu(event_data->EnclosureHandle),
- (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
- le16_to_cpu(event_data->StartSlot));
-}
-#endif
-
-/**
- * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_enclosure_dev_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_enclosure_dev_status_change_event_debug(ioc,
- (Mpi2EventDataSasEnclDevStatusChange_t *)
- fw_event->event_data);
-#endif
-}
-
-/**
- * _scsih_sas_broadcast_primitive_event - handle broadcast events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- struct scsi_cmnd *scmd;
- struct scsi_device *sdev;
- u16 smid, handle;
- u32 lun;
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- u32 termination_count;
- u32 query_count;
- Mpi2SCSITaskManagementReply_t *mpi_reply;
- Mpi2EventDataSasBroadcastPrimitive_t *event_data =
- (Mpi2EventDataSasBroadcastPrimitive_t *)
- fw_event->event_data;
- u16 ioc_status;
- unsigned long flags;
- int r;
- u8 max_retries = 0;
- u8 task_abort_retries;
-
- mutex_lock(&ioc->tm_cmds.mutex);
- pr_info(MPT2SAS_FMT
- "%s: enter: phy number(%d), width(%d)\n",
- ioc->name, __func__, event_data->PhyNum,
- event_data->PortWidth);
-
- _scsih_block_io_all_device(ioc);
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- mpi_reply = ioc->tm_cmds.reply;
-broadcast_aen_retry:
-
- /* sanity checks for retrying this loop */
- if (max_retries++ == 5) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n",
- ioc->name, __func__));
- goto out;
- } else if (max_retries > 1)
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n",
- ioc->name, __func__, max_retries - 1));
-
- termination_count = 0;
- query_count = 0;
- for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
- if (ioc->shost_recovery)
- goto out;
- scmd = _scsih_scsi_lookup_get(ioc, smid);
- if (!scmd)
- continue;
- sdev = scmd->device;
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
- continue;
- /* skip hidden raid components */
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT)
- continue;
- /* skip volumes */
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_VOLUME)
- continue;
-
- handle = sas_device_priv_data->sas_target->handle;
- lun = sas_device_priv_data->lun;
- query_count++;
-
- if (ioc->shost_recovery)
- goto out;
-
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
- MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30,
- TM_MUTEX_OFF);
- if (r == FAILED) {
- sdev_printk(KERN_WARNING, sdev,
- "mpt2sas_scsih_issue_tm: FAILED when sending "
- "QUERY_TASK: scmd(%p)\n", scmd);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- goto broadcast_aen_retry;
- }
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
- & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- sdev_printk(KERN_WARNING, sdev, "query task: FAILED "
- "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status,
- scmd);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- goto broadcast_aen_retry;
- }
-
- /* see if IO is still owned by IOC and target */
- if (mpi_reply->ResponseCode ==
- MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
- mpi_reply->ResponseCode ==
- MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) {
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- continue;
- }
- task_abort_retries = 0;
- tm_retry:
- if (task_abort_retries++ == 60) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: ABORT_TASK: giving up\n", ioc->name,
- __func__));
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- goto broadcast_aen_retry;
- }
-
- if (ioc->shost_recovery)
- goto out_no_lock;
-
- r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
- sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
- TM_MUTEX_OFF);
- if (r == FAILED) {
- sdev_printk(KERN_WARNING, sdev,
- "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : "
- "scmd(%p)\n", scmd);
- goto tm_retry;
- }
-
- if (task_abort_retries > 1)
- sdev_printk(KERN_WARNING, sdev,
- "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):"
- " scmd(%p)\n",
- task_abort_retries - 1, scmd);
-
- termination_count += le32_to_cpu(mpi_reply->TerminationCount);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- }
-
- if (ioc->broadcast_aen_pending) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to"
- " pending AEN\n", ioc->name, __func__));
- ioc->broadcast_aen_pending = 0;
- goto broadcast_aen_retry;
- }
-
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- out_no_lock:
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s - exit, query_count = %d termination_count = %d\n",
- ioc->name, __func__, query_count, termination_count));
-
- ioc->broadcast_aen_busy = 0;
- if (!ioc->shost_recovery)
- _scsih_ublock_io_all_device(ioc);
- mutex_unlock(&ioc->tm_cmds.mutex);
-}
-
-/**
- * _scsih_sas_discovery_event - handle discovery events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- Mpi2EventDataSasDiscovery_t *event_data =
- (Mpi2EventDataSasDiscovery_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
- printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
- (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
- "start" : "stop");
- if (event_data->DiscoveryStatus)
- printk("discovery_status(0x%08x)",
- le32_to_cpu(event_data->DiscoveryStatus));
- printk("\n");
- }
-#endif
-
- if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
- !ioc->sas_hba.num_phys) {
- if (disable_discovery > 0 && ioc->shost_recovery) {
- /* Wait for the reset to complete */
- while (ioc->shost_recovery)
- ssleep(1);
- }
- _scsih_sas_host_add(ioc);
- }
-}
-
-/**
- * _scsih_reprobe_lun - reprobing lun
- * @sdev: scsi device struct
- * @no_uld_attach: sdev->no_uld_attach flag setting
- *
- **/
-static void
-_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
-{
- int rc;
-
- sdev->no_uld_attach = no_uld_attach ? 1 : 0;
- sdev_printk(KERN_INFO, sdev, "%s raid component\n",
- sdev->no_uld_attach ? "hidding" : "exposing");
- rc = scsi_device_reprobe(sdev);
-}
-
-/**
- * _scsih_sas_volume_add - add new volume
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _raid_device *raid_device;
- unsigned long flags;
- u64 wwid;
- u16 handle = le16_to_cpu(element->VolDevHandle);
- int rc;
-
- mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
- if (!wwid) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return;
- }
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (raid_device)
- return;
-
- raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
- if (!raid_device) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return;
- }
-
- raid_device->id = ioc->sas_id++;
- raid_device->channel = RAID_CHANNEL;
- raid_device->handle = handle;
- raid_device->wwid = wwid;
- _scsih_raid_device_add(ioc, raid_device);
- if (!ioc->wait_for_discovery_to_complete) {
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- } else {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- _scsih_determine_boot_device(ioc, raid_device, 1);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
-}
-
-/**
- * _scsih_sas_volume_delete - delete volume
- * @ioc: per adapter object
- * @handle: volume device handle
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _raid_device *raid_device;
- unsigned long flags;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct scsi_target *starget = NULL;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device) {
- if (raid_device->starget) {
- starget = raid_device->starget;
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->deleted = 1;
- }
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
- "(0x%016llx)\n", ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
- list_del(&raid_device->list);
- kfree(raid_device);
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (starget)
- scsi_remove_target(&starget->dev);
-}
-
-/**
- * _scsih_sas_pd_expose - expose pd component to /dev/sdX
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _sas_device *sas_device;
- struct scsi_target *starget = NULL;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- unsigned long flags;
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device->volume_handle = 0;
- sas_device->volume_wwid = 0;
- clear_bit(handle, ioc->pd_handles);
- if (sas_device->starget && sas_device->starget->hostdata) {
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->flags &=
- ~MPT_TARGET_FLAGS_RAID_COMPONENT;
- }
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- return;
-
- /* exposing raid component */
- if (starget)
- starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
-
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_sas_pd_hide - hide pd component from /dev/sdX
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _sas_device *sas_device;
- struct scsi_target *starget = NULL;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- unsigned long flags;
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
- u16 volume_handle = 0;
- u64 volume_wwid = 0;
-
- mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle);
- if (volume_handle)
- mpt2sas_config_get_volume_wwid(ioc, volume_handle,
- &volume_wwid);
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- set_bit(handle, ioc->pd_handles);
- if (sas_device->starget && sas_device->starget->hostdata) {
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->flags |=
- MPT_TARGET_FLAGS_RAID_COMPONENT;
- sas_device->volume_handle = volume_handle;
- sas_device->volume_wwid = volume_wwid;
- }
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- return;
-
- /* hiding raid component */
- if (starget)
- starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
-
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_sas_pd_delete - delete pd component
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
-
- _scsih_device_remove_by_handle(ioc, handle);
-}
-
-/**
- * _scsih_sas_pd_add - remove pd component
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _sas_device *sas_device;
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- u32 ioc_status;
- u64 sas_address;
- u16 parent_handle;
-
- set_bit(handle, ioc->pd_handles);
-
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device_put(sas_device);
- return;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
- mpt2sas_transport_update_links(ioc, sas_address, handle,
- sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
-
- _scsih_add_device(ioc, handle, 0, 1);
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrConfigChangeList_t *event_data)
-{
- Mpi2EventIrConfigElement_t *element;
- u8 element_type;
- int i;
- char *reason_str = NULL, *element_str = NULL;
-
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
-
- printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n",
- ioc->name, (le32_to_cpu(event_data->Flags) &
- MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
- "foreign" : "native", event_data->NumElements);
- for (i = 0; i < event_data->NumElements; i++, element++) {
- switch (element->ReasonCode) {
- case MPI2_EVENT_IR_CHANGE_RC_ADDED:
- reason_str = "add";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
- reason_str = "remove";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
- reason_str = "no change";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_HIDE:
- reason_str = "hide";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
- reason_str = "unhide";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
- reason_str = "volume_created";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
- reason_str = "volume_deleted";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
- reason_str = "pd_created";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
- reason_str = "pd_deleted";
- break;
- default:
- reason_str = "unknown reason";
- break;
- }
- element_type = le16_to_cpu(element->ElementFlags) &
- MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
- switch (element_type) {
- case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
- element_str = "volume";
- break;
- case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
- element_str = "phys disk";
- break;
- case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
- element_str = "hot spare";
- break;
- default:
- element_str = "unknown element";
- break;
- }
- printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), "
- "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
- reason_str, le16_to_cpu(element->VolDevHandle),
- le16_to_cpu(element->PhysDiskDevHandle),
- element->PhysDiskNum);
- }
-}
-#endif
-
-/**
- * _scsih_sas_ir_config_change_event - handle ir configuration change events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_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 =
- (Mpi2EventDataIrConfigChangeList_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- && !ioc->hide_ir_msg)
- _scsih_sas_ir_config_change_event_debug(ioc, event_data);
-
-#endif
-
- if (ioc->shost_recovery)
- return;
-
- foreign_config = (le32_to_cpu(event_data->Flags) &
- MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
-
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
-
- switch (element->ReasonCode) {
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
- case MPI2_EVENT_IR_CHANGE_RC_ADDED:
- if (!foreign_config)
- _scsih_sas_volume_add(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
- case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
- if (!foreign_config)
- _scsih_sas_volume_delete(ioc,
- le16_to_cpu(element->VolDevHandle));
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_hide(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_expose(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_HIDE:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_add(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_delete(ioc, element);
- break;
- }
- }
-}
-
-/**
- * _scsih_sas_ir_volume_event - IR volume event
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- u64 wwid;
- unsigned long flags;
- struct _raid_device *raid_device;
- u16 handle;
- u32 state;
- int rc;
- Mpi2EventDataIrVolume_t *event_data =
- (Mpi2EventDataIrVolume_t *)
- fw_event->event_data;
-
- if (ioc->shost_recovery)
- return;
-
- if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
- return;
-
- handle = le16_to_cpu(event_data->VolDevHandle);
- state = le32_to_cpu(event_data->NewValue);
- if (!ioc->hide_ir_msg)
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
- "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
-
- switch (state) {
- case MPI2_RAID_VOL_STATE_MISSING:
- case MPI2_RAID_VOL_STATE_FAILED:
- _scsih_sas_volume_delete(ioc, handle);
- break;
-
- case MPI2_RAID_VOL_STATE_ONLINE:
- case MPI2_RAID_VOL_STATE_DEGRADED:
- case MPI2_RAID_VOL_STATE_OPTIMAL:
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (raid_device)
- break;
-
- mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
- if (!wwid) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- break;
- }
-
- raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
- if (!raid_device) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- break;
- }
-
- raid_device->id = ioc->sas_id++;
- raid_device->channel = RAID_CHANNEL;
- raid_device->handle = handle;
- raid_device->wwid = wwid;
- _scsih_raid_device_add(ioc, raid_device);
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- break;
-
- case MPI2_RAID_VOL_STATE_INITIALIZING:
- default:
- break;
- }
-}
-
-/**
- * _scsih_sas_ir_physical_disk_event - PD event
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- u16 handle, parent_handle;
- u32 state;
- struct _sas_device *sas_device;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- u32 ioc_status;
- Mpi2EventDataIrPhysicalDisk_t *event_data =
- (Mpi2EventDataIrPhysicalDisk_t *)
- fw_event->event_data;
- u64 sas_address;
-
- if (ioc->shost_recovery)
- return;
-
- if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
- return;
-
- handle = le16_to_cpu(event_data->PhysDiskDevHandle);
- state = le32_to_cpu(event_data->NewValue);
-
- if (!ioc->hide_ir_msg)
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
- "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
-
- switch (state) {
- case MPI2_RAID_PD_STATE_ONLINE:
- case MPI2_RAID_PD_STATE_DEGRADED:
- case MPI2_RAID_PD_STATE_REBUILDING:
- case MPI2_RAID_PD_STATE_OPTIMAL:
- case MPI2_RAID_PD_STATE_HOT_SPARE:
-
- if (!ioc->is_warpdrive)
- set_bit(handle, ioc->pd_handles);
-
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device_put(sas_device);
- return;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
- handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
- mpt2sas_transport_update_links(ioc, sas_address, handle,
- sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
-
- _scsih_add_device(ioc, handle, 0, 1);
-
- break;
-
- case MPI2_RAID_PD_STATE_OFFLINE:
- case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
- case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
- default:
- break;
- }
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrOperationStatus_t *event_data)
-{
- char *reason_str = NULL;
-
- switch (event_data->RAIDOperation) {
- case MPI2_EVENT_IR_RAIDOP_RESYNC:
- reason_str = "resync";
- break;
- case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
- reason_str = "online capacity expansion";
- break;
- case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
- reason_str = "consistency check";
- break;
- case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
- reason_str = "background init";
- break;
- case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
- reason_str = "make data consistent";
- break;
- }
-
- if (!reason_str)
- return;
-
- printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
- "\thandle(0x%04x), percent complete(%d)\n",
- ioc->name, reason_str,
- le16_to_cpu(event_data->VolDevHandle),
- event_data->PercentComplete);
-}
-#endif
-
-/**
- * _scsih_sas_ir_operation_status_event - handle RAID operation events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- Mpi2EventDataIrOperationStatus_t *event_data =
- (Mpi2EventDataIrOperationStatus_t *)
- fw_event->event_data;
- static struct _raid_device *raid_device;
- unsigned long flags;
- u16 handle;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- && !ioc->hide_ir_msg)
- _scsih_sas_ir_operation_status_event_debug(ioc,
- event_data);
-#endif
-
- /* code added for raid transport support */
- if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- handle = le16_to_cpu(event_data->VolDevHandle);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device)
- raid_device->percent_complete =
- event_data->PercentComplete;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
-}
-
-/**
- * _scsih_prep_device_scan - initialize parameters prior to device scan
- * @ioc: per adapter object
- *
- * Set the deleted flag prior to device scan. If the device is found during
- * the scan, then we clear the deleted flag.
- */
-static void
-_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (sas_device_priv_data && sas_device_priv_data->sas_target)
- sas_device_priv_data->sas_target->deleted = 1;
- }
-}
-
-/**
- * _scsih_mark_responding_sas_device - mark a sas_devices as responding
- * @ioc: per adapter object
- * @sas_address: sas address
- * @slot: enclosure slot id
- * @handle: device handle
- *
- * After host reset, find out whether devices are still responding.
- * Used in _scsi_remove_unresponsive_sas_devices.
- *
- * Return nothing.
- */
-static void
-_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 slot, u16 handle)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
- struct scsi_target *starget;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
- if (sas_device->sas_address == sas_address &&
- sas_device->slot == slot) {
- sas_device->responding = 1;
- starget = sas_device->starget;
- if (starget && starget->hostdata) {
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->tm_busy = 0;
- sas_target_priv_data->deleted = 0;
- } else
- sas_target_priv_data = NULL;
- if (starget)
- starget_printk(KERN_INFO, starget,
- "handle(0x%04x), sas_addr(0x%016llx), "
- "enclosure logical id(0x%016llx), "
- "slot(%d)\n", handle,
- (unsigned long long)sas_device->sas_address,
- (unsigned long long)
- sas_device->enclosure_logical_id,
- sas_device->slot);
- if (sas_device->handle == handle)
- goto out;
- printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
- sas_device->handle);
- sas_device->handle = handle;
- if (sas_target_priv_data)
- sas_target_priv_data->handle = handle;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-/**
- * _scsih_search_responding_sas_devices -
- * @ioc: per adapter object
- *
- * After host reset, find out whether devices are still responding.
- * If not remove.
- *
- * Return nothing.
- */
-static void
-_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- __le64 sas_address;
- u16 handle;
- u32 device_info;
- u16 slot;
-
- printk(MPT2SAS_INFO_FMT "search for end-devices: start\n", ioc->name);
-
- if (list_empty(&ioc->sas_device_list))
- goto out;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
- handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
- handle = le16_to_cpu(sas_device_pg0.DevHandle);
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
- if (!(_scsih_is_end_device(device_info)))
- continue;
- sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- slot = le16_to_cpu(sas_device_pg0.Slot);
- _scsih_mark_responding_sas_device(ioc, sas_address, slot,
- handle);
- }
-out:
- printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n",
- ioc->name);
-}
-
-/**
- * _scsih_mark_responding_raid_device - mark a raid_device as responding
- * @ioc: per adapter object
- * @wwid: world wide identifier for raid volume
- * @handle: device handle
- *
- * After host reset, find out whether devices are still responding.
- * Used in _scsi_remove_unresponsive_raid_devices.
- *
- * Return nothing.
- */
-static void
-_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
- u16 handle)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct scsi_target *starget;
- struct _raid_device *raid_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->wwid == wwid && raid_device->starget) {
- starget = raid_device->starget;
- if (starget && starget->hostdata) {
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->deleted = 0;
- } else
- sas_target_priv_data = NULL;
- raid_device->responding = 1;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- starget_printk(KERN_INFO, raid_device->starget,
- "handle(0x%04x), wwid(0x%016llx)\n", handle,
- (unsigned long long)raid_device->wwid);
- /*
- * WARPDRIVE: The handles of the PDs might have changed
- * across the host reset so re-initialize the
- * required data for Direct IO
- */
- _scsih_init_warpdrive_properties(ioc, raid_device);
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- if (raid_device->handle == handle) {
- spin_unlock_irqrestore(&ioc->raid_device_lock,
- flags);
- return;
- }
- printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
- raid_device->handle);
- raid_device->handle = handle;
- if (sas_target_priv_data)
- sas_target_priv_data->handle = handle;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- return;
- }
- }
-
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * _scsih_search_responding_raid_devices -
- * @ioc: per adapter object
- *
- * After host reset, find out whether devices are still responding.
- * If not remove.
- *
- * Return nothing.
- */
-static void
-_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidVolPage1_t volume_pg1;
- Mpi2RaidVolPage0_t volume_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u16 handle;
- u8 phys_disk_num;
-
- if (!ioc->ir_firmware)
- return;
-
- printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n",
- ioc->name);
-
- if (list_empty(&ioc->raid_device_list))
- goto out;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
- handle = le16_to_cpu(volume_pg1.DevHandle);
-
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
- &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t)))
- continue;
-
- if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED)
- _scsih_mark_responding_raid_device(ioc,
- le64_to_cpu(volume_pg1.WWID), handle);
- }
-
- /* refresh the pd_handles */
- if (!ioc->is_warpdrive) {
- phys_disk_num = 0xFF;
- memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
- while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
- phys_disk_num))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
- phys_disk_num = pd_pg0.PhysDiskNum;
- handle = le16_to_cpu(pd_pg0.DevHandle);
- set_bit(handle, ioc->pd_handles);
- }
- }
-out:
- printk(MPT2SAS_INFO_FMT "search for responding raid volumes: "
- "complete\n", ioc->name);
-}
-
-/**
- * _scsih_mark_responding_expander - mark a expander as responding
- * @ioc: per adapter object
- * @sas_address: sas address
- * @handle:
- *
- * After host reset, find out whether devices are still responding.
- * Used in _scsi_remove_unresponsive_expanders.
- *
- * Return nothing.
- */
-static void
-_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 handle)
-{
- struct _sas_node *sas_expander;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->sas_address != sas_address)
- continue;
- sas_expander->responding = 1;
- if (sas_expander->handle == handle)
- goto out;
- printk(KERN_INFO "\texpander(0x%016llx): handle changed"
- " from(0x%04x) to (0x%04x)!!!\n",
- (unsigned long long)sas_expander->sas_address,
- sas_expander->handle, handle);
- sas_expander->handle = handle;
- for (i = 0 ; i < sas_expander->num_phys ; i++)
- sas_expander->phy[i].handle = handle;
- goto out;
- }
- out:
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-}
-
-/**
- * _scsih_search_responding_expanders -
- * @ioc: per adapter object
- *
- * After host reset, find out whether devices are still responding.
- * If not remove.
- *
- * Return nothing.
- */
-static void
-_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2ExpanderPage0_t expander_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u64 sas_address;
- u16 handle;
-
- printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name);
-
- if (list_empty(&ioc->sas_expander_list))
- goto out;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
- MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
-
- handle = le16_to_cpu(expander_pg0.DevHandle);
- sas_address = le64_to_cpu(expander_pg0.SASAddress);
- printk(KERN_INFO "\texpander present: handle(0x%04x), "
- "sas_addr(0x%016llx)\n", handle,
- (unsigned long long)sas_address);
- _scsih_mark_responding_expander(ioc, sas_address, handle);
- }
-
- out:
- printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name);
-}
-
-/**
- * _scsih_remove_unresponding_sas_devices - removing unresponding devices
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _sas_device *sas_device, *sas_device_next;
- struct _sas_node *sas_expander, *sas_expander_next;
- struct _raid_device *raid_device, *raid_device_next;
- struct list_head tmp_list;
- unsigned long flags;
- LIST_HEAD(head);
-
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n",
- ioc->name);
-
- /* removing unresponding end devices */
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n",
- ioc->name);
-
- /*
- * Iterate, pulling off devices marked as non-responding. We become the
- * owner for the reference the list had on any object we prune.
- */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_for_each_entry_safe(sas_device, sas_device_next,
- &ioc->sas_device_list, list) {
- if (!sas_device->responding)
- list_move_tail(&sas_device->list, &head);
- else
- sas_device->responding = 0;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- /*
- * Now, uninitialize and remove the unresponding devices we pruned.
- */
- list_for_each_entry_safe(sas_device, sas_device_next, &head, list) {
- _scsih_remove_device(ioc, sas_device);
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
-
- /* removing unresponding volumes */
- if (ioc->ir_firmware) {
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: "
- "volumes\n", ioc->name);
- list_for_each_entry_safe(raid_device, raid_device_next,
- &ioc->raid_device_list, list) {
- if (!raid_device->responding)
- _scsih_sas_volume_delete(ioc,
- raid_device->handle);
- else
- raid_device->responding = 0;
- }
- }
- /* removing unresponding expanders */
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n",
- ioc->name);
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- INIT_LIST_HEAD(&tmp_list);
- list_for_each_entry_safe(sas_expander, sas_expander_next,
- &ioc->sas_expander_list, list) {
- if (!sas_expander->responding)
- list_move_tail(&sas_expander->list, &tmp_list);
- else
- sas_expander->responding = 0;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list,
- list) {
- list_del(&sas_expander->list);
- _scsih_expander_node_remove(ioc, sas_expander);
- }
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n",
- ioc->name);
- /* unblock devices */
- _scsih_ublock_io_all_device(ioc);
-}
-
-static void
-_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander, u16 handle)
-{
- Mpi2ExpanderPage1_t expander_pg1;
- Mpi2ConfigReply_t mpi_reply;
- int i;
-
- for (i = 0 ; i < sas_expander->num_phys ; i++) {
- if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
- &expander_pg1, i, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- mpt2sas_transport_update_links(ioc, sas_expander->sas_address,
- le16_to_cpu(expander_pg1.AttachedDevHandle), i,
- expander_pg1.NegotiatedLinkRate >> 4);
- }
-}
-
-/**
- * _scsih_scan_for_devices_after_reset - scan for devices after host reset
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2ExpanderPage0_t expander_pg0;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2RaidVolPage1_t volume_pg1;
- Mpi2RaidVolPage0_t volume_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2EventIrConfigElement_t element;
- Mpi2ConfigReply_t mpi_reply;
- u8 phys_disk_num;
- u16 ioc_status;
- u16 handle, parent_handle;
- u64 sas_address;
- struct _sas_device *sas_device;
- struct _sas_node *expander_device;
- static struct _raid_device *raid_device;
- u8 retry_count;
- unsigned long flags;
-
- printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name);
-
- _scsih_sas_host_refresh(ioc);
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: expanders start\n",
- ioc->name);
- /* expanders */
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
- MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- handle = le16_to_cpu(expander_pg0.DevHandle);
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- expander_device = mpt2sas_scsih_expander_find_by_sas_address(
- ioc, le64_to_cpu(expander_pg0.SASAddress));
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (expander_device)
- _scsih_refresh_expander_links(ioc, expander_device,
- handle);
- else {
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding expander: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(expander_pg0.SASAddress));
- _scsih_expander_add(ioc, handle);
- printk(MPT2SAS_INFO_FMT "\tAFTER adding expander: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(expander_pg0.SASAddress));
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: expanders complete\n",
- ioc->name);
-
- if (!ioc->ir_firmware)
- goto skip_to_sas;
-
- printk(MPT2SAS_INFO_FMT "\tscan devices phys disk start\n", ioc->name);
- /* phys disk */
- phys_disk_num = 0xFF;
- while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
- phys_disk_num))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:"
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- phys_disk_num = pd_pg0.PhysDiskNum;
- handle = le16_to_cpu(pd_pg0.DevHandle);
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device_put(sas_device);
- continue;
- }
- if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
- handle) != 0)
- continue;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle,
- &sas_address)) {
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding phys disk: "
- " handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- mpt2sas_transport_update_links(ioc, sas_address,
- handle, sas_device_pg0.PhyNum,
- MPI2_SAS_NEG_LINK_RATE_1_5);
- set_bit(handle, ioc->pd_handles);
- retry_count = 0;
- /* This will retry adding the end device.
- * _scsih_add_device() will decide on retries and
- * return "1" when it should be retried
- */
- while (_scsih_add_device(ioc, handle, retry_count++,
- 1)) {
- ssleep(1);
- }
- printk(MPT2SAS_INFO_FMT "\tAFTER adding phys disk: "
- " handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: phys disk complete\n",
- ioc->name);
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: volumes start\n", ioc->name);
- /* volumes */
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- handle = le16_to_cpu(volume_pg1.DevHandle);
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_wwid(ioc,
- le64_to_cpu(volume_pg1.WWID));
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (raid_device)
- continue;
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
- &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t)))
- continue;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) {
- memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t));
- element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED;
- element.VolDevHandle = volume_pg1.DevHandle;
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding volume: "
- " handle (0x%04x)\n", ioc->name,
- volume_pg1.DevHandle);
- _scsih_sas_volume_add(ioc, &element);
- printk(MPT2SAS_INFO_FMT "\tAFTER adding volume: "
- " handle (0x%04x)\n", ioc->name,
- volume_pg1.DevHandle);
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: volumes complete\n",
- ioc->name);
-
- skip_to_sas:
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: end devices start\n",
- ioc->name);
- /* sas devices */
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
- handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:"
- " ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- handle = le16_to_cpu(sas_device_pg0.DevHandle);
- if (!(_scsih_is_end_device(
- le32_to_cpu(sas_device_pg0.DeviceInfo))))
- continue;
- sas_device = mpt2sas_get_sdev_by_addr(ioc,
- le64_to_cpu(sas_device_pg0.SASAddress));
- if (sas_device) {
- sas_device_put(sas_device);
- continue;
- }
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding end device: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- mpt2sas_transport_update_links(ioc, sas_address, handle,
- sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
- retry_count = 0;
- /* This will retry adding the end device.
- * _scsih_add_device() will decide on retries and
- * return "1" when it should be retried
- */
- while (_scsih_add_device(ioc, handle, retry_count++,
- 0)) {
- ssleep(1);
- }
- printk(MPT2SAS_INFO_FMT "\tAFTER adding end device: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: end devices complete\n",
- ioc->name);
-
- printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name);
-}
-
-
-/**
- * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
- * @ioc: per adapter object
- * @reset_phase: phase
- *
- * The handler for doing any required cleanup or initialization.
- *
- * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
- * MPT2_IOC_DONE_RESET
- *
- * Return nothing.
- */
-void
-mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
-{
- switch (reset_phase) {
- case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
- break;
- case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
- if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
- ioc->scsih_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
- complete(&ioc->scsih_cmds.done);
- }
- if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
- ioc->tm_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
- complete(&ioc->tm_cmds.done);
- }
- _scsih_fw_event_cleanup_queue(ioc);
- _scsih_flush_running_cmds(ioc);
- break;
- case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
- _scsih_sas_host_refresh(ioc);
- _scsih_prep_device_scan(ioc);
- _scsih_search_responding_sas_devices(ioc);
- _scsih_search_responding_raid_devices(ioc);
- _scsih_search_responding_expanders(ioc);
- if ((!ioc->is_driver_loading) && !(disable_discovery > 0 &&
- !ioc->sas_hba.num_phys)) {
- _scsih_prep_device_scan(ioc);
- _scsih_search_responding_sas_devices(ioc);
- _scsih_search_responding_raid_devices(ioc);
- _scsih_search_responding_expanders(ioc);
- _scsih_error_recovery_delete_devices(ioc);
- }
- break;
- }
-}
-
-/**
- * _firmware_event_work - delayed task for processing firmware events
- * @ioc: per adapter object
- * @work: equal to the fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_firmware_event_work(struct work_struct *work)
-{
- struct fw_event_work *fw_event = container_of(work,
- struct fw_event_work, delayed_work.work);
- struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
-
- _scsih_fw_event_del_from_list(ioc, fw_event);
-
- /* the queue is being flushed so ignore this event */
- if (ioc->remove_host || ioc->pci_error_recovery) {
- fw_event_work_put(fw_event);
- return;
- }
-
- switch (fw_event->event) {
- case MPT2SAS_REMOVE_UNRESPONDING_DEVICES:
- while (scsi_host_in_recovery(ioc->shost) ||
- ioc->shost_recovery) {
- /*
- * If we're unloading, bail. Otherwise, this can become
- * an infinite loop.
- */
- if (ioc->remove_host)
- goto out;
-
- ssleep(1);
- }
- _scsih_remove_unresponding_sas_devices(ioc);
- _scsih_scan_for_devices_after_reset(ioc);
- break;
- case MPT2SAS_PORT_ENABLE_COMPLETE:
- ioc->start_scan = 0;
-
- if (missing_delay[0] != -1 && missing_delay[1] != -1)
- mpt2sas_base_update_missing_delay(ioc, missing_delay[0],
- missing_delay[1]);
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete "
- "from worker thread\n", ioc->name));
- break;
- case MPT2SAS_TURN_ON_PFA_LED:
- _scsih_turn_on_pfa_led(ioc, fw_event->device_handle);
- break;
- case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- _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);
- break;
- case MPI2_EVENT_SAS_DISCOVERY:
- _scsih_sas_discovery_event(ioc,
- fw_event);
- break;
- case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- _scsih_sas_broadcast_primitive_event(ioc,
- fw_event);
- break;
- case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- _scsih_sas_enclosure_dev_status_change_event(ioc,
- fw_event);
- break;
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- _scsih_sas_ir_config_change_event(ioc, fw_event);
- break;
- case MPI2_EVENT_IR_VOLUME:
- _scsih_sas_ir_volume_event(ioc, fw_event);
- break;
- case MPI2_EVENT_IR_PHYSICAL_DISK:
- _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);
- break;
- }
-out:
- fw_event_work_put(fw_event);
-}
-
-/**
- * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
- * @ioc: per adapter object
- * @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.
- *
- * Returns void.
- */
-void
-mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
- u32 reply)
-{
- struct fw_event_work *fw_event;
- Mpi2EventNotificationReply_t *mpi_reply;
- u16 event;
- u16 sz;
-
- /* events turned off due to host reset or driver unloading */
- if (ioc->remove_host || ioc->pci_error_recovery)
- return;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
-
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- event = le16_to_cpu(mpi_reply->Event);
-
- switch (event) {
- /* handle these */
- case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- {
- Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
- (Mpi2EventDataSasBroadcastPrimitive_t *)
- mpi_reply->EventData;
-
- if (baen_data->Primitive !=
- MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
- return;
-
- if (ioc->broadcast_aen_busy) {
- ioc->broadcast_aen_pending++;
- return;
- } else
- ioc->broadcast_aen_busy = 1;
- break;
- }
-
- case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- _scsih_check_topo_delete_events(ioc,
- (Mpi2EventDataSasTopologyChangeList_t *)
- mpi_reply->EventData);
- break;
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- _scsih_check_ir_config_unhide_events(ioc,
- (Mpi2EventDataIrConfigChangeList_t *)
- mpi_reply->EventData);
- break;
- case MPI2_EVENT_IR_VOLUME:
- _scsih_check_volume_delete_events(ioc,
- (Mpi2EventDataIrVolume_t *)
- mpi_reply->EventData);
- break;
- case MPI2_EVENT_LOG_ENTRY_ADDED:
- {
- Mpi2EventDataLogEntryAdded_t *log_entry;
- __le32 *log_code;
-
- if (!ioc->is_warpdrive)
- break;
-
- log_entry = (Mpi2EventDataLogEntryAdded_t *)
- mpi_reply->EventData;
- log_code = (__le32 *)log_entry->LogData;
-
- if (le16_to_cpu(log_entry->LogEntryQualifier)
- != MPT2_WARPDRIVE_LOGENTRY)
- break;
-
- switch (le32_to_cpu(*log_code)) {
- case MPT2_WARPDRIVE_LC_SSDT:
- printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
- "IO Throttling has occurred in the WarpDrive "
- "subsystem. Check WarpDrive documentation for "
- "additional details.\n", ioc->name);
- break;
- case MPT2_WARPDRIVE_LC_SSDLW:
- printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
- "Program/Erase Cycles for the WarpDrive subsystem "
- "in degraded range. Check WarpDrive documentation "
- "for additional details.\n", ioc->name);
- break;
- case MPT2_WARPDRIVE_LC_SSDLF:
- printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
- "There are no Program/Erase Cycles for the "
- "WarpDrive subsystem. The storage device will be "
- "in read-only mode. Check WarpDrive documentation "
- "for additional details.\n", ioc->name);
- break;
- case MPT2_WARPDRIVE_LC_BRMF:
- printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
- "The Backup Rail Monitor has failed on the "
- "WarpDrive subsystem. Check WarpDrive "
- "documentation for additional details.\n",
- ioc->name);
- break;
- }
-
- break;
- }
- case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
- case MPI2_EVENT_IR_OPERATION_STATUS:
- case MPI2_EVENT_SAS_DISCOVERY:
- case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- case MPI2_EVENT_IR_PHYSICAL_DISK:
- break;
-
- case MPI2_EVENT_TEMP_THRESHOLD:
- _scsih_temp_threshold_events(ioc,
- (Mpi2EventDataTemperature_t *)
- mpi_reply->EventData);
- break;
-
- default: /* ignore the rest */
- return;
- }
-
- sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
- fw_event = alloc_fw_event_work(sz);
- if (!fw_event) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- memcpy(fw_event->event_data, mpi_reply->EventData, sz);
- fw_event->ioc = ioc;
- 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);
- fw_event_work_put(fw_event);
- return;
-}
-
-/* shost template */
-static struct scsi_host_template scsih_driver_template = {
- .module = THIS_MODULE,
- .name = "Fusion MPT SAS Host",
- .proc_name = MPT2SAS_DRIVER_NAME,
- .queuecommand = _scsih_qcmd,
- .target_alloc = _scsih_target_alloc,
- .slave_alloc = _scsih_slave_alloc,
- .slave_configure = _scsih_slave_configure,
- .target_destroy = _scsih_target_destroy,
- .slave_destroy = _scsih_slave_destroy,
- .scan_finished = _scsih_scan_finished,
- .scan_start = _scsih_scan_start,
- .change_queue_depth = _scsih_change_queue_depth,
- .eh_abort_handler = _scsih_abort,
- .eh_device_reset_handler = _scsih_dev_reset,
- .eh_target_reset_handler = _scsih_target_reset,
- .eh_host_reset_handler = _scsih_host_reset,
- .bios_param = _scsih_bios_param,
- .can_queue = 1,
- .this_id = -1,
- .sg_tablesize = MPT2SAS_SG_DEPTH,
- .max_sectors = 32767,
- .cmd_per_lun = 7,
- .use_clustering = ENABLE_CLUSTERING,
- .shost_attrs = mpt2sas_host_attrs,
- .sdev_attrs = mpt2sas_dev_attrs,
- .track_queue_depth = 1,
-};
-
-/**
- * _scsih_expander_node_remove - removing expander device from list.
- * @ioc: per adapter object
- * @sas_expander: the sas_device object
- * Context: Calling function should acquire ioc->sas_node_lock.
- *
- * Removing object and freeing associated memory from the
- * ioc->sas_expander_list.
- *
- * Return nothing.
- */
-static void
-_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander)
-{
- struct _sas_port *mpt2sas_port, *next;
-
- /* remove sibling ports attached to this expander */
- list_for_each_entry_safe(mpt2sas_port, next,
- &sas_expander->sas_port_list, port_list) {
- if (ioc->shost_recovery)
- return;
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE)
- mpt2sas_device_remove_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- else if (mpt2sas_port->remote_identify.device_type ==
- SAS_EDGE_EXPANDER_DEVICE ||
- mpt2sas_port->remote_identify.device_type ==
- SAS_FANOUT_EXPANDER_DEVICE)
- mpt2sas_expander_remove(ioc,
- mpt2sas_port->remote_identify.sas_address);
- }
-
- mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_expander->sas_address_parent);
-
- printk(MPT2SAS_INFO_FMT "expander_remove: handle"
- "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
- sas_expander->handle, (unsigned long long)
- sas_expander->sas_address);
-
- kfree(sas_expander->phy);
- kfree(sas_expander);
-}
-
-/**
- * _scsih_ir_shutdown - IR shutdown notification
- * @ioc: per adapter object
- *
- * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
- * the host system is shutting down.
- *
- * Return nothing.
- */
-static void
-_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidActionRequest_t *mpi_request;
- Mpi2RaidActionReply_t *mpi_reply;
- u16 smid;
-
- /* is IR firmware build loaded ? */
- if (!ioc->ir_firmware)
- return;
-
- mutex_lock(&ioc->scsih_cmds.mutex);
-
- if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
- ioc->name, __func__);
- goto out;
- }
- ioc->scsih_cmds.status = MPT2_CMD_PENDING;
-
- smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
- goto out;
- }
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->scsih_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
-
- mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
- mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
-
- if (!ioc->hide_ir_msg)
- printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
- init_completion(&ioc->scsih_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
-
- if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- goto out;
- }
-
- if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
- mpi_reply = ioc->scsih_cmds.reply;
-
- if (!ioc->hide_ir_msg)
- printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
- }
-
- out:
- ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->scsih_cmds.mutex);
-}
-
-/**
- * _scsih_shutdown - routine call during system shutdown
- * @pdev: PCI device struct
- *
- * Return nothing.
- */
-static void
-_scsih_shutdown(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct workqueue_struct *wq;
- unsigned long flags;
-
- ioc->remove_host = 1;
- _scsih_fw_event_cleanup_queue(ioc);
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- wq = ioc->firmware_event_thread;
- ioc->firmware_event_thread = NULL;
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- if (wq)
- destroy_workqueue(wq);
-
- _scsih_ir_shutdown(ioc);
- mpt2sas_base_detach(ioc);
-}
-
-/**
- * _scsih_remove - detach and remove add host
- * @pdev: PCI device struct
- *
- * Routine called when unloading the driver.
- * Return nothing.
- */
-static void
-_scsih_remove(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct _sas_port *mpt2sas_port, *next_port;
- struct _raid_device *raid_device, *next;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct workqueue_struct *wq;
- unsigned long flags;
-
- ioc->remove_host = 1;
- _scsih_fw_event_cleanup_queue(ioc);
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- wq = ioc->firmware_event_thread;
- ioc->firmware_event_thread = NULL;
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- if (wq)
- destroy_workqueue(wq);
-
- /* release all the volumes */
- _scsih_ir_shutdown(ioc);
- list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
- list) {
- if (raid_device->starget) {
- sas_target_priv_data =
- raid_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- scsi_remove_target(&raid_device->starget->dev);
- }
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
- "(0x%016llx)\n", ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
- _scsih_raid_device_remove(ioc, raid_device);
- }
-
- /* free ports attached to the sas_host */
- list_for_each_entry_safe(mpt2sas_port, next_port,
- &ioc->sas_hba.sas_port_list, port_list) {
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE)
- mpt2sas_device_remove_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- else if (mpt2sas_port->remote_identify.device_type ==
- SAS_EDGE_EXPANDER_DEVICE ||
- mpt2sas_port->remote_identify.device_type ==
- SAS_FANOUT_EXPANDER_DEVICE)
- mpt2sas_expander_remove(ioc,
- mpt2sas_port->remote_identify.sas_address);
- }
-
- /* free phys attached to the sas_host */
- if (ioc->sas_hba.num_phys) {
- kfree(ioc->sas_hba.phy);
- ioc->sas_hba.phy = NULL;
- ioc->sas_hba.num_phys = 0;
- }
-
- sas_remove_host(shost);
- scsi_remove_host(shost);
- mpt2sas_base_detach(ioc);
- spin_lock(&gioc_lock);
- list_del(&ioc->list);
- spin_unlock(&gioc_lock);
- scsi_host_put(shost);
-}
-
-/**
- * _scsih_probe_boot_devices - reports 1st device
- * @ioc: per adapter object
- *
- * If specified in bios page 2, this routine reports the 1st
- * device scsi-ml or sas transport for persistent boot device
- * purposes. Please refer to function _scsih_determine_boot_device()
- */
-static void
-_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- u8 is_raid;
- void *device;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- u16 handle;
- u64 sas_address_parent;
- u64 sas_address;
- unsigned long flags;
- int rc;
-
- /* no Bios, return immediately */
- if (!ioc->bios_pg3.BiosVersion)
- return;
-
- device = NULL;
- is_raid = 0;
- if (ioc->req_boot_device.device) {
- device = ioc->req_boot_device.device;
- is_raid = ioc->req_boot_device.is_raid;
- } else if (ioc->req_alt_boot_device.device) {
- device = ioc->req_alt_boot_device.device;
- is_raid = ioc->req_alt_boot_device.is_raid;
- } else if (ioc->current_boot_device.device) {
- device = ioc->current_boot_device.device;
- is_raid = ioc->current_boot_device.is_raid;
- }
-
- if (!device)
- return;
-
- if (is_raid) {
- raid_device = device;
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- } else {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = device;
- handle = sas_device->handle;
- sas_address_parent = sas_device->sas_address_parent;
- sas_address = sas_device->sas_address;
- list_move_tail(&sas_device->list, &ioc->sas_device_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (ioc->hide_drives)
- return;
- if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->sas_address_parent)) {
- _scsih_sas_device_remove(ioc, sas_device);
- } else if (!sas_device->starget) {
- if (!ioc->is_driver_loading) {
- mpt2sas_transport_port_remove(ioc,
- sas_address,
- sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
- }
- }
- }
-}
-
-/**
- * _scsih_probe_raid - reporting raid volumes to scsi-ml
- * @ioc: per adapter object
- *
- * Called during initial loading of the driver.
- */
-static void
-_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _raid_device *raid_device, *raid_next;
- int rc;
-
- list_for_each_entry_safe(raid_device, raid_next,
- &ioc->raid_device_list, list) {
- if (raid_device->starget)
- continue;
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- }
-}
-
-static struct _sas_device *get_next_sas_device(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _sas_device *sas_device = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- if (!list_empty(&ioc->sas_device_init_list)) {
- sas_device = list_first_entry(&ioc->sas_device_init_list,
- struct _sas_device, list);
- sas_device_get(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return sas_device;
-}
-
-static void sas_device_make_active(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
-
- /*
- * Since we dropped the lock during the call to port_add(), we need to
- * be careful here that somebody else didn't move or delete this item
- * while we were busy with other things.
- *
- * If it was on the list, we need a put() for the reference the list
- * had. Either way, we need a get() for the destination list.
- */
- if (!list_empty(&sas_device->list)) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
-
- sas_device_get(sas_device);
- list_add_tail(&sas_device->list, &ioc->sas_device_list);
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-/**
- * _scsih_probe_sas - reporting sas devices to sas transport
- * @ioc: per adapter object
- *
- * Called during initial loading of the driver.
- */
-static void
-_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _sas_device *sas_device;
-
- if (ioc->hide_drives)
- return;
-
- while ((sas_device = get_next_sas_device(ioc))) {
- if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->sas_address_parent)) {
- _scsih_sas_device_remove(ioc, sas_device);
- sas_device_put(sas_device);
- continue;
- } else if (!sas_device->starget) {
- if (!ioc->is_driver_loading) {
- mpt2sas_transport_port_remove(ioc,
- sas_device->sas_address,
- sas_device->sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
- sas_device_put(sas_device);
- continue;
- }
- }
-
- sas_device_make_active(ioc, sas_device);
- sas_device_put(sas_device);
- }
-}
-
-/**
- * _scsih_probe_devices - probing for devices
- * @ioc: per adapter object
- *
- * Called during initial loading of the driver.
- */
-static void
-_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- u16 volume_mapping_flags;
-
- if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
- return; /* return when IOC doesn't support initiator mode */
-
- _scsih_probe_boot_devices(ioc);
-
- if (ioc->ir_firmware) {
- volume_mapping_flags =
- le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
- MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
- if (volume_mapping_flags ==
- MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
- _scsih_probe_raid(ioc);
- _scsih_probe_sas(ioc);
- } else {
- _scsih_probe_sas(ioc);
- _scsih_probe_raid(ioc);
- }
- } else
- _scsih_probe_sas(ioc);
-}
-
-
-/**
- * _scsih_scan_start - scsi lld callback for .scan_start
- * @shost: SCSI host pointer
- *
- * The shost has the ability to discover targets on its own instead
- * of scanning the entire bus. In our implemention, we will kick off
- * firmware discovery.
- */
-static void
-_scsih_scan_start(struct Scsi_Host *shost)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int rc;
-
- if (diag_buffer_enable != -1 && diag_buffer_enable != 0)
- mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
-
- if (disable_discovery > 0)
- return;
-
- ioc->start_scan = 1;
- rc = mpt2sas_port_enable(ioc);
-
- if (rc != 0)
- printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name);
-}
-
-/**
- * _scsih_scan_finished - scsi lld callback for .scan_finished
- * @shost: SCSI host pointer
- * @time: elapsed time of the scan in jiffies
- *
- * This function will be called periodically until it returns 1 with the
- * scsi_host and the elapsed time of the scan in jiffies. In our implemention,
- * we wait for firmware discovery to complete, then return 1.
- */
-static int
-_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- if (disable_discovery > 0) {
- ioc->is_driver_loading = 0;
- ioc->wait_for_discovery_to_complete = 0;
- return 1;
- }
-
- if (time >= (300 * HZ)) {
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout "
- "(timeout=300s)\n", ioc->name);
- ioc->is_driver_loading = 0;
- return 1;
- }
-
- if (ioc->start_scan)
- return 0;
-
- if (ioc->start_scan_failed) {
- printk(MPT2SAS_INFO_FMT "port enable: FAILED with "
- "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed);
- ioc->is_driver_loading = 0;
- ioc->wait_for_discovery_to_complete = 0;
- ioc->remove_host = 1;
- return 1;
- }
-
- printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
-
- if (ioc->wait_for_discovery_to_complete) {
- ioc->wait_for_discovery_to_complete = 0;
- _scsih_probe_devices(ioc);
- }
- mpt2sas_base_start_watchdog(ioc);
- ioc->is_driver_loading = 0;
- return 1;
-}
-
-
-/**
- * _scsih_probe - attach and add scsi host
- * @pdev: PCI device struct
- * @id: pci device id
- *
- * Returns 0 success, anything else error.
- */
-static int
-_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- struct MPT2SAS_ADAPTER *ioc;
- struct Scsi_Host *shost;
- int rv;
-
- shost = scsi_host_alloc(&scsih_driver_template,
- sizeof(struct MPT2SAS_ADAPTER));
- if (!shost)
- return -ENODEV;
-
- /* init local params */
- ioc = shost_priv(shost);
- memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
- INIT_LIST_HEAD(&ioc->list);
- spin_lock(&gioc_lock);
- list_add_tail(&ioc->list, &mpt2sas_ioc_list);
- spin_unlock(&gioc_lock);
- ioc->shost = shost;
- ioc->id = mpt_ids++;
- sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
- ioc->pdev = pdev;
- if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) {
- ioc->is_warpdrive = 1;
- ioc->hide_ir_msg = 1;
- } else
- ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
- ioc->scsi_io_cb_idx = scsi_io_cb_idx;
- ioc->tm_cb_idx = tm_cb_idx;
- ioc->ctl_cb_idx = ctl_cb_idx;
- ioc->base_cb_idx = base_cb_idx;
- ioc->port_enable_cb_idx = port_enable_cb_idx;
- ioc->transport_cb_idx = transport_cb_idx;
- ioc->scsih_cb_idx = scsih_cb_idx;
- ioc->config_cb_idx = config_cb_idx;
- ioc->tm_tr_cb_idx = tm_tr_cb_idx;
- ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;
- ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
- ioc->logging_level = logging_level;
- ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;
- /* misc semaphores and spin locks */
- mutex_init(&ioc->reset_in_progress_mutex);
- /* initializing pci_access_mutex lock */
- mutex_init(&ioc->pci_access_mutex);
- spin_lock_init(&ioc->ioc_reset_in_progress_lock);
- spin_lock_init(&ioc->scsi_lookup_lock);
- spin_lock_init(&ioc->sas_device_lock);
- spin_lock_init(&ioc->sas_node_lock);
- spin_lock_init(&ioc->fw_event_lock);
- spin_lock_init(&ioc->raid_device_lock);
-
- INIT_LIST_HEAD(&ioc->sas_device_list);
- INIT_LIST_HEAD(&ioc->sas_device_init_list);
- INIT_LIST_HEAD(&ioc->sas_expander_list);
- 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_LIST_HEAD(&ioc->delayed_tr_volume_list);
- INIT_LIST_HEAD(&ioc->reply_queue_list);
-
- /* init shost parameters */
- shost->max_cmd_len = 32;
- shost->max_lun = max_lun;
- shost->transportt = mpt2sas_transport_template;
- shost->unique_id = ioc->id;
-
- if (max_sectors != 0xFFFF) {
- if (max_sectors < 64) {
- shost->max_sectors = 64;
- printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
- "for max_sectors, range is 64 to 32767. Assigning "
- "value of 64.\n", ioc->name, max_sectors);
- } else if (max_sectors > 32767) {
- shost->max_sectors = 32767;
- printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
- "for max_sectors, range is 64 to 8192. Assigning "
- "default value of 32767.\n", ioc->name,
- max_sectors);
- } else {
- shost->max_sectors = max_sectors & 0xFFFE;
- printk(MPT2SAS_INFO_FMT "The max_sectors value is "
- "set to %d\n", ioc->name, shost->max_sectors);
- }
- }
-
- /* register EEDP capabilities with SCSI layer */
- if (prot_mask)
- scsi_host_set_prot(shost, prot_mask);
- else
- scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
- | SHOST_DIF_TYPE2_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),
- "fw_event%d", ioc->id);
- ioc->firmware_event_thread = create_singlethread_workqueue(
- ioc->firmware_event_name);
- if (!ioc->firmware_event_thread) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rv = -ENODEV;
- goto out_thread_fail;
- }
-
- ioc->is_driver_loading = 1;
- if ((mpt2sas_base_attach(ioc))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rv = -ENODEV;
- goto out_attach_fail;
- }
-
- if (ioc->is_warpdrive) {
- if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
- ioc->hide_drives = 0;
- else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
- ioc->hide_drives = 1;
- else {
- if (_scsih_get_num_volumes(ioc))
- ioc->hide_drives = 1;
- else
- ioc->hide_drives = 0;
- }
- } else
- ioc->hide_drives = 0;
-
- rv = scsi_add_host(shost, &pdev->dev);
- if (rv) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_add_shost_fail;
- }
-
- scsi_scan_host(shost);
-
- return 0;
-
- out_add_shost_fail:
- mpt2sas_base_detach(ioc);
- out_attach_fail:
- destroy_workqueue(ioc->firmware_event_thread);
- out_thread_fail:
- spin_lock(&gioc_lock);
- list_del(&ioc->list);
- spin_unlock(&gioc_lock);
- scsi_host_put(shost);
- return rv;
-}
-
-#ifdef CONFIG_PM
-/**
- * _scsih_suspend - power management suspend main entry point
- * @pdev: PCI device struct
- * @state: PM state change to (usually PCI_D3)
- *
- * Returns 0 success, anything else error.
- */
-static int
-_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- pci_power_t device_state;
-
- mpt2sas_base_stop_watchdog(ioc);
- scsi_block_requests(shost);
- _scsih_ir_shutdown(ioc);
- device_state = pci_choose_state(pdev, state);
- printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
- "operating state [D%d]\n", ioc->name, pdev,
- pci_name(pdev), device_state);
-
- mpt2sas_base_free_resources(ioc);
- pci_save_state(pdev);
- pci_set_power_state(pdev, device_state);
- return 0;
-}
-
-/**
- * _scsih_resume - power management resume main entry point
- * @pdev: PCI device struct
- *
- * Returns 0 success, anything else error.
- */
-static int
-_scsih_resume(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- pci_power_t device_state = pdev->current_state;
- int r;
-
- printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
- "operating state [D%d]\n", ioc->name, pdev,
- pci_name(pdev), device_state);
-
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, PCI_D0, 0);
- pci_restore_state(pdev);
- ioc->pdev = pdev;
- r = mpt2sas_base_map_resources(ioc);
- if (r)
- return r;
-
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
- scsi_unblock_requests(shost);
- mpt2sas_base_start_watchdog(ioc);
- return 0;
-}
-#endif /* CONFIG_PM */
-
-/**
- * _scsih_pci_error_detected - Called when a PCI error is detected.
- * @pdev: PCI device struct
- * @state: PCI channel state
- *
- * Description: Called when a PCI error is detected.
- *
- * Return value:
- * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
- */
-static pci_ers_result_t
-_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
- ioc->name, state);
-
- switch (state) {
- case pci_channel_io_normal:
- return PCI_ERS_RESULT_CAN_RECOVER;
- case pci_channel_io_frozen:
- /* Fatal error, prepare for slot reset */
- ioc->pci_error_recovery = 1;
- scsi_block_requests(ioc->shost);
- mpt2sas_base_stop_watchdog(ioc);
- mpt2sas_base_free_resources(ioc);
- return PCI_ERS_RESULT_NEED_RESET;
- case pci_channel_io_perm_failure:
- /* Permanent error, prepare for device removal */
- ioc->pci_error_recovery = 1;
- mpt2sas_base_stop_watchdog(ioc);
- _scsih_flush_running_cmds(ioc);
- return PCI_ERS_RESULT_DISCONNECT;
- }
- return PCI_ERS_RESULT_NEED_RESET;
-}
-
-/**
- * _scsih_pci_slot_reset - Called when PCI slot has been reset.
- * @pdev: PCI device struct
- *
- * Description: This routine is called by the pci error recovery
- * code after the PCI slot has been reset, just before we
- * should resume normal operations.
- */
-static pci_ers_result_t
-_scsih_pci_slot_reset(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int rc;
-
- printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
- ioc->name);
-
- ioc->pci_error_recovery = 0;
- ioc->pdev = pdev;
- pci_restore_state(pdev);
- rc = mpt2sas_base_map_resources(ioc);
- if (rc)
- return PCI_ERS_RESULT_DISCONNECT;
-
-
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
- (rc == 0) ? "success" : "failed");
-
- if (!rc)
- return PCI_ERS_RESULT_RECOVERED;
- else
- return PCI_ERS_RESULT_DISCONNECT;
-}
-
-/**
- * _scsih_pci_resume() - resume normal ops after PCI reset
- * @pdev: pointer to PCI device
- *
- * Called when the error recovery driver tells us that its
- * OK to resume normal operation. Use completion to allow
- * halted scsi ops to resume.
- */
-static void
-_scsih_pci_resume(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
-
- pci_cleanup_aer_uncorrect_error_status(pdev);
- mpt2sas_base_start_watchdog(ioc);
- scsi_unblock_requests(ioc->shost);
-}
-
-/**
- * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
- * @pdev: pointer to PCI device
- */
-static pci_ers_result_t
-_scsih_pci_mmio_enabled(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
- ioc->name);
-
- /* TODO - dump whatever for debugging purposes */
-
- /* Request a slot reset. */
- return PCI_ERS_RESULT_NEED_RESET;
-}
-
-static const struct pci_error_handlers _scsih_err_handler = {
- .error_detected = _scsih_pci_error_detected,
- .mmio_enabled = _scsih_pci_mmio_enabled,
- .slot_reset = _scsih_pci_slot_reset,
- .resume = _scsih_pci_resume,
-};
-
-static struct pci_driver scsih_driver = {
- .name = MPT2SAS_DRIVER_NAME,
- .id_table = scsih_pci_table,
- .probe = _scsih_probe,
- .remove = _scsih_remove,
- .shutdown = _scsih_shutdown,
- .err_handler = &_scsih_err_handler,
-#ifdef CONFIG_PM
- .suspend = _scsih_suspend,
- .resume = _scsih_resume,
-#endif
-};
-
-/* raid transport support */
-static struct raid_function_template mpt2sas_raid_functions = {
- .cookie = &scsih_driver_template,
- .is_raid = _scsih_is_raid,
- .get_resync = _scsih_get_resync,
- .get_state = _scsih_get_state,
-};
-
-/**
- * _scsih_init - main entry point for this driver.
- *
- * Returns 0 success, anything else error.
- */
-static int __init
-_scsih_init(void)
-{
- int error;
-
- mpt_ids = 0;
- printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
- MPT2SAS_DRIVER_VERSION);
-
- mpt2sas_transport_template =
- sas_attach_transport(&mpt2sas_transport_functions);
- if (!mpt2sas_transport_template)
- return -ENODEV;
- /* raid transport support */
- mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
- if (!mpt2sas_raid_template) {
- sas_release_transport(mpt2sas_transport_template);
- return -ENODEV;
- }
-
- mpt2sas_base_initialize_callback_handler();
-
- /* queuecommand callback hander */
- scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
-
- /* task management callback handler */
- tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
-
- /* base internal commands callback handler */
- base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
- port_enable_cb_idx = mpt2sas_base_register_callback_handler(
- mpt2sas_port_enable_done);
-
- /* transport internal commands callback handler */
- transport_cb_idx = mpt2sas_base_register_callback_handler(
- mpt2sas_transport_done);
-
- /* scsih internal commands callback handler */
- scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
-
- /* configuration page API internal commands callback handler */
- config_cb_idx = mpt2sas_base_register_callback_handler(
- mpt2sas_config_done);
-
- /* 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_tr_volume_cb_idx = mpt2sas_base_register_callback_handler(
- _scsih_tm_volume_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);
- if (error) {
- /* raid transport support */
- raid_class_release(mpt2sas_raid_template);
- sas_release_transport(mpt2sas_transport_template);
- }
-
- return error;
-}
-
-/**
- * _scsih_exit - exit point for this driver (when it is a module).
- *
- * Returns 0 success, anything else error.
- */
-static void __exit
-_scsih_exit(void)
-{
- printk(KERN_INFO "mpt2sas version %s unloading\n",
- MPT2SAS_DRIVER_VERSION);
-
- pci_unregister_driver(&scsih_driver);
-
- mpt2sas_ctl_exit();
-
- mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
- mpt2sas_base_release_callback_handler(tm_cb_idx);
- mpt2sas_base_release_callback_handler(base_cb_idx);
- mpt2sas_base_release_callback_handler(port_enable_cb_idx);
- mpt2sas_base_release_callback_handler(transport_cb_idx);
- mpt2sas_base_release_callback_handler(scsih_cb_idx);
- 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_tr_volume_cb_idx);
- mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
-
- /* raid transport support */
- raid_class_release(mpt2sas_raid_template);
- sas_release_transport(mpt2sas_transport_template);
-
-}
-
-module_init(_scsih_init);
-module_exit(_scsih_exit);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
deleted file mode 100644
index af86800..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ /dev/null
@@ -1,2173 +0,0 @@
-/*
- * SAS Transport Layer for MPT (Message Passing Technology) based controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * 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 the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * 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.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_transport_sas.h>
-#include <scsi/scsi_dbg.h>
-
-#include "mpt2sas_base.h"
-/**
- * _transport_sas_node_find_by_sas_address - sas node search
- * @ioc: per adapter object
- * @sas_address: sas address of expander or sas host
- * Context: Calling function should acquire ioc->sas_node_lock.
- *
- * Search for either hba phys or expander device based on handle, then returns
- * the sas_node object.
- */
-static struct _sas_node *
-_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- if (ioc->sas_hba.sas_address == sas_address)
- return &ioc->sas_hba;
- else
- return mpt2sas_scsih_expander_find_by_sas_address(ioc,
- sas_address);
-}
-
-/**
- * _transport_convert_phy_link_rate -
- * @link_rate: link rate returned from mpt firmware
- *
- * Convert link_rate from mpi fusion into sas_transport form.
- */
-static enum sas_linkrate
-_transport_convert_phy_link_rate(u8 link_rate)
-{
- enum sas_linkrate rc;
-
- switch (link_rate) {
- case MPI2_SAS_NEG_LINK_RATE_1_5:
- rc = SAS_LINK_RATE_1_5_GBPS;
- break;
- case MPI2_SAS_NEG_LINK_RATE_3_0:
- rc = SAS_LINK_RATE_3_0_GBPS;
- break;
- case MPI2_SAS_NEG_LINK_RATE_6_0:
- rc = SAS_LINK_RATE_6_0_GBPS;
- break;
- case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:
- rc = SAS_PHY_DISABLED;
- break;
- case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
- rc = SAS_LINK_RATE_FAILED;
- break;
- case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:
- rc = SAS_SATA_PORT_SELECTOR;
- break;
- case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
- rc = SAS_PHY_RESET_IN_PROGRESS;
- break;
- default:
- case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
- case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
- rc = SAS_LINK_RATE_UNKNOWN;
- break;
- }
- return rc;
-}
-
-/**
- * _transport_set_identify - set identify for phys and end devices
- * @ioc: per adapter object
- * @handle: device handle
- * @identify: sas identify info
- *
- * Populates sas identify info.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- struct sas_identify *identify)
-{
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 device_info;
- u32 ioc_status;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
-
- ioc->name, __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
- "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
- __FILE__, __LINE__, __func__);
- return -EIO;
- }
-
- memset(identify, 0, sizeof(struct sas_identify));
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
-
- /* sas_address */
- identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
-
- /* phy number of the parent device this device is linked to */
- identify->phy_identifier = sas_device_pg0.PhyNum;
-
- /* device_type */
- switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
- case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
- identify->device_type = SAS_PHY_UNUSED;
- break;
- case MPI2_SAS_DEVICE_INFO_END_DEVICE:
- identify->device_type = SAS_END_DEVICE;
- break;
- case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:
- identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
- break;
- case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:
- identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
- break;
- }
-
- /* initiator_port_protocols */
- if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)
- identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
- if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)
- identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)
- identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)
- identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
-
- /* target_port_protocols */
- if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
- identify->target_port_protocols |= SAS_PROTOCOL_SSP;
- if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
- identify->target_port_protocols |= SAS_PROTOCOL_STP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)
- identify->target_port_protocols |= SAS_PROTOCOL_SMP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- identify->target_port_protocols |= SAS_PROTOCOL_SATA;
-
- return 0;
-}
-
-/**
- * mpt2sas_transport_done - internal transport layer callback handler.
- * @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)
- *
- * Callback handler when sending internal generated transport cmds.
- * The callback index passed is `ioc->transport_cb_idx`
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-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 1;
- if (ioc->transport_cmds.smid != smid)
- return 1;
- ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- memcpy(ioc->transport_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID;
- }
- ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->transport_cmds.done);
- return 1;
-}
-
-/* report manufacture request structure */
-struct rep_manu_request{
- u8 smp_frame_type;
- u8 function;
- u8 reserved;
- u8 request_length;
-};
-
-/* report manufacture reply structure */
-struct rep_manu_reply{
- u8 smp_frame_type; /* 0x41 */
- u8 function; /* 0x01 */
- u8 function_result;
- u8 response_length;
- u16 expander_change_count;
- u8 reserved0[2];
- u8 sas_format;
- u8 reserved2[3];
- u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
- u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
- u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
- u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
- u16 component_id;
- u8 component_revision_id;
- u8 reserved3;
- u8 vendor_specific[8];
-};
-
-/**
- * _transport_expander_report_manufacture - obtain SMP report_manufacture
- * @ioc: per adapter object
- * @sas_address: expander sas address
- * @edev: the sas_expander_device object
- *
- * Fills in the sas_expander_device object when SMP port is created.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address, struct sas_expander_device *edev)
-{
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- struct rep_manu_reply *manufacture_reply;
- struct rep_manu_request *manufacture_request;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- u32 sz;
- u16 wait_state_count;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- mutex_lock(&ioc->transport_cmds.mutex);
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
-
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- rc = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
-
- manufacture_request = data_out;
- manufacture_request->smp_frame_type = 0x40;
- manufacture_request->function = 1;
- manufacture_request->reserved = 0;
- manufacture_request->request_length = 0;
-
- 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;
- mpi_request->SASAddress = cpu_to_le64(sas_address);
- mpi_request->RequestDataLength =
- cpu_to_le16(sizeof(struct rep_manu_request));
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct rep_manu_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct rep_manu_reply), data_out_dma +
- sizeof(struct rep_manu_request));
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
- "send to sas_addr(0x%016llx)\n", ioc->name,
- (unsigned long long)sas_address));
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
- "complete\n", ioc->name));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
- u8 *tmp;
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "report_manufacture - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
- sizeof(struct rep_manu_reply))
- goto out;
-
- manufacture_reply = data_out + sizeof(struct rep_manu_request);
- strncpy(edev->vendor_id, manufacture_reply->vendor_id,
- SAS_EXPANDER_VENDOR_ID_LEN);
- strncpy(edev->product_id, manufacture_reply->product_id,
- SAS_EXPANDER_PRODUCT_ID_LEN);
- strncpy(edev->product_rev, manufacture_reply->product_rev,
- SAS_EXPANDER_PRODUCT_REV_LEN);
- edev->level = manufacture_reply->sas_format & 1;
- if (edev->level) {
- strncpy(edev->component_vendor_id,
- manufacture_reply->component_vendor_id,
- SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
- tmp = (u8 *)&manufacture_reply->component_id;
- edev->component_id = tmp[0] << 8 | tmp[1];
- edev->component_revision_id =
- manufacture_reply->component_revision_id;
- }
- } else
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "report_manufacture - no reply\n", ioc->name));
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
-
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-/**
- * _transport_delete_port - helper function to removing a port
- * @ioc: per adapter object
- * @mpt2sas_port: mpt2sas per port object
- *
- * Returns nothing.
- */
-static void
-_transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_port *mpt2sas_port)
-{
- u64 sas_address = mpt2sas_port->remote_identify.sas_address;
- enum sas_device_type device_type =
- mpt2sas_port->remote_identify.device_type;
-
- dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
- "remove: sas_addr(0x%016llx)\n",
- (unsigned long long) sas_address);
-
- ioc->logging_level |= MPT_DEBUG_TRANSPORT;
- if (device_type == SAS_END_DEVICE)
- mpt2sas_device_remove_by_sas_address(ioc, sas_address);
- else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
- device_type == SAS_FANOUT_EXPANDER_DEVICE)
- mpt2sas_expander_remove(ioc, sas_address);
- ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
-}
-
-/**
- * _transport_delete_phy - helper function to removing single phy from port
- * @ioc: per adapter object
- * @mpt2sas_port: mpt2sas per port object
- * @mpt2sas_phy: mpt2sas per phy object
- *
- * Returns nothing.
- */
-static void
-_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy)
-{
- u64 sas_address = mpt2sas_port->remote_identify.sas_address;
-
- dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "remove: sas_addr(0x%016llx), phy(%d)\n",
- (unsigned long long) sas_address, mpt2sas_phy->phy_id);
-
- list_del(&mpt2sas_phy->port_siblings);
- mpt2sas_port->num_phys--;
- sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
- mpt2sas_phy->phy_belongs_to_port = 0;
-}
-
-/**
- * _transport_add_phy - helper function to adding single phy to port
- * @ioc: per adapter object
- * @mpt2sas_port: mpt2sas per port object
- * @mpt2sas_phy: mpt2sas per phy object
- *
- * Returns nothing.
- */
-static void
-_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port,
- struct _sas_phy *mpt2sas_phy)
-{
- u64 sas_address = mpt2sas_port->remote_identify.sas_address;
-
- dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long)
- sas_address, mpt2sas_phy->phy_id);
-
- list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list);
- mpt2sas_port->num_phys++;
- sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy);
- mpt2sas_phy->phy_belongs_to_port = 1;
-}
-
-/**
- * _transport_add_phy_to_an_existing_port - adding new phy to existing port
- * @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @mpt2sas_phy: mpt2sas per phy object
- * @sas_address: sas address of device/expander were phy needs to be added to
- *
- * Returns nothing.
- */
-static void
-_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
-struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address)
-{
- struct _sas_port *mpt2sas_port;
- struct _sas_phy *phy_srch;
-
- if (mpt2sas_phy->phy_belongs_to_port == 1)
- return;
-
- list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list,
- port_list) {
- if (mpt2sas_port->remote_identify.sas_address !=
- sas_address)
- continue;
- list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
- port_siblings) {
- if (phy_srch == mpt2sas_phy)
- return;
- }
- _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy);
- return;
- }
-
-}
-
-/**
- * _transport_del_phy_from_an_existing_port - delete phy from existing port
- * @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @mpt2sas_phy: mpt2sas per phy object
- *
- * Returns nothing.
- */
-static void
-_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy)
-{
- struct _sas_port *mpt2sas_port, *next;
- struct _sas_phy *phy_srch;
-
- if (mpt2sas_phy->phy_belongs_to_port == 0)
- return;
-
- list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
- port_list) {
- list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
- port_siblings) {
- if (phy_srch != mpt2sas_phy)
- continue;
- if (mpt2sas_port->num_phys == 1)
- _transport_delete_port(ioc, mpt2sas_port);
- else
- _transport_delete_phy(ioc, mpt2sas_port,
- mpt2sas_phy);
- return;
- }
- }
-}
-
-/**
- * _transport_sanity_check - sanity check when adding a new port
- * @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @sas_address: sas address of device being added
- *
- * See the explanation above from _transport_delete_duplicate_port
- */
-static void
-_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node,
- u64 sas_address)
-{
- int i;
-
- for (i = 0; i < sas_node->num_phys; i++) {
- if (sas_node->phy[i].remote_identify.sas_address != sas_address)
- continue;
- if (sas_node->phy[i].phy_belongs_to_port == 1)
- _transport_del_phy_from_an_existing_port(ioc, sas_node,
- &sas_node->phy[i]);
- }
-}
-
-/**
- * mpt2sas_transport_port_add - insert port to the list
- * @ioc: per adapter object
- * @handle: handle of attached device
- * @sas_address: sas address of parent expander or sas host
- * Context: This function will acquire ioc->sas_node_lock.
- *
- * Adding new port object to the sas_node->sas_port_list.
- *
- * Returns mpt2sas_port.
- */
-struct _sas_port *
-mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u64 sas_address)
-{
- struct _sas_phy *mpt2sas_phy, *next;
- struct _sas_port *mpt2sas_port;
- unsigned long flags;
- struct _sas_node *sas_node;
- struct sas_rphy *rphy;
- int i;
- struct sas_port *port;
-
- mpt2sas_port = kzalloc(sizeof(struct _sas_port),
- GFP_KERNEL);
- if (!mpt2sas_port) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return NULL;
- }
-
- INIT_LIST_HEAD(&mpt2sas_port->port_list);
- INIT_LIST_HEAD(&mpt2sas_port->phy_list);
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- if (!sas_node) {
- printk(MPT2SAS_ERR_FMT "%s: Could not find "
- "parent sas_address(0x%016llx)!\n", ioc->name,
- __func__, (unsigned long long)sas_address);
- goto out_fail;
- }
-
- if ((_transport_set_identify(ioc, handle,
- &mpt2sas_port->remote_identify))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- _transport_sanity_check(ioc, sas_node,
- mpt2sas_port->remote_identify.sas_address);
-
- for (i = 0; i < sas_node->num_phys; i++) {
- if (sas_node->phy[i].remote_identify.sas_address !=
- mpt2sas_port->remote_identify.sas_address)
- continue;
- list_add_tail(&sas_node->phy[i].port_siblings,
- &mpt2sas_port->phy_list);
- mpt2sas_port->num_phys++;
- }
-
- if (!mpt2sas_port->num_phys) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- port = sas_port_alloc_num(sas_node->parent_dev);
- if ((sas_port_add(port))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
- port_siblings) {
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
- ", sas_addr(0x%016llx), phy(%d)\n", handle,
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address,
- mpt2sas_phy->phy_id);
- sas_port_add_phy(port, mpt2sas_phy->phy);
- mpt2sas_phy->phy_belongs_to_port = 1;
- }
-
- mpt2sas_port->port = port;
- if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
- rphy = sas_end_device_alloc(port);
- else
- rphy = sas_expander_alloc(port,
- mpt2sas_port->remote_identify.device_type);
-
- rphy->identify = mpt2sas_port->remote_identify;
- if ((sas_rphy_add(rphy))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- }
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), "
- "sas_addr(0x%016llx)\n", handle,
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address);
- mpt2sas_port->rphy = rphy;
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* fill in report manufacture */
- if (mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
- mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
- _transport_expander_report_manufacture(ioc,
- mpt2sas_port->remote_identify.sas_address,
- rphy_to_expander_device(rphy));
-
- return mpt2sas_port;
-
- out_fail:
- list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
- port_siblings)
- list_del(&mpt2sas_phy->port_siblings);
- kfree(mpt2sas_port);
- return NULL;
-}
-
-/**
- * mpt2sas_transport_port_remove - remove port from the list
- * @ioc: per adapter object
- * @sas_address: sas address of attached device
- * @sas_address_parent: sas address of parent expander or sas host
- * Context: This function will acquire ioc->sas_node_lock.
- *
- * Removing object and freeing associated memory from the
- * ioc->sas_port_list.
- *
- * Return nothing.
- */
-void
-mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u64 sas_address_parent)
-{
- int i;
- unsigned long flags;
- struct _sas_port *mpt2sas_port, *next;
- struct _sas_node *sas_node;
- u8 found = 0;
- struct _sas_phy *mpt2sas_phy, *next_phy;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_sas_address(ioc,
- sas_address_parent);
- if (!sas_node) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
- list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
- port_list) {
- if (mpt2sas_port->remote_identify.sas_address != sas_address)
- continue;
- found = 1;
- list_del(&mpt2sas_port->port_list);
- goto out;
- }
- out:
- if (!found) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
-
- for (i = 0; i < sas_node->num_phys; i++) {
- if (sas_node->phy[i].remote_identify.sas_address == sas_address)
- memset(&sas_node->phy[i].remote_identify, 0 ,
- sizeof(struct sas_identify));
- }
-
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- list_for_each_entry_safe(mpt2sas_phy, next_phy,
- &mpt2sas_port->phy_list, port_siblings) {
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
- "remove: sas_addr(0x%016llx), phy(%d)\n",
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address,
- mpt2sas_phy->phy_id);
- mpt2sas_phy->phy_belongs_to_port = 0;
- sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
- list_del(&mpt2sas_phy->port_siblings);
- }
- sas_port_delete(mpt2sas_port->port);
- kfree(mpt2sas_port);
-}
-
-/**
- * mpt2sas_transport_add_host_phy - report sas_host phy to transport
- * @ioc: per adapter object
- * @mpt2sas_phy: mpt2sas per phy object
- * @phy_pg0: sas phy page 0
- * @parent_dev: parent device class object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
-{
- struct sas_phy *phy;
- int phy_index = mpt2sas_phy->phy_id;
-
-
- INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
- phy = sas_phy_alloc(parent_dev, phy_index);
- if (!phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
- &mpt2sas_phy->identify))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- phy->identify = mpt2sas_phy->identify;
- mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
- if (mpt2sas_phy->attached_handle)
- _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
- &mpt2sas_phy->remote_identify);
- phy->identify.phy_identifier = mpt2sas_phy->phy_id;
- phy->negotiated_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
- phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
- phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
- phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
- phy_pg0.HwLinkRate >> 4);
- phy->minimum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
- phy->maximum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate >> 4);
-
- if ((sas_phy_add(phy))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- sas_phy_free(phy);
- return -1;
- }
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &phy->dev,
- "add: handle(0x%04x), sas_addr(0x%016llx)\n"
- "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- mpt2sas_phy->handle, (unsigned long long)
- mpt2sas_phy->identify.sas_address,
- mpt2sas_phy->attached_handle,
- (unsigned long long)
- mpt2sas_phy->remote_identify.sas_address);
- mpt2sas_phy->phy = phy;
- return 0;
-}
-
-
-/**
- * mpt2sas_transport_add_expander_phy - report expander phy to transport
- * @ioc: per adapter object
- * @mpt2sas_phy: mpt2sas per phy object
- * @expander_pg1: expander page 1
- * @parent_dev: parent device class object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
-{
- struct sas_phy *phy;
- int phy_index = mpt2sas_phy->phy_id;
-
- INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
- phy = sas_phy_alloc(parent_dev, phy_index);
- if (!phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
- &mpt2sas_phy->identify))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- phy->identify = mpt2sas_phy->identify;
- mpt2sas_phy->attached_handle =
- le16_to_cpu(expander_pg1.AttachedDevHandle);
- if (mpt2sas_phy->attached_handle)
- _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
- &mpt2sas_phy->remote_identify);
- phy->identify.phy_identifier = mpt2sas_phy->phy_id;
- phy->negotiated_linkrate = _transport_convert_phy_link_rate(
- expander_pg1.NegotiatedLinkRate &
- MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
- phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
- expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
- phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
- expander_pg1.HwLinkRate >> 4);
- phy->minimum_linkrate = _transport_convert_phy_link_rate(
- expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
- phy->maximum_linkrate = _transport_convert_phy_link_rate(
- expander_pg1.ProgrammedLinkRate >> 4);
-
- if ((sas_phy_add(phy))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- sas_phy_free(phy);
- return -1;
- }
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &phy->dev,
- "add: handle(0x%04x), sas_addr(0x%016llx)\n"
- "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- mpt2sas_phy->handle, (unsigned long long)
- mpt2sas_phy->identify.sas_address,
- mpt2sas_phy->attached_handle,
- (unsigned long long)
- mpt2sas_phy->remote_identify.sas_address);
- mpt2sas_phy->phy = phy;
- return 0;
-}
-
-/**
- * mpt2sas_transport_update_links - refreshing phy link changes
- * @ioc: per adapter object
- * @sas_address: sas address of parent expander or sas host
- * @handle: attached device handle
- * @phy_numberv: phy number
- * @link_rate: new link rate
- *
- * Returns nothing.
- */
-void
-mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address, u16 handle, u8 phy_number, u8 link_rate)
-{
- unsigned long flags;
- struct _sas_node *sas_node;
- struct _sas_phy *mpt2sas_phy;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
- if (!sas_node) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
-
- mpt2sas_phy = &sas_node->phy[phy_number];
- mpt2sas_phy->attached_handle = handle;
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
- _transport_set_identify(ioc, handle,
- &mpt2sas_phy->remote_identify);
- _transport_add_phy_to_an_existing_port(ioc, sas_node,
- mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
- } else
- memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
- sas_identify));
-
- if (mpt2sas_phy->phy)
- mpt2sas_phy->phy->negotiated_linkrate =
- _transport_convert_phy_link_rate(link_rate);
-
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "refresh: parent sas_addr(0x%016llx),\n"
- "\tlink_rate(0x%02x), phy(%d)\n"
- "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- (unsigned long long)sas_address,
- link_rate, phy_number, handle, (unsigned long long)
- mpt2sas_phy->remote_identify.sas_address);
-}
-
-static inline void *
-phy_to_ioc(struct sas_phy *phy)
-{
- struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
- return shost_priv(shost);
-}
-
-static inline void *
-rphy_to_ioc(struct sas_rphy *rphy)
-{
- struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
- return shost_priv(shost);
-}
-
-
-/* report phy error log structure */
-struct phy_error_log_request{
- u8 smp_frame_type; /* 0x40 */
- u8 function; /* 0x11 */
- u8 allocated_response_length;
- u8 request_length; /* 02 */
- u8 reserved_1[5];
- u8 phy_identifier;
- u8 reserved_2[2];
-};
-
-/* report phy error log reply structure */
-struct phy_error_log_reply{
- u8 smp_frame_type; /* 0x41 */
- u8 function; /* 0x11 */
- u8 function_result;
- u8 response_length;
- __be16 expander_change_count;
- u8 reserved_1[3];
- u8 phy_identifier;
- u8 reserved_2[2];
- __be32 invalid_dword;
- __be32 running_disparity_error;
- __be32 loss_of_dword_sync;
- __be32 phy_reset_problem;
-};
-
-/**
- * _transport_get_expander_phy_error_log - return expander counters
- * @ioc: per adapter object
- * @phy: The sas phy object
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,
- struct sas_phy *phy)
-{
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- struct phy_error_log_request *phy_error_log_request;
- struct phy_error_log_reply *phy_error_log_reply;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- u32 sz;
- u16 wait_state_count;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- mutex_lock(&ioc->transport_cmds.mutex);
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- sz = sizeof(struct phy_error_log_request) +
- sizeof(struct phy_error_log_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- rc = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
-
- rc = -EINVAL;
- memset(data_out, 0, sz);
- phy_error_log_request = data_out;
- phy_error_log_request->smp_frame_type = 0x40;
- phy_error_log_request->function = 0x11;
- phy_error_log_request->request_length = 2;
- phy_error_log_request->allocated_response_length = 0;
- phy_error_log_request->phy_identifier = phy->number;
-
- 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;
- mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
- mpi_request->RequestDataLength =
- cpu_to_le16(sizeof(struct phy_error_log_request));
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_error_log_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_error_log_reply), data_out_dma +
- sizeof(struct phy_error_log_request));
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
- "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name,
- (unsigned long long)phy->identify.sas_address, phy->number));
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
- "complete\n", ioc->name));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_error_log - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
- sizeof(struct phy_error_log_reply))
- goto out;
-
- phy_error_log_reply = data_out +
- sizeof(struct phy_error_log_request);
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_error_log - function_result(%d)\n",
- ioc->name, phy_error_log_reply->function_result));
-
- phy->invalid_dword_count =
- be32_to_cpu(phy_error_log_reply->invalid_dword);
- phy->running_disparity_error_count =
- be32_to_cpu(phy_error_log_reply->running_disparity_error);
- phy->loss_of_dword_sync_count =
- be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
- phy->phy_reset_problem_count =
- be32_to_cpu(phy_error_log_reply->phy_reset_problem);
- rc = 0;
- } else
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_error_log - no reply\n", ioc->name));
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
-
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-/**
- * _transport_get_linkerrors - return phy counters for both hba and expanders
- * @phy: The sas phy object
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_transport_get_linkerrors(struct sas_phy *phy)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- unsigned long flags;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasPhyPage1_t phy_pg1;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- if (phy->identify.sas_address != ioc->sas_hba.sas_address)
- return _transport_get_expander_phy_error_log(ioc, phy);
-
- /* get hba phy error logs */
- if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
- phy->number))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
- printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
- "(0x%04x), loginfo(0x%08x)\n", ioc->name,
- phy->number, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo));
-
- phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
- phy->running_disparity_error_count =
- le32_to_cpu(phy_pg1.RunningDisparityErrorCount);
- phy->loss_of_dword_sync_count =
- le32_to_cpu(phy_pg1.LossDwordSynchCount);
- phy->phy_reset_problem_count =
- le32_to_cpu(phy_pg1.PhyResetProblemCount);
- return 0;
-}
-
-/**
- * _transport_get_enclosure_identifier -
- * @phy: The sas phy object
- *
- * Obtain the enclosure logical id for an expander.
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
-{
- struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
- struct _sas_device *sas_device;
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- rphy->identify.sas_address);
- if (sas_device) {
- *identifier = sas_device->enclosure_logical_id;
- rc = 0;
- sas_device_put(sas_device);
- } else {
- *identifier = 0;
- rc = -ENXIO;
- }
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return rc;
-}
-
-/**
- * _transport_get_bay_identifier -
- * @phy: The sas phy object
- *
- * Returns the slot id for a device that resides inside an enclosure.
- */
-static int
-_transport_get_bay_identifier(struct sas_rphy *rphy)
-{
- struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
- struct _sas_device *sas_device;
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- rphy->identify.sas_address);
- if (sas_device) {
- rc = sas_device->slot;
- sas_device_put(sas_device);
- } else {
- rc = -ENXIO;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return rc;
-}
-
-/* phy control request structure */
-struct phy_control_request{
- u8 smp_frame_type; /* 0x40 */
- u8 function; /* 0x91 */
- u8 allocated_response_length;
- u8 request_length; /* 0x09 */
- u16 expander_change_count;
- u8 reserved_1[3];
- u8 phy_identifier;
- u8 phy_operation;
- u8 reserved_2[13];
- u64 attached_device_name;
- u8 programmed_min_physical_link_rate;
- u8 programmed_max_physical_link_rate;
- u8 reserved_3[6];
-};
-
-/* phy control reply structure */
-struct phy_control_reply{
- u8 smp_frame_type; /* 0x41 */
- u8 function; /* 0x11 */
- u8 function_result;
- u8 response_length;
-};
-
-#define SMP_PHY_CONTROL_LINK_RESET (0x01)
-#define SMP_PHY_CONTROL_HARD_RESET (0x02)
-#define SMP_PHY_CONTROL_DISABLE (0x03)
-
-/**
- * _transport_expander_phy_control - expander phy control
- * @ioc: per adapter object
- * @phy: The sas phy object
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,
- struct sas_phy *phy, u8 phy_operation)
-{
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- struct phy_control_request *phy_control_request;
- struct phy_control_reply *phy_control_reply;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- u32 sz;
- u16 wait_state_count;
-
- if (ioc->shost_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- mutex_lock(&ioc->transport_cmds.mutex);
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- sz = sizeof(struct phy_control_request) +
- sizeof(struct phy_control_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- rc = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
-
- rc = -EINVAL;
- memset(data_out, 0, sz);
- phy_control_request = data_out;
- phy_control_request->smp_frame_type = 0x40;
- phy_control_request->function = 0x91;
- phy_control_request->request_length = 9;
- phy_control_request->allocated_response_length = 0;
- phy_control_request->phy_identifier = phy->number;
- phy_control_request->phy_operation = phy_operation;
- phy_control_request->programmed_min_physical_link_rate =
- phy->minimum_linkrate << 4;
- phy_control_request->programmed_max_physical_link_rate =
- phy->maximum_linkrate << 4;
-
- 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;
- mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
- mpi_request->RequestDataLength =
- cpu_to_le16(sizeof(struct phy_error_log_request));
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_reply), data_out_dma +
- sizeof(struct phy_control_request));
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
- "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name,
- (unsigned long long)phy->identify.sas_address, phy->number,
- phy_operation));
-
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
- "complete\n", ioc->name));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_control - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
- sizeof(struct phy_control_reply))
- goto out;
-
- phy_control_reply = data_out +
- sizeof(struct phy_control_request);
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_control - function_result(%d)\n",
- ioc->name, phy_control_reply->function_result));
-
- rc = 0;
- } else
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_control - no reply\n", ioc->name));
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
-
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-/**
- * _transport_phy_reset -
- * @phy: The sas phy object
- * @hard_reset:
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_phy_reset(struct sas_phy *phy, int hard_reset)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- Mpi2SasIoUnitControlReply_t mpi_reply;
- Mpi2SasIoUnitControlRequest_t mpi_request;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* handle expander phys */
- if (phy->identify.sas_address != ioc->sas_hba.sas_address)
- return _transport_expander_phy_control(ioc, phy,
- (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
- SMP_PHY_CONTROL_LINK_RESET);
-
- /* handle hba phys */
- memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
- mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
- mpi_request.Operation = hard_reset ?
- MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
- mpi_request.PhyNum = phy->number;
-
- if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
- printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
- "(0x%04x), loginfo(0x%08x)\n", ioc->name,
- phy->number, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo));
-
- return 0;
-}
-
-/**
- * _transport_phy_enable - enable/disable phys
- * @phy: The sas phy object
- * @enable: enable phy when true
- *
- * Only support sas_host direct attached phys.
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_phy_enable(struct sas_phy *phy, int enable)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u16 sz;
- int rc = 0;
- unsigned long flags;
- int i, discovery_active;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* handle expander phys */
- if (phy->identify.sas_address != ioc->sas_hba.sas_address)
- return _transport_expander_phy_control(ioc, phy,
- (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
- SMP_PHY_CONTROL_DISABLE);
-
- /* handle hba phys */
-
- /* read sas_iounit page 0 */
- sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit0PhyData_t));
- sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENOMEM;
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -EIO;
- goto out;
- }
-
- /* unable to enable/disable phys when when discovery is active */
- for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) {
- if (sas_iounit_pg0->PhyData[i].PortFlags &
- MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
- printk(MPT2SAS_ERR_FMT "discovery is active on "
- "port = %d, phy = %d: unable to enable/disable "
- "phys, try again later!\n", ioc->name,
- sas_iounit_pg0->PhyData[i].Port, i);
- discovery_active = 1;
- }
- }
-
- if (discovery_active) {
- rc = -EAGAIN;
- goto out;
- }
-
- /* read sas_iounit page 1 */
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENOMEM;
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -EIO;
- goto out;
- }
- /* copy Port/PortFlags/PhyFlags from page 0 */
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- sas_iounit_pg1->PhyData[i].Port =
- sas_iounit_pg0->PhyData[i].Port;
- sas_iounit_pg1->PhyData[i].PortFlags =
- (sas_iounit_pg0->PhyData[i].PortFlags &
- MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG);
- sas_iounit_pg1->PhyData[i].PhyFlags =
- (sas_iounit_pg0->PhyData[i].PhyFlags &
- (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED +
- MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED));
- }
- if (enable)
- sas_iounit_pg1->PhyData[phy->number].PhyFlags
- &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
- else
- sas_iounit_pg1->PhyData[phy->number].PhyFlags
- |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
-
- mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
-
- /* link reset */
- if (enable)
- _transport_phy_reset(phy, 0);
-
- out:
- kfree(sas_iounit_pg1);
- kfree(sas_iounit_pg0);
- return rc;
-}
-
-/**
- * _transport_phy_speed - set phy min/max link rates
- * @phy: The sas phy object
- * @rates: rates defined in sas_phy_linkrates
- *
- * Only support sas_host direct attached phys.
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2SasPhyPage0_t phy_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u16 sz;
- int i;
- int rc = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- if (!rates->minimum_linkrate)
- rates->minimum_linkrate = phy->minimum_linkrate;
- else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
- rates->minimum_linkrate = phy->minimum_linkrate_hw;
-
- if (!rates->maximum_linkrate)
- rates->maximum_linkrate = phy->maximum_linkrate;
- else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
- rates->maximum_linkrate = phy->maximum_linkrate_hw;
-
- /* handle expander phys */
- if (phy->identify.sas_address != ioc->sas_hba.sas_address) {
- phy->minimum_linkrate = rates->minimum_linkrate;
- phy->maximum_linkrate = rates->maximum_linkrate;
- return _transport_expander_phy_control(ioc, phy,
- SMP_PHY_CONTROL_LINK_RESET);
- }
-
- /* handle hba phys */
-
- /* sas_iounit page 1 */
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENOMEM;
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -EIO;
- goto out;
- }
-
- for (i = 0; i < ioc->sas_hba.num_phys; i++) {
- if (phy->number != i) {
- sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
- (ioc->sas_hba.phy[i].phy->minimum_linkrate +
- (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
- } else {
- sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
- (rates->minimum_linkrate +
- (rates->maximum_linkrate << 4));
- }
- }
-
- if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
- sz)) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
-
- /* link reset */
- _transport_phy_reset(phy, 0);
-
- /* read phy page 0, then update the rates in the sas transport phy */
- if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
- phy->number)) {
- phy->minimum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
- phy->maximum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate >> 4);
- phy->negotiated_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.NegotiatedLinkRate &
- MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
- }
-
- out:
- kfree(sas_iounit_pg1);
- return rc;
-}
-
-
-/**
- * _transport_smp_handler - transport portal for smp passthru
- * @shost: shost object
- * @rphy: sas transport rphy object
- * @req:
- *
- * This used primarily for smp_utils.
- * Example:
- * smp_rep_general /sys/class/bsg/expander-5:0
- */
-static int
-_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
- struct request *req)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- dma_addr_t dma_addr_in = 0;
- dma_addr_t dma_addr_out = 0;
- dma_addr_t pci_dma_in = 0;
- dma_addr_t pci_dma_out = 0;
- void *pci_addr_in = NULL;
- void *pci_addr_out = NULL;
- u16 wait_state_count;
- struct request *rsp = req->next_rq;
- struct bio_vec bvec;
- struct bvec_iter iter;
-
- if (!rsp) {
- printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
- "missing\n", ioc->name, __func__);
- return -EINVAL;
- }
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
- if (rc)
- return rc;
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
- __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- /* Check if the request is split across multiple segments */
- if (bio_multiple_segments(req->bio)) {
- u32 offset = 0;
-
- /* Allocate memory and copy the request */
- pci_addr_out = pci_alloc_consistent(ioc->pdev,
- blk_rq_bytes(req), &pci_dma_out);
- if (!pci_addr_out) {
- printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto out;
- }
-
- bio_for_each_segment(bvec, req->bio, iter) {
- memcpy(pci_addr_out + offset,
- page_address(bvec.bv_page) + bvec.bv_offset,
- bvec.bv_len);
- offset += bvec.bv_len;
- }
- } else {
- dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
- blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_out) {
- printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto free_pci;
- }
- }
-
- /* Check if the response needs to be populated across
- * multiple segments */
- if (bio_multiple_segments(rsp->bio)) {
- pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
- &pci_dma_in);
- if (!pci_addr_in) {
- printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto unmap;
- }
- } else {
- dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
- blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_in) {
- printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto unmap;
- }
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto unmap;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto unmap;
- }
-
- rc = 0;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- 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;
- mpi_request->SASAddress = (rphy) ?
- cpu_to_le64(rphy->identify.sas_address) :
- cpu_to_le64(ioc->sas_hba.sas_address);
- mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- if (bio_multiple_segments(req->bio)) {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(req) - 4), pci_dma_out);
- } else {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(req) - 4), dma_addr_out);
- }
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- if (bio_multiple_segments(rsp->bio)) {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(rsp) + 4), pci_dma_in);
- } else {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(rsp) + 4), dma_addr_in);
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
- "sending smp request\n", ioc->name, __func__));
-
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s : timeout\n",
- __func__, ioc->name);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
- "complete\n", ioc->name, __func__));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s - reply data transfer size(%d)\n",
- ioc->name, __func__,
- le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
- req->sense_len = sizeof(*mpi_reply);
- req->resid_len = 0;
- rsp->resid_len -=
- le16_to_cpu(mpi_reply->ResponseDataLength);
- /* check if the resp needs to be copied from the allocated
- * pci mem */
- if (bio_multiple_segments(rsp->bio)) {
- u32 offset = 0;
- u32 bytes_to_copy =
- le16_to_cpu(mpi_reply->ResponseDataLength);
- bio_for_each_segment(bvec, rsp->bio, iter) {
- if (bytes_to_copy <= bvec.bv_len) {
- memcpy(page_address(bvec.bv_page) +
- bvec.bv_offset, pci_addr_in +
- offset, bytes_to_copy);
- break;
- } else {
- memcpy(page_address(bvec.bv_page) +
- bvec.bv_offset, pci_addr_in +
- offset, bvec.bv_len);
- bytes_to_copy -= bvec.bv_len;
- }
- offset += bvec.bv_len;
- }
- }
- } else {
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s - no reply\n", ioc->name, __func__));
- rc = -ENXIO;
- }
-
- issue_host_reset:
- if (issue_reset) {
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = -ETIMEDOUT;
- }
-
- unmap:
- if (dma_addr_out)
- pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
- PCI_DMA_BIDIRECTIONAL);
- if (dma_addr_in)
- pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
- PCI_DMA_BIDIRECTIONAL);
-
- free_pci:
- if (pci_addr_out)
- pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out,
- pci_dma_out);
-
- if (pci_addr_in)
- pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in,
- pci_dma_in);
-
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-struct sas_function_template mpt2sas_transport_functions = {
- .get_linkerrors = _transport_get_linkerrors,
- .get_enclosure_identifier = _transport_get_enclosure_identifier,
- .get_bay_identifier = _transport_get_bay_identifier,
- .phy_reset = _transport_phy_reset,
- .phy_enable = _transport_phy_enable,
- .set_phy_speed = _transport_phy_speed,
- .smp_handler = _transport_smp_handler,
-};
-
-struct scsi_transport_template *mpt2sas_transport_template;
diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig
index 4d235dd..b736dbc 100644
--- a/drivers/scsi/mpt3sas/Kconfig
+++ b/drivers/scsi/mpt3sas/Kconfig
@@ -41,15 +41,15 @@
# USA.
config SCSI_MPT3SAS
- tristate "LSI MPT Fusion SAS 3.0 Device Driver"
+ tristate "LSI MPT Fusion SAS 3.0 & SAS 2.0 Device Driver"
depends on PCI && SCSI
select SCSI_SAS_ATTRS
select RAID_ATTRS
---help---
This driver supports PCI-Express SAS 12Gb/s Host Adapters.
-config SCSI_MPT3SAS_MAX_SGE
- int "LSI MPT Fusion Max number of SG Entries (16 - 256)"
+config SCSI_MPT2SAS_MAX_SGE
+ int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)"
depends on PCI && SCSI && SCSI_MPT3SAS
default "128"
range 16 256
@@ -60,8 +60,23 @@ config SCSI_MPT3SAS_MAX_SGE
can be 256. However, it may decreased down to 16. Decreasing this
parameter will reduce memory requirements on a per controller instance.
-config SCSI_MPT3SAS_LOGGING
- bool "LSI MPT Fusion logging facility"
+config SCSI_MPT3SAS_MAX_SGE
+ int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)"
depends on PCI && SCSI && SCSI_MPT3SAS
+ default "128"
+ range 16 256
+ ---help---
+ This option allows you to specify the maximum number of scatter-
+ gather entries per I/O. The driver default is 128, which matches
+ MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this
+ can be 256. However, it may decreased down to 16. Decreasing this
+ parameter will reduce memory requirements on a per controller instance.
+
+config SCSI_MPT2SAS
+ tristate "Legacy MPT2SAS config option"
+ default n
+ select SCSI_MPT3SAS
+ depends on PCI && SCSI
---help---
- This turns on a logging facility.
+ Dummy config option for backwards compatiblity: configure the MPT3SAS
+ driver instead.
diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile
index efb0c4c..b7643f5 100644
--- a/drivers/scsi/mpt3sas/Makefile
+++ b/drivers/scsi/mpt3sas/Makefile
@@ -5,4 +5,5 @@ mpt3sas-y += mpt3sas_base.o \
mpt3sas_scsih.o \
mpt3sas_transport.o \
mpt3sas_ctl.o \
- mpt3sas_trigger_diag.o
+ mpt3sas_trigger_diag.o \
+ mpt3sas_warpdrive.o
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h
index ec27ad2..dfad5b8 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.35
+ * mpi2.h Version: 02.00.39
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -92,6 +92,14 @@
* 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
* 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT
* 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-18-14 02.00.36 Updated copyright information.
+ * Bumped MPI2_HEADER_VERSION_UNIT.
+ * 03-16-15 02.00.37 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added Scratchpad registers to
+ * MPI2_SYSTEM_INTERFACE_REGS.
+ * Added MPI2_DIAG_SBR_RELOAD.
+ * 03-19-15 02.00.38 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-25-15 02.00.39 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -124,8 +132,14 @@
MPI25_VERSION_MINOR)
#define MPI2_VERSION_02_05 (0x0205)
+/*minor version for MPI v2.6 compatible products */
+#define MPI26_VERSION_MINOR (0x06)
+#define MPI26_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+ MPI26_VERSION_MINOR)
+#define MPI2_VERSION_02_06 (0x0206)
+
/*Unit and Dev versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x23)
+#define MPI2_HEADER_VERSION_UNIT (0x27)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -179,10 +193,12 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
U32 HCBSize; /*0x74 */
U32 HCBAddressLow; /*0x78 */
U32 HCBAddressHigh; /*0x7C */
- U32 Reserved6[16]; /*0x80 */
+ U32 Reserved6[12]; /*0x80 */
+ U32 Scratchpad[4]; /*0xB0 */
U32 RequestDescriptorPostLow; /*0xC0 */
U32 RequestDescriptorPostHigh; /*0xC4 */
- U32 Reserved7[14]; /*0xC8 */
+ U32 AtomicRequestDescriptorPost;/*0xC8 */
+ U32 Reserved7[13]; /*0xCC */
} MPI2_SYSTEM_INTERFACE_REGS,
*PTR_MPI2_SYSTEM_INTERFACE_REGS,
Mpi2SystemInterfaceRegs_t,
@@ -224,6 +240,8 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
*/
#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008)
+#define MPI2_DIAG_SBR_RELOAD (0x00002000)
+
#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800)
#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000)
#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800)
@@ -298,10 +316,19 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS {
#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C)
/*
- *Offsets for the Request Queue
+ *Offsets for the Scratchpad registers
+ */
+#define MPI26_SCRATCHPAD0_OFFSET (0x000000B0)
+#define MPI26_SCRATCHPAD1_OFFSET (0x000000B4)
+#define MPI26_SCRATCHPAD2_OFFSET (0x000000B8)
+#define MPI26_SCRATCHPAD3_OFFSET (0x000000BC)
+
+/*
+ *Offsets for the Request Descriptor Post Queue
*/
#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0)
#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4)
+#define MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET (0x000000C8)
/*Hard Reset delay timings */
#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000)
@@ -329,7 +356,8 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR {
*pMpi2DefaultRequestDescriptor_t;
/*defines for the RequestFlags field */
-#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x1E)
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_RSHIFT (1)
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02)
#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
@@ -337,7 +365,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR {
#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A)
#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO (0x0C)
-#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
/*High Priority Request Descriptor */
typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR {
@@ -408,6 +436,33 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION {
Mpi2RequestDescriptorUnion_t,
*pMpi2RequestDescriptorUnion_t;
+/*Atomic Request Descriptors */
+
+/*
+ * All Atomic Request Descriptors have the same format, so the following
+ * structure is used for all Atomic Request Descriptors:
+ * Atomic Default Request Descriptor
+ * Atomic High Priority Request Descriptor
+ * Atomic SCSI IO Request Descriptor
+ * Atomic SCSI Target Request Descriptor
+ * Atomic RAID Accelerator Request Descriptor
+ * Atomic Fast Path SCSI IO Request Descriptor
+ */
+
+/*Atomic Request Descriptor */
+typedef struct _MPI26_ATOMIC_REQUEST_DESCRIPTOR {
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+} MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+ *PTR_MPI26_ATOMIC_REQUEST_DESCRIPTOR,
+ Mpi26AtomicRequestDescriptor_t,
+ *pMpi26AtomicRequestDescriptor_t;
+
+/*for the RequestFlags field, use the same
+ *defines as MPI2_DEFAULT_REQUEST_DESCRIPTOR
+ */
+
/*Reply Descriptors */
/*Default Reply Descriptor */
@@ -548,6 +603,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION {
#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18)
#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A)
#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B)
+#define MPI2_FUNCTION_IO_UNIT_CONTROL (0x1B)
#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C)
#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D)
#define MPI2_FUNCTION_DIAG_RELEASE (0x1E)
@@ -587,6 +643,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION {
#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007)
#define MPI2_IOCSTATUS_INVALID_STATE (0x0008)
#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009)
+#define MPI2_IOCSTATUS_INSUFFICIENT_POWER (0x000A)
/****************************************************************************
* Config IOCStatus values
@@ -1045,7 +1102,7 @@ typedef union _MPI2_IEEE_SGE_CHAIN_UNION {
Mpi2IeeeSgeChainUnion_t,
*pMpi2IeeeSgeChainUnion_t;
-/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 products only */
+/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 and later */
typedef struct _MPI25_IEEE_SGE_CHAIN64 {
U64 Address;
U32 Length;
@@ -1098,6 +1155,11 @@ typedef union _MPI25_SGE_IO_UNION {
#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00)
#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
+/*Next Segment Format */
+
+#define MPI26_IEEE_SGE_FLAGS_NSF_MASK (0x1C)
+#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE (0x00)
+
/*Data Location Address Space */
#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03)
@@ -1108,6 +1170,7 @@ typedef union _MPI25_SGE_IO_UNION {
#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03)
#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \
(MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR)
+#define MPI26_IEEE_SGE_FLAGS_IOCCTL_ADDR (0x02)
/****************************************************************************
* IEEE SGE operation Macros
@@ -1166,6 +1229,7 @@ typedef union _MPI2_SGE_IO_UNION {
#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00)
#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04)
#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08)
+#define MPI26_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08)
#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C)
/*values for SGL Type subfield */
#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03)
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
index 581fdb3..9cf09bf 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_cnfg.h
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.29
+ * mpi2_cnfg.h Version: 02.00.33
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -178,7 +178,14 @@
* 01-08-14 02.00.28 Added more defines for the BiosOptions field of
* MPI2_CONFIG_PAGE_BIOS_1.
* 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and
- * more defines for the BiosOptions field..
+ * more defines for the BiosOptions field.
+ * 11-18-14 02.00.30 Updated copyright information.
+ * Added MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG.
+ * Added AdapterOrderAux fields to BIOS Page 3.
+ * 03-16-15 02.00.31 Updated for MPI v2.6.
+ * Added new SAS Phy Event codes
+ * 05-25-15 02.00.33 Added more defines for the BiosOptions field of
+ * MPI2_CONFIG_PAGE_BIOS_1.
* --------------------------------------------------------------------------
*/
@@ -355,7 +362,6 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION {
#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
-
/****************************************************************************
* Configuration messages
****************************************************************************/
@@ -457,8 +463,17 @@ typedef struct _MPI2_CONFIG_REPLY {
#define MPI25_MFGPAGE_DEVID_SAS3108_5 (0x0094)
#define MPI25_MFGPAGE_DEVID_SAS3108_6 (0x0095)
-
-
+/* MPI v2.6 SAS Products */
+#define MPI26_MFGPAGE_DEVID_SAS3216 (0x00C9)
+#define MPI26_MFGPAGE_DEVID_SAS3224 (0x00C4)
+#define MPI26_MFGPAGE_DEVID_SAS3316_1 (0x00C5)
+#define MPI26_MFGPAGE_DEVID_SAS3316_2 (0x00C6)
+#define MPI26_MFGPAGE_DEVID_SAS3316_3 (0x00C7)
+#define MPI26_MFGPAGE_DEVID_SAS3316_4 (0x00C8)
+#define MPI26_MFGPAGE_DEVID_SAS3324_1 (0x00C0)
+#define MPI26_MFGPAGE_DEVID_SAS3324_2 (0x00C1)
+#define MPI26_MFGPAGE_DEVID_SAS3324_3 (0x00C2)
+#define MPI26_MFGPAGE_DEVID_SAS3324_4 (0x00C3)
/*Manufacturing Page 0 */
@@ -941,8 +956,8 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
U8
BoardTemperatureUnits; /*0x16 */
U8 Reserved3; /*0x17 */
- U32 Reserved4; /* 0x18 */
- U32 Reserved5; /* 0x1C */
+ U32 BoardPowerRequirement; /*0x18 */
+ U32 PCISlotPowerAllocation; /*0x1C */
U32 Reserved6; /* 0x20 */
U32 Reserved7; /* 0x24 */
} MPI2_CONFIG_PAGE_IO_UNIT_7,
@@ -1151,6 +1166,62 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 {
#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01)
+/* IO Unit Page 11 (for MPI v2.6 and later) */
+
+typedef struct _MPI26_IOUNIT11_SPINUP_GROUP {
+ U8 MaxTargetSpinup; /* 0x00 */
+ U8 SpinupDelay; /* 0x01 */
+ U8 SpinupFlags; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+} MPI26_IOUNIT11_SPINUP_GROUP,
+ *PTR_MPI26_IOUNIT11_SPINUP_GROUP,
+ Mpi26IOUnit11SpinupGroup_t,
+ *pMpi26IOUnit11SpinupGroup_t;
+
+/* defines for IO Unit Page 11 SpinupFlags */
+#define MPI26_IOUNITPAGE11_SPINUP_DISABLE_FLAG (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * four and check the value returned for NumPhys at runtime.
+ */
+#ifndef MPI26_IOUNITPAGE11_PHY_MAX
+#define MPI26_IOUNITPAGE11_PHY_MAX (4)
+#endif
+
+typedef struct _MPI26_CONFIG_PAGE_IO_UNIT_11 {
+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */
+ U32 Reserved1; /*0x04 */
+ MPI26_IOUNIT11_SPINUP_GROUP SpinupGroupParameters[4]; /*0x08 */
+ U32 Reserved2; /*0x18 */
+ U32 Reserved3; /*0x1C */
+ U32 Reserved4; /*0x20 */
+ U8 BootDeviceWaitTime; /*0x24 */
+ U8 Reserved5; /*0x25 */
+ U16 Reserved6; /*0x26 */
+ U8 NumPhys; /*0x28 */
+ U8 PEInitialSpinupDelay; /*0x29 */
+ U8 PEReplyDelay; /*0x2A */
+ U8 Flags; /*0x2B */
+ U8 PHY[MPI26_IOUNITPAGE11_PHY_MAX];/*0x2C */
+} MPI26_CONFIG_PAGE_IO_UNIT_11,
+ *PTR_MPI26_CONFIG_PAGE_IO_UNIT_11,
+ Mpi26IOUnitPage11_t,
+ *pMpi26IOUnitPage11_t;
+
+#define MPI26_IOUNITPAGE11_PAGEVERSION (0x00)
+
+/* defines for Flags field */
+#define MPI26_IOUNITPAGE11_FLAGS_AUTO_PORTENABLE (0x01)
+
+/* defines for PHY field */
+#define MPI26_IOUNITPAGE11_PHY_SPINUP_GROUP_MASK (0x03)
+
+
+
+
+
/****************************************************************************
* IOC Config Pages
@@ -1343,6 +1414,10 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 {
#define MPI2_BIOSPAGE1_PAGEVERSION (0x07)
/*values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_BOOT_LIST_ADD_ALT_BOOT_DEVICE (0x00008000)
+#define MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG (0x00004000)
+
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000)
#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800)
@@ -1492,6 +1567,8 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_2 {
/*BIOS Page 3 */
+#define MPI2_BIOSPAGE3_NUM_ADAPTER (4)
+
typedef struct _MPI2_ADAPTER_INFO {
U8 PciBusNumber; /*0x00 */
U8 PciDeviceAndFunctionNumber; /*0x01 */
@@ -1502,17 +1579,26 @@ typedef struct _MPI2_ADAPTER_INFO {
#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001)
#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002)
+typedef struct _MPI2_ADAPTER_ORDER_AUX {
+ U64 WWID; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+} MPI2_ADAPTER_ORDER_AUX, *PTR_MPI2_ADAPTER_ORDER_AUX,
+ Mpi2AdapterOrderAux_t, *pMpi2AdapterOrderAux_t;
+
+
typedef struct _MPI2_CONFIG_PAGE_BIOS_3 {
MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */
U32 GlobalFlags; /*0x04 */
U32 BiosVersion; /*0x08 */
- MPI2_ADAPTER_INFO AdapterOrder[4]; /*0x0C */
+ MPI2_ADAPTER_INFO AdapterOrder[MPI2_BIOSPAGE3_NUM_ADAPTER];
U32 Reserved1; /*0x1C */
+ MPI2_ADAPTER_ORDER_AUX AdapterOrderAux[MPI2_BIOSPAGE3_NUM_ADAPTER];
} MPI2_CONFIG_PAGE_BIOS_3,
*PTR_MPI2_CONFIG_PAGE_BIOS_3,
Mpi2BiosPage3_t, *pMpi2BiosPage3_t;
-#define MPI2_BIOSPAGE3_PAGEVERSION (0x00)
+#define MPI2_BIOSPAGE3_PAGEVERSION (0x01)
/*values for BIOS Page 3 GlobalFlags */
#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002)
@@ -2006,6 +2092,8 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 {
#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01)
/*values for SAS IO Unit Page 0 PhyFlags */
+#define MPI2_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40)
+#define MPI2_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20)
#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10)
#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
@@ -2108,6 +2196,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 {
#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
/*values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI2_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100)
#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080)
#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020)
@@ -2125,6 +2214,8 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 {
#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01)
/*values for SAS IO Unit Page 1 PhyFlags */
+#define MPI2_SASIOUNIT1_PHYFLAGS_INIT_PERSIST_CONNECT (0x40)
+#define MPI2_SASIOUNIT1_PHYFLAGS_TARG_PERSIST_CONNECT (0x20)
#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10)
#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
@@ -2144,7 +2235,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 {
*SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
-/*SAS IO Unit Page 4 */
+/*SAS IO Unit Page 4 (for MPI v2.5 and earlier) */
typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP {
U8 MaxTargetSpinup; /*0x00 */
@@ -2715,6 +2806,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 {
#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
+#define MPI2_SAS_DEVICE0_FLAGS_PERSIST_CAPABLE (0x0004)
#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002)
#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
@@ -2922,6 +3014,19 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG {
#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1)
#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2)
+/*Following codes are product specific and in MPI v2.6 and later */
+#define MPI2_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xD3)
+#define MPI2_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xD4)
+#define MPI2_SASPHY3_EVENT_CODE_LCCONN_TIME (0xD5)
+#define MPI2_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xD6)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_TX_START (0xD7)
+#define MPI2_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xD8)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xD9)
+#define MPI2_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xDA)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xDB)
+#define MPI2_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xDC)
+
+
/*values for the CounterType field */
#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_init.h b/drivers/scsi/mpt3sas/mpi/mpi2_init.h
index 068c98e..c38f624 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_init.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_init.h
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.15
+ * mpi2_init.h Version: 02.00.17
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -46,6 +46,11 @@
* 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.
* 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY,
* replacing the Reserved4 field.
+ * 11-18-14 02.00.16 Updated copyright information.
+ * 03-16-15 02.00.17 Updated for MPI v2.6.
+ * Added MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH.
+ * Added MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF and
+ * MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF.
* --------------------------------------------------------------------------
*/
@@ -128,6 +133,7 @@ typedef struct _MPI2_SCSI_IO_REQUEST {
#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04)
#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08)
#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C)
+#define MPI26_SCSIIO_MSGFLAGS_IOCCTL_SENSE_ADDR (0x08)
/*SCSI IO SGLFlags bits */
@@ -228,7 +234,7 @@ typedef union _MPI25_SCSI_IO_CDB_UNION {
} MPI25_SCSI_IO_CDB_UNION, *PTR_MPI25_SCSI_IO_CDB_UNION,
Mpi25ScsiIoCdb_t, *pMpi25ScsiIoCdb_t;
-/*MPI v2.5 SCSI IO Request Message */
+/*MPI v2.5/2.6 SCSI IO Request Message */
typedef struct _MPI25_SCSI_IO_REQUEST {
U16 DevHandle; /*0x00 */
U8 ChainOffset; /*0x02 */
@@ -302,12 +308,14 @@ typedef struct _MPI25_SCSI_IO_REQUEST {
#define MPI25_SCSIIO_NUM_SGLOFFSETS (4)
/*defines for the IoFlags field */
-#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000)
-#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000)
-#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000)
+#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000)
+#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000)
+#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000)
+#define MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH (0x2000)
#define MPI25_SCSIIO_IOFLAGS_LARGE_CDB (0x1000)
#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800)
+#define MPI26_SCSIIO_IOFLAGS_PORT_REQUEST (0x0400)
#define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF)
/*MPI v2.5 defines for the EEDPFlags bits */
@@ -512,6 +520,7 @@ typedef struct _MPI2_SEP_REQUEST {
#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01)
/*SlotStatus defines */
+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF (0x00080000)
#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000)
#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
@@ -547,6 +556,7 @@ typedef struct _MPI2_SEP_REPLY {
Mpi2SepReply_t, *pMpi2SepReply_t;
/*SlotStatus defines */
+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF (0x00080000)
#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000)
#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
index d7598cc..cf510ed 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.24
+ * mpi2_ioc.h Version: 02.00.26
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -133,6 +133,10 @@
* Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
* Added Encrypted Hash Extended Image.
* 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
+ * 11-18-14 02.00.25 Updated copyright information.
+ * 03-16-15 02.00.26 Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and
+ * MPI26_FW_HEADER_PID_FAMILY_3516_SAS.
+ * Added MPI26_CTRL_OP_SHUTDOWN.
* --------------------------------------------------------------------------
*/
@@ -165,7 +169,7 @@ typedef struct _MPI2_IOC_INIT_REQUEST {
U16 HeaderVersion; /*0x0E */
U32 Reserved5; /*0x10 */
U16 Reserved6; /*0x14 */
- U8 Reserved7; /*0x16 */
+ U8 HostPageSize; /*0x16 */
U8 HostMSIxVectors; /*0x17 */
U16 Reserved8; /*0x18 */
U16 SystemRequestFrameSize; /*0x1A */
@@ -289,7 +293,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
U16 MaxDevHandle; /*0x38 */
U16 MaxPersistentEntries; /*0x3A */
U16 MinDevHandle; /*0x3C */
- U16 Reserved4; /*0x3E */
+ U8 CurrentHostPageSize; /* 0x3E */
+ U8 Reserved4; /* 0x3F */
} MPI2_IOC_FACTS_REPLY, *PTR_MPI2_IOC_FACTS_REPLY,
Mpi2IOCFactsReply_t, *pMpi2IOCFactsReply_t;
@@ -326,6 +331,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
/*ProductID field uses MPI2_FW_HEADER_PID_ */
/*IOCCapabilities */
+#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000)
#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000)
#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
@@ -343,8 +349,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
/*ProtocolFlags */
-#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002)
+#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
/****************************************************************************
* PortFacts message
@@ -1247,6 +1253,7 @@ typedef struct _MPI2_FW_UPLOAD_REQUEST {
#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09)
#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
+#define MPI2_FW_UPLOAD_ITYPE_CBB_BACKUP (0x0D)
/*MPI v2.0 FWUpload TransactionContext Element */
typedef struct _MPI2_FW_UPLOAD_TCSGE {
@@ -1328,7 +1335,7 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
U32 Reserved54; /*0x54 */
U32 Reserved58; /*0x58 */
U32 Reserved5C; /*0x5C */
- U32 Reserved60; /*0x60 */
+ U32 BootFlags; /*0x60 */
U32 FirmwareVersionNameWhat; /*0x64 */
U8 FirmwareVersionName[32]; /*0x68 */
U32 VendorNameWhat; /*0x88 */
@@ -1354,18 +1361,22 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00)
#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000)
#define MPI2_FW_HEADER_SIGNATURE (0xEA000000)
+#define MPI26_FW_HEADER_SIGNATURE (0xEB000000)
/*Signature0 field */
#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04)
#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A)
+#define MPI26_FW_HEADER_SIGNATURE0 (0x5AEAA55A)
/*Signature1 field */
#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08)
#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5)
+#define MPI26_FW_HEADER_SIGNATURE1 (0xA55AEAA5)
/*Signature2 field */
#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C)
#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA)
+#define MPI26_FW_HEADER_SIGNATURE2 (0x5AA55AEA)
/*defines for using the ProductID field */
#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000)
@@ -1381,6 +1392,8 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013)
#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014)
#define MPI25_FW_HEADER_PID_FAMILY_3108_SAS (0x0021)
+#define MPI26_FW_HEADER_PID_FAMILY_3324_SAS (0x0028)
+#define MPI26_FW_HEADER_PID_FAMILY_3516_SAS (0x0031)
/*use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
@@ -1388,6 +1401,7 @@ typedef struct _MPI2_FW_IMAGE_HEADER {
#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C)
#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30)
+#define MPI26_FW_HEADER_BOOTFLAGS_OFFSET (0x60)
#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64)
#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840)
@@ -1493,7 +1507,9 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA {
#define MPI2_FLASH_REGION_CONFIG_1 (0x07)
#define MPI2_FLASH_REGION_CONFIG_2 (0x08)
#define MPI2_FLASH_REGION_MEGARAID (0x09)
-#define MPI2_FLASH_REGION_INIT (0x0A)
+#define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK (0x0A)
+#define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK)
+#define MPI2_FLASH_REGION_CBB_BACKUP (0x0D)
/*ImageRevision */
#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
@@ -1619,7 +1635,6 @@ typedef struct _MPI25_ENCRYPTED_HASH_DATA {
Mpi25EncryptedHashData_t, *pMpi25EncryptedHashData_t;
-
/****************************************************************************
* PowerManagementControl message
****************************************************************************/
@@ -1726,4 +1741,90 @@ typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY {
} MPI2_PWR_MGMT_CONTROL_REPLY, *PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
Mpi2PwrMgmtControlReply_t, *pMpi2PwrMgmtControlReply_t;
+/****************************************************************************
+* IO Unit Control messages (MPI v2.6 and later only.)
+****************************************************************************/
+
+/* IO Unit Control Request Message */
+typedef struct _MPI26_IOUNIT_CONTROL_REQUEST {
+ U8 Operation; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 DevHandle; /* 0x04 */
+ U8 IOCParameter; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U16 Reserved4; /* 0x0C */
+ U8 PhyNum; /* 0x0E */
+ U8 PrimFlags; /* 0x0F */
+ U32 Primitive; /* 0x10 */
+ U8 LookupMethod; /* 0x14 */
+ U8 Reserved5; /* 0x15 */
+ U16 SlotNumber; /* 0x16 */
+ U64 LookupAddress; /* 0x18 */
+ U32 IOCParameterValue; /* 0x20 */
+ U32 Reserved7; /* 0x24 */
+ U32 Reserved8; /* 0x28 */
+} MPI26_IOUNIT_CONTROL_REQUEST,
+ *PTR_MPI26_IOUNIT_CONTROL_REQUEST,
+ Mpi26IoUnitControlRequest_t,
+ *pMpi26IoUnitControlRequest_t;
+
+/* values for the Operation field */
+#define MPI26_CTRL_OP_CLEAR_ALL_PERSISTENT (0x02)
+#define MPI26_CTRL_OP_SAS_PHY_LINK_RESET (0x06)
+#define MPI26_CTRL_OP_SAS_PHY_HARD_RESET (0x07)
+#define MPI26_CTRL_OP_PHY_CLEAR_ERROR_LOG (0x08)
+#define MPI26_CTRL_OP_SAS_SEND_PRIMITIVE (0x0A)
+#define MPI26_CTRL_OP_FORCE_FULL_DISCOVERY (0x0B)
+#define MPI26_CTRL_OP_REMOVE_DEVICE (0x0D)
+#define MPI26_CTRL_OP_LOOKUP_MAPPING (0x0E)
+#define MPI26_CTRL_OP_SET_IOC_PARAMETER (0x0F)
+#define MPI26_CTRL_OP_ENABLE_FP_DEVICE (0x10)
+#define MPI26_CTRL_OP_DISABLE_FP_DEVICE (0x11)
+#define MPI26_CTRL_OP_ENABLE_FP_ALL (0x12)
+#define MPI26_CTRL_OP_DISABLE_FP_ALL (0x13)
+#define MPI26_CTRL_OP_DEV_ENABLE_NCQ (0x14)
+#define MPI26_CTRL_OP_DEV_DISABLE_NCQ (0x15)
+#define MPI26_CTRL_OP_SHUTDOWN (0x16)
+#define MPI26_CTRL_OP_DEV_ENABLE_PERSIST_CONNECTION (0x17)
+#define MPI26_CTRL_OP_DEV_DISABLE_PERSIST_CONNECTION (0x18)
+#define MPI26_CTRL_OP_DEV_CLOSE_PERSIST_CONNECTION (0x19)
+#define MPI26_CTRL_OP_PRODUCT_SPECIFIC_MIN (0x80)
+
+/* values for the PrimFlags field */
+#define MPI26_CTRL_PRIMFLAGS_SINGLE (0x08)
+#define MPI26_CTRL_PRIMFLAGS_TRIPLE (0x02)
+#define MPI26_CTRL_PRIMFLAGS_REDUNDANT (0x01)
+
+/* values for the LookupMethod field */
+#define MPI26_CTRL_LOOKUP_METHOD_WWID_ADDRESS (0x01)
+#define MPI26_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT (0x02)
+#define MPI26_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03)
+
+
+/* IO Unit Control Reply Message */
+typedef struct _MPI26_IOUNIT_CONTROL_REPLY {
+ U8 Operation; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 DevHandle; /* 0x04 */
+ U8 IOCParameter; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved3; /* 0x0A */
+ U16 Reserved4; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+} MPI26_IOUNIT_CONTROL_REPLY,
+ *PTR_MPI26_IOUNIT_CONTROL_REPLY,
+ Mpi26IoUnitControlReply_t,
+ *pMpi26IoUnitControlReply_t;
+
+
#endif
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_raid.h b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
index 13d93ca..1c0eeee 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_raid.h
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.10
+ * mpi2_raid.h Version: 02.00.11
*
* Version History
* ---------------
@@ -31,6 +31,7 @@
* 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
* Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
* 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI.
+ * 11-18-14 02.00.11 Updated copyright information.
* --------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_sas.h b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
index 156e305..c10c2c0 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2015 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
- * mpi2_sas.h Version: 02.00.08
+ * mpi2_sas.h Version: 02.00.10
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@@ -32,6 +32,9 @@
* Passthrough Request message.
* 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete
* for anything newer than MPI v2.0.
+ * 11-18-14 02.00.09 Updated copyright information.
+ * 03-16-15 02.00.10 Updated for MPI v2.6.
+ * Added MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA.
* --------------------------------------------------------------------------
*/
@@ -183,6 +186,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST {
/*values for PassthroughFlags field */
#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100)
+#define MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA (0x0040)
#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020)
#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010)
#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004)
@@ -216,6 +220,8 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REPLY {
/****************************************************************************
* SAS IO Unit Control messages
+* (MPI v2.5 and earlier only.
+* Replaced by IO Unit Control messages in MPI v2.6 and later.)
****************************************************************************/
/*SAS IO Unit Control Request Message */
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
index 1629e5b..5f9289a 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_tool.h
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.12
+ * mpi2_tool.h Version: 02.00.13
*
* Version History
* ---------------
@@ -34,6 +34,7 @@
* it uses MPI Chain SGE as well as MPI Simple SGE.
* 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
* 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
+ * 11-18-14 02.00.13 Updated copyright information.
* --------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_type.h b/drivers/scsi/mpt3sas/mpi/mpi2_type.h
index 99ab093..92a81ab 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_type.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_type.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2014 LSI Corporation.
+ * Copyright 2000-2014 Avago Technologies. All rights reserved.
*
*
* Name: mpi2_type.h
* Title: MPI basic type definitions
* Creation Date: August 16, 2006
*
- * mpi2_type.h Version: 02.00.00
+ * mpi2_type.h Version: 02.00.01
*
* Version History
* ---------------
@@ -14,6 +14,7 @@
* Date Version Description
* -------- -------- ------------------------------------------------------
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 11-18-14 02.00.01 Updated copyright information.
* --------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index d4f1dcd..8c44b9c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -83,6 +83,10 @@ static int msix_disable = -1;
module_param(msix_disable, int, 0);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+static int smp_affinity_enable = 1;
+module_param(smp_affinity_enable, int, S_IRUGO);
+MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
+
static int max_msix_vectors = -1;
module_param(max_msix_vectors, int, 0);
MODULE_PARM_DESC(max_msix_vectors,
@@ -108,9 +112,12 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
if (ret)
return ret;
+ /* global ioc spinlock to protect controller list on list operations */
pr_info("setting fwfault_debug(%d)\n", mpt3sas_fwfault_debug);
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list)
ioc->fwfault_debug = mpt3sas_fwfault_debug;
+ spin_unlock(&gioc_lock);
return 0;
}
module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug,
@@ -157,7 +164,7 @@ _base_fault_reset_work(struct work_struct *work)
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->shost_recovery)
+ if (ioc->shost_recovery || ioc->pci_error_recovery)
goto rearm_timer;
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
@@ -166,6 +173,20 @@ _base_fault_reset_work(struct work_struct *work)
pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n",
ioc->name);
+ /* It may be possible that EEH recovery can resolve some of
+ * pci bus failure issues rather removing the dead ioc function
+ * by considering controller is in a non-operational state. So
+ * here priority is given to the EEH recovery. If it doesn't
+ * not resolve this issue, mpt3sas driver will consider this
+ * controller to non-operational state and remove the dead ioc
+ * function.
+ */
+ if (ioc->non_operational_loop++ < 5) {
+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock,
+ flags);
+ goto rearm_timer;
+ }
+
/*
* Call _scsih_flush_pending_cmds callback so that we flush all
* pending commands back to OS. This call is required to aovid
@@ -181,7 +202,7 @@ _base_fault_reset_work(struct work_struct *work)
ioc->remove_host = 1;
/*Remove the Dead Host */
p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc,
- "mpt3sas_dead_ioc_%d", ioc->id);
+ "%s_dead_ioc_%d", ioc->driver_name, ioc->id);
if (IS_ERR(p))
pr_err(MPT3SAS_FMT
"%s: Running mpt3sas_dead_ioc thread failed !!!!\n",
@@ -193,6 +214,8 @@ _base_fault_reset_work(struct work_struct *work)
return; /* don't rearm timer */
}
+ ioc->non_operational_loop = 0;
+
if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) {
rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
@@ -235,7 +258,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc)
INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
snprintf(ioc->fault_reset_work_q_name,
- sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
+ sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status",
+ ioc->driver_name, ioc->id);
ioc->fault_reset_work_q =
create_singlethread_workqueue(ioc->fault_reset_work_q_name);
if (!ioc->fault_reset_work_q) {
@@ -324,7 +348,6 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc)
panic("panic in %s\n", __func__);
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _base_sas_ioc_info - verbose translation of the ioc status
* @ioc: per adapter object
@@ -376,6 +399,9 @@ _base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
desc = "insufficient resources";
break;
+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
+ desc = "insufficient power";
+ break;
case MPI2_IOCSTATUS_INVALID_FIELD:
desc = "invalid field";
break;
@@ -578,7 +604,8 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
desc = "Device Status Change";
break;
case MPI2_EVENT_IR_OPERATION_STATUS:
- desc = "IR Operation Status";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Operation Status";
break;
case MPI2_EVENT_SAS_DISCOVERY:
{
@@ -609,16 +636,20 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
desc = "SAS Enclosure Device Status Change";
break;
case MPI2_EVENT_IR_VOLUME:
- desc = "IR Volume";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Volume";
break;
case MPI2_EVENT_IR_PHYSICAL_DISK:
- desc = "IR Physical Disk";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Physical Disk";
break;
case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- desc = "IR Configuration Change List";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Configuration Change List";
break;
case MPI2_EVENT_LOG_ENTRY_ADDED:
- desc = "Log Entry Added";
+ if (!ioc->hide_ir_msg)
+ desc = "Log Entry Added";
break;
case MPI2_EVENT_TEMP_THRESHOLD:
desc = "Temperature Threshold";
@@ -630,7 +661,6 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc);
}
-#endif
/**
* _base_sas_log_info - verbose translation of firmware log info
@@ -675,7 +705,10 @@ _base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info)
originator_str = "PL";
break;
case 2:
- originator_str = "IR";
+ if (!ioc->hide_ir_msg)
+ originator_str = "IR";
+ else
+ originator_str = "WarpDrive";
break;
}
@@ -710,13 +743,13 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
return;
}
ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
(ioc->logging_level & MPT_DEBUG_REPLY)) {
_base_sas_ioc_info(ioc , mpi_reply,
mpt3sas_base_get_msg_frame(ioc, smid));
}
-#endif
+
if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
loginfo = le32_to_cpu(mpi_reply->IOCLogInfo);
_base_sas_log_info(ioc, loginfo);
@@ -746,7 +779,7 @@ mpt3sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
- return 1;
+ return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
if (ioc->base_cmds.status == MPT3_CMD_NOT_USED)
return 1;
@@ -777,21 +810,32 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
Mpi2EventNotificationReply_t *mpi_reply;
Mpi2EventAckRequest_t *ack_request;
u16 smid;
+ struct _event_ack_list *delayed_event_ack;
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
if (!mpi_reply)
return 1;
if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
return 1;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
_base_display_event_data(ioc, mpi_reply);
-#endif
+
if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
goto out;
smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
if (!smid) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
+ delayed_event_ack = kzalloc(sizeof(*delayed_event_ack),
+ GFP_ATOMIC);
+ if (!delayed_event_ack)
+ goto out;
+ INIT_LIST_HEAD(&delayed_event_ack->list);
+ delayed_event_ack->Event = mpi_reply->Event;
+ delayed_event_ack->EventContext = mpi_reply->EventContext;
+ list_add_tail(&delayed_event_ack->list,
+ &ioc->delayed_event_ack_list);
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "DELAYED: EVENT ACK: event (0x%04x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->Event)));
goto out;
}
@@ -1009,6 +1053,12 @@ _base_interrupt(int irq, void *bus_id)
}
wmb();
+ if (ioc->is_warpdrive) {
+ writel(reply_q->reply_post_host_index,
+ ioc->reply_post_host_index[msix_index]);
+ atomic_dec(&reply_q->busy);
+ return IRQ_HANDLED;
+ }
/* Update Reply Post Host Index.
* For those HBA's which support combined reply queue feature
@@ -1316,10 +1366,154 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr)
u8 sgl_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
MPI25_IEEE_SGE_FLAGS_END_OF_LIST);
+
_base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1);
}
/**
+ * _base_build_sg_scmd - main sg creation routine
+ * @ioc: per adapter object
+ * @scmd: scsi command
+ * @smid: system request message index
+ * Context: none.
+ *
+ * The main routine that builds scatter gather table from a given
+ * scsi request sent via the .queuecommand main handler.
+ *
+ * Returns 0 success, anything else error
+ */
+static int
+_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd, u16 smid)
+{
+ Mpi2SCSIIORequest_t *mpi_request;
+ dma_addr_t chain_dma;
+ struct scatterlist *sg_scmd;
+ void *sg_local, *chain;
+ u32 chain_offset;
+ u32 chain_length;
+ u32 chain_flags;
+ int sges_left;
+ u32 sges_in_segment;
+ u32 sgl_flags;
+ u32 sgl_flags_last_element;
+ u32 sgl_flags_end_buffer;
+ struct chain_tracker *chain_req;
+
+ mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+
+ /* init scatter gather flags */
+ sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
+ if (scmd->sc_data_direction == DMA_TO_DEVICE)
+ sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
+ sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
+ << MPI2_SGE_FLAGS_SHIFT;
+ sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
+ << MPI2_SGE_FLAGS_SHIFT;
+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+
+ sg_scmd = scsi_sglist(scmd);
+ sges_left = scsi_dma_map(scmd);
+ if (sges_left < 0) {
+ sdev_printk(KERN_ERR, scmd->device,
+ "pci_map_sg failed: request for %d bytes!\n",
+ scsi_bufflen(scmd));
+ return -ENOMEM;
+ }
+
+ sg_local = &mpi_request->SGL;
+ sges_in_segment = ioc->max_sges_in_main_message;
+ if (sges_left <= sges_in_segment)
+ goto fill_in_last_segment;
+
+ mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
+ (sges_in_segment * ioc->sge_size))/4;
+
+ /* fill in main message segment when there is a chain following */
+ while (sges_in_segment) {
+ if (sges_in_segment == 1)
+ ioc->base_add_sg_single(sg_local,
+ sgl_flags_last_element | sg_dma_len(sg_scmd),
+ sg_dma_address(sg_scmd));
+ else
+ ioc->base_add_sg_single(sg_local, sgl_flags |
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += ioc->sge_size;
+ sges_left--;
+ sges_in_segment--;
+ }
+
+ /* initializing the chain flags and pointers */
+ chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
+ chain_req = _base_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
+ do {
+ sges_in_segment = (sges_left <=
+ ioc->max_sges_in_chain_message) ? sges_left :
+ ioc->max_sges_in_chain_message;
+ chain_offset = (sges_left == sges_in_segment) ?
+ 0 : (sges_in_segment * ioc->sge_size)/4;
+ chain_length = sges_in_segment * ioc->sge_size;
+ if (chain_offset) {
+ chain_offset = chain_offset <<
+ MPI2_SGE_CHAIN_OFFSET_SHIFT;
+ chain_length += ioc->sge_size;
+ }
+ ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
+ chain_length, chain_dma);
+ sg_local = chain;
+ if (!chain_offset)
+ goto fill_in_last_segment;
+
+ /* fill in chain segments */
+ while (sges_in_segment) {
+ if (sges_in_segment == 1)
+ ioc->base_add_sg_single(sg_local,
+ sgl_flags_last_element |
+ sg_dma_len(sg_scmd),
+ sg_dma_address(sg_scmd));
+ else
+ ioc->base_add_sg_single(sg_local, sgl_flags |
+ sg_dma_len(sg_scmd),
+ sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += ioc->sge_size;
+ sges_left--;
+ sges_in_segment--;
+ }
+
+ chain_req = _base_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
+ } while (1);
+
+
+ fill_in_last_segment:
+
+ /* fill the last segment */
+ while (sges_left) {
+ if (sges_left == 1)
+ ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ else
+ ioc->base_add_sg_single(sg_local, sgl_flags |
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += ioc->sge_size;
+ sges_left--;
+ }
+
+ return 0;
+}
+
+/**
* _base_build_sg_scmd_ieee - main sg creation routine for IEEE format
* @ioc: per adapter object
* @scmd: scsi command
@@ -1571,6 +1765,14 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
int base;
u16 message_control;
+ /* Check whether controller SAS2008 B0 controller,
+ * if it is SAS2008 B0 controller use IO-APIC instead of MSIX
+ */
+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 &&
+ ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) {
+ return -EINVAL;
+ }
+
base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
if (!base) {
dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n",
@@ -1579,9 +1781,19 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
}
/* get msix vector count */
-
- pci_read_config_word(ioc->pdev, base + 2, &message_control);
- ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+ /* NUMA_IO not supported for older controllers */
+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
+ ioc->msix_vector_count = 1;
+ else {
+ pci_read_config_word(ioc->pdev, base + 2, &message_control);
+ ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+ }
dinitprintk(ioc, pr_info(MPT3SAS_FMT
"msix is supported, vector_count(%d)\n",
ioc->name, ioc->msix_vector_count));
@@ -1604,9 +1816,10 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc)
list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
list_del(&reply_q->list);
- irq_set_affinity_hint(reply_q->vector, NULL);
- free_cpumask_var(reply_q->affinity_hint);
- synchronize_irq(reply_q->vector);
+ if (smp_affinity_enable) {
+ irq_set_affinity_hint(reply_q->vector, NULL);
+ free_cpumask_var(reply_q->affinity_hint);
+ }
free_irq(reply_q->vector, reply_q);
kfree(reply_q);
}
@@ -1636,22 +1849,26 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector)
reply_q->msix_index = index;
reply_q->vector = vector;
- if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL))
- return -ENOMEM;
- cpumask_clear(reply_q->affinity_hint);
+ if (smp_affinity_enable) {
+ if (!zalloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) {
+ kfree(reply_q);
+ return -ENOMEM;
+ }
+ }
atomic_set(&reply_q->busy, 0);
if (ioc->msix_enable)
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
- MPT3SAS_DRIVER_NAME, ioc->id, index);
+ ioc->driver_name, ioc->id, index);
else
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
- MPT3SAS_DRIVER_NAME, ioc->id);
+ ioc->driver_name, ioc->id);
r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
reply_q);
if (r) {
pr_err(MPT3SAS_FMT "unable to allocate interrupt %d!\n",
reply_q->name, vector);
+ free_cpumask_var(reply_q->affinity_hint);
kfree(reply_q);
return -EBUSY;
}
@@ -1701,16 +1918,17 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
for (i = 0 ; i < group ; i++) {
ioc->cpu_msix_table[cpu] = index;
- cpumask_or(reply_q->affinity_hint,
+ if (smp_affinity_enable)
+ cpumask_or(reply_q->affinity_hint,
reply_q->affinity_hint, get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
-
- if (irq_set_affinity_hint(reply_q->vector,
+ if (smp_affinity_enable)
+ if (irq_set_affinity_hint(reply_q->vector,
reply_q->affinity_hint))
- dinitprintk(ioc, pr_info(MPT3SAS_FMT
- "error setting affinity hint for irq vector %d\n",
- ioc->name, reply_q->vector));
+ dinitprintk(ioc, pr_info(MPT3SAS_FMT
+ "Err setting affinity hint to irq vector %d\n",
+ ioc->name, reply_q->vector));
index++;
}
}
@@ -1768,6 +1986,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
} else if (max_msix_vectors == 0)
goto try_ioapic;
+ if (ioc->msix_vector_count < ioc->cpu_count)
+ smp_affinity_enable = 0;
+
entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
GFP_KERNEL);
if (!entries) {
@@ -1827,8 +2048,10 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
_base_free_irq(ioc);
_base_disable_msix(ioc);
- if (ioc->msix96_vector)
+ if (ioc->msix96_vector) {
kfree(ioc->replyPostRegisterIndex);
+ ioc->replyPostRegisterIndex = NULL;
+ }
if (ioc->chip_phys) {
iounmap(ioc->chip);
@@ -1872,7 +2095,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
if (pci_request_selected_regions(pdev, ioc->bars,
- MPT3SAS_DRIVER_NAME)) {
+ ioc->driver_name)) {
pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
ioc->name);
ioc->bars = 0;
@@ -2036,6 +2259,12 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
}
+static inline u8
+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
+{
+ return ioc->cpu_msix_table[raw_smp_processor_id()];
+}
+
/**
* mpt3sas_base_get_smid - obtain a free smid from internal queue
* @ioc: per adapter object
@@ -2096,6 +2325,7 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
request->scmd = scmd;
request->cb_idx = cb_idx;
smid = request->smid;
+ request->msix_io = _base_get_msix_index(ioc);
list_del(&request->tracker_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
return smid;
@@ -2158,6 +2388,7 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].scmd = NULL;
+ ioc->scsi_lookup[i].direct_io = 0;
list_add(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
@@ -2217,12 +2448,6 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
}
#endif
-static inline u8
-_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
-{
- return ioc->cpu_msix_table[raw_smp_processor_id()];
-}
-
/**
* mpt3sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
* @ioc: per adapter object
@@ -2276,18 +2501,19 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
* mpt3sas_base_put_smid_hi_priority - send Task Managment request to firmware
* @ioc: per adapter object
* @smid: system request message index
- *
+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
* Return nothing.
*/
void
-mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 msix_task)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.HighPriority.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
- descriptor.HighPriority.MSIxIndex = 0;
+ descriptor.HighPriority.MSIxIndex = msix_task;
descriptor.HighPriority.SMID = cpu_to_le16(smid);
descriptor.HighPriority.LMID = 0;
descriptor.HighPriority.Reserved1 = 0;
@@ -2318,143 +2544,261 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
/**
- * _base_display_intel_branding - Display branding string
+ * _base_display_OEMs_branding - Display branding string
* @ioc: per adapter object
*
* Return nothing.
*/
static void
-_base_display_intel_branding(struct MPT3SAS_ADAPTER *ioc)
+_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
{
if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL)
return;
- switch (ioc->pdev->device) {
- case MPI25_MFGPAGE_DEVID_SAS3008:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_INTEL_RMS3JC080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RMS3JC080_BRANDING);
- break;
-
- case MPT3SAS_INTEL_RS3GC008_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3GC008_BRANDING);
- break;
- case MPT3SAS_INTEL_RS3FC044_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3FC044_BRANDING);
- break;
- case MPT3SAS_INTEL_RS3UC080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3UC080_BRANDING);
+ switch (ioc->pdev->subsystem_vendor) {
+ case PCI_VENDOR_ID_INTEL:
+ switch (ioc->pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SAS2008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_INTEL_RMS2LL080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS2LL080_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS2LL040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS2LL040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_SSD910_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_SSD910_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ case MPI2_MFGPAGE_DEVID_SAS2308_2:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_INTEL_RS25GB008_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RS25GB008_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25JB080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25JB080_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25JB040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25JB040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25KB080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25KB080_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25KB040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25KB040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25LB040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25LB040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25LB080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25LB080_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_INTEL_RMS3JC080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RMS3JC080_BRANDING);
+ break;
+
+ case MPT3SAS_INTEL_RS3GC008_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RS3GC008_BRANDING);
+ break;
+ case MPT3SAS_INTEL_RS3FC044_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RS3FC044_BRANDING);
+ break;
+ case MPT3SAS_INTEL_RS3UC080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RS3UC080_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
default:
pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
break;
}
break;
- default:
- pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
- break;
- }
-}
-
-
-
-/**
- * _base_display_dell_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_dell_branding(struct MPT3SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL)
- return;
-
- switch (ioc->pdev->device) {
- case MPI25_MFGPAGE_DEVID_SAS3008:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_DELL_12G_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_DELL_12G_HBA_BRANDING);
+ case PCI_VENDOR_ID_DELL:
+ switch (ioc->pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SAS2008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_BRANDING);
+ break;
+ case MPT2SAS_DELL_6GBPS_SAS_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_6GBPS_SAS_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Dell 6Gbps HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ break;
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_DELL_12G_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_DELL_12G_HBA_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Dell 12Gbps HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
default:
pr_info(MPT3SAS_FMT
- "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name,
+ "Dell HBA: Subsystem ID: 0x%X\n", ioc->name,
ioc->pdev->subsystem_device);
break;
}
break;
- default:
- pr_info(MPT3SAS_FMT
- "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name,
- ioc->pdev->subsystem_device);
- break;
- }
-}
-
-/**
- * _base_display_cisco_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_CISCO)
- return;
-
- switch (ioc->pdev->device) {
- case MPI25_MFGPAGE_DEVID_SAS3008:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_CISCO_12G_8E_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
- break;
- case MPT3SAS_CISCO_12G_8I_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
+ case PCI_VENDOR_ID_CISCO:
+ switch (ioc->pdev->device) {
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_CISCO_12G_8E_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
+ break;
+ case MPT3SAS_CISCO_12G_8I_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
+ break;
+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
- case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ case MPI25_MFGPAGE_DEVID_SAS3108_1:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
+ break;
+ case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING
+ );
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
default:
pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ "Cisco SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
break;
}
break;
- case MPI25_MFGPAGE_DEVID_SAS3108_1:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
- break;
- case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING);
- break;
+ case MPT2SAS_HP_3PAR_SSVID:
+ switch (ioc->pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SAS2004:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ case MPI2_MFGPAGE_DEVID_SAS2308_2:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_HP_2_4_INTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_2_4_INTERNAL_BRANDING);
+ break;
+ case MPT2SAS_HP_2_4_EXTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_2_4_EXTERNAL_BRANDING);
+ break;
+ case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING);
+ break;
+ case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
default:
pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ "HP SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
break;
}
- break;
default:
- pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
break;
}
}
@@ -2488,9 +2832,7 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
(bios_version & 0x0000FF00) >> 8,
bios_version & 0x000000FF);
- _base_display_intel_branding(ioc);
- _base_display_dell_branding(ioc);
- _base_display_cisco_branding(ioc);
+ _base_display_OEMs_branding(ioc);
pr_info(MPT3SAS_FMT "Protocol=(", ioc->name);
@@ -2508,10 +2850,12 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
pr_info("), ");
pr_info("Capabilities=(");
- if (ioc->facts.IOCCapabilities &
+ if (!ioc->hide_ir_msg) {
+ if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
pr_info("Raid");
i++;
+ }
}
if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
@@ -2852,35 +3196,54 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/* command line tunables for max sgl entries */
if (max_sgl_entries != -1)
sg_tablesize = max_sgl_entries;
- else
- sg_tablesize = MPT3SAS_SG_DEPTH;
+ else {
+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ sg_tablesize = MPT2SAS_SG_DEPTH;
+ else
+ sg_tablesize = MPT3SAS_SG_DEPTH;
+ }
- if (sg_tablesize < MPT3SAS_MIN_PHYS_SEGMENTS)
- sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS;
- else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) {
+ if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS)
+ sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
+ else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) {
sg_tablesize = min_t(unsigned short, sg_tablesize,
SCSI_MAX_SG_CHAIN_SEGMENTS);
pr_warn(MPT3SAS_FMT
"sg_tablesize(%u) is bigger than kernel"
" defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name,
- sg_tablesize, MPT3SAS_MAX_PHYS_SEGMENTS);
+ sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
}
ioc->shost->sg_tablesize = sg_tablesize;
- ioc->hi_priority_depth = facts->HighPriorityCredit;
- ioc->internal_depth = ioc->hi_priority_depth + (5);
+ ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)),
+ (facts->RequestCredit / 4));
+ if (ioc->internal_depth < INTERNAL_CMDS_COUNT) {
+ if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT +
+ INTERNAL_SCSIIO_CMDS_COUNT)) {
+ pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \
+ Credits, it has just %d number of credits\n",
+ ioc->name, facts->RequestCredit);
+ return -ENOMEM;
+ }
+ ioc->internal_depth = 10;
+ }
+
+ ioc->hi_priority_depth = ioc->internal_depth - (5);
/* command line tunables for max controller queue depth */
if (max_queue_depth != -1 && max_queue_depth != 0) {
max_request_credit = min_t(u16, max_queue_depth +
- ioc->hi_priority_depth + ioc->internal_depth,
- facts->RequestCredit);
+ ioc->internal_depth, facts->RequestCredit);
if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
max_request_credit = MAX_HBA_QUEUE_DEPTH;
} else
max_request_credit = min_t(u16, facts->RequestCredit,
MAX_HBA_QUEUE_DEPTH);
- ioc->hba_queue_depth = max_request_credit;
+ /* Firmware maintains additional facts->HighPriorityCredit number of
+ * credits for HiPriprity Request messages, so hba queue depth will be
+ * sum of max_request_credit and high priority queue depth.
+ */
+ ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth;
/* request frame size */
ioc->request_sz = facts->IOCRequestFrameSize * 4;
@@ -2888,6 +3251,19 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/* reply frame size */
ioc->reply_sz = facts->ReplyFrameSize * 4;
+ /* chain segment size */
+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+ if (facts->IOCMaxChainSegmentSize)
+ ioc->chain_segment_sz =
+ facts->IOCMaxChainSegmentSize *
+ MAX_CHAIN_ELEMT_SZ;
+ else
+ /* set to 128 bytes size if IOCMaxChainSegmentSize is zero */
+ ioc->chain_segment_sz = DEFAULT_NUM_FWCHAIN_ELEMTS *
+ MAX_CHAIN_ELEMT_SZ;
+ } else
+ ioc->chain_segment_sz = ioc->request_sz;
+
/* calculate the max scatter element size */
sge_size = max_t(u16, ioc->sge_size, ioc->sge_size_ieee);
@@ -2899,7 +3275,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->max_sges_in_main_message = max_sge_elements/sge_size;
/* now do the same for a chain buffer */
- max_sge_elements = ioc->request_sz - sge_size;
+ max_sge_elements = ioc->chain_segment_sz - sge_size;
ioc->max_sges_in_chain_message = max_sge_elements/sge_size;
/*
@@ -2927,7 +3303,6 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->reply_post_queue_depth += 16 -
(ioc->reply_post_queue_depth % 16);
-
if (ioc->reply_post_queue_depth >
facts->MaxReplyDescriptorPostQueueDepth) {
ioc->reply_post_queue_depth =
@@ -3009,7 +3384,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/* set the scsi host can_queue depth
* with some internal commands that could be outstanding
*/
- ioc->shost->can_queue = ioc->scsiio_depth;
+ ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT;
dinitprintk(ioc, pr_info(MPT3SAS_FMT
"scsi host: can_queue depth (%d)\n",
ioc->name, ioc->shost->can_queue));
@@ -3036,8 +3411,9 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH)
goto out;
- retry_sz += 64;
- ioc->hba_queue_depth = max_request_credit - retry_sz;
+ retry_sz = 64;
+ ioc->hba_queue_depth -= retry_sz;
+ _base_release_memory_pools(ioc);
goto retry_allocation;
}
@@ -3092,7 +3468,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
goto out;
}
ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
- ioc->request_sz, 16, 0);
+ ioc->chain_segment_sz, 16, 0);
if (!ioc->chain_dma_pool) {
pr_err(MPT3SAS_FMT "chain_dma_pool: pci_pool_create failed\n",
ioc->name);
@@ -3106,13 +3482,13 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->chain_depth = i;
goto chain_done;
}
- total_sz += ioc->request_sz;
+ total_sz += ioc->chain_segment_sz;
}
chain_done:
dinitprintk(ioc, pr_info(MPT3SAS_FMT
"chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n",
- ioc->name, ioc->chain_depth, ioc->request_sz,
- ((ioc->chain_depth * ioc->request_sz))/1024));
+ ioc->name, ioc->chain_depth, ioc->chain_segment_sz,
+ ((ioc->chain_depth * ioc->chain_segment_sz))/1024));
/* initialize hi-priority queue smid's */
ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
@@ -3973,6 +4349,10 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
facts->IOCRequestFrameSize =
le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+ facts->IOCMaxChainSegmentSize =
+ le16_to_cpu(mpi_reply.IOCMaxChainSegmentSize);
+ }
facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
ioc->shost->max_id = -1;
@@ -4021,7 +4401,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
mpi_request.VF_ID = 0; /* TODO */
mpi_request.VP_ID = 0;
- mpi_request.MsgVersion = cpu_to_le16(MPI25_VERSION);
+ mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged);
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
if (_base_is_controller_msix_enabled(ioc))
@@ -4650,14 +5030,16 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
static int
_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
{
- int r, i;
+ int r, i, index;
unsigned long flags;
u32 reply_address;
u16 smid;
struct _tr_list *delayed_tr, *delayed_tr_next;
+ struct _sc_list *delayed_sc, *delayed_sc_next;
+ struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next;
+ u8 hide_flag;
struct adapter_reply_queue *reply_q;
- long reply_post_free;
- u32 reply_post_free_sz, index = 0;
+ Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig;
dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
@@ -4676,6 +5058,18 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
kfree(delayed_tr);
}
+ list_for_each_entry_safe(delayed_sc, delayed_sc_next,
+ &ioc->delayed_sc_list, list) {
+ list_del(&delayed_sc->list);
+ kfree(delayed_sc);
+ }
+
+ list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next,
+ &ioc->delayed_event_ack_list, list) {
+ list_del(&delayed_event_ack->list);
+ kfree(delayed_event_ack);
+ }
+
/* initialize the scsi lookup free list */
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
INIT_LIST_HEAD(&ioc->free_list);
@@ -4685,6 +5079,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].smid = smid;
ioc->scsi_lookup[i].scmd = NULL;
+ ioc->scsi_lookup[i].direct_io = 0;
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
&ioc->free_list);
}
@@ -4728,27 +5123,27 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
_base_assign_reply_queues(ioc);
/* initialize Reply Post Free Queue */
- reply_post_free_sz = ioc->reply_post_queue_depth *
- sizeof(Mpi2DefaultReplyDescriptor_t);
- reply_post_free = (long)ioc->reply_post[index].reply_post_free;
+ index = 0;
+ reply_post_free_contig = ioc->reply_post[0].reply_post_free;
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+ /*
+ * If RDPQ is enabled, switch to the next allocation.
+ * Otherwise advance within the contiguous region.
+ */
+ if (ioc->rdpq_array_enable) {
+ reply_q->reply_post_free =
+ ioc->reply_post[index++].reply_post_free;
+ } else {
+ reply_q->reply_post_free = reply_post_free_contig;
+ reply_post_free_contig += ioc->reply_post_queue_depth;
+ }
+
reply_q->reply_post_host_index = 0;
- reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
- reply_post_free;
for (i = 0; i < ioc->reply_post_queue_depth; i++)
reply_q->reply_post_free[i].Words =
cpu_to_le64(ULLONG_MAX);
if (!_base_is_controller_msix_enabled(ioc))
goto skip_init_reply_post_free_queue;
- /*
- * If RDPQ is enabled, switch to the next allocation.
- * Otherwise advance within the contiguous region.
- */
- if (ioc->rdpq_array_enable)
- reply_post_free = (long)
- ioc->reply_post[++index].reply_post_free;
- else
- reply_post_free += reply_post_free_sz;
}
skip_init_reply_post_free_queue:
@@ -4787,6 +5182,16 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
if (ioc->is_driver_loading) {
+
+ if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
+ == 0x80) {
+ hide_flag = (u8) (
+ le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) &
+ MFG_PAGE10_HIDE_SSDS_MASK);
+ if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK)
+ ioc->mfg_pg10_hide_flag = hide_flag;
+ }
+
ioc->wait_for_discovery_to_complete =
_base_determine_wait_on_discovery(ioc);
@@ -4812,6 +5217,8 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
+ /* synchronizing freeing resource with pci_access_mutex lock */
+ mutex_lock(&ioc->pci_access_mutex);
if (ioc->chip_phys && ioc->chip) {
_base_mask_interrupts(ioc);
ioc->shost_recovery = 1;
@@ -4820,6 +5227,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
}
mpt3sas_base_unmap_resources(ioc);
+ mutex_unlock(&ioc->pci_access_mutex);
return;
}
@@ -4834,7 +5242,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
{
int r, i;
int cpu_id, last_cpu_id = 0;
- u8 revision;
dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
@@ -4854,19 +5261,16 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
goto out_free_resources;
}
- /* Check whether the controller revision is C0 or above.
- * only C0 and above revision controllers support 96 MSI-X vectors.
- */
- revision = ioc->pdev->revision;
-
- if ((ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3004 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3008 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_1 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_2 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_5 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_6) &&
- (revision >= 0x02))
- ioc->msix96_vector = 1;
+ if (ioc->is_warpdrive) {
+ ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
+ sizeof(resource_size_t *), GFP_KERNEL);
+ if (!ioc->reply_post_host_index) {
+ dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation "
+ "for cpu_msix_table failed!!!\n", ioc->name));
+ r = -ENOMEM;
+ goto out_free_resources;
+ }
+ }
ioc->rdpq_array_enable_assigned = 0;
ioc->dma_mask = 0;
@@ -4874,23 +5278,42 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
if (r)
goto out_free_resources;
+ if (ioc->is_warpdrive) {
+ ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
+ &ioc->chip->ReplyPostHostIndex;
+
+ for (i = 1; i < ioc->cpu_msix_table_sz; i++)
+ ioc->reply_post_host_index[i] =
+ (resource_size_t __iomem *)
+ ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
+ * 4)));
+ }
pci_set_drvdata(ioc->pdev, ioc->shost);
r = _base_get_ioc_facts(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
- /*
- * In SAS3.0,
- * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
- * Target Status - all require the IEEE formated scatter gather
- * elements.
- */
-
- ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
- ioc->build_sg = &_base_build_sg_ieee;
- ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
- ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
+ ioc->build_sg_scmd = &_base_build_sg_scmd;
+ ioc->build_sg = &_base_build_sg;
+ ioc->build_zero_len_sge = &_base_build_zero_len_sge;
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
+ /*
+ * In SAS3.0,
+ * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
+ * Target Status - all require the IEEE formated scatter gather
+ * elements.
+ */
+ ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
+ ioc->build_sg = &_base_build_sg_ieee;
+ ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
+ ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
+ break;
+ }
/*
* These function pointers for other requests that don't
@@ -5006,6 +5429,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
if (r)
goto out_free_resources;
+ ioc->non_operational_loop = 0;
return 0;
out_free_resources:
@@ -5016,6 +5440,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
_base_release_memory_pools(ioc);
pci_set_drvdata(ioc->pdev, NULL);
kfree(ioc->cpu_msix_table);
+ if (ioc->is_warpdrive)
+ kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
kfree(ioc->blocking_handles);
kfree(ioc->tm_cmds.reply);
@@ -5055,6 +5481,8 @@ mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc)
_base_release_memory_pools(ioc);
pci_set_drvdata(ioc->pdev, NULL);
kfree(ioc->cpu_msix_table);
+ if (ioc->is_warpdrive)
+ kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
kfree(ioc->blocking_handles);
kfree(ioc->pfacts);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index f0e462b..32580b5 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -63,6 +63,8 @@
#include <scsi/scsi_transport_sas.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
#include "mpt3sas_debug.h"
#include "mpt3sas_trigger_diag.h"
@@ -71,23 +73,37 @@
#define MPT3SAS_DRIVER_NAME "mpt3sas"
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION "09.100.00.00"
-#define MPT3SAS_MAJOR_VERSION 9
+#define MPT3SAS_DRIVER_VERSION "12.100.00.00"
+#define MPT3SAS_MAJOR_VERSION 12
#define MPT3SAS_MINOR_VERSION 100
#define MPT3SAS_BUILD_VERSION 0
#define MPT3SAS_RELEASE_VERSION 00
+#define MPT2SAS_DRIVER_NAME "mpt2sas"
+#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
+#define MPT2SAS_DRIVER_VERSION "20.102.00.00"
+#define MPT2SAS_MAJOR_VERSION 20
+#define MPT2SAS_MINOR_VERSION 102
+#define MPT2SAS_BUILD_VERSION 0
+#define MPT2SAS_RELEASE_VERSION 00
+
/*
* Set MPT3SAS_SG_DEPTH value based on user input.
*/
-#define MPT3SAS_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS
-#define MPT3SAS_MIN_PHYS_SEGMENTS 16
+#define MPT_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS
+#define MPT_MIN_PHYS_SEGMENTS 16
+
#ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE
#define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE
#else
-#define MPT3SAS_SG_DEPTH MPT3SAS_MAX_PHYS_SEGMENTS
+#define MPT3SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS
#endif
+#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE
+#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE
+#else
+#define MPT2SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS
+#endif
/*
* Generic Defines
@@ -106,11 +122,16 @@
#define NO_SLEEP 0
#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
+/* reserved for issuing internally framed scsi io cmds */
+#define INTERNAL_SCSIIO_CMDS_COUNT 3
#define MPI3_HIM_MASK 0xFFFFFFFF /* mask every bit*/
#define MPT3SAS_INVALID_DEVICE_HANDLE 0xFFFF
+#define MAX_CHAIN_ELEMT_SZ 16
+#define DEFAULT_NUM_FWCHAIN_ELEMTS 8
+
/*
* reset phases
*/
@@ -124,6 +145,16 @@
#define MPT3SAS_FMT "%s: "
/*
+ * WarpDrive Specific Log codes
+ */
+
+#define MPT2_WARPDRIVE_LOGENTRY (0x8002)
+#define MPT2_WARPDRIVE_LC_SSDT (0x41)
+#define MPT2_WARPDRIVE_LC_SSDLW (0x43)
+#define MPT2_WARPDRIVE_LC_SSDLF (0x44)
+#define MPT2_WARPDRIVE_LC_BRMF (0x4D)
+
+/*
* per target private data
*/
#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01
@@ -131,9 +162,33 @@
#define MPT_TARGET_FLAGS_DELETED 0x04
#define MPT_TARGET_FASTPATH_IO 0x08
+#define SAS2_PCI_DEVICE_B0_REVISION (0x01)
+#define SAS3_PCI_DEVICE_C0_REVISION (0x02)
+
/*
* Intel HBA branding
*/
+#define MPT2SAS_INTEL_RMS25JB080_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25JB080"
+#define MPT2SAS_INTEL_RMS25JB040_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25JB040"
+#define MPT2SAS_INTEL_RMS25KB080_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25KB080"
+#define MPT2SAS_INTEL_RMS25KB040_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25KB040"
+#define MPT2SAS_INTEL_RMS25LB040_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25LB040"
+#define MPT2SAS_INTEL_RMS25LB080_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25LB080"
+#define MPT2SAS_INTEL_RMS2LL080_BRANDING \
+ "Intel Integrated RAID Module RMS2LL080"
+#define MPT2SAS_INTEL_RMS2LL040_BRANDING \
+ "Intel Integrated RAID Module RMS2LL040"
+#define MPT2SAS_INTEL_RS25GB008_BRANDING \
+ "Intel(R) RAID Controller RS25GB008"
+#define MPT2SAS_INTEL_SSD910_BRANDING \
+ "Intel(R) SSD 910 Series"
+
#define MPT3SAS_INTEL_RMS3JC080_BRANDING \
"Intel(R) Integrated RAID Module RMS3JC080"
#define MPT3SAS_INTEL_RS3GC008_BRANDING \
@@ -146,33 +201,62 @@
/*
* Intel HBA SSDIDs
*/
-#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521
-#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522
-#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523
-#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524
+#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516
+#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517
+#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518
+#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519
+#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A
+#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B
+#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E
+#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F
+#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000
+#define MPT2SAS_INTEL_SSD910_SSDID 0x3700
+
+#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521
+#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522
+#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523
+#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524
/*
* Dell HBA branding
*/
+#define MPT2SAS_DELL_BRANDING_SIZE 32
+
+#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA"
+#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter"
+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated"
+#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular"
+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded"
+#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200"
+#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS"
+
#define MPT3SAS_DELL_12G_HBA_BRANDING \
"Dell 12Gbps HBA"
/*
* Dell HBA SSDIDs
*/
-#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46
+#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C
+#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D
+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E
+#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F
+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20
+#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21
+#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22
+
+#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46
/*
* Cisco HBA branding
*/
#define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \
- "Cisco 9300-8E 12G SAS HBA"
+ "Cisco 9300-8E 12G SAS HBA"
#define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \
- "Cisco 9300-8i 12G SAS HBA"
+ "Cisco 9300-8i 12G SAS HBA"
#define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \
- "Cisco 12G Modular SAS Pass through Controller"
+ "Cisco 12G Modular SAS Pass through Controller"
#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \
- "UCS C3X60 12G SAS Pass through Controller"
+ "UCS C3X60 12G SAS Pass through Controller"
/*
* Cisco HBA SSSDIDs
*/
@@ -189,6 +273,31 @@
#define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04)
/*
+ * HP HBA branding
+ */
+#define MPT2SAS_HP_3PAR_SSVID 0x1590
+
+#define MPT2SAS_HP_2_4_INTERNAL_BRANDING \
+ "HP H220 Host Bus Adapter"
+#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING \
+ "HP H221 Host Bus Adapter"
+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING \
+ "HP H222 Host Bus Adapter"
+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING \
+ "HP H220i Host Bus Adapter"
+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING \
+ "HP H210i Host Bus Adapter"
+
+/*
+ * HO HBA SSDIDs
+ */
+#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041
+#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042
+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043
+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044
+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046
+
+/*
* Combined Reply Queue constants,
* There are twelve Supplemental Reply Post Host Index Registers
* and each register is at offset 0x10 bytes from the previous one.
@@ -243,20 +352,24 @@ struct Mpi2ManufacturingPage11_t {
* struct MPT3SAS_TARGET - starget private hostdata
* @starget: starget object
* @sas_address: target sas address
+ * @raid_device: raid_device pointer to access volume data
* @handle: device handle
* @num_luns: number luns
* @flags: MPT_TARGET_FLAGS_XXX flags
* @deleted: target flaged for deletion
* @tm_busy: target is busy with TM request.
+ * @sdev: The sas_device associated with this target
*/
struct MPT3SAS_TARGET {
struct scsi_target *starget;
u64 sas_address;
+ struct _raid_device *raid_device;
u16 handle;
int num_luns;
u32 flags;
u8 deleted;
u8 tm_busy;
+ struct _sas_device *sdev;
};
@@ -266,6 +379,11 @@ struct MPT3SAS_TARGET {
#define MPT_DEVICE_FLAGS_INIT 0x01
#define MPT_DEVICE_TLR_ON 0x02
+#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003)
+#define MFG_PAGE10_HIDE_ALL_DISKS (0x00)
+#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01)
+#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02)
+
/**
* struct MPT3SAS_DEVICE - sdev private hostdata
* @sas_target: starget private hostdata
@@ -285,6 +403,7 @@ struct MPT3SAS_DEVICE {
u8 configured_lun;
u8 block;
u8 tlr_snoop_check;
+ u8 ignore_delay_remove;
};
#define MPT3_CMD_NOT_USED 0x8000 /* free */
@@ -358,8 +477,24 @@ struct _sas_device {
u8 pend_sas_rphy_add;
u8 enclosure_level;
u8 connector_name[4];
+ struct kref refcount;
};
+static inline void sas_device_get(struct _sas_device *s)
+{
+ kref_get(&s->refcount);
+}
+
+static inline void sas_device_free(struct kref *r)
+{
+ kfree(container_of(r, struct _sas_device, refcount));
+}
+
+static inline void sas_device_put(struct _sas_device *s)
+{
+ kref_put(&s->refcount, sas_device_free);
+}
+
/**
* struct _raid_device - raid volume link list
* @list: sas device list
@@ -367,6 +502,7 @@ struct _sas_device {
* @sdev: scsi device struct (volumes are single lun)
* @wwid: unique identifier for the volume
* @handle: device handle
+ * @block_size: Block size of the volume
* @id: target id
* @channel: target channel
* @volume_type: the raid level
@@ -374,6 +510,13 @@ struct _sas_device {
* @num_pds: number of hidden raid components
* @responding: used in _scsih_raid_device_mark_responding
* @percent_complete: resync percent complete
+ * @direct_io_enabled: Whether direct io to PDs are allowed or not
+ * @stripe_exponent: X where 2powX is the stripe sz in blocks
+ * @block_exponent: X where 2powX is the block sz in bytes
+ * @max_lba: Maximum number of LBA in the volume
+ * @stripe_sz: Stripe Size of the volume
+ * @device_info: Device info of the volume member disk
+ * @pd_handle: Array of handles of the physical drives for direct I/O in le16
*/
#define MPT_MAX_WARPDRIVE_PDS 8
struct _raid_device {
@@ -382,13 +525,20 @@ struct _raid_device {
struct scsi_device *sdev;
u64 wwid;
u16 handle;
+ u16 block_sz;
int id;
int channel;
u8 volume_type;
u8 num_pds;
u8 responding;
u8 percent_complete;
+ u8 direct_io_enabled;
+ u8 stripe_exponent;
+ u8 block_exponent;
+ u64 max_lba;
+ u32 stripe_sz;
u32 device_info;
+ u16 pd_handle[MPT_MAX_WARPDRIVE_PDS];
};
/**
@@ -497,14 +647,18 @@ struct chain_tracker {
* @smid: system message id
* @scmd: scsi request pointer
* @cb_idx: callback index
+ * @direct_io: To indicate whether I/O is direct (WARPDRIVE)
* @tracker_list: list of free request (ioc->free_list)
+ * @msix_io: IO's msix
*/
struct scsiio_tracker {
u16 smid;
struct scsi_cmnd *scmd;
u8 cb_idx;
+ u8 direct_io;
struct list_head chain_list;
struct list_head tracker_list;
+ u16 msix_io;
};
/**
@@ -530,6 +684,25 @@ struct _tr_list {
u16 state;
};
+/**
+ * struct _sc_list - delayed SAS_IO_UNIT_CONTROL message list
+ * @handle: device handle
+ */
+struct _sc_list {
+ struct list_head list;
+ u16 handle;
+};
+
+/**
+ * struct _event_ack_list - delayed event acknowledgment list
+ * @Event: Event ID
+ * @EventContext: used to track the event uniquely
+ */
+struct _event_ack_list {
+ struct list_head list;
+ u16 Event;
+ u32 EventContext;
+};
/**
* struct adapter_reply_queue - the reply queue struct
@@ -591,7 +764,7 @@ struct mpt3sas_facts {
u32 IOCCapabilities;
union mpi3_version_union FWVersion;
u16 IOCRequestFrameSize;
- u16 Reserved3;
+ u16 IOCMaxChainSegmentSize;
u16 MaxInitiators;
u16 MaxTargets;
u16 MaxSasExpanders;
@@ -738,6 +911,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @max_sges_in_chain_message: number sg elements per chain
* @chains_needed_per_io: max chains per io
* @chain_depth: total chains allocated
+ * @chain_segment_sz: gives the max number of
+ * SGEs accommodate on single chain buffer
* @hi_priority_smid:
* @hi_priority:
* @hi_priority_dma:
@@ -775,7 +950,15 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @replyPostRegisterIndex: index of next position in Reply Desc Post Queue
* @delayed_tr_list: target reset link list
* @delayed_tr_volume_list: volume target reset link list
- * @@temp_sensors_count: flag to carry the number of temperature sensors
+ * @delayed_sc_list:
+ * @delayed_event_ack_list:
+ * @temp_sensors_count: flag to carry the number of temperature sensors
+ * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
+ * pci resource handling. PCI resource freeing will lead to free
+ * vital hardware/memory resource, which might be in use by cli/sysfs
+ * path functions resulting in Null pointer reference followed by kernel
+ * crash. To avoid the above race condition we use mutex syncrhonization
+ * which ensures the syncrhonization between cli/sysfs_show path.
*/
struct MPT3SAS_ADAPTER {
struct list_head list;
@@ -783,6 +966,7 @@ struct MPT3SAS_ADAPTER {
u8 id;
int cpu_count;
char name[MPT_NAME_LENGTH];
+ char driver_name[MPT_NAME_LENGTH];
char tmp_string[MPT_STRING_LENGTH];
struct pci_dev *pdev;
Mpi2SystemInterfaceRegs_t __iomem *chip;
@@ -829,8 +1013,10 @@ struct MPT3SAS_ADAPTER {
u16 msix_vector_count;
u8 *cpu_msix_table;
u16 cpu_msix_table_sz;
+ resource_size_t __iomem **reply_post_host_index;
u32 ioc_reset_count;
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
+ u32 non_operational_loop;
/* internal commands, callback index */
u8 scsi_io_cb_idx;
@@ -859,6 +1045,7 @@ struct MPT3SAS_ADAPTER {
MPT_BUILD_SG build_sg;
MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge;
u16 sge_size_ieee;
+ u16 hba_mpi_version_belonged;
/* function ptr for MPI sg elements only */
MPT_BUILD_SG build_sg_mpi;
@@ -933,6 +1120,7 @@ struct MPT3SAS_ADAPTER {
u16 max_sges_in_chain_message;
u16 chains_needed_per_io;
u32 chain_depth;
+ u16 chain_segment_sz;
/* hi-priority queue */
u16 hi_priority_smid;
@@ -986,7 +1174,10 @@ struct MPT3SAS_ADAPTER {
struct list_head delayed_tr_list;
struct list_head delayed_tr_volume_list;
+ struct list_head delayed_sc_list;
+ struct list_head delayed_event_ack_list;
u8 temp_sensors_count;
+ struct mutex pci_access_mutex;
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -998,6 +1189,10 @@ struct MPT3SAS_ADAPTER {
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
u32 ring_buffer_offset;
u32 ring_buffer_sz;
+ u8 is_warpdrive;
+ u8 hide_ir_msg;
+ u8 mfg_pg10_hide_flag;
+ u8 hide_drives;
spinlock_t diag_trigger_lock;
u8 diag_trigger_active;
struct SL_WH_MASTER_TRIGGER_T diag_trigger_master;
@@ -1012,6 +1207,19 @@ typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
/* base shared API */
extern struct list_head mpt3sas_ioc_list;
+extern char driver_name[MPT_NAME_LENGTH];
+/* spinlock on list operations over IOCs
+ * Case: when multiple warpdrive cards(IOCs) are in use
+ * Each IOC will added to the ioc list structure on initialization.
+ * Watchdog threads run at regular intervals to check IOC for any
+ * fault conditions which will trigger the dead_ioc thread to
+ * deallocate pci resource, resulting deleting the IOC netry from list,
+ * this deletion need to protected by spinlock to enusre that
+ * ioc removal is syncrhonized, if not synchronized it might lead to
+ * list_del corruption as the ioc list is traversed in cli path.
+ */
+extern spinlock_t gioc_lock;
+
void mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc);
@@ -1039,7 +1247,8 @@ void mpt3sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 handle);
void mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 handle);
-void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid, u16 msix_task);
void mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid);
void mpt3sas_base_initialize_callback_handler(void);
u8 mpt3sas_base_register_callback_handler(MPT_CALLBACK cb_func);
@@ -1085,15 +1294,21 @@ void mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle);
void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
void mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
u64 sas_address);
+u8 mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid);
struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
struct MPT3SAS_ADAPTER *ioc, u16 handle);
struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address(
struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
-struct _sas_device *mpt3sas_scsih_sas_device_find_by_sas_address(
- struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
+struct _sas_device *mpt3sas_get_sdev_by_addr(
+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
+struct _sas_device *__mpt3sas_get_sdev_by_addr(
+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc);
+struct _raid_device *
+mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle);
/* config shared API */
u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
@@ -1133,6 +1348,8 @@ int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc,
u16 sz);
int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
+int mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
@@ -1177,8 +1394,8 @@ int mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc,
/* ctl shared API */
extern struct device_attribute *mpt3sas_host_attrs[];
extern struct device_attribute *mpt3sas_dev_attrs[];
-void mpt3sas_ctl_init(void);
-void mpt3sas_ctl_exit(void);
+void mpt3sas_ctl_init(ushort hbas_to_enumerate);
+void mpt3sas_ctl_exit(ushort hbas_to_enumerate);
u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
void mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase);
@@ -1193,6 +1410,7 @@ int mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
u8 *issue_reset);
/* transport shared API */
+extern struct scsi_transport_template *mpt3sas_transport_template;
u8 mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
struct _sas_port *mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc,
@@ -1224,4 +1442,18 @@ void mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key,
u8 asc, u8 ascq);
void mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status,
u32 loginfo);
+
+/* warpdrive APIs */
+u8 mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc);
+void mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
+ struct _raid_device *raid_device);
+u8
+mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+void
+mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io);
+void
+mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
+ u16 smid);
+
#endif /* MPT3SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index e45c461..a6914ec 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -83,7 +83,6 @@ struct config_request {
dma_addr_t page_dma;
};
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _config_display_some_debug - debug routine
* @ioc: per adapter object
@@ -173,7 +172,6 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo));
}
-#endif
/**
* _config_alloc_config_dma_memory - obtain physical memory
@@ -255,9 +253,7 @@ mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_reply->MsgLength*4);
}
ioc->config_cmds.status &= ~MPT3_CMD_PENDING;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_config_display_some_debug(ioc, smid, "config_done", mpi_reply);
-#endif
ioc->config_cmds.smid = USHRT_MAX;
complete(&ioc->config_cmds.done);
return 1;
@@ -387,9 +383,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
config_request = mpt3sas_base_get_msg_frame(ioc, smid);
ioc->config_cmds.smid = smid;
memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_config_display_some_debug(ioc, smid, "config_request", NULL);
-#endif
init_completion(&ioc->config_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
@@ -872,6 +866,42 @@ mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
}
/**
+ * mpt3sas_config_get_iounit_pg3 - obtain iounit page 3
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz)
+{
+ Mpi2ConfigRequest_t mpi_request;
+ int r;
+
+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+ mpi_request.Function = MPI2_FUNCTION_CONFIG;
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+ mpi_request.Header.PageNumber = 3;
+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION;
+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+ if (r)
+ goto out;
+
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
+ out:
+ return r;
+}
+
+/**
* mpt3sas_config_get_iounit_pg8 - obtain iounit page 8
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 080c8a7..7d00f09 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -78,7 +78,6 @@ enum block_state {
BLOCKING,
};
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _ctl_sas_device_find_by_handle - sas device search
* @ioc: per adapter object
@@ -254,8 +253,6 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
}
}
-#endif
-
/**
* mpt3sas_ctl_done - ctl module completion routine
* @ioc: per adapter object
@@ -302,9 +299,7 @@ mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
}
}
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
-#endif
ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING;
complete(&ioc->ctl_cmds.done);
return 1;
@@ -406,7 +401,8 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
Mpi2EventNotificationReply_t *mpi_reply;
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
- mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
+ if (mpi_reply)
+ mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
return 1;
}
@@ -414,20 +410,45 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
* _ctl_verify_adapter - validates ioc_number passed from application
* @ioc: per adapter object
* @iocpp: The ioc pointer is returned in this.
+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
*
* Return (-1) means error, else ioc_number.
*/
static int
-_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp)
+_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp,
+ int mpi_version)
{
struct MPT3SAS_ADAPTER *ioc;
-
+ int version = 0;
+ /* global ioc lock to protect controller on list operations */
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
if (ioc->id != ioc_number)
continue;
+ /* Check whether this ioctl command is from right
+ * ioctl device or not, if not continue the search.
+ */
+ version = ioc->hba_mpi_version_belonged;
+ /* MPI25_VERSION and MPI26_VERSION uses same ioctl
+ * device.
+ */
+ if (mpi_version == (MPI25_VERSION | MPI26_VERSION)) {
+ if ((version == MPI25_VERSION) ||
+ (version == MPI26_VERSION))
+ goto out;
+ else
+ continue;
+ } else {
+ if (version != mpi_version)
+ continue;
+ }
+out:
+ spin_unlock(&gioc_lock);
*iocpp = ioc;
return ioc_number;
}
+ spin_unlock(&gioc_lock);
*iocpp = NULL;
return -1;
}
@@ -497,7 +518,7 @@ mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
*
* Called when application request fasyn callback handler.
*/
-static int
+int
_ctl_fasync(int fd, struct file *filep, int mode)
{
return fasync_helper(fd, filep, mode, &async_queue);
@@ -509,17 +530,22 @@ _ctl_fasync(int fd, struct file *filep, int mode)
* @wait -
*
*/
-static unsigned int
+unsigned int
_ctl_poll(struct file *filep, poll_table *wait)
{
struct MPT3SAS_ADAPTER *ioc;
poll_wait(filep, &ctl_poll_wait, wait);
+ /* global ioc lock to protect controller on list operations */
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
- if (ioc->aen_event_read_flag)
+ if (ioc->aen_event_read_flag) {
+ spin_unlock(&gioc_lock);
return POLLIN | POLLRDNORM;
+ }
}
+ spin_unlock(&gioc_lock);
return 0;
}
@@ -759,9 +785,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
psge = (void *)request + (karg.data_sge_offset*4);
/* send command to firmware */
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_ctl_display_some_debug(ioc, smid, "ctl_request", NULL);
-#endif
init_completion(&ioc->ctl_cmds.done);
switch (mpi_request->Function) {
@@ -808,7 +832,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
tm_request->DevHandle));
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
break;
}
case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -916,7 +940,6 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
mpi_reply = ioc->ctl_cmds.reply;
ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
(ioc->logging_level & MPT_DEBUG_TM)) {
Mpi2SCSITaskManagementReply_t *tm_reply =
@@ -929,7 +952,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
le32_to_cpu(tm_reply->IOCLogInfo),
le32_to_cpu(tm_reply->TerminationCount));
}
-#endif
+
/* copy out xdata to user */
if (data_in_sz) {
if (copy_to_user(karg.data_in_buf_ptr, data_in,
@@ -1023,7 +1046,6 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
__func__));
memset(&karg, 0 , sizeof(karg));
- karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3;
if (ioc->pfacts)
karg.port_number = ioc->pfacts[0].PortNumber;
karg.hw_rev = ioc->pdev->revision;
@@ -1035,9 +1057,22 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);
karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);
karg.firmware_version = ioc->facts.FWVersion.Word;
- strcpy(karg.driver_version, MPT3SAS_DRIVER_NAME);
+ strcpy(karg.driver_version, ioc->driver_name);
strcat(karg.driver_version, "-");
- strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
+ if (ioc->is_warpdrive)
+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200;
+ else
+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
+ strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
+ karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3;
+ strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
+ break;
+ }
karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
if (copy_to_user(arg, &karg, sizeof(karg))) {
@@ -2181,12 +2216,14 @@ _ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd,
* _ctl_ioctl_main - main ioctl entry point
* @file - (struct file)
* @cmd - ioctl opcode
- * @arg -
- * compat - handles 32 bit applications in 64bit os
+ * @arg - user space data buffer
+ * @compat - handles 32 bit applications in 64bit os
+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
*/
static long
_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
- u8 compat)
+ u8 compat, u16 mpi_version)
{
struct MPT3SAS_ADAPTER *ioc;
struct mpt3_ioctl_header ioctl_header;
@@ -2201,19 +2238,29 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
return -EFAULT;
}
- if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
+ if (_ctl_verify_adapter(ioctl_header.ioc_number,
+ &ioc, mpi_version) == -1 || !ioc)
return -ENODEV;
+ /* pci_access_mutex lock acquired by ioctl path */
+ mutex_lock(&ioc->pci_access_mutex);
+
if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
+ ioc->is_driver_loading || ioc->remove_host) {
+ ret = -EAGAIN;
+ goto out_unlock_pciaccess;
+ }
state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
if (state == NON_BLOCKING) {
- if (!mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
+ if (!mutex_trylock(&ioc->ctl_cmds.mutex)) {
+ ret = -EAGAIN;
+ goto out_unlock_pciaccess;
+ }
+ } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) {
+ ret = -ERESTARTSYS;
+ goto out_unlock_pciaccess;
+ }
switch (cmd) {
@@ -2294,39 +2341,81 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
}
mutex_unlock(&ioc->ctl_cmds.mutex);
+out_unlock_pciaccess:
+ mutex_unlock(&ioc->pci_access_mutex);
return ret;
}
/**
- * _ctl_ioctl - main ioctl entry point (unlocked)
+ * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked)
* @file - (struct file)
* @cmd - ioctl opcode
* @arg -
*/
-static long
+long
_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);
+ /* pass MPI25_VERSION | MPI26_VERSION value,
+ * to indicate that this ioctl cmd
+ * came from mpt3ctl ioctl device.
+ */
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0,
+ MPI25_VERSION | MPI26_VERSION);
return ret;
}
+/**
+ * _ctl_mpt2_ioctl - mpt2ctl main ioctl entry point (unlocked)
+ * @file - (struct file)
+ * @cmd - ioctl opcode
+ * @arg -
+ */
+long
+_ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long ret;
+
+ /* pass MPI2_VERSION value, to indicate that this ioctl cmd
+ * came from mpt2ctl ioctl device.
+ */
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION);
+ return ret;
+}
#ifdef CONFIG_COMPAT
/**
- * _ctl_ioctl_compat - main ioctl entry point (compat)
+ *_ ctl_ioctl_compat - main ioctl entry point (compat)
* @file -
* @cmd -
* @arg -
*
* This routine handles 32 bit applications in 64bit os.
*/
-static long
+long
_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1,
+ MPI25_VERSION | MPI26_VERSION);
+ return ret;
+}
+
+/**
+ *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat)
+ * @file -
+ * @cmd -
+ * @arg -
+ *
+ * This routine handles 32 bit applications in 64bit os.
+ */
+long
+_ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
+{
+ long ret;
+
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION);
return ret;
}
#endif
@@ -2713,6 +2802,82 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev,
static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
NULL);
+/**
+ * _ctl_BRM_status_show - Backup Rail Monitor Status
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is number of reply queues
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+ Mpi2IOUnitPage3_t *io_unit_pg3 = NULL;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 backup_rail_monitor_status = 0;
+ u16 ioc_status;
+ int sz;
+ ssize_t rc = 0;
+
+ if (!ioc->is_warpdrive) {
+ pr_err(MPT3SAS_FMT "%s: BRM attribute is only for"
+ " warpdrive\n", ioc->name, __func__);
+ goto out;
+ }
+ /* pci_access_mutex lock acquired by sysfs show path */
+ mutex_lock(&ioc->pci_access_mutex);
+ if (ioc->pci_error_recovery || ioc->remove_host) {
+ mutex_unlock(&ioc->pci_access_mutex);
+ return 0;
+ }
+
+ /* allocate upto GPIOVal 36 entries */
+ sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
+ io_unit_pg3 = kzalloc(sz, GFP_KERNEL);
+ if (!io_unit_pg3) {
+ pr_err(MPT3SAS_FMT "%s: failed allocating memory "
+ "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz);
+ goto out;
+ }
+
+ if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) !=
+ 0) {
+ pr_err(MPT3SAS_FMT
+ "%s: failed reading iounit_pg3\n", ioc->name,
+ __func__);
+ goto out;
+ }
+
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with "
+ "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status);
+ goto out;
+ }
+
+ if (io_unit_pg3->GPIOCount < 25) {
+ pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than "
+ "25 entries, detected (%d) entries\n", ioc->name, __func__,
+ io_unit_pg3->GPIOCount);
+ goto out;
+ }
+
+ /* BRM status is in bit zero of GPIOVal[24] */
+ backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]);
+ rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1));
+
+ out:
+ kfree(io_unit_pg3);
+ mutex_unlock(&ioc->pci_access_mutex);
+ return rc;
+}
+static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
+
struct DIAG_BUFFER_START {
__le32 Size;
__le32 DiagVersion;
@@ -3165,6 +3330,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
&dev_attr_diag_trigger_event,
&dev_attr_diag_trigger_scsi,
&dev_attr_diag_trigger_mpi,
+ &dev_attr_BRM_status,
NULL,
};
@@ -3218,6 +3384,7 @@ struct device_attribute *mpt3sas_dev_attrs[] = {
NULL,
};
+/* file operations table for mpt3ctl device */
static const struct file_operations ctl_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = _ctl_ioctl,
@@ -3228,23 +3395,53 @@ static const struct file_operations ctl_fops = {
#endif
};
+/* file operations table for mpt2ctl device */
+static const struct file_operations ctl_gen2_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = _ctl_mpt2_ioctl,
+ .poll = _ctl_poll,
+ .fasync = _ctl_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = _ctl_mpt2_ioctl_compat,
+#endif
+};
+
static struct miscdevice ctl_dev = {
.minor = MPT3SAS_MINOR,
.name = MPT3SAS_DEV_NAME,
.fops = &ctl_fops,
};
+static struct miscdevice gen2_ctl_dev = {
+ .minor = MPT2SAS_MINOR,
+ .name = MPT2SAS_DEV_NAME,
+ .fops = &ctl_gen2_fops,
+};
+
/**
* mpt3sas_ctl_init - main entry point for ctl.
*
*/
void
-mpt3sas_ctl_init(void)
+mpt3sas_ctl_init(ushort hbas_to_enumerate)
{
async_queue = NULL;
- if (misc_register(&ctl_dev) < 0)
- pr_err("%s can't register misc device [minor=%d]\n",
- MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR);
+
+ /* Don't register mpt3ctl ioctl device if
+ * hbas_to_enumarate is one.
+ */
+ if (hbas_to_enumerate != 1)
+ if (misc_register(&ctl_dev) < 0)
+ pr_err("%s can't register misc device [minor=%d]\n",
+ MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR);
+
+ /* Don't register mpt3ctl ioctl device if
+ * hbas_to_enumarate is two.
+ */
+ if (hbas_to_enumerate != 2)
+ if (misc_register(&gen2_ctl_dev) < 0)
+ pr_err("%s can't register misc device [minor=%d]\n",
+ MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
init_waitqueue_head(&ctl_poll_wait);
}
@@ -3254,7 +3451,7 @@ mpt3sas_ctl_init(void)
*
*/
void
-mpt3sas_ctl_exit(void)
+mpt3sas_ctl_exit(ushort hbas_to_enumerate)
{
struct MPT3SAS_ADAPTER *ioc;
int i;
@@ -3279,5 +3476,8 @@ mpt3sas_ctl_exit(void)
kfree(ioc->event_log);
}
- misc_deregister(&ctl_dev);
+ if (hbas_to_enumerate != 1)
+ misc_deregister(&ctl_dev);
+ if (hbas_to_enumerate != 2)
+ misc_deregister(&gen2_ctl_dev);
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
index aee99ce..8940835 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
@@ -50,10 +50,13 @@
#include <linux/miscdevice.h>
#endif
-
+#ifndef MPT2SAS_MINOR
+#define MPT2SAS_MINOR (MPT_MINOR + 1)
+#endif
#ifndef MPT3SAS_MINOR
#define MPT3SAS_MINOR (MPT_MINOR + 2)
#endif
+#define MPT2SAS_DEV_NAME "mpt2ctl"
#define MPT3SAS_DEV_NAME "mpt3ctl"
#define MPT3_MAGIC_NUMBER 'L'
#define MPT3_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */
@@ -138,6 +141,7 @@ struct mpt3_ioctl_pci_info {
#define MPT2_IOCTL_INTERFACE_FC_IP (0x02)
#define MPT2_IOCTL_INTERFACE_SAS (0x03)
#define MPT2_IOCTL_INTERFACE_SAS2 (0x04)
+#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05)
#define MPT3_IOCTL_INTERFACE_SAS3 (0x06)
#define MPT2_IOCTL_VERSION_LENGTH (32)
diff --git a/drivers/scsi/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h
index 4e8a63f..cceeb2c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_debug.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h
@@ -68,20 +68,11 @@
#define MPT_DEBUG_TRIGGER_DIAG 0x00200000
-/*
- * CONFIG_SCSI_MPT3SAS_LOGGING - enabled in Kconfig
- */
-
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \
{ \
if (IOC->logging_level & BITS) \
CMD; \
}
-#else
-#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
-#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */
-
/*
* debug macros
@@ -153,7 +144,7 @@
/* inline functions for dumping debug data*/
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
/**
* _debug_dump_mf - print message frame contents
* @mpi_request: pointer to message frame
@@ -211,10 +202,5 @@ _debug_dump_config(void *mpi_request, int sz)
}
pr_info("\n");
}
-#else
-#define _debug_dump_mf(mpi_request, sz)
-#define _debug_dump_reply(mpi_request, sz)
-#define _debug_dump_config(mpi_request, sz)
-#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */
#endif /* MPT3SAS_DEBUG_H_INCLUDED */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 8ccef38..e0e4920 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -54,14 +54,10 @@
#include <linux/interrupt.h>
#include <linux/aer.h>
#include <linux/raid_class.h>
+#include <asm/unaligned.h>
#include "mpt3sas_base.h"
-MODULE_AUTHOR(MPT3SAS_AUTHOR);
-MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MPT3SAS_DRIVER_VERSION);
-
#define RAID_CHANNEL 1
/* forward proto's */
static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
@@ -75,11 +71,16 @@ static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle,
static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid);
-static void _scsih_scan_start(struct Scsi_Host *shost);
-static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time);
-
/* global parameters */
LIST_HEAD(mpt3sas_ioc_list);
+/* global ioc lock for list operations */
+DEFINE_SPINLOCK(gioc_lock);
+
+MODULE_AUTHOR(MPT3SAS_AUTHOR);
+MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MPT3SAS_DRIVER_VERSION);
+MODULE_ALIAS("mpt2sas");
/* local parameters */
static u8 scsi_io_cb_idx = -1;
@@ -90,7 +91,8 @@ static u8 port_enable_cb_idx = -1;
static u8 transport_cb_idx = -1;
static u8 scsih_cb_idx = -1;
static u8 config_cb_idx = -1;
-static int mpt_ids;
+static int mpt2_ids;
+static int mpt3_ids;
static u8 tm_tr_cb_idx = -1 ;
static u8 tm_tr_volume_cb_idx = -1 ;
@@ -117,8 +119,12 @@ static u64 max_lun = MPT3SAS_MAX_LUN;
module_param(max_lun, ullong, 0);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-
-
+static ushort hbas_to_enumerate;
+module_param(hbas_to_enumerate, ushort, 0);
+MODULE_PARM_DESC(hbas_to_enumerate,
+ " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \
+ 1 - enumerates only SAS 2.0 generation HBAs\n \
+ 2 - enumerates only SAS 3.0 generation HBAs (default=0)");
/* diag_buffer_enable is bitwise
* bit 0 set = TRACE
@@ -143,8 +149,8 @@ MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
/* raid transport support */
-
-static struct raid_template *mpt3sas_raid_template;
+struct raid_template *mpt3sas_raid_template;
+struct raid_template *mpt2sas_raid_template;
/**
@@ -191,11 +197,36 @@ struct fw_event_work {
u8 VP_ID;
u8 ignore;
u16 event;
+ struct kref refcount;
char event_data[0] __aligned(4);
};
-/* raid transport support */
-static struct raid_template *mpt3sas_raid_template;
+static void fw_event_work_free(struct kref *r)
+{
+ kfree(container_of(r, struct fw_event_work, refcount));
+}
+
+static void fw_event_work_get(struct fw_event_work *fw_work)
+{
+ kref_get(&fw_work->refcount);
+}
+
+static void fw_event_work_put(struct fw_event_work *fw_work)
+{
+ kref_put(&fw_work->refcount, fw_event_work_free);
+}
+
+static struct fw_event_work *alloc_fw_event_work(int len)
+{
+ struct fw_event_work *fw_event;
+
+ fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC);
+ if (!fw_event)
+ return NULL;
+
+ kref_init(&fw_event->refcount);
+ return fw_event;
+}
/**
* struct _scsi_io_transfer - scsi io transfer
@@ -245,28 +276,6 @@ struct _scsi_io_transfer {
u32 transfer_length;
};
-/*
- * The pci device ids are defined in mpi/mpi2_cnfg.h.
- */
-static const struct pci_device_id scsih_pci_table[] = {
- /* Fury ~ 3004 and 3008 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Invader ~ 3108 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
- PCI_ANY_ID, PCI_ANY_ID },
- {0} /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, scsih_pci_table);
-
/**
* _scsih_set_debug_level - global setting of ioc->logging_level.
*
@@ -282,8 +291,10 @@ _scsih_set_debug_level(const char *val, struct kernel_param *kp)
return ret;
pr_info("setting logging_level(0x%08x)\n", logging_level);
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list)
ioc->logging_level = logging_level;
+ spin_unlock(&gioc_lock);
return 0;
}
module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
@@ -518,8 +529,61 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
}
}
+static struct _sas_device *
+__mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
+ struct MPT3SAS_TARGET *tgt_priv)
+{
+ struct _sas_device *ret;
+
+ assert_spin_locked(&ioc->sas_device_lock);
+
+ ret = tgt_priv->sdev;
+ if (ret)
+ sas_device_get(ret);
+
+ return ret;
+}
+
+static struct _sas_device *
+mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
+ struct MPT3SAS_TARGET *tgt_priv)
+{
+ struct _sas_device *ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ ret = __mpt3sas_get_sdev_from_target(ioc, tgt_priv);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ return ret;
+}
+
+
+struct _sas_device *
+__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
+ u64 sas_address)
+{
+ struct _sas_device *sas_device;
+
+ assert_spin_locked(&ioc->sas_device_lock);
+
+ list_for_each_entry(sas_device, &ioc->sas_device_list, list)
+ if (sas_device->sas_address == sas_address)
+ goto found_device;
+
+ list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
+ if (sas_device->sas_address == sas_address)
+ goto found_device;
+
+ return NULL;
+
+found_device:
+ sas_device_get(sas_device);
+ return sas_device;
+}
+
/**
- * mpt3sas_scsih_sas_device_find_by_sas_address - sas device search
+ * mpt3sas_get_sdev_by_addr - sas device search
* @ioc: per adapter object
* @sas_address: sas address
* Context: Calling function should acquire ioc->sas_device_lock
@@ -528,24 +592,44 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
* object.
*/
struct _sas_device *
-mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
+mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
u64 sas_address)
{
struct _sas_device *sas_device;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
+ sas_address);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ return sas_device;
+}
+
+static struct _sas_device *
+__mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _sas_device *sas_device;
+
+ assert_spin_locked(&ioc->sas_device_lock);
list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->sas_address == sas_address)
- return sas_device;
+ if (sas_device->handle == handle)
+ goto found_device;
list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->sas_address == sas_address)
- return sas_device;
+ if (sas_device->handle == handle)
+ goto found_device;
return NULL;
+
+found_device:
+ sas_device_get(sas_device);
+ return sas_device;
}
/**
- * _scsih_sas_device_find_by_handle - sas device search
+ * mpt3sas_get_sdev_by_handle - sas device search
* @ioc: per adapter object
* @handle: sas device handle (assigned by firmware)
* Context: Calling function should acquire ioc->sas_device_lock
@@ -554,19 +638,16 @@ mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
* object.
*/
static struct _sas_device *
-_scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
+mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
struct _sas_device *sas_device;
+ unsigned long flags;
- list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->handle == handle)
- return sas_device;
-
- list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->handle == handle)
- return sas_device;
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return NULL;
+ return sas_device;
}
/**
@@ -575,7 +656,7 @@ _scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
* @sas_device: the sas_device object
* Context: This function will acquire ioc->sas_device_lock.
*
- * Removing object and freeing associated memory from the ioc->sas_device_list.
+ * If sas_device is on the list, remove it and decrement its reference count.
*/
static void
_scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
@@ -602,9 +683,15 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
ioc->name, sas_device->enclosure_level,
sas_device->connector_name);
+ /*
+ * The lock serializes access to the list, but we still need to verify
+ * that nobody removed the entry while we were waiting on the lock.
+ */
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_del(&sas_device->list);
- kfree(sas_device);
+ if (!list_empty(&sas_device->list)) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
@@ -625,12 +712,16 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (sas_device)
- list_del(&sas_device->list);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (sas_device) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ if (sas_device) {
_scsih_remove_device(ioc, sas_device);
+ sas_device_put(sas_device);
+ }
}
/**
@@ -651,13 +742,16 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_address);
- if (sas_device)
- list_del(&sas_device->list);
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address);
+ if (sas_device) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ if (sas_device) {
_scsih_remove_device(ioc, sas_device);
+ sas_device_put(sas_device);
+ }
}
/**
@@ -692,6 +786,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
sas_device->enclosure_level, sas_device->connector_name));
spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device_get(sas_device);
list_add_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -745,6 +840,7 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc,
sas_device->connector_name));
spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device_get(sas_device);
list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
_scsih_determine_boot_device(ioc, sas_device, 0);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -778,7 +874,7 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
}
/**
- * _scsih_raid_device_find_by_handle - raid device search
+ * mpt3sas_raid_device_find_by_handle - raid device search
* @ioc: per adapter object
* @handle: sas device handle (assigned by firmware)
* Context: Calling function should acquire ioc->raid_device_lock
@@ -786,8 +882,8 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
* This searches for raid_device based on handle, then return raid_device
* object.
*/
-static struct _raid_device *
-_scsih_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
+struct _raid_device *
+mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
struct _raid_device *raid_device, *r;
@@ -1095,14 +1191,14 @@ _scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id,
}
/**
- * _scsih_change_queue_depth - setting device queue depth
+ * scsih_change_queue_depth - setting device queue depth
* @sdev: scsi device struct
* @qdepth: requested queue depth
*
* Returns queue depth.
*/
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+int
+scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
int max_depth;
@@ -1123,12 +1219,15 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
goto not_sata;
if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
goto not_sata;
+
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_device_priv_data->sas_target->sas_address);
- if (sas_device && sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- max_depth = MPT3SAS_SATA_QUEUE_DEPTH;
+ sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
+ if (sas_device) {
+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+ max_depth = MPT3SAS_SATA_QUEUE_DEPTH;
+
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
not_sata:
@@ -1141,14 +1240,14 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
}
/**
- * _scsih_target_alloc - target add routine
+ * scsih_target_alloc - target add routine
* @starget: scsi target struct
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-static int
-_scsih_target_alloc(struct scsi_target *starget)
+int
+scsih_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1176,7 +1275,9 @@ _scsih_target_alloc(struct scsi_target *starget)
sas_target_priv_data->handle = raid_device->handle;
sas_target_priv_data->sas_address = raid_device->wwid;
sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
- raid_device->starget = starget;
+ sas_target_priv_data->raid_device = raid_device;
+ if (ioc->is_warpdrive)
+ raid_device->starget = starget;
}
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
return 0;
@@ -1185,12 +1286,13 @@ _scsih_target_alloc(struct scsi_target *starget)
/* sas/sata devices */
spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
if (sas_device) {
sas_target_priv_data->handle = sas_device->handle;
sas_target_priv_data->sas_address = sas_device->sas_address;
+ sas_target_priv_data->sdev = sas_device;
sas_device->starget = starget;
sas_device->id = starget->id;
sas_device->channel = starget->channel;
@@ -1206,13 +1308,13 @@ _scsih_target_alloc(struct scsi_target *starget)
}
/**
- * _scsih_target_destroy - target destroy routine
+ * scsih_target_destroy - target destroy routine
* @starget: scsi target struct
*
* Returns nothing.
*/
-static void
-_scsih_target_destroy(struct scsi_target *starget)
+void
+scsih_target_destroy(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1240,13 +1342,21 @@ _scsih_target_destroy(struct scsi_target *starget)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- rphy->identify.sas_address);
+ sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
if (sas_device && (sas_device->starget == starget) &&
(sas_device->id == starget->id) &&
(sas_device->channel == starget->channel))
sas_device->starget = NULL;
+ if (sas_device) {
+ /*
+ * Corresponding get() is in _scsih_target_alloc()
+ */
+ sas_target_priv_data->sdev = NULL;
+ sas_device_put(sas_device);
+
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
out:
@@ -1255,14 +1365,14 @@ _scsih_target_destroy(struct scsi_target *starget)
}
/**
- * _scsih_slave_alloc - device add routine
+ * scsih_slave_alloc - device add routine
* @sdev: scsi device struct
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-static int
-_scsih_slave_alloc(struct scsi_device *sdev)
+int
+scsih_slave_alloc(struct scsi_device *sdev)
{
struct Scsi_Host *shost;
struct MPT3SAS_ADAPTER *ioc;
@@ -1302,14 +1412,18 @@ _scsih_slave_alloc(struct scsi_device *sdev)
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_target_priv_data->sas_address);
if (sas_device && (sas_device->starget == NULL)) {
sdev_printk(KERN_INFO, sdev,
"%s : sas_device->starget set to starget @ %d\n",
- __func__, __LINE__);
+ __func__, __LINE__);
sas_device->starget = starget;
}
+
+ if (sas_device)
+ sas_device_put(sas_device);
+
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
@@ -1317,13 +1431,13 @@ _scsih_slave_alloc(struct scsi_device *sdev)
}
/**
- * _scsih_slave_destroy - device destroy routine
+ * scsih_slave_destroy - device destroy routine
* @sdev: scsi device struct
*
* Returns nothing.
*/
-static void
-_scsih_slave_destroy(struct scsi_device *sdev)
+void
+scsih_slave_destroy(struct scsi_device *sdev)
{
struct MPT3SAS_TARGET *sas_target_priv_data;
struct scsi_target *starget;
@@ -1344,10 +1458,13 @@ _scsih_slave_destroy(struct scsi_device *sdev)
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_target_priv_data->sas_address);
+ sas_device = __mpt3sas_get_sdev_from_target(ioc,
+ sas_target_priv_data);
if (sas_device && !sas_target_priv_data->num_luns)
sas_device->starget = NULL;
+
+ if (sas_device)
+ sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
@@ -1409,23 +1526,26 @@ _scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc,
*/
/**
- * _scsih_is_raid - return boolean indicating device is raid volume
+ * scsih_is_raid - return boolean indicating device is raid volume
* @dev the device struct object
*/
-static int
-_scsih_is_raid(struct device *dev)
+int
+scsih_is_raid(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host);
+ if (ioc->is_warpdrive)
+ return 0;
return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
}
/**
- * _scsih_get_resync - get raid volume resync percent complete
+ * scsih_get_resync - get raid volume resync percent complete
* @dev the device struct object
*/
-static void
-_scsih_get_resync(struct device *dev)
+void
+scsih_get_resync(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host);
@@ -1439,6 +1559,9 @@ _scsih_get_resync(struct device *dev)
percent_complete = 0;
handle = 0;
+ if (ioc->is_warpdrive)
+ goto out;
+
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
sdev->channel);
@@ -1466,15 +1589,24 @@ _scsih_get_resync(struct device *dev)
percent_complete = 0;
out:
- raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
+
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
+ raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
+ raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
+ break;
+ }
}
/**
- * _scsih_get_state - get raid volume level
+ * scsih_get_state - get raid volume level
* @dev the device struct object
*/
-static void
-_scsih_get_state(struct device *dev)
+void
+scsih_get_state(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host);
@@ -1524,7 +1656,15 @@ _scsih_get_state(struct device *dev)
break;
}
out:
- raid_set_state(mpt3sas_raid_template, dev, state);
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
+ raid_set_state(mpt2sas_raid_template, dev, state);
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
+ raid_set_state(mpt3sas_raid_template, dev, state);
+ break;
+ }
}
/**
@@ -1533,7 +1673,8 @@ _scsih_get_state(struct device *dev)
* @volume_type: volume type
*/
static void
-_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
+_scsih_set_level(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_device *sdev, u8 volume_type)
{
enum raid_level level = RAID_LEVEL_UNKNOWN;
@@ -1552,7 +1693,17 @@ _scsih_set_level(struct scsi_device *sdev, u8 volume_type)
break;
}
- raid_set_level(mpt3sas_raid_template, &sdev->sdev_gendev, level);
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
+ raid_set_level(mpt2sas_raid_template,
+ &sdev->sdev_gendev, level);
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
+ raid_set_level(mpt3sas_raid_template,
+ &sdev->sdev_gendev, level);
+ break;
+ }
}
@@ -1622,8 +1773,6 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc,
return 0;
}
-
-
/**
* _scsih_enable_tlr - setting TLR flags
* @ioc: per adapter object
@@ -1652,14 +1801,14 @@ _scsih_enable_tlr(struct MPT3SAS_ADAPTER *ioc, struct scsi_device *sdev)
}
/**
- * _scsih_slave_configure - device configure routine.
+ * scsih_slave_configure - device configure routine.
* @sdev: scsi device struct
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-static int
-_scsih_slave_configure(struct scsi_device *sdev)
+int
+scsih_slave_configure(struct scsi_device *sdev)
{
struct Scsi_Host *shost = sdev->host;
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1686,7 +1835,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (!raid_device) {
dfailprintk(ioc, pr_warn(MPT3SAS_FMT
@@ -1702,6 +1851,10 @@ _scsih_slave_configure(struct scsi_device *sdev)
return 1;
}
+ /*
+ * WARPDRIVE: Initialize the required data for Direct IO
+ */
+ mpt3sas_init_warpdrive_properties(ioc, raid_device);
/* RAID Queue Depth Support
* IS volume = underlying qdepth of drive type, either
@@ -1750,17 +1903,19 @@ _scsih_slave_configure(struct scsi_device *sdev)
break;
}
- sdev_printk(KERN_INFO, sdev,
- "%s: handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
- r_level, raid_device->handle,
- (unsigned long long)raid_device->wwid,
- raid_device->num_pds, ds);
-
+ if (!ioc->hide_ir_msg)
+ sdev_printk(KERN_INFO, sdev,
+ "%s: handle(0x%04x), wwid(0x%016llx),"
+ " pd_count(%d), type(%s)\n",
+ r_level, raid_device->handle,
+ (unsigned long long)raid_device->wwid,
+ raid_device->num_pds, ds);
- _scsih_change_queue_depth(sdev, qdepth);
+ scsih_change_queue_depth(sdev, qdepth);
-/* raid transport support */
- _scsih_set_level(sdev, raid_device->volume_type);
+ /* raid transport support */
+ if (!ioc->is_warpdrive)
+ _scsih_set_level(ioc, sdev, raid_device->volume_type);
return 0;
}
@@ -1783,7 +1938,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
}
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_device_priv_data->sas_target->sas_address);
if (!sas_device) {
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -1798,7 +1953,15 @@ _scsih_slave_configure(struct scsi_device *sdev)
if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
qdepth = MPT3SAS_SAS_QUEUE_DEPTH;
ssp_target = 1;
- ds = "SSP";
+ if (sas_device->device_info &
+ MPI2_SAS_DEVICE_INFO_SEP) {
+ sdev_printk(KERN_WARNING, sdev,
+ "set ignore_delay_remove for handle(0x%04x)\n",
+ sas_device_priv_data->sas_target->handle);
+ sas_device_priv_data->ignore_delay_remove = 1;
+ ds = "SES";
+ } else
+ ds = "SSP";
} else {
qdepth = MPT3SAS_SATA_QUEUE_DEPTH;
if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
@@ -1823,13 +1986,14 @@ _scsih_slave_configure(struct scsi_device *sdev)
ds, sas_device->enclosure_level,
sas_device->connector_name);
+ sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!ssp_target)
_scsih_display_sata_capabilities(ioc, handle, sdev);
- _scsih_change_queue_depth(sdev, qdepth);
+ scsih_change_queue_depth(sdev, qdepth);
if (ssp_target) {
sas_read_port_mode_page(sdev);
@@ -1840,7 +2004,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
}
/**
- * _scsih_bios_param - fetch head, sector, cylinder info for a disk
+ * scsih_bios_param - fetch head, sector, cylinder info for a disk
* @sdev: scsi device struct
* @bdev: pointer to block device context
* @capacity: device size (in 512 byte sectors)
@@ -1851,8 +2015,8 @@ _scsih_slave_configure(struct scsi_device *sdev)
*
* Return nothing.
*/
-static int
-_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+int
+scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int params[])
{
int heads;
@@ -2053,6 +2217,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
unsigned long timeleft;
struct scsiio_tracker *scsi_lookup = NULL;
int rc;
+ u16 msix_task = 0;
if (m_type == TM_MUTEX_ON)
mutex_lock(&ioc->tm_cmds.mutex);
@@ -2116,7 +2281,12 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
mpt3sas_scsih_set_tm_flag(ioc, handle);
init_completion(&ioc->tm_cmds.done);
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ if ((type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) &&
+ (scsi_lookup->msix_io < ioc->reply_queue_count))
+ msix_task = scsi_lookup->msix_io;
+ else
+ msix_task = 0;
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -2209,7 +2379,10 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
if (!priv_target)
return;
- device_str = "volume";
+ if (ioc->hide_ir_msg)
+ device_str = "WarpDrive";
+ else
+ device_str = "volume";
scsi_print_command(scmd);
if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
@@ -2219,8 +2392,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
device_str, (unsigned long long)priv_target->sas_address);
} else {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- priv_target->sas_address);
+ sas_device = __mpt3sas_get_sdev_from_target(ioc, priv_target);
if (sas_device) {
if (priv_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) {
@@ -2241,24 +2413,26 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
(unsigned long long)
sas_device->enclosure_logical_id,
sas_device->slot);
- if (sas_device->connector_name)
+ if (sas_device->connector_name[0] != '\0')
starget_printk(KERN_INFO, starget,
"enclosure level(0x%04x),connector name(%s)\n",
sas_device->enclosure_level,
sas_device->connector_name);
+
+ sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
}
/**
- * _scsih_abort - eh threads main abort routine
+ * scsih_abort - eh threads main abort routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_abort(struct scsi_cmnd *scmd)
+int
+scsih_abort(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data;
@@ -2311,21 +2485,23 @@ _scsih_abort(struct scsi_cmnd *scmd)
}
/**
- * _scsih_dev_reset - eh threads main device reset routine
+ * scsih_dev_reset - eh threads main device reset routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_dev_reset(struct scsi_cmnd *scmd)
+int
+scsih_dev_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
+ struct _sas_device *sas_device = NULL;
u16 handle;
int r;
+ struct scsi_target *starget = scmd->device->sdev_target;
+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
+
sdev_printk(KERN_INFO, scmd->device,
"attempting device reset! scmd(%p)\n", scmd);
_scsih_tm_display_info(ioc, scmd);
@@ -2344,12 +2520,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
handle = 0;
if (sas_device_priv_data->sas_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc,
- sas_device_priv_data->sas_target->handle);
+ sas_device = mpt3sas_get_sdev_from_target(ioc,
+ target_priv_data);
if (sas_device)
handle = sas_device->volume_handle;
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} else
handle = sas_device_priv_data->sas_target->handle;
@@ -2366,25 +2540,29 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
out:
sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ if (sas_device)
+ sas_device_put(sas_device);
+
return r;
}
/**
- * _scsih_target_reset - eh threads main target reset routine
+ * scsih_target_reset - eh threads main target reset routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_target_reset(struct scsi_cmnd *scmd)
+int
+scsih_target_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
+ struct _sas_device *sas_device = NULL;
u16 handle;
int r;
struct scsi_target *starget = scmd->device->sdev_target;
+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n",
scmd);
@@ -2404,12 +2582,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
handle = 0;
if (sas_device_priv_data->sas_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc,
- sas_device_priv_data->sas_target->handle);
+ sas_device = mpt3sas_get_sdev_from_target(ioc,
+ target_priv_data);
if (sas_device)
handle = sas_device->volume_handle;
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} else
handle = sas_device_priv_data->sas_target->handle;
@@ -2426,18 +2602,22 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
out:
starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ if (sas_device)
+ sas_device_put(sas_device);
+
return r;
}
/**
- * _scsih_host_reset - eh threads main host reset routine
+ * scsih_host_reset - eh threads main host reset routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_host_reset(struct scsi_cmnd *scmd)
+int
+scsih_host_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
int r, retval;
@@ -2483,32 +2663,36 @@ _scsih_fw_event_add(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
return;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
+ fw_event_work_get(fw_event);
INIT_LIST_HEAD(&fw_event->list);
list_add_tail(&fw_event->list, &ioc->fw_event_list);
INIT_WORK(&fw_event->work, _firmware_event_work);
+ fw_event_work_get(fw_event);
queue_work(ioc->firmware_event_thread, &fw_event->work);
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
/**
- * _scsih_fw_event_free - delete fw_event
+ * _scsih_fw_event_del_from_list - delete fw_event from the list
* @ioc: per adapter object
* @fw_event: object describing the event
* Context: This function will acquire ioc->fw_event_lock.
*
- * This removes firmware event object from link list, frees associated memory.
+ * If the fw_event is on the fw_event_list, remove it and do a put.
*
* Return nothing.
*/
static void
-_scsih_fw_event_free(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work
+_scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work
*fw_event)
{
unsigned long flags;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
- list_del(&fw_event->list);
- kfree(fw_event);
+ if (!list_empty(&fw_event->list)) {
+ list_del_init(&fw_event->list);
+ fw_event_work_put(fw_event);
+ }
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
@@ -2525,17 +2709,19 @@ mpt3sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc,
struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
{
struct fw_event_work *fw_event;
+ u16 sz;
if (ioc->is_driver_loading)
return;
- fw_event = kzalloc(sizeof(*fw_event) + sizeof(*event_data),
- GFP_ATOMIC);
+ sz = sizeof(*event_data);
+ fw_event = alloc_fw_event_work(sz);
if (!fw_event)
return;
fw_event->event = MPT3SAS_PROCESS_TRIGGER_DIAG;
fw_event->ioc = ioc;
memcpy(fw_event->event_data, event_data, sizeof(*event_data));
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
}
/**
@@ -2551,12 +2737,13 @@ _scsih_error_recovery_delete_devices(struct MPT3SAS_ADAPTER *ioc)
if (ioc->is_driver_loading)
return;
- fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(0);
if (!fw_event)
return;
fw_event->event = MPT3SAS_REMOVE_UNRESPONDING_DEVICES;
fw_event->ioc = ioc;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
}
/**
@@ -2570,12 +2757,29 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc)
{
struct fw_event_work *fw_event;
- fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(0);
if (!fw_event)
return;
fw_event->event = MPT3SAS_PORT_ENABLE_COMPLETE;
fw_event->ioc = ioc;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
+}
+
+static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc)
+{
+ unsigned long flags;
+ struct fw_event_work *fw_event = NULL;
+
+ spin_lock_irqsave(&ioc->fw_event_lock, flags);
+ if (!list_empty(&ioc->fw_event_list)) {
+ fw_event = list_first_entry(&ioc->fw_event_list,
+ struct fw_event_work, list);
+ list_del_init(&fw_event->list);
+ }
+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+
+ return fw_event;
}
/**
@@ -2590,17 +2794,25 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc)
static void
_scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc)
{
- struct fw_event_work *fw_event, *next;
+ struct fw_event_work *fw_event;
if (list_empty(&ioc->fw_event_list) ||
!ioc->firmware_event_thread || in_interrupt())
return;
- list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
- if (cancel_delayed_work_sync(&fw_event->delayed_work)) {
- _scsih_fw_event_free(ioc, fw_event);
- continue;
- }
+ while ((fw_event = dequeue_next_fw_event(ioc))) {
+ /*
+ * Wait on the fw_event to complete. If this returns 1, then
+ * the event was never executed, and we need a put for the
+ * reference the delayed_work had on the fw_event.
+ *
+ * If it did execute, we wait for it to finish, and the put will
+ * happen from _firmware_event_work()
+ */
+ if (cancel_delayed_work_sync(&fw_event->delayed_work))
+ fw_event_work_put(fw_event);
+
+ fw_event_work_put(fw_event);
}
}
@@ -2745,6 +2957,12 @@ _scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc)
continue;
if (sas_device_priv_data->block)
continue;
+ if (sas_device_priv_data->ignore_delay_remove) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s skip device_block for SES handle(0x%04x)\n",
+ __func__, sas_device_priv_data->sas_target->handle);
+ continue;
+ }
_scsih_internal_device_block(sdev, sas_device_priv_data);
}
}
@@ -2763,7 +2981,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
struct scsi_device *sdev;
struct _sas_device *sas_device;
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
if (!sas_device)
return;
@@ -2777,8 +2995,16 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
continue;
if (sas_device->pend_sas_rphy_add)
continue;
+ if (sas_device_priv_data->ignore_delay_remove) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s skip device_block for SES handle(0x%04x)\n",
+ __func__, sas_device_priv_data->sas_target->handle);
+ continue;
+ }
_scsih_internal_device_block(sdev, sas_device_priv_data);
}
+
+ sas_device_put(sas_device);
}
/**
@@ -2807,12 +3033,13 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc,
if (mpt3sas_port->remote_identify.device_type ==
SAS_END_DEVICE) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device =
- mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- mpt3sas_port->remote_identify.sas_address);
- if (sas_device)
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
+ mpt3sas_port->remote_identify.sas_address);
+ if (sas_device) {
set_bit(sas_device->handle,
- ioc->blocking_handles);
+ ioc->blocking_handles);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
}
@@ -2880,7 +3107,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
Mpi2SCSITaskManagementRequest_t *mpi_request;
u16 smid;
- struct _sas_device *sas_device;
+ struct _sas_device *sas_device = NULL;
struct MPT3SAS_TARGET *sas_target_priv_data = NULL;
u64 sas_address = 0;
unsigned long flags;
@@ -2913,7 +3140,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device && sas_device->starget &&
sas_device->starget->hostdata) {
sas_target_priv_data = sas_device->starget->hostdata;
@@ -2933,7 +3160,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
" slot(%d)\n", ioc->name, (unsigned long long)
sas_device->enclosure_logical_id,
sas_device->slot));
- if (sas_device->connector_name)
+ if (sas_device->connector_name[0] != '\0')
dewtprintk(ioc, pr_info(MPT3SAS_FMT
"setting delete flag: enclosure level(0x%04x),"
" connector name( %s)\n", ioc->name,
@@ -2947,14 +3174,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if (!smid) {
delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
if (!delayed_tr)
- return;
+ goto out;
INIT_LIST_HEAD(&delayed_tr->list);
delayed_tr->handle = handle;
list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
dewtprintk(ioc, pr_info(MPT3SAS_FMT
"DELAYED:tr:handle(0x%04x), (open)\n",
ioc->name, handle));
- return;
+ goto out;
}
dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -2966,8 +3193,12 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
+
+out:
+ if (sas_device)
+ sas_device_put(sas_device);
}
/**
@@ -2997,6 +3228,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
Mpi2SasIoUnitControlRequest_t *mpi_request;
u16 smid_sas_ctrl;
u32 ioc_state;
+ struct _sc_list *delayed_sc;
if (ioc->remove_host) {
dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3039,9 +3271,16 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
smid_sas_ctrl = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
if (!smid_sas_ctrl) {
- pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return 1;
+ delayed_sc = kzalloc(sizeof(*delayed_sc), GFP_ATOMIC);
+ if (!delayed_sc)
+ return _scsih_check_for_pending_tm(ioc, smid);
+ INIT_LIST_HEAD(&delayed_sc->list);
+ delayed_sc->handle = mpi_request_tm->DevHandle;
+ list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list);
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "DELAYED:sc:handle(0x%04x), (open)\n",
+ ioc->name, handle));
+ return _scsih_check_for_pending_tm(ioc, smid);
}
dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -3092,7 +3331,7 @@ _scsih_sas_control_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid,
pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
}
- return 1;
+ return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
}
/**
@@ -3143,7 +3382,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- mpt3sas_base_put_smid_hi_priority(ioc, smid);
+ mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
}
/**
@@ -3199,6 +3438,142 @@ _scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid,
return _scsih_check_for_pending_tm(ioc, smid);
}
+/**
+ * _scsih_issue_delayed_event_ack - issue delayed Event ACK messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @event: Event ID
+ * @event_context: used to track events uniquely
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event,
+ u32 event_context)
+{
+ Mpi2EventAckRequest_t *ack_request;
+ int i = smid - ioc->internal_smid;
+ unsigned long flags;
+
+ /* Without releasing the smid just update the
+ * call back index and reuse the same smid for
+ * processing this delayed request
+ */
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n",
+ ioc->name, le16_to_cpu(event), smid,
+ ioc->base_cb_idx));
+ ack_request = mpt3sas_base_get_msg_frame(ioc, smid);
+ memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
+ ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
+ ack_request->Event = event;
+ ack_request->EventContext = event_context;
+ ack_request->VF_ID = 0; /* TODO */
+ ack_request->VP_ID = 0;
+ mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_issue_delayed_sas_io_unit_ctrl - issue delayed
+ * sas_io_unit_ctrl messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid, u16 handle)
+ {
+ Mpi2SasIoUnitControlRequest_t *mpi_request;
+ u32 ioc_state;
+ int i = smid - ioc->internal_smid;
+ unsigned long flags;
+
+ if (ioc->remove_host) {
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: host has been removed\n",
+ __func__, ioc->name));
+ return;
+ } else if (ioc->pci_error_recovery) {
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: host in pci error recovery\n",
+ __func__, ioc->name));
+ return;
+ }
+ ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: host is not operational\n",
+ __func__, ioc->name));
+ return;
+ }
+
+ /* Without releasing the smid just update the
+ * call back index and reuse the same smid for
+ * processing this delayed request
+ */
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+ ioc->name, le16_to_cpu(handle), smid,
+ ioc->tm_sas_control_cb_idx));
+ mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+ 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 = handle;
+ mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_check_for_pending_internal_cmds - check for pending internal messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Context: Executed in interrupt context
+ *
+ * This will check delayed internal messages list, and process the
+ * next request.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+u8
+mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ struct _sc_list *delayed_sc;
+ struct _event_ack_list *delayed_event_ack;
+
+ if (!list_empty(&ioc->delayed_event_ack_list)) {
+ delayed_event_ack = list_entry(ioc->delayed_event_ack_list.next,
+ struct _event_ack_list, list);
+ _scsih_issue_delayed_event_ack(ioc, smid,
+ delayed_event_ack->Event, delayed_event_ack->EventContext);
+ list_del(&delayed_event_ack->list);
+ kfree(delayed_event_ack);
+ return 0;
+ }
+
+ if (!list_empty(&ioc->delayed_sc_list)) {
+ delayed_sc = list_entry(ioc->delayed_sc_list.next,
+ struct _sc_list, list);
+ _scsih_issue_delayed_sas_io_unit_ctrl(ioc, smid,
+ delayed_sc->handle);
+ list_del(&delayed_sc->list);
+ kfree(delayed_sc);
+ return 0;
+ }
+ return 1;
+}
/**
* _scsih_check_for_pending_tm - check for pending task management
@@ -3337,7 +3712,7 @@ _scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle)
unsigned long flags;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
if (raid_device && raid_device->starget &&
raid_device->starget->hostdata) {
sas_target_priv_data =
@@ -3398,6 +3773,9 @@ _scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc,
a = 0;
b = 0;
+ if (ioc->is_warpdrive)
+ return;
+
/* Volume Resets for Deleted or Removed */
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
for (i = 0; i < event_data->NumElements; i++, element++) {
@@ -3634,8 +4012,9 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
}
+
/**
- * _scsih_qcmd - main scsi request entry point
+ * scsih_qcmd - main scsi request entry point
* @scmd: pointer to scsi command object
* @done: function pointer to be invoked on completion
*
@@ -3645,21 +4024,20 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
* SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
* SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
*/
-static int
-_scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
+int
+scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
struct MPT3SAS_DEVICE *sas_device_priv_data;
struct MPT3SAS_TARGET *sas_target_priv_data;
+ struct _raid_device *raid_device;
Mpi2SCSIIORequest_t *mpi_request;
u32 mpi_control;
u16 smid;
u16 handle;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_SCSI)
scsi_print_command(scmd);
-#endif
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
@@ -3709,8 +4087,11 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
/* set tags */
mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
- scmd->cmd_len != 32)
+ /* Make sure Device is not raid volume.
+ * We do not expose raid functionality to upper layer for warpdrive.
+ */
+ if (!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev)
+ && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
@@ -3752,13 +4133,19 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
} else
ioc->build_zero_len_sge(ioc, &mpi_request->SGL);
+ raid_device = sas_target_priv_data->raid_device;
+ if (raid_device && raid_device->direct_io_enabled)
+ mpt3sas_setup_direct_io(ioc, scmd, raid_device, mpi_request,
+ smid);
+
if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) {
if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) {
mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len |
MPI25_SCSIIO_IOFLAGS_FAST_PATH);
mpt3sas_base_put_smid_fast_path(ioc, smid, handle);
} else
- mpt3sas_base_put_smid_scsi_io(ioc, smid, handle);
+ mpt3sas_base_put_smid_scsi_io(ioc, smid,
+ le16_to_cpu(mpi_request->DevHandle));
} else
mpt3sas_base_put_smid_default(ioc, smid);
return 0;
@@ -3790,7 +4177,6 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
}
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
* @ioc: per adapter object
@@ -3818,14 +4204,16 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
char *desc_scsi_state = ioc->tmp_string;
u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
struct _sas_device *sas_device = NULL;
- unsigned long flags;
struct scsi_target *starget = scmd->device->sdev_target;
struct MPT3SAS_TARGET *priv_target = starget->hostdata;
char *device_str = NULL;
if (!priv_target)
return;
- device_str = "volume";
+ if (ioc->hide_ir_msg)
+ device_str = "WarpDrive";
+ else
+ device_str = "volume";
if (log_info == 0x31170000)
return;
@@ -3882,6 +4270,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
desc_ioc_state = "eedp app tag error";
break;
+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
+ desc_ioc_state = "insufficient power";
+ break;
default:
desc_ioc_state = "unknown";
break;
@@ -3946,9 +4337,7 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
device_str, (unsigned long long)priv_target->sas_address);
} else {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- priv_target->sas_address);
+ sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target);
if (sas_device) {
pr_warn(MPT3SAS_FMT
"\tsas_address(0x%016llx), phy(%d)\n",
@@ -3967,8 +4356,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
" connector name( %s)\n", ioc->name,
sas_device->enclosure_level,
sas_device->connector_name);
+
+ sas_device_put(sas_device);
}
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
pr_warn(MPT3SAS_FMT
@@ -4003,7 +4393,6 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
_scsih_response_code(ioc, response_bytes[0]);
}
}
-#endif
/**
* _scsih_turn_on_pfa_led - illuminate PFA LED
@@ -4020,7 +4409,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
Mpi2SepRequest_t mpi_request;
struct _sas_device *sas_device;
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
if (!sas_device)
return;
@@ -4035,7 +4424,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
&mpi_request)) != 0) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name,
__FILE__, __LINE__, __func__);
- return;
+ goto out;
}
sas_device->pfa_led_on = 1;
@@ -4044,9 +4433,12 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
"enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo)));
- return;
+ goto out;
}
+out:
+ sas_device_put(sas_device);
}
+
/**
* _scsih_turn_off_pfa_led - turn off Fault LED
* @ioc: per adapter object
@@ -4085,6 +4477,7 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc,
return;
}
}
+
/**
* _scsih_send_event_to_turn_on_pfa_led - fire delayed event
* @ioc: per adapter object
@@ -4098,13 +4491,14 @@ _scsih_send_event_to_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
struct fw_event_work *fw_event;
- fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(0);
if (!fw_event)
return;
fw_event->event = MPT3SAS_TURN_ON_PFA_LED;
fw_event->device_handle = handle;
fw_event->ioc = ioc;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
}
/**
@@ -4128,19 +4522,17 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
/* only handle non-raid devices */
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);
- return;
- }
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (!sas_device)
+ goto out_unlock;
+
starget = sas_device->starget;
sas_target_priv_data = starget->hostdata;
if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
- ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)))
+ goto out_unlock;
+
if (sas_device->enclosure_handle != 0)
starget_printk(KERN_INFO, starget, "predicted fault, "
"enclosure logical id(0x%016llx), slot(%d)\n",
@@ -4163,7 +4555,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if (!event_reply) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
- return;
+ goto out;
}
event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
@@ -4180,6 +4572,14 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
mpt3sas_ctl_add_to_event_log(ioc, event_reply);
kfree(event_reply);
+out:
+ if (sas_device)
+ sas_device_put(sas_device);
+ return;
+
+out_unlock:
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ goto out;
}
/**
@@ -4207,6 +4607,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
u32 log_info;
struct MPT3SAS_DEVICE *sas_device_priv_data;
u32 response_code = 0;
+ unsigned long flags;
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
@@ -4228,6 +4629,24 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
}
ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
+ /*
+ * WARPDRIVE: If direct_io is set then it is directIO,
+ * the failed direct I/O should be redirected to volume
+ */
+ if (mpt3sas_scsi_direct_io_get(ioc, smid) &&
+ ((ioc_status & MPI2_IOCSTATUS_MASK)
+ != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->scsi_lookup[smid - 1].scmd = scmd;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ mpt3sas_scsi_direct_io_set(ioc, smid, 0);
+ memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
+ mpi_request->DevHandle =
+ cpu_to_le16(sas_device_priv_data->sas_target->handle);
+ mpt3sas_base_put_smid_scsi_io(ioc, smid,
+ sas_device_priv_data->sas_target->handle);
+ return 0;
+ }
/* turning off TLR */
scsi_state = mpi_reply->SCSIState;
if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
@@ -4235,10 +4654,13 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
if (!sas_device_priv_data->tlr_snoop_check) {
sas_device_priv_data->tlr_snoop_check++;
- if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
- response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
- sas_device_priv_data->flags &=
- ~MPT_DEVICE_TLR_ON;
+ if (!ioc->is_warpdrive &&
+ !scsih_is_raid(&scmd->device->sdev_gendev) &&
+ sas_is_tlr_enabled(scmd->device) &&
+ response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
+ sas_disable_tlr(scmd->device);
+ sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
+ }
}
xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
@@ -4271,13 +4693,11 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
le16_to_cpu(mpi_reply->DevHandle));
mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq);
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (!(ioc->logging_level & MPT_DEBUG_REPLY) &&
((scmd->sense_buffer[2] == UNIT_ATTENTION) ||
(scmd->sense_buffer[2] == MEDIUM_ERROR) ||
(scmd->sense_buffer[2] == HARDWARE_ERROR)))
_scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid);
-#endif
}
switch (ioc_status) {
case MPI2_IOCSTATUS_BUSY:
@@ -4378,16 +4798,15 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
case MPI2_IOCSTATUS_INVALID_STATE:
case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER:
default:
scmd->result = DID_SOFT_ERROR << 16;
break;
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
_scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
-#endif
out:
@@ -4933,13 +5352,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_address);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (!sas_device)
+ goto out_unlock;
if (unlikely(sas_device->handle != handle)) {
starget = sas_device->starget;
@@ -4967,20 +5384,25 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
pr_err(MPT3SAS_FMT
"device is not present handle(0x%04x), flags!!!\n",
ioc->name, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
+ goto out_unlock;
}
/* check if there were any issues with discovery */
if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus)) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ sas_device_pg0.AccessStatus))
+ goto out_unlock;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
_scsih_ublock_io_device(ioc, sas_address);
+ if (sas_device)
+ sas_device_put(sas_device);
+ return;
+
+out_unlock:
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (sas_device)
+ sas_device_put(sas_device);
}
/**
@@ -5005,7 +5427,6 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
u32 ioc_status;
u64 sas_address;
u32 device_info;
- unsigned long flags;
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
@@ -5041,13 +5462,12 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
sas_device_pg0.AccessStatus))
return -1;
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_device)
+ sas_device = mpt3sas_get_sdev_by_addr(ioc,
+ sas_address);
+ if (sas_device) {
+ sas_device_put(sas_device);
return -1;
+ }
sas_device = kzalloc(sizeof(struct _sas_device),
GFP_KERNEL);
@@ -5057,6 +5477,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
return 0;
}
+ kref_init(&sas_device->refcount);
sas_device->handle = handle;
if (_scsih_get_sas_address(ioc,
le16_to_cpu(sas_device_pg0.ParentDevHandle),
@@ -5098,6 +5519,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
else
_scsih_sas_device_add(ioc, sas_device);
+ sas_device_put(sas_device);
return 0;
}
@@ -5144,7 +5566,9 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
sas_target_priv_data->handle =
MPT3SAS_INVALID_DEVICE_HANDLE;
}
- mpt3sas_transport_port_remove(ioc,
+
+ if (!ioc->hide_drives)
+ mpt3sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
@@ -5180,11 +5604,8 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
"%s: exit: enclosure level(0x%04x), connector name(%s)\n",
ioc->name, __func__, sas_device->enclosure_level,
sas_device->connector_name));
-
- kfree(sas_device);
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_topology_change_event_debug - debug for topology event
* @ioc: per adapter object
@@ -5262,7 +5683,6 @@ _scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
}
}
-#endif
/**
* _scsih_sas_topology_change_event - handle topology changes
@@ -5287,10 +5707,8 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
(Mpi2EventDataSasTopologyChangeList_t *)
fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_topology_change_event_debug(ioc, event_data);
-#endif
if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery)
return 0;
@@ -5396,7 +5814,6 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
return 0;
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_device_status_change_event_debug - debug for device event
* @event_data: event data payload
@@ -5464,7 +5881,6 @@ _scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
event_data->ASC, event_data->ASCQ);
pr_info("\n");
}
-#endif
/**
* _scsih_sas_device_status_change_event - handle device status change
@@ -5486,11 +5902,9 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc,
(Mpi2EventDataSasDeviceStatusChange_t *)
fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_device_status_change_event_debug(ioc,
event_data);
-#endif
/* In MPI Revision K (0xC), the internal device reset complete was
* implemented, so avoid setting tm_busy flag for older firmware.
@@ -5506,29 +5920,30 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_address = le64_to_cpu(event_data->SASAddress);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_address);
- if (!sas_device || !sas_device->starget) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (!sas_device || !sas_device->starget)
+ goto out;
target_priv_data = sas_device->starget->hostdata;
- if (!target_priv_data) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (!target_priv_data)
+ goto out;
if (event_data->ReasonCode ==
MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
target_priv_data->tm_busy = 1;
else
target_priv_data->tm_busy = 0;
+
+out:
+ if (sas_device)
+ sas_device_put(sas_device);
+
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure
* event
@@ -5563,7 +5978,6 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
(unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
le16_to_cpu(event_data->StartSlot));
}
-#endif
/**
* _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
@@ -5577,12 +5991,10 @@ static void
_scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_enclosure_dev_status_change_event_debug(ioc,
(Mpi2EventDataSasEnclDevStatusChange_t *)
fw_event->event_data);
-#endif
}
/**
@@ -5762,17 +6174,15 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc,
Mpi2EventDataSasDiscovery_t *event_data =
(Mpi2EventDataSasDiscovery_t *) fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name,
(event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
"start" : "stop");
- if (event_data->DiscoveryStatus)
- pr_info("discovery_status(0x%08x)",
- le32_to_cpu(event_data->DiscoveryStatus));
- pr_info("\n");
+ if (event_data->DiscoveryStatus)
+ pr_info("discovery_status(0x%08x)",
+ le32_to_cpu(event_data->DiscoveryStatus));
+ pr_info("\n");
}
-#endif
if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
!ioc->sas_hba.num_phys) {
@@ -5804,6 +6214,8 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
u16 ioc_status;
u32 log_info;
+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ return rc;
mutex_lock(&ioc->scsih_cmds.mutex);
@@ -5971,7 +6383,7 @@ _scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle)
struct scsi_target *starget = NULL;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
if (raid_device) {
if (raid_device->starget) {
starget = raid_device->starget;
@@ -6008,7 +6420,7 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device) {
sas_device->volume_handle = 0;
sas_device->volume_wwid = 0;
@@ -6027,6 +6439,8 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
/* exposing raid component */
if (starget)
starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
+
+ sas_device_put(sas_device);
}
/**
@@ -6055,7 +6469,7 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
&volume_wwid);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device) {
set_bit(handle, ioc->pd_handles);
if (sas_device->starget && sas_device->starget->hostdata) {
@@ -6073,8 +6487,11 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
/* hiding raid component */
_scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
+
if (starget)
starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
+
+ sas_device_put(sas_device);
}
/**
@@ -6107,7 +6524,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
struct _sas_device *sas_device;
- unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
@@ -6117,11 +6533,10 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
set_bit(handle, ioc->pd_handles);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device) {
_scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
+ sas_device_put(sas_device);
return;
}
@@ -6149,7 +6564,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
_scsih_add_device(ioc, handle, 0, 1);
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
* @ioc: per adapter object
@@ -6229,7 +6643,6 @@ _scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
element->PhysDiskNum);
}
}
-#endif
/**
* _scsih_sas_ir_config_change_event - handle ir configuration change events
@@ -6250,18 +6663,16 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc,
(Mpi2EventDataIrConfigChangeList_t *)
fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) &&
+ (!ioc->hide_ir_msg))
_scsih_sas_ir_config_change_event_debug(ioc, event_data);
-#endif
-
foreign_config = (le32_to_cpu(event_data->Flags) &
MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- if (ioc->shost_recovery) {
-
+ if (ioc->shost_recovery &&
+ ioc->hba_mpi_version_belonged != MPI2_VERSION) {
for (i = 0; i < event_data->NumElements; i++, element++) {
if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_HIDE)
_scsih_ir_fastpath(ioc,
@@ -6270,6 +6681,7 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc,
}
return;
}
+
for (i = 0; i < event_data->NumElements; i++, element++) {
switch (element->ReasonCode) {
@@ -6285,16 +6697,20 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc,
le16_to_cpu(element->VolDevHandle));
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
- _scsih_sas_pd_hide(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_hide(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
- _scsih_sas_pd_expose(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_expose(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_HIDE:
- _scsih_sas_pd_add(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_add(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
- _scsih_sas_pd_delete(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_delete(ioc, element);
break;
}
}
@@ -6329,10 +6745,11 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->VolDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
- ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
+ if (!ioc->hide_ir_msg)
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
+ ioc->name, __func__, handle,
+ le32_to_cpu(event_data->PreviousValue), state));
switch (state) {
case MPI2_RAID_VOL_STATE_MISSING:
case MPI2_RAID_VOL_STATE_FAILED:
@@ -6344,7 +6761,7 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc,
case MPI2_RAID_VOL_STATE_OPTIMAL:
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (raid_device)
@@ -6398,7 +6815,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
u16 handle, parent_handle;
u32 state;
struct _sas_device *sas_device;
- unsigned long flags;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status;
@@ -6415,10 +6831,12 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->PhysDiskDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
- ioc->name, __func__, handle,
+ if (!ioc->hide_ir_msg)
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
+ ioc->name, __func__, handle,
le32_to_cpu(event_data->PreviousValue), state));
+
switch (state) {
case MPI2_RAID_PD_STATE_ONLINE:
case MPI2_RAID_PD_STATE_DEGRADED:
@@ -6426,13 +6844,14 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
case MPI2_RAID_PD_STATE_OPTIMAL:
case MPI2_RAID_PD_STATE_HOT_SPARE:
- set_bit(handle, ioc->pd_handles);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (!ioc->is_warpdrive)
+ set_bit(handle, ioc->pd_handles);
- if (sas_device)
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (sas_device) {
+ sas_device_put(sas_device);
return;
+ }
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
@@ -6467,7 +6886,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
}
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_ir_operation_status_event_debug - debug for IR op event
* @ioc: per adapter object
@@ -6509,7 +6927,6 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc,
le16_to_cpu(event_data->VolDevHandle),
event_data->PercentComplete);
}
-#endif
/**
* _scsih_sas_ir_operation_status_event - handle RAID operation events
@@ -6530,18 +6947,17 @@ _scsih_sas_ir_operation_status_event(struct MPT3SAS_ADAPTER *ioc,
unsigned long flags;
u16 handle;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) &&
+ (!ioc->hide_ir_msg))
_scsih_sas_ir_operation_status_event_debug(ioc,
event_data);
-#endif
/* code added for raid transport support */
if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
handle = le16_to_cpu(event_data->VolDevHandle);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
if (raid_device)
raid_device->percent_complete =
event_data->PercentComplete;
@@ -6703,7 +7119,7 @@ static void
_scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid,
u16 handle)
{
- struct MPT3SAS_TARGET *sas_target_priv_data;
+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL;
struct scsi_target *starget;
struct _raid_device *raid_device;
unsigned long flags;
@@ -6722,6 +7138,13 @@ _scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid,
starget_printk(KERN_INFO, raid_device->starget,
"handle(0x%04x), wwid(0x%016llx)\n", handle,
(unsigned long long)raid_device->wwid);
+
+ /*
+ * WARPDRIVE: The handles of the PDs might have changed
+ * across the host reset so re-initialize the
+ * required data for Direct IO
+ */
+ mpt3sas_init_warpdrive_properties(ioc, raid_device);
spin_lock_irqsave(&ioc->raid_device_lock, flags);
if (raid_device->handle == handle) {
spin_unlock_irqrestore(&ioc->raid_device_lock,
@@ -6791,6 +7214,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
}
/* refresh the pd_handles */
+ if (!ioc->is_warpdrive) {
phys_disk_num = 0xFF;
memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
while (!(mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
@@ -6804,6 +7228,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
handle = le16_to_cpu(pd_pg0.DevHandle);
set_bit(handle, ioc->pd_handles);
}
+ }
out:
pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n",
ioc->name);
@@ -6906,6 +7331,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
struct _raid_device *raid_device, *raid_device_next;
struct list_head tmp_list;
unsigned long flags;
+ LIST_HEAD(head);
pr_info(MPT3SAS_FMT "removing unresponding devices: start\n",
ioc->name);
@@ -6913,14 +7339,28 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
/* removing unresponding end devices */
pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n",
ioc->name);
+ /*
+ * Iterate, pulling off devices marked as non-responding. We become the
+ * owner for the reference the list had on any object we prune.
+ */
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_for_each_entry_safe(sas_device, sas_device_next,
&ioc->sas_device_list, list) {
if (!sas_device->responding)
- mpt3sas_device_remove_by_sas_address(ioc,
- sas_device->sas_address);
+ list_move_tail(&sas_device->list, &head);
else
sas_device->responding = 0;
}
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ /*
+ * Now, uninitialize and remove the unresponding devices we pruned.
+ */
+ list_for_each_entry_safe(sas_device, sas_device_next, &head, list) {
+ _scsih_remove_device(ioc, sas_device);
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
/* removing unresponding volumes */
if (ioc->ir_firmware) {
@@ -7074,11 +7514,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
}
phys_disk_num = pd_pg0.PhysDiskNum;
handle = le16_to_cpu(pd_pg0.DevHandle);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (sas_device) {
+ sas_device_put(sas_device);
continue;
+ }
if (mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
handle) != 0)
@@ -7199,12 +7639,12 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
if (!(_scsih_is_end_device(
le32_to_cpu(sas_device_pg0.DeviceInfo))))
continue;
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = mpt3sas_get_sdev_by_addr(ioc,
le64_to_cpu(sas_device_pg0.SASAddress));
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ if (sas_device) {
+ sas_device_put(sas_device);
continue;
+ }
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \
@@ -7296,10 +7736,11 @@ mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
static void
_mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
{
+ _scsih_fw_event_del_from_list(ioc, fw_event);
+
/* the queue is being flushed so ignore this event */
- if (ioc->remove_host ||
- ioc->pci_error_recovery) {
- _scsih_fw_event_free(ioc, fw_event);
+ if (ioc->remove_host || ioc->pci_error_recovery) {
+ fw_event_work_put(fw_event);
return;
}
@@ -7310,8 +7751,16 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
fw_event->event_data);
break;
case MPT3SAS_REMOVE_UNRESPONDING_DEVICES:
- while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery)
+ while (scsi_host_in_recovery(ioc->shost) ||
+ ioc->shost_recovery) {
+ /*
+ * If we're unloading, bail. Otherwise, this can become
+ * an infinite loop.
+ */
+ if (ioc->remove_host)
+ goto out;
ssleep(1);
+ }
_scsih_remove_unresponding_sas_devices(ioc);
_scsih_scan_for_devices_after_reset(ioc);
break;
@@ -7356,7 +7805,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
_scsih_sas_ir_operation_status_event(ioc, fw_event);
break;
}
- _scsih_fw_event_free(ioc, fw_event);
+out:
+ fw_event_work_put(fw_event);
}
/**
@@ -7453,7 +7903,53 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
(Mpi2EventDataIrVolume_t *)
mpi_reply->EventData);
break;
+ case MPI2_EVENT_LOG_ENTRY_ADDED:
+ {
+ Mpi2EventDataLogEntryAdded_t *log_entry;
+ u32 *log_code;
+
+ if (!ioc->is_warpdrive)
+ break;
+
+ log_entry = (Mpi2EventDataLogEntryAdded_t *)
+ mpi_reply->EventData;
+ log_code = (u32 *)log_entry->LogData;
+
+ if (le16_to_cpu(log_entry->LogEntryQualifier)
+ != MPT2_WARPDRIVE_LOGENTRY)
+ break;
+
+ switch (le32_to_cpu(*log_code)) {
+ case MPT2_WARPDRIVE_LC_SSDT:
+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: "
+ "IO Throttling has occurred in the WarpDrive "
+ "subsystem. Check WarpDrive documentation for "
+ "additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_SSDLW:
+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: "
+ "Program/Erase Cycles for the WarpDrive subsystem "
+ "in degraded range. Check WarpDrive documentation "
+ "for additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_SSDLF:
+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: "
+ "There are no Program/Erase Cycles for the "
+ "WarpDrive subsystem. The storage device will be "
+ "in read-only mode. Check WarpDrive documentation "
+ "for additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_BRMF:
+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: "
+ "The Backup Rail Monitor has failed on the "
+ "WarpDrive subsystem. Check WarpDrive "
+ "documentation for additional details.\n",
+ ioc->name);
+ break;
+ }
+ break;
+ }
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_IR_OPERATION_STATUS:
case MPI2_EVENT_SAS_DISCOVERY:
@@ -7472,7 +7968,7 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
}
sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
- fw_event = kzalloc(sizeof(*fw_event) + sz, GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(sz);
if (!fw_event) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
@@ -7485,39 +7981,10 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
fw_event->VP_ID = mpi_reply->VP_ID;
fw_event->event = event;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
return 1;
}
-/* shost template */
-static struct scsi_host_template scsih_driver_template = {
- .module = THIS_MODULE,
- .name = "Fusion MPT SAS Host",
- .proc_name = MPT3SAS_DRIVER_NAME,
- .queuecommand = _scsih_qcmd,
- .target_alloc = _scsih_target_alloc,
- .slave_alloc = _scsih_slave_alloc,
- .slave_configure = _scsih_slave_configure,
- .target_destroy = _scsih_target_destroy,
- .slave_destroy = _scsih_slave_destroy,
- .scan_finished = _scsih_scan_finished,
- .scan_start = _scsih_scan_start,
- .change_queue_depth = _scsih_change_queue_depth,
- .eh_abort_handler = _scsih_abort,
- .eh_device_reset_handler = _scsih_dev_reset,
- .eh_target_reset_handler = _scsih_target_reset,
- .eh_host_reset_handler = _scsih_host_reset,
- .bios_param = _scsih_bios_param,
- .can_queue = 1,
- .this_id = -1,
- .sg_tablesize = MPT3SAS_SG_DEPTH,
- .max_sectors = 32767,
- .cmd_per_lun = 7,
- .use_clustering = ENABLE_CLUSTERING,
- .shost_attrs = mpt3sas_host_attrs,
- .sdev_attrs = mpt3sas_dev_attrs,
- .track_queue_depth = 1,
-};
-
/**
* _scsih_expander_node_remove - removing expander device from list.
* @ioc: per adapter object
@@ -7613,7 +8080,8 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
- pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name);
+ if (!ioc->hide_ir_msg)
+ pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name);
init_completion(&ioc->scsih_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
@@ -7626,10 +8094,11 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) {
mpi_reply = ioc->scsih_cmds.reply;
- pr_info(MPT3SAS_FMT
- "IR shutdown (complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
+ if (!ioc->hide_ir_msg)
+ pr_info(MPT3SAS_FMT "IR shutdown "
+ "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
}
out:
@@ -7638,13 +8107,13 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
}
/**
- * _scsih_remove - detach and remove add host
+ * scsih_remove - detach and remove add host
* @pdev: PCI device struct
*
* Routine called when unloading the driver.
* Return nothing.
*/
-static void _scsih_remove(struct pci_dev *pdev)
+void scsih_remove(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -7705,18 +8174,20 @@ static void _scsih_remove(struct pci_dev *pdev)
sas_remove_host(shost);
scsi_remove_host(shost);
mpt3sas_base_detach(ioc);
+ spin_lock(&gioc_lock);
list_del(&ioc->list);
+ spin_unlock(&gioc_lock);
scsi_host_put(shost);
}
/**
- * _scsih_shutdown - routine call during system shutdown
+ * scsih_shutdown - routine call during system shutdown
* @pdev: PCI device struct
*
* Return nothing.
*/
-static void
-_scsih_shutdown(struct pci_dev *pdev)
+void
+scsih_shutdown(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -7794,6 +8265,8 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc)
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (ioc->hide_drives)
+ return;
if (!mpt3sas_transport_port_add(ioc, handle,
sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
@@ -7831,6 +8304,48 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc)
}
}
+static struct _sas_device *get_next_sas_device(struct MPT3SAS_ADAPTER *ioc)
+{
+ struct _sas_device *sas_device = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ if (!list_empty(&ioc->sas_device_init_list)) {
+ sas_device = list_first_entry(&ioc->sas_device_init_list,
+ struct _sas_device, list);
+ sas_device_get(sas_device);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ return sas_device;
+}
+
+static void sas_device_make_active(struct MPT3SAS_ADAPTER *ioc,
+ struct _sas_device *sas_device)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+
+ /*
+ * Since we dropped the lock during the call to port_add(), we need to
+ * be careful here that somebody else didn't move or delete this item
+ * while we were busy with other things.
+ *
+ * If it was on the list, we need a put() for the reference the list
+ * had. Either way, we need a get() for the destination list.
+ */
+ if (!list_empty(&sas_device->list)) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
+
+ sas_device_get(sas_device);
+ list_add_tail(&sas_device->list, &ioc->sas_device_list);
+
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+}
+
/**
* _scsih_probe_sas - reporting sas devices to sas transport
* @ioc: per adapter object
@@ -7840,17 +8355,16 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc)
static void
_scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
{
- struct _sas_device *sas_device, *next;
- unsigned long flags;
+ struct _sas_device *sas_device;
- /* SAS Device List */
- list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
- list) {
+ if (ioc->hide_drives)
+ return;
+ while ((sas_device = get_next_sas_device(ioc))) {
if (!mpt3sas_transport_port_add(ioc, sas_device->handle,
sas_device->sas_address_parent)) {
- list_del(&sas_device->list);
- kfree(sas_device);
+ _scsih_sas_device_remove(ioc, sas_device);
+ sas_device_put(sas_device);
continue;
} else if (!sas_device->starget) {
/*
@@ -7863,15 +8377,13 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
- list_del(&sas_device->list);
- kfree(sas_device);
+ _scsih_sas_device_remove(ioc, sas_device);
+ sas_device_put(sas_device);
continue;
}
}
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_move_tail(&sas_device->list, &ioc->sas_device_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ sas_device_make_active(ioc, sas_device);
+ sas_device_put(sas_device);
}
}
@@ -7908,15 +8420,15 @@ _scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc)
}
/**
- * _scsih_scan_start - scsi lld callback for .scan_start
+ * scsih_scan_start - scsi lld callback for .scan_start
* @shost: SCSI host pointer
*
* The shost has the ability to discover targets on its own instead
* of scanning the entire bus. In our implemention, we will kick off
* firmware discovery.
*/
-static void
-_scsih_scan_start(struct Scsi_Host *shost)
+void
+scsih_scan_start(struct Scsi_Host *shost)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
int rc;
@@ -7934,7 +8446,7 @@ _scsih_scan_start(struct Scsi_Host *shost)
}
/**
- * _scsih_scan_finished - scsi lld callback for .scan_finished
+ * scsih_scan_finished - scsi lld callback for .scan_finished
* @shost: SCSI host pointer
* @time: elapsed time of the scan in jiffies
*
@@ -7942,8 +8454,8 @@ _scsih_scan_start(struct Scsi_Host *shost)
* scsi_host and the elapsed time of the scan in jiffies. In our implemention,
* we wait for firmware discovery to complete, then return 1.
*/
-static int
-_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
+int
+scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -7987,6 +8499,136 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
return 1;
}
+/* shost template for SAS 2.0 HBA devices */
+static struct scsi_host_template mpt2sas_driver_template = {
+ .module = THIS_MODULE,
+ .name = "Fusion MPT SAS Host",
+ .proc_name = MPT2SAS_DRIVER_NAME,
+ .queuecommand = scsih_qcmd,
+ .target_alloc = scsih_target_alloc,
+ .slave_alloc = scsih_slave_alloc,
+ .slave_configure = scsih_slave_configure,
+ .target_destroy = scsih_target_destroy,
+ .slave_destroy = scsih_slave_destroy,
+ .scan_finished = scsih_scan_finished,
+ .scan_start = scsih_scan_start,
+ .change_queue_depth = scsih_change_queue_depth,
+ .eh_abort_handler = scsih_abort,
+ .eh_device_reset_handler = scsih_dev_reset,
+ .eh_target_reset_handler = scsih_target_reset,
+ .eh_host_reset_handler = scsih_host_reset,
+ .bios_param = scsih_bios_param,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = MPT2SAS_SG_DEPTH,
+ .max_sectors = 32767,
+ .cmd_per_lun = 7,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mpt3sas_host_attrs,
+ .sdev_attrs = mpt3sas_dev_attrs,
+ .track_queue_depth = 1,
+};
+
+/* raid transport support for SAS 2.0 HBA devices */
+static struct raid_function_template mpt2sas_raid_functions = {
+ .cookie = &mpt2sas_driver_template,
+ .is_raid = scsih_is_raid,
+ .get_resync = scsih_get_resync,
+ .get_state = scsih_get_state,
+};
+
+/* shost template for SAS 3.0 HBA devices */
+static struct scsi_host_template mpt3sas_driver_template = {
+ .module = THIS_MODULE,
+ .name = "Fusion MPT SAS Host",
+ .proc_name = MPT3SAS_DRIVER_NAME,
+ .queuecommand = scsih_qcmd,
+ .target_alloc = scsih_target_alloc,
+ .slave_alloc = scsih_slave_alloc,
+ .slave_configure = scsih_slave_configure,
+ .target_destroy = scsih_target_destroy,
+ .slave_destroy = scsih_slave_destroy,
+ .scan_finished = scsih_scan_finished,
+ .scan_start = scsih_scan_start,
+ .change_queue_depth = scsih_change_queue_depth,
+ .eh_abort_handler = scsih_abort,
+ .eh_device_reset_handler = scsih_dev_reset,
+ .eh_target_reset_handler = scsih_target_reset,
+ .eh_host_reset_handler = scsih_host_reset,
+ .bios_param = scsih_bios_param,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = MPT3SAS_SG_DEPTH,
+ .max_sectors = 32767,
+ .cmd_per_lun = 7,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mpt3sas_host_attrs,
+ .sdev_attrs = mpt3sas_dev_attrs,
+ .track_queue_depth = 1,
+};
+
+/* raid transport support for SAS 3.0 HBA devices */
+static struct raid_function_template mpt3sas_raid_functions = {
+ .cookie = &mpt3sas_driver_template,
+ .is_raid = scsih_is_raid,
+ .get_resync = scsih_get_resync,
+ .get_state = scsih_get_state,
+};
+
+/**
+ * _scsih_determine_hba_mpi_version - determine in which MPI version class
+ * this device belongs to.
+ * @pdev: PCI device struct
+ *
+ * return MPI2_VERSION for SAS 2.0 HBA devices,
+ * MPI25_VERSION for SAS 3.0 HBA devices, and
+ * MPI26 VERSION for Cutlass & Invader SAS 3.0 HBA devices
+ */
+u16
+_scsih_determine_hba_mpi_version(struct pci_dev *pdev)
+{
+
+ switch (pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SSS6200:
+ case MPI2_MFGPAGE_DEVID_SAS2004:
+ case MPI2_MFGPAGE_DEVID_SAS2008:
+ case MPI2_MFGPAGE_DEVID_SAS2108_1:
+ case MPI2_MFGPAGE_DEVID_SAS2108_2:
+ case MPI2_MFGPAGE_DEVID_SAS2108_3:
+ case MPI2_MFGPAGE_DEVID_SAS2116_1:
+ case MPI2_MFGPAGE_DEVID_SAS2116_2:
+ case MPI2_MFGPAGE_DEVID_SAS2208_1:
+ case MPI2_MFGPAGE_DEVID_SAS2208_2:
+ case MPI2_MFGPAGE_DEVID_SAS2208_3:
+ case MPI2_MFGPAGE_DEVID_SAS2208_4:
+ case MPI2_MFGPAGE_DEVID_SAS2208_5:
+ case MPI2_MFGPAGE_DEVID_SAS2208_6:
+ case MPI2_MFGPAGE_DEVID_SAS2308_1:
+ case MPI2_MFGPAGE_DEVID_SAS2308_2:
+ case MPI2_MFGPAGE_DEVID_SAS2308_3:
+ return MPI2_VERSION;
+ case MPI25_MFGPAGE_DEVID_SAS3004:
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ case MPI25_MFGPAGE_DEVID_SAS3108_1:
+ case MPI25_MFGPAGE_DEVID_SAS3108_2:
+ case MPI25_MFGPAGE_DEVID_SAS3108_5:
+ case MPI25_MFGPAGE_DEVID_SAS3108_6:
+ return MPI25_VERSION;
+ case MPI26_MFGPAGE_DEVID_SAS3216:
+ case MPI26_MFGPAGE_DEVID_SAS3224:
+ case MPI26_MFGPAGE_DEVID_SAS3316_1:
+ case MPI26_MFGPAGE_DEVID_SAS3316_2:
+ case MPI26_MFGPAGE_DEVID_SAS3316_3:
+ case MPI26_MFGPAGE_DEVID_SAS3316_4:
+ case MPI26_MFGPAGE_DEVID_SAS3324_1:
+ case MPI26_MFGPAGE_DEVID_SAS3324_2:
+ case MPI26_MFGPAGE_DEVID_SAS3324_3:
+ case MPI26_MFGPAGE_DEVID_SAS3324_4:
+ return MPI26_VERSION;
+ }
+ return 0;
+}
+
/**
* _scsih_probe - attach and add scsi host
* @pdev: PCI device struct
@@ -7994,26 +8636,76 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
*
* Returns 0 success, anything else error.
*/
-static int
+int
_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct MPT3SAS_ADAPTER *ioc;
- struct Scsi_Host *shost;
+ struct Scsi_Host *shost = NULL;
int rv;
+ u16 hba_mpi_version;
- shost = scsi_host_alloc(&scsih_driver_template,
- sizeof(struct MPT3SAS_ADAPTER));
- if (!shost)
+ /* Determine in which MPI version class this pci device belongs */
+ hba_mpi_version = _scsih_determine_hba_mpi_version(pdev);
+ if (hba_mpi_version == 0)
return -ENODEV;
- /* init local params */
- ioc = shost_priv(shost);
- memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+ /* Enumerate only SAS 2.0 HBA's if hbas_to_enumerate is one,
+ * for other generation HBA's return with -ENODEV
+ */
+ if ((hbas_to_enumerate == 1) && (hba_mpi_version != MPI2_VERSION))
+ return -ENODEV;
+
+ /* Enumerate only SAS 3.0 HBA's if hbas_to_enumerate is two,
+ * for other generation HBA's return with -ENODEV
+ */
+ if ((hbas_to_enumerate == 2) && (!(hba_mpi_version == MPI25_VERSION
+ || hba_mpi_version == MPI26_VERSION)))
+ return -ENODEV;
+
+ switch (hba_mpi_version) {
+ case MPI2_VERSION:
+ /* Use mpt2sas driver host template for SAS 2.0 HBA's */
+ shost = scsi_host_alloc(&mpt2sas_driver_template,
+ sizeof(struct MPT3SAS_ADAPTER));
+ if (!shost)
+ return -ENODEV;
+ ioc = shost_priv(shost);
+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+ ioc->hba_mpi_version_belonged = hba_mpi_version;
+ ioc->id = mpt2_ids++;
+ sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME);
+ if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) {
+ ioc->is_warpdrive = 1;
+ ioc->hide_ir_msg = 1;
+ } else
+ ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
+ break;
+ case MPI25_VERSION:
+ case MPI26_VERSION:
+ /* Use mpt3sas driver host template for SAS 3.0 HBA's */
+ shost = scsi_host_alloc(&mpt3sas_driver_template,
+ sizeof(struct MPT3SAS_ADAPTER));
+ if (!shost)
+ return -ENODEV;
+ ioc = shost_priv(shost);
+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+ ioc->hba_mpi_version_belonged = hba_mpi_version;
+ ioc->id = mpt3_ids++;
+ sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME);
+ if ((ioc->hba_mpi_version_belonged == MPI25_VERSION &&
+ pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION) ||
+ (ioc->hba_mpi_version_belonged == MPI26_VERSION))
+ ioc->msix96_vector = 1;
+ break;
+ default:
+ return -ENODEV;
+ }
+
INIT_LIST_HEAD(&ioc->list);
+ spin_lock(&gioc_lock);
list_add_tail(&ioc->list, &mpt3sas_ioc_list);
+ spin_unlock(&gioc_lock);
ioc->shost = shost;
- ioc->id = mpt_ids++;
- sprintf(ioc->name, "%s%d", MPT3SAS_DRIVER_NAME, ioc->id);
ioc->pdev = pdev;
ioc->scsi_io_cb_idx = scsi_io_cb_idx;
ioc->tm_cb_idx = tm_cb_idx;
@@ -8030,6 +8722,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;
/* misc semaphores and spin locks */
mutex_init(&ioc->reset_in_progress_mutex);
+ /* initializing pci_access_mutex lock */
+ mutex_init(&ioc->pci_access_mutex);
spin_lock_init(&ioc->ioc_reset_in_progress_lock);
spin_lock_init(&ioc->scsi_lookup_lock);
spin_lock_init(&ioc->sas_device_lock);
@@ -8045,9 +8739,13 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->raid_device_list);
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
INIT_LIST_HEAD(&ioc->delayed_tr_list);
+ INIT_LIST_HEAD(&ioc->delayed_sc_list);
+ INIT_LIST_HEAD(&ioc->delayed_event_ack_list);
INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
INIT_LIST_HEAD(&ioc->reply_queue_list);
+ sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id);
+
/* init shost parameters */
shost->max_cmd_len = 32;
shost->max_lun = max_lun;
@@ -8086,7 +8784,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* event thread */
snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
- "fw_event%d", ioc->id);
+ "fw_event_%s%d", ioc->driver_name, ioc->id);
ioc->firmware_event_thread = alloc_ordered_workqueue(
ioc->firmware_event_name, WQ_MEM_RECLAIM);
if (!ioc->firmware_event_thread) {
@@ -8103,6 +8801,21 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
rv = -ENODEV;
goto out_attach_fail;
}
+
+ if (ioc->is_warpdrive) {
+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
+ ioc->hide_drives = 0;
+ else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
+ ioc->hide_drives = 1;
+ else {
+ if (mpt3sas_get_num_volumes(ioc))
+ ioc->hide_drives = 1;
+ else
+ ioc->hide_drives = 0;
+ }
+ } else
+ ioc->hide_drives = 0;
+
rv = scsi_add_host(shost, &pdev->dev);
if (rv) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
@@ -8117,21 +8830,23 @@ out_add_shost_fail:
out_attach_fail:
destroy_workqueue(ioc->firmware_event_thread);
out_thread_fail:
+ spin_lock(&gioc_lock);
list_del(&ioc->list);
+ spin_unlock(&gioc_lock);
scsi_host_put(shost);
return rv;
}
#ifdef CONFIG_PM
/**
- * _scsih_suspend - power management suspend main entry point
+ * scsih_suspend - power management suspend main entry point
* @pdev: PCI device struct
* @state: PM state change to (usually PCI_D3)
*
* Returns 0 success, anything else error.
*/
-static int
-_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
+int
+scsih_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8152,13 +8867,13 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
}
/**
- * _scsih_resume - power management resume main entry point
+ * scsih_resume - power management resume main entry point
* @pdev: PCI device struct
*
* Returns 0 success, anything else error.
*/
-static int
-_scsih_resume(struct pci_dev *pdev)
+int
+scsih_resume(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8185,7 +8900,7 @@ _scsih_resume(struct pci_dev *pdev)
#endif /* CONFIG_PM */
/**
- * _scsih_pci_error_detected - Called when a PCI error is detected.
+ * scsih_pci_error_detected - Called when a PCI error is detected.
* @pdev: PCI device struct
* @state: PCI channel state
*
@@ -8194,8 +8909,8 @@ _scsih_resume(struct pci_dev *pdev)
* Return value:
* PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
*/
-static pci_ers_result_t
-_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+pci_ers_result_t
+scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8224,15 +8939,15 @@ _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
}
/**
- * _scsih_pci_slot_reset - Called when PCI slot has been reset.
+ * scsih_pci_slot_reset - Called when PCI slot has been reset.
* @pdev: PCI device struct
*
* Description: This routine is called by the pci error recovery
* code after the PCI slot has been reset, just before we
* should resume normal operations.
*/
-static pci_ers_result_t
-_scsih_pci_slot_reset(struct pci_dev *pdev)
+pci_ers_result_t
+scsih_pci_slot_reset(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8261,15 +8976,15 @@ _scsih_pci_slot_reset(struct pci_dev *pdev)
}
/**
- * _scsih_pci_resume() - resume normal ops after PCI reset
+ * scsih_pci_resume() - resume normal ops after PCI reset
* @pdev: pointer to PCI device
*
* Called when the error recovery driver tells us that its
* OK to resume normal operation. Use completion to allow
* halted scsi ops to resume.
*/
-static void
-_scsih_pci_resume(struct pci_dev *pdev)
+void
+scsih_pci_resume(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8282,11 +8997,11 @@ _scsih_pci_resume(struct pci_dev *pdev)
}
/**
- * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
+ * scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
* @pdev: pointer to PCI device
*/
-static pci_ers_result_t
-_scsih_pci_mmio_enabled(struct pci_dev *pdev)
+pci_ers_result_t
+scsih_pci_mmio_enabled(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8300,61 +9015,121 @@ _scsih_pci_mmio_enabled(struct pci_dev *pdev)
return PCI_ERS_RESULT_NEED_RESET;
}
-/* raid transport support */
-static struct raid_function_template mpt3sas_raid_functions = {
- .cookie = &scsih_driver_template,
- .is_raid = _scsih_is_raid,
- .get_resync = _scsih_get_resync,
- .get_state = _scsih_get_state,
+/*
+ * The pci device ids are defined in mpi/mpi2_cnfg.h.
+ */
+static const struct pci_device_id mpt3sas_pci_table[] = {
+ /* Spitfire ~ 2004 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Falcon ~ 2008 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Liberator ~ 2108 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Meteor ~ 2116 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Thunderbolt ~ 2208 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Mustang ~ 2308 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* SSS6200 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Fury ~ 3004 and 3008 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Invader ~ 3108 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Cutlass ~ 3216 and 3224 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Intruder ~ 3316 and 3324 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_4,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_4,
+ PCI_ANY_ID, PCI_ANY_ID },
+ {0} /* Terminating entry */
};
+MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table);
-static struct pci_error_handlers _scsih_err_handler = {
- .error_detected = _scsih_pci_error_detected,
- .mmio_enabled = _scsih_pci_mmio_enabled,
- .slot_reset = _scsih_pci_slot_reset,
- .resume = _scsih_pci_resume,
+static struct pci_error_handlers _mpt3sas_err_handler = {
+ .error_detected = scsih_pci_error_detected,
+ .mmio_enabled = scsih_pci_mmio_enabled,
+ .slot_reset = scsih_pci_slot_reset,
+ .resume = scsih_pci_resume,
};
-static struct pci_driver scsih_driver = {
+static struct pci_driver mpt3sas_driver = {
.name = MPT3SAS_DRIVER_NAME,
- .id_table = scsih_pci_table,
+ .id_table = mpt3sas_pci_table,
.probe = _scsih_probe,
- .remove = _scsih_remove,
- .shutdown = _scsih_shutdown,
- .err_handler = &_scsih_err_handler,
+ .remove = scsih_remove,
+ .shutdown = scsih_shutdown,
+ .err_handler = &_mpt3sas_err_handler,
#ifdef CONFIG_PM
- .suspend = _scsih_suspend,
- .resume = _scsih_resume,
+ .suspend = scsih_suspend,
+ .resume = scsih_resume,
#endif
};
-
/**
- * _scsih_init - main entry point for this driver.
+ * scsih_init - main entry point for this driver.
*
* Returns 0 success, anything else error.
*/
-static int __init
-_scsih_init(void)
+int
+scsih_init(void)
{
- int error;
-
- mpt_ids = 0;
-
- pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME,
- MPT3SAS_DRIVER_VERSION);
-
- mpt3sas_transport_template =
- sas_attach_transport(&mpt3sas_transport_functions);
- if (!mpt3sas_transport_template)
- return -ENODEV;
-
-/* raid transport support */
- mpt3sas_raid_template = raid_class_attach(&mpt3sas_raid_functions);
- if (!mpt3sas_raid_template) {
- sas_release_transport(mpt3sas_transport_template);
- return -ENODEV;
- }
+ mpt2_ids = 0;
+ mpt3_ids = 0;
mpt3sas_base_initialize_callback_handler();
@@ -8392,33 +9167,17 @@ _scsih_init(void)
tm_sas_control_cb_idx = mpt3sas_base_register_callback_handler(
_scsih_sas_control_complete);
- mpt3sas_ctl_init();
-
- error = pci_register_driver(&scsih_driver);
- if (error) {
- /* raid transport support */
- raid_class_release(mpt3sas_raid_template);
- sas_release_transport(mpt3sas_transport_template);
- }
-
- return error;
+ return 0;
}
/**
- * _scsih_exit - exit point for this driver (when it is a module).
+ * scsih_exit - exit point for this driver (when it is a module).
*
* Returns 0 success, anything else error.
*/
-static void __exit
-_scsih_exit(void)
+void
+scsih_exit(void)
{
- pr_info("mpt3sas version %s unloading\n",
- MPT3SAS_DRIVER_VERSION);
-
- mpt3sas_ctl_exit();
-
- pci_unregister_driver(&scsih_driver);
-
mpt3sas_base_release_callback_handler(scsi_io_cb_idx);
mpt3sas_base_release_callback_handler(tm_cb_idx);
@@ -8434,9 +9193,86 @@ _scsih_exit(void)
mpt3sas_base_release_callback_handler(tm_sas_control_cb_idx);
/* raid transport support */
- raid_class_release(mpt3sas_raid_template);
+ if (hbas_to_enumerate != 1)
+ raid_class_release(mpt3sas_raid_template);
+ if (hbas_to_enumerate != 2)
+ raid_class_release(mpt2sas_raid_template);
sas_release_transport(mpt3sas_transport_template);
}
-module_init(_scsih_init);
-module_exit(_scsih_exit);
+/**
+ * _mpt3sas_init - main entry point for this driver.
+ *
+ * Returns 0 success, anything else error.
+ */
+static int __init
+_mpt3sas_init(void)
+{
+ int error;
+
+ pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME,
+ MPT3SAS_DRIVER_VERSION);
+
+ mpt3sas_transport_template =
+ sas_attach_transport(&mpt3sas_transport_functions);
+ if (!mpt3sas_transport_template)
+ return -ENODEV;
+
+ /* No need attach mpt3sas raid functions template
+ * if hbas_to_enumarate value is one.
+ */
+ if (hbas_to_enumerate != 1) {
+ mpt3sas_raid_template =
+ raid_class_attach(&mpt3sas_raid_functions);
+ if (!mpt3sas_raid_template) {
+ sas_release_transport(mpt3sas_transport_template);
+ return -ENODEV;
+ }
+ }
+
+ /* No need to attach mpt2sas raid functions template
+ * if hbas_to_enumarate value is two
+ */
+ if (hbas_to_enumerate != 2) {
+ mpt2sas_raid_template =
+ raid_class_attach(&mpt2sas_raid_functions);
+ if (!mpt2sas_raid_template) {
+ sas_release_transport(mpt3sas_transport_template);
+ return -ENODEV;
+ }
+ }
+
+ error = scsih_init();
+ if (error) {
+ scsih_exit();
+ return error;
+ }
+
+ mpt3sas_ctl_init(hbas_to_enumerate);
+
+ error = pci_register_driver(&mpt3sas_driver);
+ if (error)
+ scsih_exit();
+
+ return error;
+}
+
+/**
+ * _mpt3sas_exit - exit point for this driver (when it is a module).
+ *
+ */
+static void __exit
+_mpt3sas_exit(void)
+{
+ pr_info("mpt3sas version %s unloading\n",
+ MPT3SAS_DRIVER_VERSION);
+
+ pci_unregister_driver(&mpt3sas_driver);
+
+ mpt3sas_ctl_exit(hbas_to_enumerate);
+
+ scsih_exit();
+}
+
+module_init(_mpt3sas_init);
+module_exit(_mpt3sas_exit);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 70fd019..6a84b82 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
rphy->identify = mpt3sas_port->remote_identify;
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = mpt3sas_get_sdev_by_addr(ioc,
mpt3sas_port->remote_identify.sas_address);
if (!sas_device) {
dfailprintk(ioc, printk(MPT3SAS_FMT
@@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
ioc->name, __FILE__, __LINE__, __func__);
}
- if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE)
+ if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
sas_device->pend_sas_rphy_add = 0;
+ sas_device_put(sas_device);
+ }
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &rphy->dev,
@@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
if (sas_device) {
*identifier = sas_device->enclosure_logical_id;
rc = 0;
+ sas_device_put(sas_device);
} else {
*identifier = 0;
rc = -ENXIO;
}
+
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc;
}
@@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
- if (sas_device)
+ if (sas_device) {
rc = sas_device->slot;
- else
+ sas_device_put(sas_device);
+ } else {
rc = -ENXIO;
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc;
}
@@ -1412,7 +1418,6 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
u32 ioc_state;
unsigned long timeleft;
void *psge;
- u32 sgl_flags;
u8 issue_reset = 0;
void *data_out = NULL;
dma_addr_t data_out_dma;
@@ -1501,24 +1506,10 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
cpu_to_le16(sizeof(struct phy_error_log_request));
psge = &mpi_request->SGL;
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_reply), data_out_dma +
- sizeof(struct phy_control_request));
+ ioc->build_sg(ioc, psge, data_out_dma,
+ sizeof(struct phy_control_request),
+ data_out_dma + sizeof(struct phy_control_request),
+ sizeof(struct phy_control_reply));
dtransportprintk(ioc, pr_info(MPT3SAS_FMT
"phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n",
@@ -1609,7 +1600,7 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
SMP_PHY_CONTROL_LINK_RESET);
/* handle hba phys */
- memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
+ memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request.Operation = hard_reset ?
MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
new file mode 100644
index 0000000..540bd50
--- /dev/null
+++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
@@ -0,0 +1,344 @@
+/*
+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers
+ *
+ * Copyright (C) 2012-2014 LSI Corporation
+ * Copyright (C) 2013-2015 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
+ *
+ * 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 the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <asm/unaligned.h>
+
+#include "mpt3sas_base.h"
+
+/**
+ * _warpdrive_disable_ddio - Disable direct I/O for all the volumes
+ * @ioc: per adapter object
+ */
+static void
+_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc)
+{
+ Mpi2RaidVolPage1_t vol_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+ struct _raid_device *raid_device;
+ u16 handle;
+ u16 ioc_status;
+ unsigned long flags;
+
+ handle = 0xFFFF;
+ while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ handle = le16_to_cpu(vol_pg1.DevHandle);
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
+ if (raid_device)
+ raid_device->direct_io_enabled = 0;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+ }
+ return;
+}
+
+
+/**
+ * mpt3sas_get_num_volumes - Get number of volumes in the ioc
+ * @ioc: per adapter object
+ */
+u8
+mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc)
+{
+ Mpi2RaidVolPage1_t vol_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 handle;
+ u8 vol_cnt = 0;
+ u16 ioc_status;
+
+ handle = 0xFFFF;
+ while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ vol_cnt++;
+ handle = le16_to_cpu(vol_pg1.DevHandle);
+ }
+ return vol_cnt;
+}
+
+
+/**
+ * mpt3sas_init_warpdrive_properties - Set properties for warpdrive direct I/O.
+ * @ioc: per adapter object
+ * @raid_device: the raid_device object
+ */
+void
+mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
+ struct _raid_device *raid_device)
+{
+ Mpi2RaidVolPage0_t *vol_pg0;
+ Mpi2RaidPhysDiskPage0_t pd_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 sz;
+ u8 num_pds, count;
+ unsigned long stripe_sz, block_sz;
+ u8 stripe_exp, block_exp;
+ u64 dev_max_lba;
+
+ if (!ioc->is_warpdrive)
+ return;
+
+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "globally as drives are exposed\n", ioc->name);
+ return;
+ }
+ if (mpt3sas_get_num_volumes(ioc) > 1) {
+ _warpdrive_disable_ddio(ioc);
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "globally as number of drives > 1\n", ioc->name);
+ return;
+ }
+ if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle,
+ &num_pds)) || !num_pds) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "Failure in computing number of drives\n", ioc->name);
+ return;
+ }
+
+ sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
+ sizeof(Mpi2RaidVol0PhysDisk_t));
+ vol_pg0 = kzalloc(sz, GFP_KERNEL);
+ if (!vol_pg0) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "Memory allocation failure for RVPG0\n", ioc->name);
+ return;
+ }
+
+ if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "Failure in retrieving RVPG0\n", ioc->name);
+ kfree(vol_pg0);
+ return;
+ }
+
+ /*
+ * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
+ * assumed for WARPDRIVE, disable direct I/O
+ */
+ if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
+ pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x): num_mem=%d, "
+ "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
+ num_pds, MPT_MAX_WARPDRIVE_PDS);
+ kfree(vol_pg0);
+ return;
+ }
+ for (count = 0; count < num_pds; count++) {
+ if (mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
+ vol_pg0->PhysDisk[count].PhysDiskNum) ||
+ pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
+ "disabled for the drive with handle(0x%04x) member"
+ "handle retrieval failed for member number=%d\n",
+ ioc->name, raid_device->handle,
+ vol_pg0->PhysDisk[count].PhysDiskNum);
+ goto out_error;
+ }
+ /* Disable direct I/O if member drive lba exceeds 4 bytes */
+ dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
+ if (dev_max_lba >> 32) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
+ "disabled for the drive with handle(0x%04x) member"
+ " handle (0x%04x) unsupported max lba 0x%016llx\n",
+ ioc->name, raid_device->handle,
+ le16_to_cpu(pd_pg0.DevHandle),
+ (unsigned long long)dev_max_lba);
+ goto out_error;
+ }
+
+ raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
+ }
+
+ /*
+ * Assumption for WD: Direct I/O is not supported if the volume is
+ * not RAID0
+ */
+ if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x): type=%d, "
+ "s_sz=%uK, blk_size=%u\n", ioc->name,
+ raid_device->handle, raid_device->volume_type,
+ (le32_to_cpu(vol_pg0->StripeSize) *
+ le16_to_cpu(vol_pg0->BlockSize)) / 1024,
+ le16_to_cpu(vol_pg0->BlockSize));
+ goto out_error;
+ }
+
+ stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+ stripe_exp = find_first_bit(&stripe_sz, 32);
+ if (stripe_exp == 32) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
+ ioc->name, raid_device->handle,
+ (le32_to_cpu(vol_pg0->StripeSize) *
+ le16_to_cpu(vol_pg0->BlockSize)) / 1024);
+ goto out_error;
+ }
+ raid_device->stripe_exponent = stripe_exp;
+ block_sz = le16_to_cpu(vol_pg0->BlockSize);
+ block_exp = find_first_bit(&block_sz, 16);
+ if (block_exp == 16) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x) invalid block sz %u\n",
+ ioc->name, raid_device->handle,
+ le16_to_cpu(vol_pg0->BlockSize));
+ goto out_error;
+ }
+ raid_device->block_exponent = block_exp;
+ raid_device->direct_io_enabled = 1;
+
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive"
+ " with handle(0x%04x)\n", ioc->name, raid_device->handle);
+ /*
+ * WARPDRIVE: Though the following fields are not used for direct IO,
+ * stored for future purpose:
+ */
+ raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
+ raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+ raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
+
+
+ kfree(vol_pg0);
+ return;
+
+out_error:
+ raid_device->direct_io_enabled = 0;
+ for (count = 0; count < num_pds; count++)
+ raid_device->pd_handle[count] = 0;
+ kfree(vol_pg0);
+ return;
+}
+
+/**
+ * mpt3sas_scsi_direct_io_get - returns direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns the smid stored scmd pointer.
+ */
+inline u8
+mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ return ioc->scsi_lookup[smid - 1].direct_io;
+}
+
+/**
+ * mpt3sas_scsi_direct_io_set - sets direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @direct_io: Zero or non-zero value to set in the direct_io flag
+ *
+ * Returns Nothing.
+ */
+inline void
+mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
+{
+ ioc->scsi_lookup[smid - 1].direct_io = direct_io;
+}
+
+/**
+ * mpt3sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
+ * @ioc: per adapter object
+ * @scmd: pointer to scsi command object
+ * @raid_device: pointer to raid device data structure
+ * @mpi_request: pointer to the SCSI_IO reqest message frame
+ * @smid: system request message index
+ *
+ * Returns nothing
+ */
+void
+mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
+ u16 smid)
+{
+ sector_t v_lba, p_lba, stripe_off, column, io_size;
+ u32 stripe_sz, stripe_exp;
+ u8 num_pds, cmd = scmd->cmnd[0];
+
+ if (cmd != READ_10 && cmd != WRITE_10 &&
+ cmd != READ_16 && cmd != WRITE_16)
+ return;
+
+ if (cmd == READ_10 || cmd == WRITE_10)
+ v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]);
+ else
+ v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]);
+
+ io_size = scsi_bufflen(scmd) >> raid_device->block_exponent;
+
+ if (v_lba + io_size - 1 > raid_device->max_lba)
+ return;
+
+ stripe_sz = raid_device->stripe_sz;
+ stripe_exp = raid_device->stripe_exponent;
+ stripe_off = v_lba & (stripe_sz - 1);
+
+ /* Return unless IO falls within a stripe */
+ if (stripe_off + io_size > stripe_sz)
+ return;
+
+ num_pds = raid_device->num_pds;
+ p_lba = v_lba >> stripe_exp;
+ column = sector_div(p_lba, num_pds);
+ p_lba = (p_lba << stripe_exp) + stripe_off;
+ mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]);
+
+ if (cmd == READ_10 || cmd == WRITE_10)
+ put_unaligned_be32(lower_32_bits(p_lba),
+ &mpi_request->CDB.CDB32[2]);
+ else
+ put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]);
+
+ mpt3sas_scsi_direct_io_set(ioc, smid, 1);
+}
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
index 9270d15..f6fc4a7 100644
--- a/drivers/scsi/mvsas/mv_94xx.c
+++ b/drivers/scsi/mvsas/mv_94xx.c
@@ -330,6 +330,51 @@ static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
}
+static void mvs_94xx_sgpio_init(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+ u32 tmp;
+
+ tmp = mr32(MVS_HST_CHIP_CONFIG);
+ tmp |= 0x100;
+ mw32(MVS_HST_CHIP_CONFIG, tmp);
+
+ mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT);
+
+ mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ 8 << MVS_SGPIO_CFG1_LOWA_SHIFT |
+ 8 << MVS_SGPIO_CFG1_HIA_SHIFT |
+ 4 << MVS_SGPIO_CFG1_LOWB_SHIFT |
+ 4 << MVS_SGPIO_CFG1_HIB_SHIFT |
+ 2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT |
+ 1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT
+ );
+
+ mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ (300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */
+ 66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/
+ );
+
+ mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ MVS_SGPIO_CFG0_ENABLE |
+ MVS_SGPIO_CFG0_BLINKA |
+ MVS_SGPIO_CFG0_BLINKB |
+ /* 3*4 data bits / PDU */
+ (12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT
+ );
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ DEFAULT_SGPIO_BITS);
+
+ mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ ((mvi->id * 4) + 3) << (8 * 3) |
+ ((mvi->id * 4) + 2) << (8 * 2) |
+ ((mvi->id * 4) + 1) << (8 * 1) |
+ ((mvi->id * 4) + 0) << (8 * 0));
+
+}
+
static int mvs_94xx_init(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
@@ -533,6 +578,8 @@ static int mvs_94xx_init(struct mvs_info *mvi)
/* Enable SRS interrupt */
mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
+ mvs_94xx_sgpio_init(mvi);
+
return 0;
}
@@ -1005,6 +1052,92 @@ static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
}
+static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
+ u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data)
+{
+ int i;
+
+ switch (reg_type) {
+
+ case SAS_GPIO_REG_TX_GP:
+ if (reg_index == 0)
+ return -EINVAL;
+
+ if (reg_count > 1)
+ return -EINVAL;
+
+ if (reg_count == 0)
+ return 0;
+
+ /* maximum supported bits = hosts * 4 drives * 3 bits */
+ for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) {
+
+ /* select host */
+ struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)];
+
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+
+ int drive = (i/3) & (4-1); /* drive number on host */
+ u32 block = mr32(MVS_SGPIO_DCTRL +
+ MVS_SGPIO_HOST_OFFSET * mvi->id);
+
+
+ /*
+ * if bit is set then create a mask with the first
+ * bit of the drive set in the mask ...
+ */
+ u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ?
+ 1<<(24-drive*8) : 0;
+
+ /*
+ * ... and then shift it to the right position based
+ * on the led type (activity/id/fail)
+ */
+ switch (i%3) {
+ case 0: /* activity */
+ block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
+ << (24-drive*8));
+ /* hardwire activity bit to SOF */
+ block |= LED_BLINKA_SOF << (
+ MVS_SGPIO_DCTRL_ACT_SHIFT +
+ (24-drive*8));
+ break;
+ case 1: /* id */
+ block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
+ << (24-drive*8));
+ block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
+ break;
+ case 2: /* fail */
+ block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
+ << (24-drive*8));
+ block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
+ break;
+ }
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ block);
+
+ }
+
+ return reg_count;
+
+ case SAS_GPIO_REG_TX:
+ if (reg_index + reg_count > mvs_prv->n_host)
+ return -EINVAL;
+
+ for (i = 0; i < reg_count; i++) {
+ struct mvs_info *mvi = mvs_prv->mvi[i+reg_index];
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ be32_to_cpu(((u32 *) write_data)[i]));
+ }
+ return reg_count;
+ }
+ return -ENOSYS;
+}
+
const struct mvs_dispatch mvs_94xx_dispatch = {
"mv94xx",
mvs_94xx_init,
@@ -1057,5 +1190,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
mvs_94xx_fix_dma,
mvs_94xx_tune_interrupt,
mvs_94xx_non_spec_ncq_error,
+ mvs_94xx_gpio_write,
};
diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h
index 14e1974..5789608 100644
--- a/drivers/scsi/mvsas/mv_94xx.h
+++ b/drivers/scsi/mvsas/mv_94xx.h
@@ -38,6 +38,10 @@ enum VANIR_REVISION_ID {
VANIR_C2_REV = 0xC2,
};
+enum host_registers {
+ MVS_HST_CHIP_CONFIG = 0x10104, /* chip configuration */
+};
+
enum hw_registers {
MVS_GBL_CTL = 0x04, /* global control */
MVS_GBL_INT_STAT = 0x00, /* global irq status */
@@ -239,6 +243,73 @@ struct mvs_prd {
__le32 im_len;
} __attribute__ ((packed));
+enum sgpio_registers {
+ MVS_SGPIO_HOST_OFFSET = 0x100, /* offset between hosts */
+
+ MVS_SGPIO_CFG0 = 0xc200,
+ MVS_SGPIO_CFG0_ENABLE = (1 << 0), /* enable pins */
+ MVS_SGPIO_CFG0_BLINKB = (1 << 1), /* blink generators */
+ MVS_SGPIO_CFG0_BLINKA = (1 << 2),
+ MVS_SGPIO_CFG0_INVSCLK = (1 << 3), /* invert signal? */
+ MVS_SGPIO_CFG0_INVSLOAD = (1 << 4),
+ MVS_SGPIO_CFG0_INVSDOUT = (1 << 5),
+ MVS_SGPIO_CFG0_SLOAD_FALLEDGE = (1 << 6), /* rise/fall edge? */
+ MVS_SGPIO_CFG0_SDOUT_FALLEDGE = (1 << 7),
+ MVS_SGPIO_CFG0_SDIN_RISEEDGE = (1 << 8),
+ MVS_SGPIO_CFG0_MAN_BITLEN_SHIFT = 18, /* bits/frame manual mode */
+ MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT = 24, /* bits/frame auto mode */
+
+ MVS_SGPIO_CFG1 = 0xc204, /* blink timing register */
+ MVS_SGPIO_CFG1_LOWA_SHIFT = 0, /* A off time */
+ MVS_SGPIO_CFG1_HIA_SHIFT = 4, /* A on time */
+ MVS_SGPIO_CFG1_LOWB_SHIFT = 8, /* B off time */
+ MVS_SGPIO_CFG1_HIB_SHIFT = 12, /* B on time */
+ MVS_SGPIO_CFG1_MAXACTON_SHIFT = 16, /* max activity on time */
+
+ /* force activity off time */
+ MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT = 20,
+ /* stretch activity on time */
+ MVS_SGPIO_CFG1_STRCHACTON_SHIFT = 24,
+ /* stretch activiity off time */
+ MVS_SGPIO_CFG1_STRCHACTOFF_SHIFT = 28,
+
+
+ MVS_SGPIO_CFG2 = 0xc208, /* clock speed register */
+ MVS_SGPIO_CFG2_CLK_SHIFT = 0,
+ MVS_SGPIO_CFG2_BLINK_SHIFT = 20,
+
+ MVS_SGPIO_CTRL = 0xc20c, /* SDOUT/SDIN mode control */
+ MVS_SGPIO_CTRL_SDOUT_AUTO = 2,
+ MVS_SGPIO_CTRL_SDOUT_SHIFT = 2,
+
+ MVS_SGPIO_DSRC = 0xc220, /* map ODn bits to drives */
+
+ MVS_SGPIO_DCTRL = 0xc238,
+ MVS_SGPIO_DCTRL_ERR_SHIFT = 0,
+ MVS_SGPIO_DCTRL_LOC_SHIFT = 3,
+ MVS_SGPIO_DCTRL_ACT_SHIFT = 5,
+};
+
+enum sgpio_led_status {
+ LED_OFF = 0,
+ LED_ON = 1,
+ LED_BLINKA = 2,
+ LED_BLINKA_INV = 3,
+ LED_BLINKA_SOF = 4,
+ LED_BLINKA_EOF = 5,
+ LED_BLINKB = 6,
+ LED_BLINKB_INV = 7,
+};
+
+#define DEFAULT_SGPIO_BITS ((LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 3) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 2) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 1) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 0))
+
/*
* these registers are accessed through port vendor
* specific address/data registers
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index e2d555c..c7c2505 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -65,7 +65,6 @@ static struct scsi_host_template mvs_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = mvst_host_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -85,6 +84,8 @@ static struct sas_domain_function_template mvs_transport_ops = {
.lldd_port_formed = mvs_port_formed,
.lldd_port_deformed = mvs_port_deformed,
+ .lldd_write_gpio = mvs_gpio_write,
+
};
static void mvs_phy_init(struct mvs_info *mvi, int phy_id)
@@ -641,9 +642,9 @@ static void mvs_pci_remove(struct pci_dev *pdev)
tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
#endif
+ scsi_remove_host(mvi->shost);
sas_unregister_ha(sha);
sas_remove_host(mvi->shost);
- scsi_remove_host(mvi->shost);
MVS_CHIP_DISP->interrupt_disable(mvi);
free_irq(mvi->pdev->irq, sha);
@@ -759,7 +760,7 @@ mvs_store_interrupt_coalescing(struct device *cdev,
struct device_attribute *attr,
const char *buffer, size_t size)
{
- int val = 0;
+ unsigned int val = 0;
struct mvs_info *mvi = NULL;
struct Scsi_Host *shost = class_to_shost(cdev);
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
@@ -767,7 +768,7 @@ mvs_store_interrupt_coalescing(struct device *cdev,
if (buffer == NULL)
return size;
- if (sscanf(buffer, "%d", &val) != 1)
+ if (sscanf(buffer, "%u", &val) != 1)
return -EINVAL;
if (val >= 0x10000) {
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 9c78074..83cd3ea 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -737,8 +737,8 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
mv_dprintk("device %016llx not ready.\n",
SAS_ADDR(dev->sas_addr));
- rc = SAS_PHY_DOWN;
- return rc;
+ rc = SAS_PHY_DOWN;
+ return rc;
}
tei.port = dev->port->lldd_port;
if (tei.port && !tei.port->port_attached && !tmf) {
@@ -2105,3 +2105,16 @@ int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
return 0;
}
+int mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data)
+{
+ struct mvs_prv_info *mvs_prv = sha->lldd_ha;
+ struct mvs_info *mvi = mvs_prv->mvi[0];
+
+ if (MVS_CHIP_DISP->gpio_write) {
+ return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type,
+ reg_index, reg_count, write_data);
+ }
+
+ return -ENOSYS;
+}
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index dc409c0..f9afd4c 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -103,6 +103,7 @@ enum dev_reset {
};
struct mvs_info;
+struct mvs_prv_info;
struct mvs_dispatch {
char *name;
@@ -172,6 +173,8 @@ struct mvs_dispatch {
int buf_len, int from, void *prd);
void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
void (*non_spec_ncq_error)(struct mvs_info *mvi);
+ int (*gpio_write)(struct mvs_prv_info *mvs_prv, u8 reg_type,
+ u8 reg_index, u8 reg_count, u8 *write_data);
};
@@ -476,5 +479,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
+int mvs_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data);
#endif
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 3e6b866..3928507 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -31,6 +31,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/ktime.h>
#include <linux/blkdev.h>
#include <linux/io.h>
#include <scsi/scsi.h>
@@ -858,8 +859,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba,
struct mvumi_hs_page2 *hs_page2;
struct mvumi_hs_page4 *hs_page4;
struct mvumi_hs_page3 *hs_page3;
- struct timeval time;
- unsigned int local_time;
+ u64 time;
+ u64 local_time;
switch (hs_header->page_code) {
case HS_PAGE_HOST_INFO:
@@ -877,9 +878,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba,
hs_page2->slot_number = 0;
hs_page2->intr_level = 0;
hs_page2->intr_vector = 0;
- do_gettimeofday(&time);
- local_time = (unsigned int) (time.tv_sec -
- (sys_tz.tz_minuteswest * 60));
+ time = ktime_get_real_seconds();
+ local_time = (time - (sys_tz.tz_minuteswest * 60));
hs_page2->seconds_since1970 = local_time;
hs_header->checksum = mvumi_calculate_checksum(hs_header,
hs_header->frame_length);
@@ -2629,7 +2629,7 @@ static void mvumi_shutdown(struct pci_dev *pdev)
mvumi_flush_cache(mhba);
}
-static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct mvumi_hba *mhba = NULL;
@@ -2648,7 +2648,7 @@ static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
-static int mvumi_resume(struct pci_dev *pdev)
+static int __maybe_unused mvumi_resume(struct pci_dev *pdev)
{
int ret;
struct mvumi_hba *mhba = NULL;
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 0cccd60..3b11aad 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -170,10 +170,7 @@ static int _osd_get_print_system_info(struct osd_dev *od,
/* FIXME: Where are the time utilities */
pFirst = get_attrs[a++].val_ptr;
- OSD_INFO("CLOCK [0x%02x%02x%02x%02x%02x%02x]\n",
- ((char *)pFirst)[0], ((char *)pFirst)[1],
- ((char *)pFirst)[2], ((char *)pFirst)[3],
- ((char *)pFirst)[4], ((char *)pFirst)[5]);
+ OSD_INFO("CLOCK [0x%6phN]\n", pFirst);
if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */
unsigned len = get_attrs[a].len;
@@ -2009,9 +2006,8 @@ EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
*/
void osd_set_caps(struct osd_cdb *cdb, const void *caps)
{
- bool is_ver1 = true;
/* NOTE: They start at same address */
- memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN);
+ memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
}
bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index e81eadd..512037e 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -1,6 +1,4 @@
#define PSEUDO_DMA
-#define UNSAFE /* Not unsafe for PAS16 -- use it */
-#define PDEBUG 0
/*
* This driver adapted from Drew Eckhardt's Trantor T128 driver
@@ -71,14 +69,10 @@
#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/proc_fs.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/stat.h>
#include <linux/init.h>
#include <scsi/scsi_host.h>
@@ -87,8 +81,8 @@
#include "NCR5380.h"
-static unsigned short pas16_addr = 0;
-static int pas16_irq = 0;
+static unsigned short pas16_addr;
+static int pas16_irq;
static const int scsi_irq_translate[] =
@@ -146,22 +140,6 @@ static const unsigned short pas16_offset[ 8 ] =
* START_DMA_INITIATOR_RECEIVE_REG wo
*/
};
-/*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
- where something crashed or gets stuck at */
-/* 1 = blue
- 2 = green
- 3 = cyan
- 4 = red
- 5 = magenta
- 6 = yellow
- 7 = white
-*/
-#if 1
-#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
/*
@@ -205,7 +183,7 @@ static void __init
outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */
outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+ inb(io_port + pas16_offset[RESET_PARITY_INTERRUPT_REG]);
/* Set the SCSI interrupt pointer without mucking up the sound
* interrupt pointer in the same byte.
@@ -280,13 +258,13 @@ static int __init
* put in an additional test to try to weed them out.
*/
- outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
- NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */
- if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */
- return 0; /* and try to read */
- NCR5380_write( MODE_REG, 0x00 ); /* it back. */
- if( NCR5380_read( MODE_REG ) != 0x00 )
- return 0;
+ outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */
+ outb(0x20, io_port + pas16_offset[MODE_REG]); /* Is it really SCSI? */
+ if (inb(io_port + pas16_offset[MODE_REG]) != 0x20) /* Write to a reg. */
+ return 0; /* and try to read */
+ outb(0x00, io_port + pas16_offset[MODE_REG]); /* it back. */
+ if (inb(io_port + pas16_offset[MODE_REG]) != 0x00)
+ return 0;
return 1;
}
@@ -305,7 +283,7 @@ static int __init
static int __init pas16_setup(char *str)
{
- static int commandline_current = 0;
+ static int commandline_current;
int i;
int ints[10];
@@ -344,8 +322,8 @@ __setup("pas16=", pas16_setup);
static int __init pas16_detect(struct scsi_host_template *tpnt)
{
- static int current_override = 0;
- static unsigned short current_base = 0;
+ static int current_override;
+ static unsigned short current_base;
struct Scsi_Host *instance;
unsigned short io_port;
int count;
@@ -377,34 +355,32 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
}
else
for (; !io_port && (current_base < NO_BASES); ++current_base) {
-#if (PDEBUG & PDEBUG_INIT)
- printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
-#endif
+ dprintk(NDEBUG_INIT, "pas16: probing io_port 0x%04x\n",
+ (unsigned int)bases[current_base].io_port);
if ( !bases[current_base].noauto &&
pas16_hw_detect( current_base ) ){
io_port = bases[current_base].io_port;
init_board( io_port, default_irqs[ current_base ], 0 );
-#if (PDEBUG & PDEBUG_INIT)
- printk("scsi-pas16 : detected board.\n");
-#endif
+ dprintk(NDEBUG_INIT, "pas16: detected board\n");
}
}
-
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
- printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port);
-#endif
+ dprintk(NDEBUG_INIT, "pas16: io_port = 0x%04x\n",
+ (unsigned int)io_port);
if (!io_port)
break;
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
if(instance == NULL)
- break;
+ goto out;
instance->io_port = io_port;
- NCR5380_init(instance, 0);
+ if (NCR5380_init(instance, 0))
+ goto out_unregister;
+
+ NCR5380_maybe_reset_bus(instance);
if (overrides[current_override].irq != IRQ_AUTO)
instance->irq = overrides[current_override].irq;
@@ -431,14 +407,18 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
}
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
- printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+ dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
+ instance->host_no, instance->irq);
++current_override;
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out:
+ return count;
}
/*
@@ -561,29 +541,29 @@ static int pas16_release(struct Scsi_Host *shost)
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
scsi_unregister(shost);
return 0;
}
static struct scsi_host_template driver_template = {
- .name = "Pro Audio Spectrum-16 SCSI",
- .detect = pas16_detect,
- .release = pas16_release,
- .proc_name = "pas16",
- .show_info = pas16_show_info,
- .write_info = pas16_write_info,
- .info = pas16_info,
- .queuecommand = pas16_queue_command,
- .eh_abort_handler = pas16_abort,
- .eh_bus_reset_handler = pas16_bus_reset,
- .bios_param = pas16_biosparam,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .name = "Pro Audio Spectrum-16 SCSI",
+ .detect = pas16_detect,
+ .release = pas16_release,
+ .proc_name = "pas16",
+ .show_info = pas16_show_info,
+ .write_info = pas16_write_info,
+ .info = pas16_info,
+ .queuecommand = pas16_queue_command,
+ .eh_abort_handler = pas16_abort,
+ .eh_bus_reset_handler = pas16_bus_reset,
+ .bios_param = pas16_biosparam,
+ .can_queue = 32,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index c6109c8..d375277 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -24,9 +24,6 @@
#ifndef PAS16_H
#define PAS16_H
-#define PDEBUG_INIT 0x1
-#define PDEBUG_TRANSFER 0x2
-
#define PAS16_DEFAULT_BASE_1 0x388
#define PAS16_DEFAULT_BASE_2 0x384
#define PAS16_DEFAULT_BASE_3 0x38c
@@ -98,46 +95,16 @@
#define OPERATION_MODE_1 0xec03
#define IO_CONFIG_3 0xf002
+#define NCR5380_implementation_fields /* none */
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
-#endif
-
-#define NCR5380_implementation_fields \
- volatile unsigned short io_port
-
-#define NCR5380_local_declare() \
- volatile unsigned short io_port
+#define PAS16_io_port(reg) (instance->io_port + pas16_offset[(reg)])
-#define NCR5380_setup(instance) \
- io_port = (instance)->io_port
-
-#define PAS16_io_port(reg) ( io_port + pas16_offset[(reg)] )
-
-#if !(PDEBUG & PDEBUG_TRANSFER)
#define NCR5380_read(reg) ( inb(PAS16_io_port(reg)) )
#define NCR5380_write(reg, value) ( outb((value),PAS16_io_port(reg)) )
-#else
-#define NCR5380_read(reg) \
- (((unsigned char) printk("scsi%d : read register %d at io_port %04x\n"\
- , instance->hostno, (reg), PAS16_io_port(reg))), inb( PAS16_io_port(reg)) )
-
-#define NCR5380_write(reg, value) \
- (printk("scsi%d : write %02x to register %d at io_port %04x\n", \
- instance->hostno, (value), (reg), PAS16_io_port(reg)), \
- outb( (value),PAS16_io_port(reg) ) )
-
-#endif
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_intr pas16_intr
-#define do_NCR5380_intr do_pas16_intr
#define NCR5380_queue_command pas16_queue_command
#define NCR5380_abort pas16_abort
#define NCR5380_bus_reset pas16_bus_reset
@@ -150,5 +117,4 @@
#define PAS16_IRQS 0xd4a8
-#endif /* ndef ASM */
#endif /* PAS16_H */
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
index f14ec6e..199527d 100644
--- a/drivers/scsi/pm8001/pm8001_defs.h
+++ b/drivers/scsi/pm8001/pm8001_defs.h
@@ -51,6 +51,8 @@ enum chip_flavors {
chip_8076,
chip_8077,
chip_8006,
+ chip_8070,
+ chip_8072
};
enum phy_speed {
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 5c0356f..062ab34 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -58,6 +58,8 @@ static const struct pm8001_chip_info pm8001_chips[] = {
[chip_8076] = {0, 16, &pm8001_80xx_dispatch,},
[chip_8077] = {0, 16, &pm8001_80xx_dispatch,},
[chip_8006] = {0, 16, &pm8001_80xx_dispatch,},
+ [chip_8070] = {0, 8, &pm8001_80xx_dispatch,},
+ [chip_8072] = {0, 16, &pm8001_80xx_dispatch,},
};
static int pm8001_id;
@@ -88,7 +90,6 @@ static struct scsi_host_template pm8001_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = pm8001_host_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -480,7 +481,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
#ifdef PM8001_USE_TASKLET
/* Tasklet for non msi-x interrupt handler */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled())
+ || (pm8001_ha->chip_id == chip_8001))
tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
(unsigned long)&(pm8001_ha->irq_vector[0]));
else
@@ -634,6 +636,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
payload.minor_function = 0;
payload.length = 128;
}
+ } else if ((pm8001_ha->chip_id == chip_8070 ||
+ pm8001_ha->chip_id == chip_8072) &&
+ pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) {
+ payload.minor_function = 4;
+ payload.length = 4096;
} else {
payload.minor_function = 1;
payload.length = 4096;
@@ -660,6 +667,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
else if (deviceid == 0x0042)
pm8001_ha->sas_addr[j] =
payload.func_specific[0x010 + i];
+ } else if ((pm8001_ha->chip_id == chip_8070 ||
+ pm8001_ha->chip_id == chip_8072) &&
+ pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) {
+ pm8001_ha->sas_addr[j] =
+ payload.func_specific[0x010 + i];
} else
pm8001_ha->sas_addr[j] =
payload.func_specific[0x804 + i];
@@ -720,6 +732,153 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
return 0;
}
+struct pm8001_mpi3_phy_pg_trx_config {
+ u32 LaneLosCfg;
+ u32 LanePgaCfg1;
+ u32 LanePisoCfg1;
+ u32 LanePisoCfg2;
+ u32 LanePisoCfg3;
+ u32 LanePisoCfg4;
+ u32 LanePisoCfg5;
+ u32 LanePisoCfg6;
+ u32 LaneBctCtrl;
+};
+
+/**
+ * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings
+ * @pm8001_ha : our adapter
+ * @phycfg : PHY config page to populate
+ */
+static
+void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_mpi3_phy_pg_trx_config *phycfg)
+{
+ phycfg->LaneLosCfg = 0x00000132;
+ phycfg->LanePgaCfg1 = 0x00203949;
+ phycfg->LanePisoCfg1 = 0x000000FF;
+ phycfg->LanePisoCfg2 = 0xFF000001;
+ phycfg->LanePisoCfg3 = 0xE7011300;
+ phycfg->LanePisoCfg4 = 0x631C40C0;
+ phycfg->LanePisoCfg5 = 0xF8102036;
+ phycfg->LanePisoCfg6 = 0xF74A1000;
+ phycfg->LaneBctCtrl = 0x00FB33F8;
+}
+
+/**
+ * pm8001_get_external_phy_settings : Retrieves the external PHY settings
+ * @pm8001_ha : our adapter
+ * @phycfg : PHY config page to populate
+ */
+static
+void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_mpi3_phy_pg_trx_config *phycfg)
+{
+ phycfg->LaneLosCfg = 0x00000132;
+ phycfg->LanePgaCfg1 = 0x00203949;
+ phycfg->LanePisoCfg1 = 0x000000FF;
+ phycfg->LanePisoCfg2 = 0xFF000001;
+ phycfg->LanePisoCfg3 = 0xE7011300;
+ phycfg->LanePisoCfg4 = 0x63349140;
+ phycfg->LanePisoCfg5 = 0xF8102036;
+ phycfg->LanePisoCfg6 = 0xF80D9300;
+ phycfg->LaneBctCtrl = 0x00FB33F8;
+}
+
+/**
+ * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext
+ * @pm8001_ha : our adapter
+ * @phymask : The PHY mask
+ */
+static
+void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask)
+{
+ switch (pm8001_ha->pdev->subsystem_device) {
+ case 0x0070: /* H1280 - 8 external 0 internal */
+ case 0x0072: /* H12F0 - 16 external 0 internal */
+ *phymask = 0x0000;
+ break;
+
+ case 0x0071: /* H1208 - 0 external 8 internal */
+ case 0x0073: /* H120F - 0 external 16 internal */
+ *phymask = 0xFFFF;
+ break;
+
+ case 0x0080: /* H1244 - 4 external 4 internal */
+ *phymask = 0x00F0;
+ break;
+
+ case 0x0081: /* H1248 - 4 external 8 internal */
+ *phymask = 0x0FF0;
+ break;
+
+ case 0x0082: /* H1288 - 8 external 8 internal */
+ *phymask = 0xFF00;
+ break;
+
+ default:
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Unknown subsystem device=0x%.04x",
+ pm8001_ha->pdev->subsystem_device));
+ }
+}
+
+/**
+ * pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings
+ * @pm8001_ha : our adapter
+ */
+static
+int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha)
+{
+ struct pm8001_mpi3_phy_pg_trx_config phycfg_int;
+ struct pm8001_mpi3_phy_pg_trx_config phycfg_ext;
+ int phymask = 0;
+ int i = 0;
+
+ memset(&phycfg_int, 0, sizeof(phycfg_int));
+ memset(&phycfg_ext, 0, sizeof(phycfg_ext));
+
+ pm8001_get_internal_phy_settings(pm8001_ha, &phycfg_int);
+ pm8001_get_external_phy_settings(pm8001_ha, &phycfg_ext);
+ pm8001_get_phy_mask(pm8001_ha, &phymask);
+
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+ if (phymask & (1 << i)) {/* Internal PHY */
+ pm8001_set_phy_profile_single(pm8001_ha, i,
+ sizeof(phycfg_int) / sizeof(u32),
+ (u32 *)&phycfg_int);
+
+ } else { /* External PHY */
+ pm8001_set_phy_profile_single(pm8001_ha, i,
+ sizeof(phycfg_ext) / sizeof(u32),
+ (u32 *)&phycfg_ext);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID.
+ * @pm8001_ha : our hba.
+ */
+static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha)
+{
+ switch (pm8001_ha->pdev->subsystem_vendor) {
+ case PCI_VENDOR_ID_ATTO:
+ if (pm8001_ha->pdev->device == 0x0042) /* 6Gb */
+ return 0;
+ else
+ return pm8001_set_phy_settings_ven_117c_12G(pm8001_ha);
+
+ case PCI_VENDOR_ID_ADAPTEC2:
+ case 0:
+ return 0;
+
+ default:
+ return pm8001_get_phy_settings_info(pm8001_ha);
+ }
+}
+
#ifdef PM8001_USE_MSIX
/**
* pm8001_setup_msix - enable MSI-X interrupt
@@ -792,7 +951,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
pdev = pm8001_ha->pdev;
#ifdef PM8001_USE_MSIX
- if (pdev->msix_cap)
+ if (pdev->msix_cap && pci_msi_enabled())
return pm8001_setup_msix(pm8001_ha);
else {
PM8001_INIT_DBG(pm8001_ha,
@@ -803,6 +962,8 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
intx:
/* initialize the INT-X interrupt */
+ pm8001_ha->irq_vector[0].irq_id = 0;
+ pm8001_ha->irq_vector[0].drv_inst = pm8001_ha;
rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED,
DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost));
return rc;
@@ -902,12 +1063,9 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
pm8001_init_sas_add(pm8001_ha);
/* phy setting support for motherboard controller */
- if (pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 &&
- pdev->subsystem_vendor != 0) {
- rc = pm8001_get_phy_settings_info(pm8001_ha);
- if (rc)
- goto err_out_shost;
- }
+ if (pm8001_configure_phy_settings(pm8001_ha))
+ goto err_out_shost;
+
pm8001_post_sas_ha_init(shost, chip);
rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
if (rc)
@@ -937,10 +1095,10 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
struct pm8001_hba_info *pm8001_ha;
int i, j;
pm8001_ha = sha->lldd_ha;
+ scsi_remove_host(pm8001_ha->shost);
sas_unregister_ha(sha);
sas_remove_host(pm8001_ha->shost);
list_del(&pm8001_ha->list);
- scsi_remove_host(pm8001_ha->shost);
PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
@@ -956,7 +1114,8 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
#endif
#ifdef PM8001_USE_TASKLET
/* For non-msix and msix interrupts */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001))
tasklet_kill(&pm8001_ha->tasklet[0]);
else
for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
@@ -1005,7 +1164,8 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
#endif
#ifdef PM8001_USE_TASKLET
/* For non-msix and msix interrupts */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001))
tasklet_kill(&pm8001_ha->tasklet[0]);
else
for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
@@ -1074,7 +1234,8 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
goto err_out_disable;
#ifdef PM8001_USE_TASKLET
/* Tasklet for non msi-x interrupt handler */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001))
tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
(unsigned long)&(pm8001_ha->irq_vector[0]));
else
@@ -1087,6 +1248,19 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
for (i = 1; i < pm8001_ha->number_of_intr; i++)
PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i);
}
+
+ /* Chip documentation for the 8070 and 8072 SPCv */
+ /* states that a 500ms minimum delay is required */
+ /* before issuing commands. Otherwise, the firmare */
+ /* will enter an unrecoverable state. */
+
+ if (pm8001_ha->chip_id == chip_8070 ||
+ pm8001_ha->chip_id == chip_8072) {
+ mdelay(500);
+ }
+
+ /* Spin up the PHYs */
+
pm8001_ha->flags = PM8001F_RUN_TIME;
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
pm8001_ha->phy[i].enable_completion = &completion;
@@ -1165,6 +1339,20 @@ static struct pci_device_id pm8001_pci_table[] = {
PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8077 },
{ PCI_VENDOR_ID_ADAPTEC2, 0x8074,
PCI_VENDOR_ID_ADAPTEC2, 0x0404, 0, 0, chip_8074 },
+ { PCI_VENDOR_ID_ATTO, 0x8070,
+ PCI_VENDOR_ID_ATTO, 0x0070, 0, 0, chip_8070 },
+ { PCI_VENDOR_ID_ATTO, 0x8070,
+ PCI_VENDOR_ID_ATTO, 0x0071, 0, 0, chip_8070 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0072, 0, 0, chip_8072 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0073, 0, 0, chip_8072 },
+ { PCI_VENDOR_ID_ATTO, 0x8070,
+ PCI_VENDOR_ID_ATTO, 0x0080, 0, 0, chip_8070 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0081, 0, 0, chip_8072 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0082, 0, 0, chip_8072 },
{} /* terminate list */
};
@@ -1220,7 +1408,7 @@ MODULE_AUTHOR("Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>");
MODULE_AUTHOR("Sangeetha Gnanasekaran <Sangeetha.Gnanasekaran@pmcs.com>");
MODULE_AUTHOR("Nikith Ganigarakoppal <Nikith.Ganigarakoppal@pmcs.com>");
MODULE_DESCRIPTION(
- "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077 "
+ "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077/8070/8072 "
"SAS/SATA controller driver");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index e2e97db..6628cc3 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -106,7 +106,9 @@ do { \
#define DEV_IS_EXPANDER(type) ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
#define IS_SPCV_12G(dev) ((dev->device == 0X8074) \
|| (dev->device == 0X8076) \
- || (dev->device == 0X8077))
+ || (dev->device == 0X8077) \
+ || (dev->device == 0X8070) \
+ || (dev->device == 0X8072))
#define PM8001_NAME_LENGTH 32/* generic length of strings */
extern struct list_head hba_list;
@@ -708,6 +710,8 @@ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha);
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
u32 length, u8 *buf);
+void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
+ u32 phy, u32 length, u32 *buf);
int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
ssize_t pm80xx_get_fatal_dump(struct device *cdev,
struct device_attribute *attr, char *buf);
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 9a389f1..eb4fee6 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -1267,6 +1267,8 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
/* check iButton feature support for motherboard controller */
if (pm8001_ha->pdev->subsystem_vendor !=
PCI_VENDOR_ID_ADAPTEC2 &&
+ pm8001_ha->pdev->subsystem_vendor !=
+ PCI_VENDOR_ID_ATTO &&
pm8001_ha->pdev->subsystem_vendor != 0) {
ibutton0 = pm8001_cr32(pm8001_ha, 0,
MSGU_HOST_SCRATCH_PAD_6);
@@ -4576,6 +4578,38 @@ void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
}
PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n"));
}
+
+void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
+ u32 phy, u32 length, u32 *buf)
+{
+ u32 tag, opc;
+ int rc, i;
+ struct set_phy_profile_req payload;
+ struct inbound_queue_table *circularQ;
+
+ memset(&payload, 0, sizeof(payload));
+
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ PM8001_INIT_DBG(pm8001_ha, pm8001_printk("Invalid tag"));
+
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ opc = OPC_INB_SET_PHY_PROFILE;
+
+ payload.tag = cpu_to_le32(tag);
+ payload.ppc_phyid = (((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8)
+ | (phy & 0xFF));
+
+ for (i = 0; i < length; i++)
+ payload.reserved[i] = cpu_to_le32(*(buf + i));
+
+ rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
+
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("PHY %d settings applied", phy));
+}
const struct pm8001_dispatch pm8001_80xx_dispatch = {
.name = "pmc80xx",
.chip_init = pm80xx_chip_init,
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index ed31d8c..b2a8820 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -45,6 +45,7 @@
#include <asm/processor.h>
#include <linux/libata.h>
#include <linux/mutex.h>
+#include <linux/ktime.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
@@ -4254,7 +4255,6 @@ static struct scsi_host_template pmcraid_host_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = pmcraid_host_attrs,
.proc_name = PMCRAID_DRIVER_NAME,
- .use_blk_tags = 1,
};
/*
@@ -5563,11 +5563,9 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd)
__be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN);
struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
- struct timeval tv;
__le64 timestamp;
- do_gettimeofday(&tv);
- timestamp = tv.tv_sec * 1000;
+ timestamp = ktime_get_real_seconds() * 1000;
pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp);
pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8);
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index ee00e27..f6ad579 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -37,6 +37,7 @@ typedef struct {
unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */
unsigned int failed:1; /* Failure flag */
unsigned wanted:1; /* Parport sharing busy flag */
+ unsigned int dev_no; /* Device number */
wait_queue_head_t *waiting;
struct Scsi_Host *host;
struct list_head list;
@@ -985,15 +986,40 @@ static struct scsi_host_template ppa_template = {
static LIST_HEAD(ppa_hosts);
+/*
+ * Finds the first available device number that can be alloted to the
+ * new ppa device and returns the address of the previous node so that
+ * we can add to the tail and have a list in the ascending order.
+ */
+
+static inline ppa_struct *find_parent(void)
+{
+ ppa_struct *dev, *par = NULL;
+ unsigned int cnt = 0;
+
+ if (list_empty(&ppa_hosts))
+ return NULL;
+
+ list_for_each_entry(dev, &ppa_hosts, list) {
+ if (dev->dev_no != cnt)
+ return par;
+ cnt++;
+ par = dev;
+ }
+
+ return par;
+}
+
static int __ppa_attach(struct parport *pb)
{
struct Scsi_Host *host;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
DEFINE_WAIT(wait);
- ppa_struct *dev;
+ ppa_struct *dev, *temp;
int ports;
int modes, ppb, ppb_hi;
int err = -ENOMEM;
+ struct pardev_cb ppa_cb;
dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL);
if (!dev)
@@ -1002,8 +1028,15 @@ static int __ppa_attach(struct parport *pb)
dev->mode = PPA_AUTODETECT;
dev->recon_tmo = PPA_RECON_TMO;
init_waitqueue_head(&waiting);
- dev->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup,
- NULL, 0, dev);
+ temp = find_parent();
+ if (temp)
+ dev->dev_no = temp->dev_no + 1;
+
+ memset(&ppa_cb, 0, sizeof(ppa_cb));
+ ppa_cb.private = dev;
+ ppa_cb.wakeup = ppa_wakeup;
+
+ dev->dev = parport_register_dev_model(pb, "ppa", &ppa_cb, dev->dev_no);
if (!dev->dev)
goto out;
@@ -1110,9 +1143,10 @@ static void ppa_detach(struct parport *pb)
}
static struct parport_driver ppa_driver = {
- .name = "ppa",
- .attach = ppa_attach,
- .detach = ppa_detach,
+ .name = "ppa",
+ .match_port = ppa_attach,
+ .detach = ppa_detach,
+ .devmodel = true,
};
static int __init ppa_driver_init(void)
diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig
index a0f732b..10aa18b 100644
--- a/drivers/scsi/qla2xxx/Kconfig
+++ b/drivers/scsi/qla2xxx/Kconfig
@@ -18,9 +18,6 @@ config SCSI_QLA_FC
2322, 6322 ql2322_fw.bin
24xx, 54xx ql2400_fw.bin
25xx ql2500_fw.bin
- 2031 ql2600_fw.bin
- 8031 ql8300_fw.bin
- 27xx ql2700_fw.bin
Upon request, the driver caches the firmware image until
the driver is unloaded.
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6b942d9..4dc06a13 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -272,8 +272,8 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
iter = (uint32_t *)buf;
chksum = 0;
- for (cnt = 0; cnt < ((count >> 2) - 1); cnt++)
- chksum += le32_to_cpu(*iter++);
+ for (cnt = 0; cnt < ((count >> 2) - 1); cnt++, iter++)
+ chksum += le32_to_cpu(*iter);
chksum = ~chksum + 1;
*iter = cpu_to_le32(chksum);
} else {
@@ -562,6 +562,7 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
+ uint32_t faddr;
if (unlikely(pci_channel_offline(ha->pdev)))
return -EAGAIN;
@@ -569,9 +570,16 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EINVAL;
- if (IS_NOCACHE_VPD_TYPE(ha))
- ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2,
+ if (IS_NOCACHE_VPD_TYPE(ha)) {
+ faddr = ha->flt_region_vpd << 2;
+
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_vpd_sec << 2;
+
+ ha->isp_ops->read_optrom(vha, ha->vpd, faddr,
ha->vpd_size);
+ }
return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
}
@@ -824,6 +832,41 @@ static struct bin_attribute sysfs_reset_attr = {
};
static ssize_t
+qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ int type;
+ int rval = 0;
+ port_id_t did;
+
+ type = simple_strtol(buf, NULL, 10);
+
+ did.b.domain = (type & 0x00ff0000) >> 16;
+ did.b.area = (type & 0x0000ff00) >> 8;
+ did.b.al_pa = (type & 0x000000ff);
+
+ ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
+ did.b.domain, did.b.area, did.b.al_pa);
+
+ ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
+
+ rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+ return count;
+}
+
+static struct bin_attribute sysfs_issue_logo_attr = {
+ .attr = {
+ .name = "issue_logo",
+ .mode = S_IWUSR,
+ },
+ .size = 0,
+ .write = qla2x00_issue_logo,
+};
+
+static ssize_t
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
@@ -937,6 +980,7 @@ static struct sysfs_entry {
{ "vpd", &sysfs_vpd_attr, 1 },
{ "sfp", &sysfs_sfp_attr, 1 },
{ "reset", &sysfs_reset_attr, },
+ { "issue_logo", &sysfs_issue_logo_attr, },
{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
{ NULL },
@@ -1873,7 +1917,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
if (qla2x00_reset_active(vha))
goto done;
- stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
+ stats = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct link_statistics), &stats_dma, GFP_KERNEL);
if (stats == NULL) {
ql_log(ql_log_warn, vha, 0x707d,
"Failed to allocate memory for stats.\n");
@@ -1921,7 +1966,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
do_div(pfc_host_stat->seconds_since_last_reset, HZ);
done_free:
- dma_pool_free(ha->s_dma_pool, stats, stats_dma);
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
+ stats, stats_dma);
done:
return pfc_host_stat;
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index c26acde..392c147 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -2107,6 +2107,195 @@ qla8044_serdes_op(struct fc_bsg_job *bsg_job)
}
static int
+qla27xx_get_flash_upd_cap(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ struct qla_flash_update_caps cap;
+
+ if (!(IS_QLA27XX(ha)))
+ return -EPERM;
+
+ memset(&cap, 0, sizeof(cap));
+ cap.capabilities = (uint64_t)ha->fw_attributes_ext[1] << 48 |
+ (uint64_t)ha->fw_attributes_ext[0] << 32 |
+ (uint64_t)ha->fw_attributes_h << 16 |
+ (uint64_t)ha->fw_attributes;
+
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, &cap, sizeof(cap));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(cap);
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+ return 0;
+}
+
+static int
+qla27xx_set_flash_upd_cap(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ uint64_t online_fw_attr = 0;
+ struct qla_flash_update_caps cap;
+
+ if (!(IS_QLA27XX(ha)))
+ return -EPERM;
+
+ memset(&cap, 0, sizeof(cap));
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, &cap, sizeof(cap));
+
+ online_fw_attr = (uint64_t)ha->fw_attributes_ext[1] << 48 |
+ (uint64_t)ha->fw_attributes_ext[0] << 32 |
+ (uint64_t)ha->fw_attributes_h << 16 |
+ (uint64_t)ha->fw_attributes;
+
+ if (online_fw_attr != cap.capabilities) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_INVALID_PARAM;
+ return -EINVAL;
+ }
+
+ if (cap.outage_duration < MAX_LOOP_TIMEOUT) {
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_INVALID_PARAM;
+ return -EINVAL;
+ }
+
+ bsg_job->reply->reply_payload_rcv_len = 0;
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+ return 0;
+}
+
+static int
+qla27xx_get_bbcr_data(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ struct qla_bbcr_data bbcr;
+ uint16_t loop_id, topo, sw_cap;
+ uint8_t domain, area, al_pa, state;
+ int rval;
+
+ if (!(IS_QLA27XX(ha)))
+ return -EPERM;
+
+ memset(&bbcr, 0, sizeof(bbcr));
+
+ if (vha->flags.bbcr_enable)
+ bbcr.status = QLA_BBCR_STATUS_ENABLED;
+ else
+ bbcr.status = QLA_BBCR_STATUS_DISABLED;
+
+ if (bbcr.status == QLA_BBCR_STATUS_ENABLED) {
+ rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
+ &area, &domain, &topo, &sw_cap);
+ if (rval != QLA_SUCCESS) {
+ bbcr.status = QLA_BBCR_STATUS_UNKNOWN;
+ bbcr.state = QLA_BBCR_STATE_OFFLINE;
+ bbcr.mbx1 = loop_id;
+ goto done;
+ }
+
+ state = (vha->bbcr >> 12) & 0x1;
+
+ if (state) {
+ bbcr.state = QLA_BBCR_STATE_OFFLINE;
+ bbcr.offline_reason_code = QLA_BBCR_REASON_LOGIN_REJECT;
+ } else {
+ bbcr.state = QLA_BBCR_STATE_ONLINE;
+ bbcr.negotiated_bbscn = (vha->bbcr >> 8) & 0xf;
+ }
+
+ bbcr.configured_bbscn = vha->bbcr & 0xf;
+ }
+
+done:
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, &bbcr, sizeof(bbcr));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(bbcr);
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+ return 0;
+}
+
+static int
+qla2x00_get_priv_stats(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+ struct link_statistics *stats = NULL;
+ dma_addr_t stats_dma;
+ int rval = QLA_FUNCTION_FAILED;
+
+ if (test_bit(UNLOADING, &vha->dpc_flags))
+ goto done;
+
+ if (unlikely(pci_channel_offline(ha->pdev)))
+ goto done;
+
+ if (qla2x00_reset_active(vha))
+ goto done;
+
+ if (!IS_FWI2_CAPABLE(ha))
+ goto done;
+
+ stats = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct link_statistics), &stats_dma, GFP_KERNEL);
+ if (!stats) {
+ ql_log(ql_log_warn, vha, 0x70e2,
+ "Failed to allocate memory for stats.\n");
+ goto done;
+ }
+
+ memset(stats, 0, sizeof(struct link_statistics));
+
+ rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma);
+
+ if (rval != QLA_SUCCESS)
+ goto done_free;
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3,
+ (uint8_t *)stats, sizeof(struct link_statistics));
+
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, stats, sizeof(struct link_statistics));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(struct link_statistics);
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+
+done_free:
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
+ stats, stats_dma);
+done:
+ return rval;
+}
+
+static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -2161,6 +2350,18 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_SERDES_OP_EX:
return qla8044_serdes_op(bsg_job);
+ case QL_VND_GET_FLASH_UPDATE_CAPS:
+ return qla27xx_get_flash_upd_cap(bsg_job);
+
+ case QL_VND_SET_FLASH_UPDATE_CAPS:
+ return qla27xx_set_flash_upd_cap(bsg_job);
+
+ case QL_VND_GET_BBCR_DATA:
+ return qla27xx_get_bbcr_data(bsg_job);
+
+ case QL_VND_GET_PRIV_STATS:
+ return qla2x00_get_priv_stats(bsg_job);
+
default:
return -ENOSYS;
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index d38f9ef..c80192d 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -25,6 +25,10 @@
#define QL_VND_FX00_MGMT_CMD 0x12
#define QL_VND_SERDES_OP 0x13
#define QL_VND_SERDES_OP_EX 0x14
+#define QL_VND_GET_FLASH_UPDATE_CAPS 0x15
+#define QL_VND_SET_FLASH_UPDATE_CAPS 0x16
+#define QL_VND_GET_BBCR_DATA 0x17
+#define QL_VND_GET_PRIV_STATS 0x18
/* BSG Vendor specific subcode returns */
#define EXT_STATUS_OK 0
@@ -232,4 +236,34 @@ struct qla_serdes_reg_ex {
uint32_t val;
} __packed;
+struct qla_flash_update_caps {
+ uint64_t capabilities;
+ uint32_t outage_duration;
+ uint8_t reserved[20];
+} __packed;
+
+/* BB_CR Status */
+#define QLA_BBCR_STATUS_DISABLED 0
+#define QLA_BBCR_STATUS_ENABLED 1
+#define QLA_BBCR_STATUS_UNKNOWN 2
+
+/* BB_CR State */
+#define QLA_BBCR_STATE_OFFLINE 0
+#define QLA_BBCR_STATE_ONLINE 1
+
+/* BB_CR Offline Reason Code */
+#define QLA_BBCR_REASON_PORT_SPEED 1
+#define QLA_BBCR_REASON_PEER_PORT 2
+#define QLA_BBCR_REASON_SWITCH 3
+#define QLA_BBCR_REASON_LOGIN_REJECT 4
+
+struct qla_bbcr_data {
+ uint8_t status; /* 1 - enabled, 0 - Disabled */
+ uint8_t state; /* 1 - online, 0 - offline */
+ uint8_t configured_bbscn; /* 0-15 */
+ uint8_t negotiated_bbscn; /* 0-15 */
+ uint8_t offline_reason_code;
+ uint16_t mbx1; /* Port state */
+ uint8_t reserved[9];
+} __packed;
#endif
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 34dc9a3..b64c504 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,28 +11,28 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x017f | 0x0146 |
+ * | Module Init and Probe | 0x018f | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e-0x0170 |
- * | Mailbox commands | 0x118d | 0x1115-0x1116 |
- * | | | 0x111a-0x111b |
+ * | Mailbox commands | 0x1192 | |
+ * | | | |
* | Device Discovery | 0x2016 | 0x2020-0x2022, |
* | | | 0x2011-0x2012, |
* | | | 0x2099-0x20a4 |
- * | Queue Command and IO tracing | 0x3075 | 0x300b |
+ * | Queue Command and IO tracing | 0x3074 | 0x300b |
* | | | 0x3027-0x3028 |
* | | | 0x303d-0x3041 |
* | | | 0x302d,0x3033 |
* | | | 0x3036,0x3038 |
* | | | 0x303a |
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
- * | Async Events | 0x508a | 0x502b-0x502f |
- * | | | 0x5047 |
+ * | Async Events | 0x5089 | 0x502b-0x502f |
+ * | | | 0x505e |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
* | | | 0x507b,0x505f |
* | Timer Routines | 0x6012 | |
- * | User Space Interactions | 0x70e2 | 0x7018,0x702e |
+ * | User Space Interactions | 0x70e3 | 0x7018,0x702e |
* | | | 0x7020,0x7024 |
* | | | 0x7039,0x7045 |
* | | | 0x7073-0x7075 |
@@ -60,15 +60,11 @@
* | | | 0xb13c-0xb140 |
* | | | 0xb149 |
* | MultiQ | 0xc00c | |
- * | Misc | 0xd300 | 0xd016-0xd017 |
- * | | | 0xd021,0xd024 |
- * | | | 0xd025,0xd029 |
- * | | | 0xd02a,0xd02e |
- * | | | 0xd031-0xd0ff |
+ * | Misc | 0xd301 | 0xd031-0xd0ff |
* | | | 0xd101-0xd1fe |
* | | | 0xd214-0xd2fe |
* | Target Mode | 0xe080 | |
- * | Target Mode Management | 0xf096 | 0xf002 |
+ * | Target Mode Management | 0xf09b | 0xf002 |
* | | | 0xf046-0xf049 |
* | Target Mode Task Management | 0x1000d | |
* ----------------------------------------------------------------------
@@ -298,8 +294,8 @@ qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
WRT_REG_DWORD(&reg->iobase_addr, iobase);
dmp_reg = &reg->iobase_window;
- while (count--)
- *buf++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for ( ; count--; dmp_reg++)
+ *buf++ = htonl(RD_REG_DWORD(dmp_reg));
return buf;
}
@@ -461,8 +457,8 @@ qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
{
uint16_t __iomem *dmp_reg = &reg->u.isp2300.fb_cmd;
- while (count--)
- *buf++ = htons(RD_REG_WORD(dmp_reg++));
+ for ( ; count--; dmp_reg++)
+ *buf++ = htons(RD_REG_WORD(dmp_reg));
}
static inline void *
@@ -737,16 +733,18 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
if (rval == QLA_SUCCESS) {
dmp_reg = &reg->flash_address;
- for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++, dmp_reg++)
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
dmp_reg = &reg->u.isp2300.req_q_in;
- for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
- fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2;
+ cnt++, dmp_reg++)
+ fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
dmp_reg = &reg->u.isp2300.mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2;
+ cnt++, dmp_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->ctrl_status, 0x40);
qla2xxx_read_window(reg, 32, fw->resp_dma_reg);
@@ -756,8 +754,9 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = &reg->risc_hw;
- for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2;
+ cnt++, dmp_reg++)
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->pcr, 0x2000);
qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
@@ -900,25 +899,25 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
}
if (rval == QLA_SUCCESS) {
dmp_reg = &reg->flash_address;
- for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++, dmp_reg++)
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
dmp_reg = &reg->u.isp2100.mailbox0;
- for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+ for (cnt = 0; cnt < ha->mbx_count; cnt++, dmp_reg++) {
if (cnt == 8)
dmp_reg = &reg->u_end.isp2200.mailbox8;
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
}
dmp_reg = &reg->u.isp2100.unused_2[0];
- for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++, dmp_reg++)
+ fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = &reg->risc_hw;
- for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++, dmp_reg++)
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg));
WRT_REG_WORD(&reg->pcr, 0x2000);
qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
@@ -1100,8 +1099,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1133,8 +1132,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, dmp_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -1172,20 +1171,20 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
@@ -1363,8 +1362,10 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
RD_REG_DWORD(&reg->iobase_addr);
WRT_REG_DWORD(&reg->iobase_window, 0x01);
dmp_reg = &reg->iobase_c4;
- fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
- fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
@@ -1373,8 +1374,8 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1422,8 +1423,8 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, mbx_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -1486,20 +1487,20 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
@@ -1684,8 +1685,10 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
RD_REG_DWORD(&reg->iobase_addr);
WRT_REG_DWORD(&reg->iobase_window, 0x01);
dmp_reg = &reg->iobase_c4;
- fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
- fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
@@ -1694,8 +1697,8 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1743,8 +1746,8 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, mbx_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -1807,20 +1810,20 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
@@ -2027,8 +2030,10 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
RD_REG_DWORD(&reg->iobase_addr);
WRT_REG_DWORD(&reg->iobase_window, 0x01);
dmp_reg = &reg->iobase_c4;
- fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
- fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg));
+ dmp_reg++;
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
@@ -2037,8 +2042,8 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Host interface registers. */
dmp_reg = &reg->flash_addr;
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++, dmp_reg++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -2086,8 +2091,8 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Mailbox registers. */
mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++, dmp_reg++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
@@ -2182,20 +2187,20 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = fw->req0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->resp0_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
iter_reg = fw->req1_dma_reg;
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+ for (cnt = 0; cnt < 7; cnt++, dmp_reg++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 388d790..47f8b9b4 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -259,7 +259,7 @@
#define LOOP_DOWN_TIME 255 /* 240 */
#define LOOP_DOWN_RESET (LOOP_DOWN_TIME - 30)
-#define DEFAULT_OUTSTANDING_COMMANDS 1024
+#define DEFAULT_OUTSTANDING_COMMANDS 4096
#define MIN_OUTSTANDING_COMMANDS 128
/* ISP request and response entry counts (37-65535) */
@@ -267,11 +267,13 @@
#define REQUEST_ENTRY_CNT_2200 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_24XX 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_83XX 8192 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_83XX 4096 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
+#define EXTENDED_EXCH_ENTRY_CNT 32768 /* Entries for offload case */
struct req_que;
struct qla_tgt_sess;
@@ -309,6 +311,14 @@ struct srb_cmd {
/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
+struct els_logo_payload {
+ uint8_t opcode;
+ uint8_t rsvd[3];
+ uint8_t s_id[3];
+ uint8_t rsvd1[1];
+ uint8_t wwpn[WWN_SIZE];
+};
+
/*
* SRB extensions.
*/
@@ -322,6 +332,15 @@ struct srb_iocb {
uint16_t data[2];
} logio;
struct {
+#define ELS_DCMD_TIMEOUT 20
+#define ELS_DCMD_LOGO 0x5
+ uint32_t flags;
+ uint32_t els_cmd;
+ struct completion comp;
+ struct els_logo_payload *els_logo_pyld;
+ dma_addr_t els_logo_pyld_dma;
+ } els_logo;
+ struct {
/*
* Values for flags field below are as
* defined in tsk_mgmt_entry struct
@@ -382,7 +401,7 @@ struct srb_iocb {
#define SRB_FXIOCB_DCMD 10
#define SRB_FXIOCB_BCMD 11
#define SRB_ABT_CMD 12
-
+#define SRB_ELS_DCMD 13
typedef struct srb {
atomic_t ref_count;
@@ -891,6 +910,7 @@ struct mbx_cmd_32 {
#define MBC_DISABLE_VI 0x24 /* Disable VI operation. */
#define MBC_ENABLE_VI 0x25 /* Enable VI operation. */
#define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */
+#define MBC_GET_MEM_OFFLOAD_CNTRL_STAT 0x34 /* Memory Offload ctrl/Stat*/
#define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */
#define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */
#define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */
@@ -1040,6 +1060,12 @@ struct mbx_cmd_32 {
#define FSTATE_FATAL_ERROR 4
#define FSTATE_LOOP_BACK_CONN 5
+#define QLA27XX_IMG_STATUS_VER_MAJOR 0x01
+#define QLA27XX_IMG_STATUS_VER_MINOR 0x00
+#define QLA27XX_IMG_STATUS_SIGN 0xFACEFADE
+#define QLA27XX_PRIMARY_IMAGE 1
+#define QLA27XX_SECONDARY_IMAGE 2
+
/*
* Port Database structure definition
* Little endian except where noted.
@@ -1228,13 +1254,41 @@ struct link_statistics {
uint32_t inval_xmit_word_cnt;
uint32_t inval_crc_cnt;
uint32_t lip_cnt;
- uint32_t unused1[0x1a];
+ uint32_t link_up_cnt;
+ uint32_t link_down_loop_init_tmo;
+ uint32_t link_down_los;
+ uint32_t link_down_loss_rcv_clk;
+ uint32_t reserved0[5];
+ uint32_t port_cfg_chg;
+ uint32_t reserved1[11];
+ uint32_t rsp_q_full;
+ uint32_t atio_q_full;
+ uint32_t drop_ae;
+ uint32_t els_proto_err;
+ uint32_t reserved2;
uint32_t tx_frames;
uint32_t rx_frames;
uint32_t discarded_frames;
uint32_t dropped_frames;
- uint32_t unused2[1];
+ uint32_t reserved3;
uint32_t nos_rcvd;
+ uint32_t reserved4[4];
+ uint32_t tx_prjt;
+ uint32_t rcv_exfail;
+ uint32_t rcv_abts;
+ uint32_t seq_frm_miss;
+ uint32_t corr_err;
+ uint32_t mb_rqst;
+ uint32_t nport_full;
+ uint32_t eofa;
+ uint32_t reserved5;
+ uint32_t fpm_recv_word_cnt_lo;
+ uint32_t fpm_recv_word_cnt_hi;
+ uint32_t fpm_disc_word_cnt_lo;
+ uint32_t fpm_disc_word_cnt_hi;
+ uint32_t fpm_xmit_word_cnt_lo;
+ uint32_t fpm_xmit_word_cnt_hi;
+ uint32_t reserved6[70];
};
/*
@@ -2695,11 +2749,16 @@ struct isp_operations {
struct scsi_qla_host;
+
+#define QLA83XX_RSPQ_MSIX_ENTRY_NUMBER 1 /* refer to qla83xx_msix_entries */
+
struct qla_msix_entry {
int have_irq;
uint32_t vector;
uint16_t entry;
struct rsp_que *rsp;
+ struct irq_affinity_notify irq_notify;
+ int cpuid;
};
#define WATCH_INTERVAL 1 /* number of seconds */
@@ -2904,18 +2963,22 @@ struct qlt_hw_data {
uint8_t tgt_node_name[WWN_SIZE];
+ struct dentry *dfs_tgt_sess;
struct list_head q_full_list;
uint32_t num_pend_cmds;
uint32_t num_qfull_cmds_alloc;
uint32_t num_qfull_cmds_dropped;
spinlock_t q_full_lock;
uint32_t leak_exchg_thresh_hold;
+ spinlock_t sess_lock;
+ int rspq_vector_cpuid;
+ spinlock_t atio_lock ____cacheline_aligned;
};
#define MAX_QFULL_CMDS_ALLOC 8192
#define Q_FULL_THRESH_HOLD_PERCENT 90
#define Q_FULL_THRESH_HOLD(ha) \
- ((ha->fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
+ ((ha->cur_fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
#define LEAK_EXCHG_THRESH_HOLD_PERCENT 75 /* 75 percent */
@@ -2962,10 +3025,12 @@ struct qla_hw_data {
uint32_t isp82xx_no_md_cap:1;
uint32_t host_shutting_down:1;
uint32_t idc_compl_status:1;
-
uint32_t mr_reset_hdlr_active:1;
uint32_t mr_intr_valid:1;
+
uint32_t fawwpn_enabled:1;
+ uint32_t exlogins_enabled:1;
+ uint32_t exchoffld_enabled:1;
/* 35 bits */
} flags;
@@ -3237,6 +3302,21 @@ struct qla_hw_data {
void *async_pd;
dma_addr_t async_pd_dma;
+#define ENABLE_EXTENDED_LOGIN BIT_7
+
+ /* Extended Logins */
+ void *exlogin_buf;
+ dma_addr_t exlogin_buf_dma;
+ int exlogin_size;
+
+#define ENABLE_EXCHANGE_OFFLD BIT_2
+
+ /* Exchange Offload */
+ void *exchoffld_buf;
+ dma_addr_t exchoffld_buf_dma;
+ int exchoffld_size;
+ int exchoffld_count;
+
void *swl;
/* These are used by mailbox operations. */
@@ -3279,8 +3359,14 @@ struct qla_hw_data {
#define RISC_START_ADDRESS_2100 0x1000
#define RISC_START_ADDRESS_2300 0x800
#define RISC_START_ADDRESS_2400 0x100000
- uint16_t fw_xcb_count;
- uint16_t fw_iocb_count;
+
+ uint16_t orig_fw_tgt_xcb_count;
+ uint16_t cur_fw_tgt_xcb_count;
+ uint16_t orig_fw_xcb_count;
+ uint16_t cur_fw_xcb_count;
+ uint16_t orig_fw_iocb_count;
+ uint16_t cur_fw_iocb_count;
+ uint16_t fw_max_fcf_count;
uint32_t fw_shared_ram_start;
uint32_t fw_shared_ram_end;
@@ -3323,6 +3409,9 @@ struct qla_hw_data {
uint32_t chain_offset;
struct dentry *dfs_dir;
struct dentry *dfs_fce;
+ struct dentry *dfs_tgt_counters;
+ struct dentry *dfs_fw_resource_cnt;
+
dma_addr_t fce_dma;
void *fce;
uint32_t fce_bufs;
@@ -3379,14 +3468,20 @@ struct qla_hw_data {
uint32_t flt_region_flt;
uint32_t flt_region_fdt;
uint32_t flt_region_boot;
+ uint32_t flt_region_boot_sec;
uint32_t flt_region_fw;
+ uint32_t flt_region_fw_sec;
uint32_t flt_region_vpd_nvram;
uint32_t flt_region_vpd;
+ uint32_t flt_region_vpd_sec;
uint32_t flt_region_nvram;
uint32_t flt_region_npiv_conf;
uint32_t flt_region_gold_fw;
uint32_t flt_region_fcp_prio;
uint32_t flt_region_bootload;
+ uint32_t flt_region_img_status_pri;
+ uint32_t flt_region_img_status_sec;
+ uint8_t active_image;
/* Needed for BEACON */
uint16_t beacon_blink_led;
@@ -3480,6 +3575,18 @@ struct qla_hw_data {
int allow_cna_fw_dump;
};
+struct qla_tgt_counters {
+ uint64_t qla_core_sbt_cmd;
+ uint64_t core_qla_que_buf;
+ uint64_t qla_core_ret_ctio;
+ uint64_t core_qla_snd_status;
+ uint64_t qla_core_ret_sta_ctio;
+ uint64_t core_qla_free_cmd;
+ uint64_t num_q_full_sent;
+ uint64_t num_alloc_iocb_failed;
+ uint64_t num_term_xchg_sent;
+};
+
/*
* Qlogic scsi host structure
*/
@@ -3505,6 +3612,7 @@ typedef struct scsi_qla_host {
uint32_t delete_progress:1;
uint32_t fw_tgt_reported:1;
+ uint32_t bbcr_enable:1;
} flags;
atomic_t loop_state;
@@ -3595,6 +3703,10 @@ typedef struct scsi_qla_host {
atomic_t generation_tick;
/* Time when global fcport update has been scheduled */
int total_fcport_update_gen;
+ /* List of pending LOGOs, protected by tgt_mutex */
+ struct list_head logo_list;
+ /* List of pending PLOGI acks, protected by hw lock */
+ struct list_head plogi_ack_list;
uint32_t vp_abort_cnt;
@@ -3632,8 +3744,20 @@ typedef struct scsi_qla_host {
atomic_t vref_count;
struct qla8044_reset_template reset_tmplt;
+ struct qla_tgt_counters tgt_counters;
+ uint16_t bbcr;
} scsi_qla_host_t;
+struct qla27xx_image_status {
+ uint8_t image_status_mask;
+ uint16_t generation_number;
+ uint8_t reserved[3];
+ uint8_t ver_minor;
+ uint8_t ver_major;
+ uint32_t checksum;
+ uint32_t signature;
+} __packed;
+
#define SET_VP_IDX 1
#define SET_AL_PA 2
#define RESET_VP_IDX 3
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 15cf074..34272fd 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,126 @@ static struct dentry *qla2x00_dfs_root;
static atomic_t qla2x00_dfs_root_count;
static int
+qla2x00_dfs_tgt_sess_show(struct seq_file *s, void *unused)
+{
+ scsi_qla_host_t *vha = s->private;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags;
+ struct qla_tgt_sess *sess = NULL;
+ struct qla_tgt *tgt= vha->vha_tgt.qla_tgt;
+
+ seq_printf(s, "%s\n",vha->host_str);
+ if (tgt) {
+ seq_printf(s, "Port ID Port Name Handle\n");
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+ list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) {
+ seq_printf(s, "%02x:%02x:%02x %8phC %d\n",
+ sess->s_id.b.domain,sess->s_id.b.area,
+ sess->s_id.b.al_pa, sess->port_name,
+ sess->loop_id);
+ }
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+ }
+
+ return 0;
+}
+
+static int
+qla2x00_dfs_tgt_sess_open(struct inode *inode, struct file *file)
+{
+ scsi_qla_host_t *vha = inode->i_private;
+ return single_open(file, qla2x00_dfs_tgt_sess_show, vha);
+}
+
+
+static const struct file_operations dfs_tgt_sess_ops = {
+ .open = qla2x00_dfs_tgt_sess_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+ struct qla_hw_data *ha = vha->hw;
+
+ seq_puts(s, "FW Resource count\n\n");
+ seq_printf(s, "Original TGT exchg count[%d]\n",
+ ha->orig_fw_tgt_xcb_count);
+ seq_printf(s, "current TGT exchg count[%d]\n",
+ ha->cur_fw_tgt_xcb_count);
+ seq_printf(s, "original Initiator Exchange count[%d]\n",
+ ha->orig_fw_xcb_count);
+ seq_printf(s, "Current Initiator Exchange count[%d]\n",
+ ha->cur_fw_xcb_count);
+ seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
+ seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
+ seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
+ seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
+
+ return 0;
+}
+
+static int
+qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
+}
+
+static const struct file_operations dfs_fw_resource_cnt_ops = {
+ .open = qla_dfs_fw_resource_cnt_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+
+ seq_puts(s, "Target Counters\n");
+ seq_printf(s, "qla_core_sbt_cmd = %lld\n",
+ vha->tgt_counters.qla_core_sbt_cmd);
+ seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_sta_ctio);
+ seq_printf(s, "qla_core_ret_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_ctio);
+ seq_printf(s, "core_qla_que_buf = %lld\n",
+ vha->tgt_counters.core_qla_que_buf);
+ seq_printf(s, "core_qla_snd_status = %lld\n",
+ vha->tgt_counters.core_qla_snd_status);
+ seq_printf(s, "core_qla_free_cmd = %lld\n",
+ vha->tgt_counters.core_qla_free_cmd);
+ seq_printf(s, "num alloc iocb failed = %lld\n",
+ vha->tgt_counters.num_alloc_iocb_failed);
+ seq_printf(s, "num term exchange sent = %lld\n",
+ vha->tgt_counters.num_term_xchg_sent);
+ seq_printf(s, "num Q full sent = %lld\n",
+ vha->tgt_counters.num_q_full_sent);
+
+ return 0;
+}
+
+static int
+qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_tgt_counters_show, vha);
+}
+
+static const struct file_operations dfs_tgt_counters_ops = {
+ .open = qla_dfs_tgt_counters_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
{
scsi_qla_host_t *vha = s->private;
@@ -146,6 +266,22 @@ create_dir:
atomic_inc(&qla2x00_dfs_root_count);
create_nodes:
+ ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
+ S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
+ if (!ha->dfs_fw_resource_cnt) {
+ ql_log(ql_log_warn, vha, 0x00fd,
+ "Unable to create debugFS fw_resource_count node.\n");
+ goto out;
+ }
+
+ ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
+ ha->dfs_dir, vha, &dfs_tgt_counters_ops);
+ if (!ha->dfs_tgt_counters) {
+ ql_log(ql_log_warn, vha, 0xd301,
+ "Unable to create debugFS tgt_counters node.\n");
+ goto out;
+ }
+
ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
&dfs_fce_ops);
if (!ha->dfs_fce) {
@@ -153,6 +289,15 @@ create_nodes:
"Unable to create debugfs fce node.\n");
goto out;
}
+
+ ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess",
+ S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops);
+ if (!ha->tgt.dfs_tgt_sess) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to create debugFS tgt_sess node.\n");
+ goto out;
+ }
+
out:
return 0;
}
@@ -161,6 +306,22 @@ int
qla2x00_dfs_remove(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+
+ if (ha->tgt.dfs_tgt_sess) {
+ debugfs_remove(ha->tgt.dfs_tgt_sess);
+ ha->tgt.dfs_tgt_sess = NULL;
+ }
+
+ if (ha->dfs_fw_resource_cnt) {
+ debugfs_remove(ha->dfs_fw_resource_cnt);
+ ha->dfs_fw_resource_cnt = NULL;
+ }
+
+ if (ha->dfs_tgt_counters) {
+ debugfs_remove(ha->dfs_tgt_counters);
+ ha->dfs_tgt_counters = NULL;
+ }
+
if (ha->dfs_fce) {
debugfs_remove(ha->dfs_fce);
ha->dfs_fce = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 42bb357..4c0f3a7 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1288,7 +1288,9 @@ struct vp_rpt_id_entry_24xx {
uint8_t vp_idx_map[16];
- uint8_t reserved_4[32];
+ uint8_t reserved_4[28];
+ uint16_t bbcr;
+ uint8_t reserved_5[6];
};
#define VF_EVFP_IOCB_TYPE 0x26 /* Exchange Virtual Fabric Parameters entry. */
@@ -1393,6 +1395,16 @@ struct qla_flt_header {
#define FLT_REG_FCOE_NVRAM_0 0xAA
#define FLT_REG_FCOE_NVRAM_1 0xAC
+/* 27xx */
+#define FLT_REG_IMG_PRI_27XX 0x95
+#define FLT_REG_IMG_SEC_27XX 0x96
+#define FLT_REG_FW_SEC_27XX 0x02
+#define FLT_REG_BOOTLOAD_SEC_27XX 0x9
+#define FLT_REG_VPD_SEC_27XX_0 0x50
+#define FLT_REG_VPD_SEC_27XX_1 0x52
+#define FLT_REG_VPD_SEC_27XX_2 0xD8
+#define FLT_REG_VPD_SEC_27XX_3 0xDA
+
struct qla_flt_region {
uint32_t code;
uint32_t size;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 7686bfe..fe94377 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -44,6 +44,8 @@ extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
+extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
+
extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
@@ -88,6 +90,7 @@ extern int qla2xxx_mctp_dump(scsi_qla_host_t *);
extern int
qla2x00_alloc_outstanding_cmds(struct qla_hw_data *, struct req_que *);
extern int qla2x00_init_rings(scsi_qla_host_t *);
+extern uint8_t qla27xx_find_valid_image(struct scsi_qla_host *);
/*
* Global Data in qla_os.c source file.
@@ -117,6 +120,9 @@ extern int ql2xdontresethba;
extern uint64_t ql2xmaxlun;
extern int ql2xmdcapmask;
extern int ql2xmdenable;
+extern int ql2xexlogins;
+extern int ql2xexchoffld;
+extern int ql2xfwholdabts;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -135,6 +141,10 @@ extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
+extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
+extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exchoffld_buffer(struct qla_hw_data *);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -323,8 +333,7 @@ extern int
qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
- uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *);
extern int
qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -766,4 +775,11 @@ extern int qla8044_abort_isp(scsi_qla_host_t *);
extern int qla8044_check_fw_alive(struct scsi_qla_host *);
extern void qlt_host_reset_handler(struct qla_hw_data *ha);
+extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
+ uint16_t *);
+extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
+extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *, dma_addr_t);
+extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *);
+
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 16a1935c..c56cdb3 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -157,8 +157,12 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
lio->u.logio.flags |= SRB_LOGIN_RETRIED;
rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
+ if (rval != QLA_SUCCESS) {
+ fcport->flags &= ~FCF_ASYNC_SENT;
+ fcport->flags |= FCF_LOGIN_NEEDED;
+ set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
goto done_free_sp;
+ }
ql_dbg(ql_dbg_disc, vha, 0x2072,
"Async-login - hdl=%x, loopid=%x portid=%02x%02x%02x "
@@ -1766,10 +1770,10 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req)
(ql2xmultique_tag || ql2xmaxqueues > 1)))
req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS;
else {
- if (ha->fw_xcb_count <= ha->fw_iocb_count)
- req->num_outstanding_cmds = ha->fw_xcb_count;
+ if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count)
+ req->num_outstanding_cmds = ha->cur_fw_xcb_count;
else
- req->num_outstanding_cmds = ha->fw_iocb_count;
+ req->num_outstanding_cmds = ha->cur_fw_iocb_count;
}
req->outstanding_cmds = kzalloc(sizeof(srb_t *) *
@@ -1843,9 +1847,23 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_init, vha, 0x00ca,
"Starting firmware.\n");
+ if (ql2xexlogins)
+ ha->flags.exlogins_enabled = 1;
+
+ if (ql2xexchoffld)
+ ha->flags.exchoffld_enabled = 1;
+
rval = qla2x00_execute_fw(vha, srisc_address);
/* Retrieve firmware information. */
if (rval == QLA_SUCCESS) {
+ rval = qla2x00_set_exlogins_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
+ rval = qla2x00_set_exchoffld_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
enable_82xx_npiv:
fw_major_version = ha->fw_major_version;
if (IS_P3P_TYPE(ha))
@@ -1864,9 +1882,7 @@ enable_82xx_npiv:
ha->max_npiv_vports =
MIN_MULTI_ID_FABRIC - 1;
}
- qla2x00_get_resource_cnts(vha, NULL,
- &ha->fw_xcb_count, NULL, &ha->fw_iocb_count,
- &ha->max_npiv_vports, NULL);
+ qla2x00_get_resource_cnts(vha);
/*
* Allocate the array of outstanding commands
@@ -2050,6 +2066,10 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
if (IS_P3P_TYPE(ha))
return;
+ /* Hold status IOCBs until ABTS response received. */
+ if (ql2xfwholdabts)
+ ha->fw_options[3] |= BIT_12;
+
/* Update Serial Link options. */
if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
return;
@@ -2192,7 +2212,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
/* Clear outstanding commands array. */
for (que = 0; que < ha->max_req_queues; que++) {
req = ha->req_q_map[que];
- if (!req)
+ if (!req || !test_bit(que, ha->req_qid_map))
continue;
req->out_ptr = (void *)(req->ring + req->length);
*req->out_ptr = 0;
@@ -2209,7 +2229,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
for (que = 0; que < ha->max_rsp_queues; que++) {
rsp = ha->rsp_q_map[que];
- if (!rsp)
+ if (!rsp || !test_bit(que, ha->rsp_qid_map))
continue;
rsp->in_ptr = (void *)(rsp->ring + rsp->length);
*rsp->in_ptr = 0;
@@ -2248,7 +2268,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
if (IS_FWI2_CAPABLE(ha)) {
mid_init_cb->options = cpu_to_le16(BIT_1);
mid_init_cb->init_cb.execution_throttle =
- cpu_to_le16(ha->fw_xcb_count);
+ cpu_to_le16(ha->cur_fw_xcb_count);
/* D-Port Status */
if (IS_DPORT_CAPABLE(ha))
mid_init_cb->init_cb.firmware_options_1 |=
@@ -2832,7 +2852,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
if (nv->login_timeout < 4)
nv->login_timeout = 4;
ha->login_timeout = nv->login_timeout;
- icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
@@ -3053,6 +3072,26 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
atomic_set(&vha->loop_state, LOOP_READY);
ql_dbg(ql_dbg_disc, vha, 0x2069,
"LOOP READY.\n");
+
+ /*
+ * Process any ATIO queue entries that came in
+ * while we weren't online.
+ */
+ if (qla_tgt_mode_enabled(vha)) {
+ if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+ spin_lock_irqsave(&ha->tgt.atio_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(
+ &ha->tgt.atio_lock, flags);
+ } else {
+ spin_lock_irqsave(&ha->hardware_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
+ }
+ }
}
}
@@ -4907,7 +4946,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
- unsigned long flags;
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
@@ -4929,17 +4967,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
- vha->flags.online = 1;
-
- /*
- * Process any ATIO queue entries that came in
- * while we weren't online.
- */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla_tgt_mode_enabled(vha))
- qlt_24xx_process_atio_queue(vha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
}
@@ -4961,7 +4988,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
for (i = 1; i < ha->max_rsp_queues; i++) {
rsp = ha->rsp_q_map[i];
- if (rsp) {
+ if (rsp && test_bit(i, ha->rsp_qid_map)) {
rsp->options &= ~BIT_0;
ret = qla25xx_init_rsp_que(base_vha, rsp);
if (ret != QLA_SUCCESS)
@@ -4976,8 +5003,8 @@ qla25xx_init_queues(struct qla_hw_data *ha)
}
for (i = 1; i < ha->max_req_queues; i++) {
req = ha->req_q_map[i];
- if (req) {
- /* Clear outstanding commands array. */
+ if (req && test_bit(i, ha->req_qid_map)) {
+ /* Clear outstanding commands array. */
req->options &= ~BIT_0;
ret = qla25xx_init_req_que(base_vha, req);
if (ret != QLA_SUCCESS)
@@ -5102,8 +5129,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
dptr = (uint32_t *)nv;
ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
ha->nvram_size);
- for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
- chksum += le32_to_cpu(*dptr++);
+ for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
+ chksum += le32_to_cpu(*dptr);
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x006a,
"Contents of NVRAM\n");
@@ -5254,7 +5281,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
if (le16_to_cpu(nv->login_timeout) < 4)
nv->login_timeout = cpu_to_le16(4);
ha->login_timeout = le16_to_cpu(nv->login_timeout);
- icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
@@ -5326,6 +5352,93 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
return (rval);
}
+uint8_t qla27xx_find_valid_image(struct scsi_qla_host *vha)
+{
+ struct qla27xx_image_status pri_image_status, sec_image_status;
+ uint8_t valid_pri_image, valid_sec_image;
+ uint32_t *wptr;
+ uint32_t cnt, chksum, size;
+ struct qla_hw_data *ha = vha->hw;
+
+ valid_pri_image = valid_sec_image = 1;
+ ha->active_image = 0;
+ size = sizeof(struct qla27xx_image_status) / sizeof(uint32_t);
+
+ if (!ha->flt_region_img_status_pri) {
+ valid_pri_image = 0;
+ goto check_sec_image;
+ }
+
+ qla24xx_read_flash_data(vha, (uint32_t *)(&pri_image_status),
+ ha->flt_region_img_status_pri, size);
+
+ if (pri_image_status.signature != QLA27XX_IMG_STATUS_SIGN) {
+ ql_dbg(ql_dbg_init, vha, 0x018b,
+ "Primary image signature (0x%x) not valid\n",
+ pri_image_status.signature);
+ valid_pri_image = 0;
+ goto check_sec_image;
+ }
+
+ wptr = (uint32_t *)(&pri_image_status);
+ cnt = size;
+
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le32_to_cpu(*wptr);
+ if (chksum) {
+ ql_dbg(ql_dbg_init, vha, 0x018c,
+ "Checksum validation failed for primary image (0x%x)\n",
+ chksum);
+ valid_pri_image = 0;
+ }
+
+check_sec_image:
+ if (!ha->flt_region_img_status_sec) {
+ valid_sec_image = 0;
+ goto check_valid_image;
+ }
+
+ qla24xx_read_flash_data(vha, (uint32_t *)(&sec_image_status),
+ ha->flt_region_img_status_sec, size);
+
+ if (sec_image_status.signature != QLA27XX_IMG_STATUS_SIGN) {
+ ql_dbg(ql_dbg_init, vha, 0x018d,
+ "Secondary image signature(0x%x) not valid\n",
+ sec_image_status.signature);
+ valid_sec_image = 0;
+ goto check_valid_image;
+ }
+
+ wptr = (uint32_t *)(&sec_image_status);
+ cnt = size;
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le32_to_cpu(*wptr);
+ if (chksum) {
+ ql_dbg(ql_dbg_init, vha, 0x018e,
+ "Checksum validation failed for secondary image (0x%x)\n",
+ chksum);
+ valid_sec_image = 0;
+ }
+
+check_valid_image:
+ if (valid_pri_image && (pri_image_status.image_status_mask & 0x1))
+ ha->active_image = QLA27XX_PRIMARY_IMAGE;
+ if (valid_sec_image && (sec_image_status.image_status_mask & 0x1)) {
+ if (!ha->active_image ||
+ pri_image_status.generation_number <
+ sec_image_status.generation_number)
+ ha->active_image = QLA27XX_SECONDARY_IMAGE;
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x018f, "%s image\n",
+ ha->active_image == 0 ? "default bootld and fw" :
+ ha->active_image == 1 ? "primary" :
+ ha->active_image == 2 ? "secondary" :
+ "Invalid");
+
+ return ha->active_image;
+}
+
static int
qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
uint32_t faddr)
@@ -5348,6 +5461,10 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
dcode = (uint32_t *)req->ring;
*srisc_addr = 0;
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_fw_sec;
+
/* Validate firmware image by checking version. */
qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
for (i = 0; i < 4; i++)
@@ -6048,8 +6165,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
ha->nvram_size);
dptr = (uint32_t *)nv;
- for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
- chksum += le32_to_cpu(*dptr++);
+ for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
+ chksum += le32_to_cpu(*dptr);
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
"Contents of NVRAM:\n");
@@ -6211,7 +6328,6 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
if (le16_to_cpu(nv->login_timeout) < 4)
nv->login_timeout = cpu_to_le16(4);
ha->login_timeout = le16_to_cpu(nv->login_timeout);
- icb->login_timeout = nv->login_timeout;
/* Set minimum RATOV to 100 tenths of a second. */
ha->r_a_tov = 100;
@@ -6393,12 +6509,17 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+ /* Hold status IOCBs until ABTS response received. */
+ if (ql2xfwholdabts)
+ ha->fw_options[3] |= BIT_12;
+
if (!ql2xetsenable)
- return;
+ goto out;
/* Enable ETS Burst. */
memset(ha->fw_options, 0, sizeof(ha->fw_options));
ha->fw_options[2] |= BIT_9;
+out:
qla2x00_set_fw_options(vha, ha->fw_options);
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index fee9eb7..edc48f3 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -87,8 +87,8 @@ host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
__le32 *odest = (__le32 *) dst;
uint32_t iter = bsize >> 2;
- for (; iter ; iter--)
- *odest++ = cpu_to_le32(*isrc++);
+ for ( ; iter--; isrc++)
+ *odest++ = cpu_to_le32(*isrc);
}
static inline void
@@ -258,6 +258,8 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
(sp->type == SRB_FXIOCB_DCMD))
init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
+ if (sp->type == SRB_ELS_DCMD)
+ init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
}
static inline int
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c49df34..b41265a 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1868,6 +1868,7 @@ skip_cmd_array:
}
queuing_error:
+ vha->tgt_counters.num_alloc_iocb_failed++;
return pkt;
}
@@ -2010,6 +2011,190 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
}
static void
+qla2x00_els_dcmd_sp_free(void *ptr, void *data)
+{
+ struct scsi_qla_host *vha = (scsi_qla_host_t *)ptr;
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ kfree(sp->fcport);
+
+ if (elsio->u.els_logo.els_logo_pyld)
+ dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+ elsio->u.els_logo.els_logo_pyld,
+ elsio->u.els_logo.els_logo_pyld_dma);
+
+ del_timer(&elsio->timer);
+ qla2x00_rel_sp(vha, sp);
+}
+
+static void
+qla2x00_els_dcmd_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags = 0;
+
+ ql_dbg(ql_dbg_io, vha, 0x3069,
+ "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
+ sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa);
+
+ /* Abort the exchange */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x3070,
+ "mbx abort_command failed.\n");
+ } else {
+ ql_dbg(ql_dbg_io, vha, 0x3071,
+ "mbx abort_command success.\n");
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+static void
+qla2x00_els_dcmd_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ fc_port_t *fcport = sp->fcport;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ struct scsi_qla_host *vha = fcport->vha;
+
+ ql_dbg(ql_dbg_io, vha, 0x3072,
+ "%s hdl=%x, portid=%02x%02x%02x done\n",
+ sp->name, sp->handle, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+int
+qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
+ port_id_t remote_did)
+{
+ srb_t *sp;
+ fc_port_t *fcport = NULL;
+ struct srb_iocb *elsio = NULL;
+ struct qla_hw_data *ha = vha->hw;
+ struct els_logo_payload logo_pyld;
+ int rval = QLA_SUCCESS;
+
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport) {
+ ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp) {
+ kfree(fcport);
+ ql_log(ql_log_info, vha, 0x70e6,
+ "SRB allocation failed\n");
+ return -ENOMEM;
+ }
+
+ elsio = &sp->u.iocb_cmd;
+ fcport->loop_id = 0xFFFF;
+ fcport->d_id.b.domain = remote_did.b.domain;
+ fcport->d_id.b.area = remote_did.b.area;
+ fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+ ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
+ fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ sp->type = SRB_ELS_DCMD;
+ sp->name = "ELS_DCMD";
+ sp->fcport = fcport;
+ qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+ elsio->timeout = qla2x00_els_dcmd_iocb_timeout;
+ sp->done = qla2x00_els_dcmd_sp_done;
+ sp->free = qla2x00_els_dcmd_sp_free;
+
+ elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
+ DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
+ GFP_KERNEL);
+
+ if (!elsio->u.els_logo.els_logo_pyld) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
+
+ elsio->u.els_logo.els_cmd = els_opcode;
+ logo_pyld.opcode = els_opcode;
+ logo_pyld.s_id[0] = vha->d_id.b.al_pa;
+ logo_pyld.s_id[1] = vha->d_id.b.area;
+ logo_pyld.s_id[2] = vha->d_id.b.domain;
+ host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
+ memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
+
+ memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
+ sizeof(struct els_logo_payload));
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_io, vha, 0x3074,
+ "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
+ sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ wait_for_completion(&elsio->u.els_logo.comp);
+
+ sp->free(vha, sp);
+ return rval;
+}
+
+static void
+qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+{
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ els_iocb->entry_type = ELS_IOCB_TYPE;
+ els_iocb->entry_count = 1;
+ els_iocb->sys_define = 0;
+ els_iocb->entry_status = 0;
+ els_iocb->handle = sp->handle;
+ els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ els_iocb->tx_dsd_count = 1;
+ els_iocb->vp_index = vha->vp_idx;
+ els_iocb->sof_type = EST_SOFI3;
+ els_iocb->rx_dsd_count = 0;
+ els_iocb->opcode = elsio->u.els_logo.els_cmd;
+
+ els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ els_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ els_iocb->control_flags = 0;
+
+ els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+ els_iocb->tx_address[0] =
+ cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_address[1] =
+ cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+
+ els_iocb->rx_byte_count = 0;
+ els_iocb->rx_address[0] = 0;
+ els_iocb->rx_address[1] = 0;
+ els_iocb->rx_len = 0;
+
+ sp->fcport->vha->qla_stats.control_requests++;
+}
+
+static void
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
@@ -2623,6 +2808,9 @@ qla2x00_start_sp(srb_t *sp)
qlafx00_abort_iocb(sp, pkt) :
qla24xx_abort_iocb(sp, pkt);
break;
+ case SRB_ELS_DCMD:
+ qla24xx_els_logo_iocb(sp, pkt);
+ break;
default:
break;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ccf6a7f..5649c20 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -18,6 +18,10 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
+static void qla_irq_affinity_notify(struct irq_affinity_notify *,
+ const cpumask_t *);
+static void qla_irq_affinity_release(struct kref *);
+
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -930,10 +934,6 @@ skip_rio:
break;
global_port_update:
- /* Port unavailable. */
- ql_log(ql_log_warn, vha, 0x505e,
- "Link is offline.\n");
-
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer,
@@ -1418,6 +1418,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
case SRB_CT_CMD:
type = "ct pass-through";
break;
+ case SRB_ELS_DCMD:
+ type = "Driver ELS logo";
+ ql_dbg(ql_dbg_user, vha, 0x5047,
+ "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
+ sp->done(vha, sp, 0);
+ return;
default:
ql_dbg(ql_dbg_user, vha, 0x503e,
"Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
@@ -2542,6 +2548,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
if (!vha->flags.online)
return;
+ if (rsp->msix->cpuid != smp_processor_id()) {
+ /* if kernel does not notify qla of IRQ's CPU change,
+ * then set it here.
+ */
+ rsp->msix->cpuid = smp_processor_id();
+ ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
+ }
+
while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
@@ -2587,8 +2601,14 @@ process_err:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break;
case ABTS_RECV_24XX:
- /* ensure that the ATIO queue is empty */
- qlt_24xx_process_atio_queue(vha);
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ /* ensure that the ATIO queue is empty */
+ qlt_handle_abts_recv(vha, (response_t *)pkt);
+ break;
+ } else {
+ /* drop through */
+ qlt_24xx_process_atio_queue(vha, 1);
+ }
case ABTS_RESP_24XX:
case CTIO_TYPE7:
case NOTIFY_ACK_TYPE:
@@ -2755,13 +2775,22 @@ qla24xx_intr_handler(int irq, void *dev_id)
case INTR_RSP_QUE_UPDATE_83XX:
qla24xx_process_response_queue(vha, rsp);
break;
- case INTR_ATIO_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ case INTR_ATIO_QUE_UPDATE:{
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
break;
- case INTR_ATIO_RSP_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ }
+ case INTR_ATIO_RSP_QUE_UPDATE: {
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
qla24xx_process_response_queue(vha, rsp);
break;
+ }
default:
ql_dbg(ql_dbg_async, vha, 0x504f,
"Unrecognized interrupt type (%d).\n", stat * 0xff);
@@ -2920,13 +2949,22 @@ qla24xx_msix_default(int irq, void *dev_id)
case INTR_RSP_QUE_UPDATE_83XX:
qla24xx_process_response_queue(vha, rsp);
break;
- case INTR_ATIO_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ case INTR_ATIO_QUE_UPDATE:{
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
break;
- case INTR_ATIO_RSP_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ }
+ case INTR_ATIO_RSP_QUE_UPDATE: {
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
qla24xx_process_response_queue(vha, rsp);
break;
+ }
default:
ql_dbg(ql_dbg_async, vha, 0x5051,
"Unrecognized interrupt type (%d).\n", stat & 0xff);
@@ -2973,8 +3011,11 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
for (i = 0; i < ha->msix_count; i++) {
qentry = &ha->msix_entries[i];
- if (qentry->have_irq)
+ if (qentry->have_irq) {
+ /* un-register irq cpu affinity notification */
+ irq_set_affinity_notifier(qentry->vector, NULL);
free_irq(qentry->vector, qentry->rsp);
+ }
}
pci_disable_msix(ha->pdev);
kfree(ha->msix_entries);
@@ -3018,9 +3059,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
"MSI-X: Failed to enable support "
"-- %d/%d\n Retry with %d vectors.\n",
ha->msix_count, ret, ret);
+ ha->msix_count = ret;
+ ha->max_rsp_queues = ha->msix_count - 1;
}
- ha->msix_count = ret;
- ha->max_rsp_queues = ha->msix_count - 1;
ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
ha->msix_count, GFP_KERNEL);
if (!ha->msix_entries) {
@@ -3037,6 +3078,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
qentry->entry = entries[i].entry;
qentry->have_irq = 0;
qentry->rsp = NULL;
+ qentry->irq_notify.notify = qla_irq_affinity_notify;
+ qentry->irq_notify.release = qla_irq_affinity_release;
+ qentry->cpuid = -1;
}
/* Enable MSI-X vectors for the base queue */
@@ -3055,6 +3099,18 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
qentry->have_irq = 1;
qentry->rsp = rsp;
rsp->msix = qentry;
+
+ /* Register for CPU affinity notification. */
+ irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
+
+ /* Schedule work (ie. trigger a notification) to read cpu
+ * mask for this specific irq.
+ * kref_get is required because
+ * irq_affinity_notify() will do
+ * kref_put().
+ */
+ kref_get(&qentry->irq_notify.kref);
+ schedule_work(&qentry->irq_notify.work);
}
/*
@@ -3234,3 +3290,47 @@ int qla25xx_request_irq(struct rsp_que *rsp)
msix->rsp = rsp;
return ret;
}
+
+
+/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
+static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
+ const cpumask_t *mask)
+{
+ struct qla_msix_entry *e =
+ container_of(notify, struct qla_msix_entry, irq_notify);
+ struct qla_hw_data *ha;
+ struct scsi_qla_host *base_vha;
+
+ /* user is recommended to set mask to just 1 cpu */
+ e->cpuid = cpumask_first(mask);
+
+ ha = e->rsp->hw;
+ base_vha = pci_get_drvdata(ha->pdev);
+
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host %ld : vector %d cpu %d \n", __func__,
+ base_vha->host_no, e->vector, e->cpuid);
+
+ if (e->have_irq) {
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
+ (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) {
+ ha->tgt.rspq_vector_cpuid = e->cpuid;
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host%ld: rspq vector %d cpu %d runtime change\n",
+ __func__, base_vha->host_no, e->vector, e->cpuid);
+ }
+ }
+}
+
+static void qla_irq_affinity_release(struct kref *ref)
+{
+ struct irq_affinity_notify *notify =
+ container_of(ref, struct irq_affinity_notify, kref);
+ struct qla_msix_entry *e =
+ container_of(notify, struct qla_msix_entry, irq_notify);
+ struct scsi_qla_host *base_vha = pci_get_drvdata(e->rsp->hw->pdev);
+
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host%ld: vector %d cpu %d \n", __func__,
+ base_vha->host_no, e->vector, e->cpuid);
+}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index cb11e04..968b846 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -489,6 +489,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
EXTENDED_BB_CREDITS);
} else
mcp->mb[4] = 0;
+
+ if (ha->flags.exlogins_enabled)
+ mcp->mb[4] |= ENABLE_EXTENDED_LOGIN;
+
+ if (ha->flags.exchoffld_enabled)
+ mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD;
+
mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
mcp->in_mb |= MBX_1;
} else {
@@ -521,6 +528,226 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
}
/*
+ * qla_get_exlogin_status
+ * Get extended login status
+ * uses the memory offload control/status Mailbox
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * fwopt: firmware options
+ *
+ * Returns:
+ * qla2x00 local function status
+ *
+ * Context:
+ * Kernel context.
+ */
+#define FETCH_XLOGINS_STAT 0x8
+int
+qla_get_exlogin_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+ uint16_t *ex_logins_cnt)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118f,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = FETCH_XLOGINS_STAT;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_10|MBX_4|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1115, "Failed=%x.\n", rval);
+ } else {
+ *buf_sz = mcp->mb[4];
+ *ex_logins_cnt = mcp->mb[10];
+
+ ql_log(ql_log_info, vha, 0x1190,
+ "buffer size 0x%x, exchange login count=%d\n",
+ mcp->mb[4], mcp->mb[10]);
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1116,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_set_exlogin_mem_cfg
+ * set extended login memory configuration
+ * Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * buffer: buffer pointer
+ * phys_addr: physical address of buffer
+ * size: size of buffer
+ * TARGET_QUEUE_LOCK must be released
+ * ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ * qla2x00 local funxtion status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+#define CONFIG_XLOGINS_MEM 0x3
+int
+qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+ int configured_count;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111a,
+ "Entered %s.\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = CONFIG_XLOGINS_MEM;
+ mcp->mb[2] = MSW(phys_addr);
+ mcp->mb[3] = LSW(phys_addr);
+ mcp->mb[6] = MSW(MSD(phys_addr));
+ mcp->mb[7] = LSW(MSD(phys_addr));
+ mcp->mb[8] = MSW(ha->exlogin_size);
+ mcp->mb[9] = LSW(ha->exlogin_size);
+ mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ ql_dbg(ql_dbg_mbx, vha, 0x111b, "Failed=%x.\n", rval);
+ } else {
+ configured_count = mcp->mb[11];
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_get_exchoffld_status
+ * Get exchange offload status
+ * uses the memory offload control/status Mailbox
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * fwopt: firmware options
+ *
+ * Returns:
+ * qla2x00 local function status
+ *
+ * Context:
+ * Kernel context.
+ */
+#define FETCH_XCHOFFLD_STAT 0x2
+int
+qla_get_exchoffld_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+ uint16_t *ex_logins_cnt)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1019,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = FETCH_XCHOFFLD_STAT;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_10|MBX_4|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1155, "Failed=%x.\n", rval);
+ } else {
+ *buf_sz = mcp->mb[4];
+ *ex_logins_cnt = mcp->mb[10];
+
+ ql_log(ql_log_info, vha, 0x118e,
+ "buffer size 0x%x, exchange offload count=%d\n",
+ mcp->mb[4], mcp->mb[10]);
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1156,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_set_exchoffld_mem_cfg
+ * Set exchange offload memory configuration
+ * Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * buffer: buffer pointer
+ * phys_addr: physical address of buffer
+ * size: size of buffer
+ * TARGET_QUEUE_LOCK must be released
+ * ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ * qla2x00 local funxtion status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+#define CONFIG_XCHOFFLD_MEM 0x3
+int
+qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1157,
+ "Entered %s.\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = CONFIG_XCHOFFLD_MEM;
+ mcp->mb[2] = MSW(phys_addr);
+ mcp->mb[3] = LSW(phys_addr);
+ mcp->mb[6] = MSW(MSD(phys_addr));
+ mcp->mb[7] = LSW(MSD(phys_addr));
+ mcp->mb[8] = MSW(ha->exlogin_size);
+ mcp->mb[9] = LSW(ha->exlogin_size);
+ mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ ql_dbg(ql_dbg_mbx, vha, 0x1158, "Failed=%x.\n", rval);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
* qla2x00_get_fw_version
* Get firmware version.
*
@@ -594,6 +821,16 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x112f,
"%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
__func__, mcp->mb[17], mcp->mb[16]);
+
+ if (ha->fw_attributes_h & 0x4)
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118d,
+ "%s: Firmware supports Extended Login 0x%x\n",
+ __func__, ha->fw_attributes_h);
+
+ if (ha->fw_attributes_h & 0x8)
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1191,
+ "%s: Firmware supports Exchange Offload 0x%x\n",
+ __func__, ha->fw_attributes_h);
}
if (IS_QLA27XX(ha)) {
@@ -1112,6 +1349,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
if (IS_FWI2_CAPABLE(vha->hw))
mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16;
+ if (IS_QLA27XX(vha->hw))
+ mcp->in_mb |= MBX_15;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
rval = qla2x00_mailbox_command(vha, mcp);
@@ -1163,6 +1402,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
wwn_to_u64(vha->port_name));
}
}
+
+ if (IS_QLA27XX(vha->hw))
+ vha->bbcr = mcp->mb[15];
}
return rval;
@@ -2383,10 +2625,9 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
* Kernel context.
*/
int
-qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
- uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
- uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports, uint16_t *max_fcfs)
+qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
{
+ struct qla_hw_data *ha = vha->hw;
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
@@ -2414,19 +2655,16 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10],
mcp->mb[11], mcp->mb[12]);
- if (cur_xchg_cnt)
- *cur_xchg_cnt = mcp->mb[3];
- if (orig_xchg_cnt)
- *orig_xchg_cnt = mcp->mb[6];
- if (cur_iocb_cnt)
- *cur_iocb_cnt = mcp->mb[7];
- if (orig_iocb_cnt)
- *orig_iocb_cnt = mcp->mb[10];
- if (vha->hw->flags.npiv_supported && max_npiv_vports)
- *max_npiv_vports = mcp->mb[11];
- if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) ||
- IS_QLA27XX(vha->hw)) && max_fcfs)
- *max_fcfs = mcp->mb[12];
+ ha->orig_fw_tgt_xcb_count = mcp->mb[1];
+ ha->cur_fw_tgt_xcb_count = mcp->mb[2];
+ ha->cur_fw_xcb_count = mcp->mb[3];
+ ha->orig_fw_xcb_count = mcp->mb[6];
+ ha->cur_fw_iocb_count = mcp->mb[7];
+ ha->orig_fw_iocb_count = mcp->mb[10];
+ if (ha->flags.npiv_supported)
+ ha->max_npiv_vports = mcp->mb[11];
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ ha->fw_max_fcf_count = mcp->mb[12];
}
return (rval);
@@ -2521,7 +2759,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- uint32_t *siter, *diter, dwords;
+ uint32_t *iter, dwords;
struct qla_hw_data *ha = vha->hw;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1084,
@@ -2561,10 +2799,11 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
/* Copy over data -- firmware data is LE. */
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1086,
"Done %s.\n", __func__);
- dwords = offsetof(struct link_statistics, unused1) / 4;
- siter = diter = &stats->link_fail_cnt;
- while (dwords--)
- *diter++ = le32_to_cpu(*siter++);
+ dwords = offsetof(struct link_statistics,
+ link_up_cnt) / 4;
+ iter = &stats->link_fail_cnt;
+ for ( ; dwords--; iter++)
+ le32_to_cpus(iter);
}
} else {
/* Failed. */
@@ -2581,7 +2820,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- uint32_t *siter, *diter, dwords;
+ uint32_t *iter, dwords;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1088,
"Entered %s.\n", __func__);
@@ -2610,9 +2849,9 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
"Done %s.\n", __func__);
/* Copy over data -- firmware data is LE. */
dwords = sizeof(struct link_statistics) / 4;
- siter = diter = &stats->link_fail_cnt;
- while (dwords--)
- *diter++ = le32_to_cpu(*siter++);
+ iter = &stats->link_fail_cnt;
+ for ( ; dwords--; iter++)
+ le32_to_cpus(iter);
}
} else {
/* Failed. */
@@ -3379,6 +3618,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]);
+ /* buffer to buffer credit flag */
+ vha->flags.bbcr_enable = (rptid_entry->bbcr & 0xf) != 0;
+
/* FA-WWN is only for physical port */
if (!vp_idx) {
void *wwpn = ha->init_cb->port_name;
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index c5dd594..cf7ba52 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -600,7 +600,7 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
/* Delete request queues */
for (cnt = 1; cnt < ha->max_req_queues; cnt++) {
req = ha->req_q_map[cnt];
- if (req) {
+ if (req && test_bit(cnt, ha->req_qid_map)) {
ret = qla25xx_delete_req_que(vha, req);
if (ret != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x00ea,
@@ -614,7 +614,7 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
/* Delete response queues */
for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) {
rsp = ha->rsp_q_map[cnt];
- if (rsp) {
+ if (rsp && test_bit(cnt, ha->rsp_qid_map)) {
ret = qla25xx_delete_rsp_que(vha, rsp);
if (ret != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x00eb,
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index eb0cc54..b6b4cfd 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -433,7 +433,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
if (off_in < QLA82XX_PCI_CRBSPACE)
return -1;
- *off_out = (void __iomem *)(off_in - QLA82XX_PCI_CRBSPACE);
+ off_in -= QLA82XX_PCI_CRBSPACE;
/* Try direct map */
m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)];
@@ -443,6 +443,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
return 0;
}
/* Not in direct map, use crb window */
+ *off_out = (void __iomem *)off_in;
return 1;
}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c2dd17b..7c0b60c 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -221,6 +221,25 @@ MODULE_PARM_DESC(ql2xmdenable,
"0 - MiniDump disabled. "
"1 (Default) - MiniDump enabled.");
+int ql2xexlogins = 0;
+module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexlogins,
+ "Number of extended Logins. "
+ "0 (Default)- Disabled.");
+
+int ql2xexchoffld = 0;
+module_param(ql2xexchoffld, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexchoffld,
+ "Number of exchanges to offload. "
+ "0 (Default)- Disabled.");
+
+int ql2xfwholdabts = 0;
+module_param(ql2xfwholdabts, int, S_IRUGO);
+MODULE_PARM_DESC(ql2xfwholdabts,
+ "Allow FW to hold status IOCB until ABTS rsp received. "
+ "0 (Default) Do not set fw option. "
+ "1 - Set fw option to hold ABTS.");
+
/*
* SCSI host template entry points
*/
@@ -267,7 +286,6 @@ struct scsi_host_template qla2xxx_driver_template = {
.shost_attrs = qla2x00_host_attrs,
.supported_mode = MODE_INITIATOR,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -398,6 +416,9 @@ static void qla2x00_free_queues(struct qla_hw_data *ha)
int cnt;
for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
+ if (!test_bit(cnt, ha->req_qid_map))
+ continue;
+
req = ha->req_q_map[cnt];
qla2x00_free_req_que(ha, req);
}
@@ -405,6 +426,9 @@ static void qla2x00_free_queues(struct qla_hw_data *ha)
ha->req_q_map = NULL;
for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
+ if (!test_bit(cnt, ha->rsp_qid_map))
+ continue;
+
rsp = ha->rsp_q_map[cnt];
qla2x00_free_rsp_que(ha, rsp);
}
@@ -2199,6 +2223,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_ZIO_SUPPORTED;
ha->device_type |= DT_FWI2;
ha->device_type |= DT_IIDMA;
+ ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP2271:
@@ -2206,6 +2231,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_ZIO_SUPPORTED;
ha->device_type |= DT_FWI2;
ha->device_type |= DT_IIDMA;
+ ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP2261:
@@ -2213,6 +2239,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_ZIO_SUPPORTED;
ha->device_type |= DT_FWI2;
ha->device_type |= DT_IIDMA;
+ ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
}
@@ -2325,6 +2352,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->tgt.enable_class_2 = ql2xenableclass2;
INIT_LIST_HEAD(&ha->tgt.q_full_list);
spin_lock_init(&ha->tgt.q_full_lock);
+ spin_lock_init(&ha->tgt.sess_lock);
+ spin_lock_init(&ha->tgt.atio_lock);
+
/* Clear our data area */
ha->bars = bars;
@@ -2469,7 +2499,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_83XX;
- rsp_length = RESPONSE_ENTRY_CNT_2300;
+ rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -2499,8 +2529,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->portnum = PCI_FUNC(ha->pdev->devfn);
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
- req_length = REQUEST_ENTRY_CNT_24XX;
- rsp_length = RESPONSE_ENTRY_CNT_2300;
+ req_length = REQUEST_ENTRY_CNT_83XX;
+ rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -3129,6 +3159,14 @@ qla2x00_remove_one(struct pci_dev *pdev)
base_vha->flags.online = 0;
+ /* free DMA memory */
+ if (ha->exlogin_buf)
+ qla2x00_free_exlogin_buffer(ha);
+
+ /* free DMA memory */
+ if (ha->exchoffld_buf)
+ qla2x00_free_exchoffld_buffer(ha);
+
qla2x00_destroy_deferred_work(ha);
qlt_remove_target(ha, base_vha);
@@ -3588,6 +3626,140 @@ fail:
return -ENOMEM;
}
+int
+qla2x00_set_exlogins_buffer(scsi_qla_host_t *vha)
+{
+ int rval;
+ uint16_t size, max_cnt, temp;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Return if we don't need to alloacate any extended logins */
+ if (!ql2xexlogins)
+ return QLA_SUCCESS;
+
+ ql_log(ql_log_info, vha, 0xd021, "EXLOGIN count: %d.\n", ql2xexlogins);
+ max_cnt = 0;
+ rval = qla_get_exlogin_status(vha, &size, &max_cnt);
+ if (rval != QLA_SUCCESS) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd029,
+ "Failed to get exlogin status.\n");
+ return rval;
+ }
+
+ temp = (ql2xexlogins > max_cnt) ? max_cnt : ql2xexlogins;
+ ha->exlogin_size = (size * temp);
+ ql_log(ql_log_info, vha, 0xd024,
+ "EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n",
+ max_cnt, size, temp);
+
+ ql_log(ql_log_info, vha, 0xd025, "EXLOGIN: requested size=0x%x\n",
+ ha->exlogin_size);
+
+ /* Get consistent memory for extended logins */
+ ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev,
+ ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL);
+ if (!ha->exlogin_buf) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a,
+ "Failed to allocate memory for exlogin_buf_dma.\n");
+ return -ENOMEM;
+ }
+
+ /* Now configure the dma buffer */
+ rval = qla_set_exlogin_mem_cfg(vha, ha->exlogin_buf_dma);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0x00cf,
+ "Setup extended login buffer ****FAILED****.\n");
+ qla2x00_free_exlogin_buffer(ha);
+ }
+
+ return rval;
+}
+
+/*
+* qla2x00_free_exlogin_buffer
+*
+* Input:
+* ha = adapter block pointer
+*/
+void
+qla2x00_free_exlogin_buffer(struct qla_hw_data *ha)
+{
+ if (ha->exlogin_buf) {
+ dma_free_coherent(&ha->pdev->dev, ha->exlogin_size,
+ ha->exlogin_buf, ha->exlogin_buf_dma);
+ ha->exlogin_buf = NULL;
+ ha->exlogin_size = 0;
+ }
+}
+
+int
+qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
+{
+ int rval;
+ uint16_t size, max_cnt, temp;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Return if we don't need to alloacate any extended logins */
+ if (!ql2xexchoffld)
+ return QLA_SUCCESS;
+
+ ql_log(ql_log_info, vha, 0xd014,
+ "Exchange offload count: %d.\n", ql2xexlogins);
+
+ max_cnt = 0;
+ rval = qla_get_exchoffld_status(vha, &size, &max_cnt);
+ if (rval != QLA_SUCCESS) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd012,
+ "Failed to get exlogin status.\n");
+ return rval;
+ }
+
+ temp = (ql2xexchoffld > max_cnt) ? max_cnt : ql2xexchoffld;
+ ha->exchoffld_size = (size * temp);
+ ql_log(ql_log_info, vha, 0xd016,
+ "Exchange offload: max_count=%d, buffers=0x%x, total=%d.\n",
+ max_cnt, size, temp);
+
+ ql_log(ql_log_info, vha, 0xd017,
+ "Exchange Buffers requested size = 0x%x\n", ha->exchoffld_size);
+
+ /* Get consistent memory for extended logins */
+ ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev,
+ ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL);
+ if (!ha->exchoffld_buf) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd013,
+ "Failed to allocate memory for exchoffld_buf_dma.\n");
+ return -ENOMEM;
+ }
+
+ /* Now configure the dma buffer */
+ rval = qla_set_exchoffld_mem_cfg(vha, ha->exchoffld_buf_dma);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0xd02e,
+ "Setup exchange offload buffer ****FAILED****.\n");
+ qla2x00_free_exchoffld_buffer(ha);
+ }
+
+ return rval;
+}
+
+/*
+* qla2x00_free_exchoffld_buffer
+*
+* Input:
+* ha = adapter block pointer
+*/
+void
+qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha)
+{
+ if (ha->exchoffld_buf) {
+ dma_free_coherent(&ha->pdev->dev, ha->exchoffld_size,
+ ha->exchoffld_buf, ha->exchoffld_buf_dma);
+ ha->exchoffld_buf = NULL;
+ ha->exchoffld_size = 0;
+ }
+}
+
/*
* qla2x00_free_fw_dump
* Frees fw dump stuff.
@@ -3767,6 +3939,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->list);
INIT_LIST_HEAD(&vha->qla_cmd_list);
INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
+ INIT_LIST_HEAD(&vha->logo_list);
+ INIT_LIST_HEAD(&vha->plogi_ack_list);
spin_lock_init(&vha->work_lock);
spin_lock_init(&vha->cmd_list_lock);
@@ -5844,6 +6018,3 @@ MODULE_FIRMWARE(FW_FILE_ISP2300);
MODULE_FIRMWARE(FW_FILE_ISP2322);
MODULE_FIRMWARE(FW_FILE_ISP24XX);
MODULE_FIRMWARE(FW_FILE_ISP25XX);
-MODULE_FIRMWARE(FW_FILE_ISP2031);
-MODULE_FIRMWARE(FW_FILE_ISP8031);
-MODULE_FIRMWARE(FW_FILE_ISP27XX);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 3272ed5b..5e93923 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -610,8 +610,8 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
wptr = (uint16_t *)req->ring;
cnt = sizeof(struct qla_flt_location) >> 1;
- for (chksum = 0; cnt; cnt--)
- chksum += le16_to_cpu(*wptr++);
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_log(ql_log_fatal, vha, 0x0045,
"Inconsistent FLTL detected: checksum=0x%x.\n", chksum);
@@ -702,8 +702,8 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
}
cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
- for (chksum = 0; cnt; cnt--)
- chksum += le16_to_cpu(*wptr++);
+ for (chksum = 0; cnt--; wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_log(ql_log_fatal, vha, 0x0048,
"Inconsistent FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
@@ -846,6 +846,38 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
if (ha->port_no == 1)
ha->flt_region_nvram = start;
break;
+ case FLT_REG_IMG_PRI_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_img_status_pri = start;
+ break;
+ case FLT_REG_IMG_SEC_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_img_status_sec = start;
+ break;
+ case FLT_REG_FW_SEC_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_fw_sec = start;
+ break;
+ case FLT_REG_BOOTLOAD_SEC_27XX:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_boot_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_0:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_1:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_2:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
+ case FLT_REG_VPD_SEC_27XX_3:
+ if (IS_QLA27XX(ha))
+ ha->flt_region_vpd_sec = start;
+ break;
}
}
goto done;
@@ -898,9 +930,8 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
fdt->sig[3] != 'D')
goto no_flash_data;
- for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1;
- cnt++)
- chksum += le16_to_cpu(*wptr++);
+ for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_dbg(ql_dbg_init, vha, 0x004c,
"Inconsistent FDT detected:"
@@ -995,7 +1026,8 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
ha->fcoe_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
} else {
- ha->fcoe_dev_init_timeout = le32_to_cpu(*wptr++);
+ ha->fcoe_dev_init_timeout = le32_to_cpu(*wptr);
+ wptr++;
ha->fcoe_reset_timeout = le32_to_cpu(*wptr);
}
ql_dbg(ql_dbg_init, vha, 0x004e,
@@ -1072,10 +1104,9 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
ha->isp_ops->read_optrom(vha, (uint8_t *)data,
ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE);
- cnt = (sizeof(struct qla_npiv_header) + le16_to_cpu(hdr.entries) *
- sizeof(struct qla_npiv_entry)) >> 1;
- for (wptr = data, chksum = 0; cnt; cnt--)
- chksum += le16_to_cpu(*wptr++);
+ cnt = (sizeof(hdr) + le16_to_cpu(hdr.entries) * sizeof(*entry)) >> 1;
+ for (wptr = data, chksum = 0; cnt--; wptr++)
+ chksum += le16_to_cpu(*wptr);
if (chksum) {
ql_dbg(ql_dbg_user, vha, 0x7092,
"Inconsistent NPIV-Config "
@@ -2989,6 +3020,9 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
uint8_t code_type, last_image;
int i;
struct qla_hw_data *ha = vha->hw;
+ uint32_t faddr = 0;
+
+ pcihdr = pcids = 0;
if (IS_P3P_TYPE(ha))
return ret;
@@ -3002,9 +3036,11 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
dcode = mbuf;
-
- /* Begin with first PCI expansion ROM header. */
pcihdr = ha->flt_region_boot << 2;
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ pcihdr = ha->flt_region_boot_sec << 2;
+
last_image = 1;
do {
/* Verify PCI expansion ROM header. */
@@ -3077,8 +3113,12 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
/* Read firmware image information. */
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
dcode = mbuf;
+ faddr = ha->flt_region_fw;
+ if (IS_QLA27XX(ha) &&
+ qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_fw_sec;
- qla24xx_read_flash_data(vha, dcode, ha->flt_region_fw + 4, 4);
+ qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
for (i = 0; i < 4; i++)
dcode[i] = be32_to_cpu(dcode[i]);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 75514a1..8a44d15 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -100,12 +100,12 @@ enum fcp_resp_rsp_codes {
*/
/* Predefs for callbacks handed to qla2xxx LLD */
static void qlt_24xx_atio_pkt(struct scsi_qla_host *ha,
- struct atio_from_isp *pkt);
+ struct atio_from_isp *pkt, uint8_t);
static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
int fn, void *iocb, int flags);
static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
- *cmd, struct atio_from_isp *atio, int ha_locked);
+ *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
struct qla_tgt_srr_imm *imm, int ha_lock);
static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
@@ -118,10 +118,13 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha,
struct imm_ntfy_from_isp *ntfy,
uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+ struct imm_ntfy_from_isp *imm, int ha_locked);
/*
* Global Variables
*/
static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
+static struct kmem_cache *qla_tgt_plogi_cachep;
static mempool_t *qla_tgt_mgmt_cmd_mempool;
static struct workqueue_struct *qla_tgt_wq;
static DEFINE_MUTEX(qla_tgt_mutex);
@@ -226,8 +229,8 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha)
spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
}
-static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
- struct atio_from_isp *atio)
+static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
+ struct atio_from_isp *atio, uint8_t ha_locked)
{
ql_dbg(ql_dbg_tgt, vha, 0xe072,
"%s: qla_target(%d): type %x ox_id %04x\n",
@@ -248,7 +251,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
atio->u.isp24.fcp_hdr.d_id[2]);
break;
}
- qlt_24xx_atio_pkt(host, atio);
+ qlt_24xx_atio_pkt(host, atio, ha_locked);
break;
}
@@ -271,7 +274,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
break;
}
}
- qlt_24xx_atio_pkt(host, atio);
+ qlt_24xx_atio_pkt(host, atio, ha_locked);
break;
}
@@ -282,7 +285,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
break;
}
- return;
+ return false;
}
void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
@@ -389,6 +392,131 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
}
+/*
+ * All qlt_plogi_ack_t operations are protected by hardware_lock
+ */
+
+/*
+ * This is a zero-base ref-counting solution, since hardware_lock
+ * guarantees that ref_count is not modified concurrently.
+ * Upon successful return content of iocb is undefined
+ */
+static qlt_plogi_ack_t *
+qlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id,
+ struct imm_ntfy_from_isp *iocb)
+{
+ qlt_plogi_ack_t *pla;
+
+ list_for_each_entry(pla, &vha->plogi_ack_list, list) {
+ if (pla->id.b24 == id->b24) {
+ qlt_send_term_imm_notif(vha, &pla->iocb, 1);
+ pla->iocb = *iocb;
+ return pla;
+ }
+ }
+
+ pla = kmem_cache_zalloc(qla_tgt_plogi_cachep, GFP_ATOMIC);
+ if (!pla) {
+ ql_dbg(ql_dbg_async, vha, 0x5088,
+ "qla_target(%d): Allocation of plogi_ack failed\n",
+ vha->vp_idx);
+ return NULL;
+ }
+
+ pla->iocb = *iocb;
+ pla->id = *id;
+ list_add_tail(&pla->list, &vha->plogi_ack_list);
+
+ return pla;
+}
+
+static void qlt_plogi_ack_unref(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla)
+{
+ BUG_ON(!pla->ref_count);
+ pla->ref_count--;
+
+ if (pla->ref_count)
+ return;
+
+ ql_dbg(ql_dbg_async, vha, 0x5089,
+ "Sending PLOGI ACK to wwn %8phC s_id %02x:%02x:%02x loop_id %#04x"
+ " exch %#x ox_id %#x\n", pla->iocb.u.isp24.port_name,
+ pla->iocb.u.isp24.port_id[2], pla->iocb.u.isp24.port_id[1],
+ pla->iocb.u.isp24.port_id[0],
+ le16_to_cpu(pla->iocb.u.isp24.nport_handle),
+ pla->iocb.u.isp24.exchange_address, pla->iocb.ox_id);
+ qlt_send_notify_ack(vha, &pla->iocb, 0, 0, 0, 0, 0, 0);
+
+ list_del(&pla->list);
+ kmem_cache_free(qla_tgt_plogi_cachep, pla);
+}
+
+static void
+qlt_plogi_ack_link(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla,
+ struct qla_tgt_sess *sess, qlt_plogi_link_t link)
+{
+ /* Inc ref_count first because link might already be pointing at pla */
+ pla->ref_count++;
+
+ if (sess->plogi_link[link])
+ qlt_plogi_ack_unref(vha, sess->plogi_link[link]);
+
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf097,
+ "Linking sess %p [%d] wwn %8phC with PLOGI ACK to wwn %8phC"
+ " s_id %02x:%02x:%02x, ref=%d\n", sess, link, sess->port_name,
+ pla->iocb.u.isp24.port_name, pla->iocb.u.isp24.port_id[2],
+ pla->iocb.u.isp24.port_id[1], pla->iocb.u.isp24.port_id[0],
+ pla->ref_count);
+
+ sess->plogi_link[link] = pla;
+}
+
+typedef struct {
+ /* These fields must be initialized by the caller */
+ port_id_t id;
+ /*
+ * number of cmds dropped while we were waiting for
+ * initiator to ack LOGO initialize to 1 if LOGO is
+ * triggered by a command, otherwise, to 0
+ */
+ int cmd_count;
+
+ /* These fields are used by callee */
+ struct list_head list;
+} qlt_port_logo_t;
+
+static void
+qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
+{
+ qlt_port_logo_t *tmp;
+ int res;
+
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+
+ list_for_each_entry(tmp, &vha->logo_list, list) {
+ if (tmp->id.b24 == logo->id.b24) {
+ tmp->cmd_count += logo->cmd_count;
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+ return;
+ }
+ }
+
+ list_add_tail(&logo->list, &vha->logo_list);
+
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+ res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id);
+
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+ list_del(&logo->list);
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf098,
+ "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
+ logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
+ logo->cmd_count, res);
+}
+
static void qlt_free_session_done(struct work_struct *work)
{
struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess,
@@ -402,14 +530,21 @@ static void qlt_free_session_done(struct work_struct *work)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
"%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
- " s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+ " s_id %02x:%02x:%02x logout %d keep %d els_logo %d\n",
__func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
sess->logout_on_delete, sess->keep_nport_handle,
- sess->plogi_ack_needed);
+ sess->send_els_logo);
BUG_ON(!tgt);
+ if (sess->send_els_logo) {
+ qlt_port_logo_t logo;
+ logo.id = sess->s_id;
+ logo.cmd_count = 0;
+ qlt_send_first_logo(vha, &logo);
+ }
+
if (sess->logout_on_delete) {
int rc;
@@ -455,9 +590,34 @@ static void qlt_free_session_done(struct work_struct *work)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (sess->plogi_ack_needed)
- qlt_send_notify_ack(vha, &sess->tm_iocb,
- 0, 0, 0, 0, 0, 0);
+ {
+ qlt_plogi_ack_t *own =
+ sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
+ qlt_plogi_ack_t *con =
+ sess->plogi_link[QLT_PLOGI_LINK_CONFLICT];
+
+ if (con) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf099,
+ "se_sess %p / sess %p port %8phC is gone,"
+ " %s (ref=%d), releasing PLOGI for %8phC (ref=%d)\n",
+ sess->se_sess, sess, sess->port_name,
+ own ? "releasing own PLOGI" :
+ "no own PLOGI pending",
+ own ? own->ref_count : -1,
+ con->iocb.u.isp24.port_name, con->ref_count);
+ qlt_plogi_ack_unref(vha, con);
+ } else {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09a,
+ "se_sess %p / sess %p port %8phC is gone, %s (ref=%d)\n",
+ sess->se_sess, sess, sess->port_name,
+ own ? "releasing own PLOGI" :
+ "no own PLOGI pending",
+ own ? own->ref_count : -1);
+ }
+
+ if (own)
+ qlt_plogi_ack_unref(vha, own);
+ }
list_del(&sess->sess_list_entry);
@@ -476,12 +636,13 @@ static void qlt_free_session_done(struct work_struct *work)
wake_up_all(&tgt->waitQ);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
void qlt_unreg_sess(struct qla_tgt_sess *sess)
{
struct scsi_qla_host *vha = sess->vha;
- vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess);
+ if (sess->se_sess)
+ vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess);
if (!list_empty(&sess->del_list_entry))
list_del_init(&sess->del_list_entry);
@@ -492,7 +653,7 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess)
}
EXPORT_SYMBOL(qlt_unreg_sess);
-/* ha->hardware_lock supposed to be held on entry */
+
static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
{
struct qla_hw_data *ha = vha->hw;
@@ -502,12 +663,15 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
int res = 0;
struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb;
struct atio_from_isp *a = (struct atio_from_isp *)iocb;
+ unsigned long flags;
loop_id = le16_to_cpu(n->u.isp24.nport_handle);
if (loop_id == 0xFFFF) {
/* Global event */
atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
#if 0 /* FIXME: do we need to choose a session here? */
if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
@@ -534,7 +698,9 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
sess = NULL;
#endif
} else {
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
ql_dbg(ql_dbg_tgt, vha, 0xe000,
@@ -556,7 +722,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
iocb, QLA24XX_MGMT_SEND_NACK);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
bool immediate)
{
@@ -600,7 +766,7 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
sess->expires - jiffies);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_clear_tgt_db(struct qla_tgt *tgt)
{
struct qla_tgt_sess *sess;
@@ -636,12 +802,12 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id,
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045,
"qla_target(%d): get_id_list() failed: %x\n",
vha->vp_idx, rc);
- res = -1;
+ res = -EBUSY;
goto out_free_id_list;
}
id_iter = (char *)gid_list;
- res = -1;
+ res = -ENOENT;
for (i = 0; i < entries; i++) {
struct gid_list_info *gid = (struct gid_list_info *)id_iter;
if ((gid->al_pa == s_id[2]) &&
@@ -660,7 +826,7 @@ out_free_id_list:
return res;
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_undelete_sess(struct qla_tgt_sess *sess)
{
BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
@@ -678,7 +844,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
struct qla_tgt_sess *sess;
unsigned long flags, elapsed;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
while (!list_empty(&tgt->del_sess_list)) {
sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
del_list_entry);
@@ -691,15 +857,19 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
"Timeout: sess %p about to be deleted\n",
sess);
- ha->tgt.tgt_ops->shutdown_sess(sess);
- ha->tgt.tgt_ops->put_sess(sess);
+ if (sess->se_sess) {
+ ha->tgt.tgt_ops->shutdown_sess(sess);
+ ha->tgt.tgt_ops->put_sess(sess);
+ } else {
+ qlt_unreg_sess(sess);
+ }
} else {
schedule_delayed_work(&tgt->sess_del_work,
sess->expires - elapsed);
break;
}
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
/*
@@ -714,10 +884,9 @@ static struct qla_tgt_sess *qlt_create_sess(
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess;
unsigned long flags;
- unsigned char be_sid[3];
/* Check to avoid double sessions */
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_for_each_entry(sess, &vha->vha_tgt.qla_tgt->sess_list,
sess_list_entry) {
if (!memcmp(sess->port_name, fcport->port_name, WWN_SIZE)) {
@@ -732,7 +901,7 @@ static struct qla_tgt_sess *qlt_create_sess(
/* Cannot undelete at this point */
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
- spin_unlock_irqrestore(&ha->hardware_lock,
+ spin_unlock_irqrestore(&ha->tgt.sess_lock,
flags);
return NULL;
}
@@ -740,6 +909,14 @@ static struct qla_tgt_sess *qlt_create_sess(
if (sess->deleted)
qlt_undelete_sess(sess);
+ if (!sess->se_sess) {
+ if (ha->tgt.tgt_ops->check_initiator_node_acl(vha,
+ &sess->port_name[0], sess) < 0) {
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+ return NULL;
+ }
+ }
+
kref_get(&sess->se_sess->sess_kref);
ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
(fcport->flags & FCF_CONF_COMP_SUPPORTED));
@@ -749,12 +926,12 @@ static struct qla_tgt_sess *qlt_create_sess(
qlt_do_generation_tick(vha, &sess->generation);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return sess;
}
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
sess = kzalloc(sizeof(*sess), GFP_KERNEL);
if (!sess) {
@@ -783,35 +960,15 @@ static struct qla_tgt_sess *qlt_create_sess(
"Adding sess %p to tgt %p via ->check_initiator_node_acl()\n",
sess, vha->vha_tgt.qla_tgt);
- be_sid[0] = sess->s_id.b.domain;
- be_sid[1] = sess->s_id.b.area;
- be_sid[2] = sess->s_id.b.al_pa;
- /*
- * Determine if this fc_port->port_name is allowed to access
- * target mode using explict NodeACLs+MappedLUNs, or using
- * TPG demo mode. If this is successful a target mode FC nexus
- * is created.
- */
- if (ha->tgt.tgt_ops->check_initiator_node_acl(vha,
- &fcport->port_name[0], sess, &be_sid[0], fcport->loop_id) < 0) {
- kfree(sess);
- return NULL;
- }
- /*
- * Take an extra reference to ->sess_kref here to handle qla_tgt_sess
- * access across ->hardware_lock reaquire.
- */
- kref_get(&sess->se_sess->sess_kref);
-
sess->conf_compl_supported = (fcport->flags & FCF_CONF_COMP_SUPPORTED);
BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name));
memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
vha->vha_tgt.qla_tgt->sess_count++;
qlt_do_generation_tick(vha, &sess->generation);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
"qla_target(%d): %ssession for wwn %8phC (loop_id %d, "
@@ -820,6 +977,23 @@ static struct qla_tgt_sess *qlt_create_sess(
fcport->loop_id, sess->s_id.b.domain, sess->s_id.b.area,
sess->s_id.b.al_pa, sess->conf_compl_supported ? "" : "not ");
+ /*
+ * Determine if this fc_port->port_name is allowed to access
+ * target mode using explict NodeACLs+MappedLUNs, or using
+ * TPG demo mode. If this is successful a target mode FC nexus
+ * is created.
+ */
+ if (ha->tgt.tgt_ops->check_initiator_node_acl(vha,
+ &fcport->port_name[0], sess) < 0) {
+ return NULL;
+ } else {
+ /*
+ * Take an extra reference to ->sess_kref here to handle qla_tgt_sess
+ * access across ->tgt.sess_lock reaquire.
+ */
+ kref_get(&sess->se_sess->sess_kref);
+ }
+
return sess;
}
@@ -842,23 +1016,23 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
if (qla_ini_mode_enabled(vha))
return;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (tgt->tgt_stop) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
}
sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_create_sess(vha, fcport, false);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
} else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
/* Point of no return */
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
} else {
kref_get(&sess->se_sess->sess_kref);
@@ -887,7 +1061,7 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
sess->local = 0;
}
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
/*
@@ -899,6 +1073,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
struct qla_tgt_sess *sess;
+ unsigned long flags;
if (!vha->hw->tgt.tgt_ops)
return;
@@ -906,15 +1081,19 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
if (!tgt)
return;
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
if (tgt->tgt_stop) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return;
}
sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
if (!sess) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return;
}
if (max_gen - sess->generation < 0) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092,
"Ignoring stale deletion request for se_sess %p / sess %p"
" for port %8phC, req_gen %d, sess_gen %d\n",
@@ -927,6 +1106,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
sess->local = 1;
qlt_schedule_sess_for_deletion(sess, false);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -984,10 +1164,10 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
* Lock is needed, because we still can get an incoming packet.
*/
mutex_lock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
tgt->tgt_stop = 1;
qlt_clear_tgt_db(tgt);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
mutex_unlock(&qla_tgt_mutex);
@@ -1040,7 +1220,7 @@ void qlt_stop_phase2(struct qla_tgt *tgt)
mutex_lock(&vha->vha_tgt.tgt_mutex);
spin_lock_irqsave(&ha->hardware_lock, flags);
- while (tgt->irq_cmd_count != 0) {
+ while ((tgt->irq_cmd_count != 0) || (tgt->atio_irq_cmd_count != 0)) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
udelay(2);
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1309,7 +1489,7 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
if (tag == cmd->atio.u.isp24.exchange_addr) {
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
spin_unlock(&vha->cmd_list_lock);
return 1;
}
@@ -1351,7 +1531,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha,
cmd_lun = scsilun_to_int(
(struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
if (cmd_key == key && cmd_lun == lun)
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
}
spin_unlock(&vha->cmd_list_lock);
}
@@ -1435,6 +1615,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
uint32_t tag = abts->exchange_addr_to_abort;
uint8_t s_id[3];
int rc;
+ unsigned long flags;
if (le32_to_cpu(abts->fcp_hdr_le.parameter) & ABTS_PARAM_ABORT_SEQ) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053,
@@ -1462,6 +1643,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
s_id[1] = abts->fcp_hdr_le.s_id[1];
s_id[2] = abts->fcp_hdr_le.s_id[0];
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
if (!sess) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012,
@@ -1469,12 +1651,17 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
vha->vp_idx);
rc = qlt_sched_sess_work(vha->vha_tgt.qla_tgt,
QLA_TGT_SESS_WORK_ABORT, abts, sizeof(*abts));
+
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (rc != 0) {
qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED,
false);
}
return;
}
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false);
@@ -1560,15 +1747,15 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || mcmd->reset_count != ha->chip_reset) {
+ if (!vha->flags.online || mcmd->reset_count != ha->chip_reset) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
ql_dbg(ql_dbg_async, vha, 0xe100,
- "RESET-TMR active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), mcmd->reset_count,
- ha->chip_reset);
+ "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ mcmd->reset_count, ha->chip_reset);
ha->tgt.tgt_ops->free_mcmd(mcmd);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return;
@@ -1578,7 +1765,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
qlt_send_notify_ack(vha, &mcmd->orig_iocb.imm_ntfy,
0, 0, 0, 0, 0, 0);
else {
- if (mcmd->se_cmd.se_tmr_req->function == TMR_ABORT_TASK)
+ if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
qlt_24xx_send_abts_resp(vha, &mcmd->orig_iocb.abts,
mcmd->fc_tm_rsp, false);
else
@@ -1694,15 +1881,17 @@ static int qlt_check_reserve_free_req(struct scsi_qla_host *vha,
else
vha->req->cnt = vha->req->length -
(vha->req->ring_index - cnt);
- }
- if (unlikely(vha->req->cnt < (req_cnt + 2))) {
- ql_dbg(ql_dbg_io, vha, 0x305a,
- "qla_target(%d): There is no room in the request ring: vha->req->ring_index=%d, vha->req->cnt=%d, req_cnt=%d Req-out=%d Req-in=%d Req-Length=%d\n",
- vha->vp_idx, vha->req->ring_index,
- vha->req->cnt, req_cnt, cnt, cnt_in, vha->req->length);
- return -EAGAIN;
+ if (unlikely(vha->req->cnt < (req_cnt + 2))) {
+ ql_dbg(ql_dbg_io, vha, 0x305a,
+ "qla_target(%d): There is no room in the request ring: vha->req->ring_index=%d, vha->req->cnt=%d, req_cnt=%d Req-out=%d Req-in=%d Req-Length=%d\n",
+ vha->vp_idx, vha->req->ring_index,
+ vha->req->cnt, req_cnt, cnt, cnt_in,
+ vha->req->length);
+ return -EAGAIN;
+ }
}
+
vha->req->cnt -= req_cnt;
return 0;
@@ -2487,7 +2676,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
/* no need to terminate. FW already freed exchange. */
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
else
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2510,17 +2699,22 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+ if (xmit_type == QLA_TGT_XMIT_STATUS)
+ vha->tgt_counters.core_qla_snd_status++;
+ else
+ vha->tgt_counters.core_qla_que_buf++;
+
+ if (!vha->flags.online || cmd->reset_count != ha->chip_reset) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
cmd->state = QLA_TGT_STATE_PROCESSED;
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
ql_dbg(ql_dbg_async, vha, 0xe101,
- "RESET-RSP active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), cmd->reset_count,
- ha->chip_reset);
+ "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ cmd->reset_count, ha->chip_reset);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2651,18 +2845,18 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+ if (!vha->flags.online || (cmd->reset_count != ha->chip_reset) ||
(cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
cmd->state = QLA_TGT_STATE_NEED_DATA;
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
ql_dbg(ql_dbg_async, vha, 0xe102,
- "RESET-XFR active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), cmd->reset_count,
- ha->chip_reset);
+ "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ cmd->reset_count, ha->chip_reset);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2957,12 +3151,13 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
ret = 1;
}
+ vha->tgt_counters.num_term_xchg_sent++;
pkt->entry_count = 1;
pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
ctio24 = (struct ctio7_to_24xx *)pkt;
ctio24->entry_type = CTIO_TYPE7;
- ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED;
+ ctio24->nport_handle = CTIO7_NHANDLE_UNRECOGNIZED;
ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
ctio24->vp_index = vha->vp_idx;
ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
@@ -2989,7 +3184,8 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
}
static void qlt_send_term_exchange(struct scsi_qla_host *vha,
- struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
+ struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked,
+ int ul_abort)
{
unsigned long flags = 0;
int rc;
@@ -3009,8 +3205,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
qlt_alloc_qfull_cmd(vha, atio, 0, 0);
done:
- if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
- !cmd->cmd_sent_to_fw)) {
+ if (cmd && !ul_abort && !cmd->aborted) {
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
vha->hw->tgt.tgt_ops->free_cmd(cmd);
@@ -3028,7 +3223,7 @@ static void qlt_init_term_exchange(struct scsi_qla_host *vha)
struct qla_tgt_cmd *cmd, *tcmd;
vha->hw->tgt.leak_exchg_thresh_hold =
- (vha->hw->fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
+ (vha->hw->cur_fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
cmd = tcmd = NULL;
if (!list_empty(&vha->hw->tgt.q_full_list)) {
@@ -3058,7 +3253,7 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
ql_dbg(ql_dbg_tgt, vha, 0xe079,
"Chip reset due to exchange starvation: %d/%d.\n",
- total_leaked, vha->hw->fw_xcb_count);
+ total_leaked, vha->hw->cur_fw_xcb_count);
if (IS_P3P_TYPE(vha->hw))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -3069,21 +3264,38 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
}
-void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
{
struct qla_tgt *tgt = cmd->tgt;
struct scsi_qla_host *vha = tgt->vha;
struct se_cmd *se_cmd = &cmd->se_cmd;
+ unsigned long flags;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
"qla_target(%d): terminating exchange for aborted cmd=%p "
"(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
se_cmd->tag);
- cmd->state = QLA_TGT_STATE_ABORTED;
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ if (cmd->aborted) {
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ /*
+ * It's normal to see 2 calls in this path:
+ * 1) XFER Rdy completion + CMD_T_ABORT
+ * 2) TCM TMR - drain_state_list
+ */
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
+ "multiple abort. %p transport_state %x, t_state %x,"
+ " se_cmd_flags %x \n", cmd, cmd->se_cmd.transport_state,
+ cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+ return EIO;
+ }
+ cmd->aborted = 1;
cmd->cmd_flags |= BIT_6;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
+ return 0;
}
EXPORT_SYMBOL(qlt_abort_cmd);
@@ -3098,6 +3310,9 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
BUG_ON(cmd->cmd_in_wq);
+ if (cmd->sg_mapped)
+ qlt_unmap_sg(cmd->vha, cmd);
+
if (!cmd->q_full)
qlt_decr_num_pend_cmds(cmd->vha);
@@ -3215,7 +3430,7 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio,
term = 1;
if (term)
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
return term;
}
@@ -3300,9 +3515,6 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
ha->tgt.tgt_ops->handle_data(cmd);
return;
- } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
- ql_dbg(ql_dbg_io, vha, 0xff02,
- "HOST-ABORT: handle=%d, state=ABORTED.\n", handle);
} else {
ql_dbg(ql_dbg_io, vha, 0xff03,
"HOST-ABORT: handle=%d, state=BAD(%d).\n", handle,
@@ -3398,13 +3610,27 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
case CTIO_PORT_LOGGED_OUT:
case CTIO_PORT_UNAVAILABLE:
+ {
+ int logged_out =
+ (status & 0xFFFF) == CTIO_PORT_LOGGED_OUT;
+
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
- "qla_target(%d): CTIO with PORT LOGGED "
- "OUT (29) or PORT UNAVAILABLE (28) status %x "
+ "qla_target(%d): CTIO with %s status %x "
"received (state %x, se_cmd %p)\n", vha->vp_idx,
+ logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE",
status, cmd->state, se_cmd);
- break;
+ if (logged_out && cmd->sess) {
+ /*
+ * Session is already logged out, but we need
+ * to notify initiator, who's not aware of this
+ */
+ cmd->sess->logout_on_delete = 0;
+ cmd->sess->send_els_logo = 1;
+ qlt_schedule_sess_for_deletion(cmd->sess, true);
+ }
+ break;
+ }
case CTIO_SRR_RECEIVED:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a,
"qla_target(%d): CTIO with SRR_RECEIVED"
@@ -3454,14 +3680,14 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
}
- /* "cmd->state == QLA_TGT_STATE_ABORTED" means
+ /* "cmd->aborted" means
* cmd is already aborted/terminated, we don't
* need to terminate again. The exchange is already
* cleaned up/freed at FW level. Just cleanup at driver
* level.
*/
if ((cmd->state != QLA_TGT_STATE_NEED_DATA) &&
- (cmd->state != QLA_TGT_STATE_ABORTED)) {
+ (!cmd->aborted)) {
cmd->cmd_flags |= BIT_13;
if (qlt_term_ctio_exchange(vha, ctio, cmd, status))
return;
@@ -3479,7 +3705,7 @@ skip_term:
ha->tgt.tgt_ops->handle_data(cmd);
return;
- } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+ } else if (cmd->aborted) {
cmd->cmd_flags |= BIT_18;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
"Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
@@ -3491,7 +3717,7 @@ skip_term:
}
if (unlikely(status != CTIO_SUCCESS) &&
- (cmd->state != QLA_TGT_STATE_ABORTED)) {
+ !cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n");
dump_stack();
}
@@ -3553,13 +3779,14 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
if (tgt->tgt_stop)
goto out_term;
- if (cmd->state == QLA_TGT_STATE_ABORTED) {
+ if (cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
"cmd with tag %u is aborted\n",
cmd->atio.u.isp24.exchange_addr);
goto out_term;
}
+ spin_lock_init(&cmd->cmd_lock);
cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
cmd->unpacked_lun = scsilun_to_int(
@@ -3589,9 +3816,9 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
/*
* Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
*/
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
out_term:
@@ -3602,12 +3829,15 @@ out_term:
*/
cmd->cmd_flags |= BIT_2;
spin_lock_irqsave(&ha->hardware_lock, flags);
- qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0);
qlt_decr_num_pend_cmds(vha);
percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
- ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+ ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
static void qlt_do_work(struct work_struct *work)
@@ -3692,10 +3922,8 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
goto out_term;
}
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has an extra creation ref. */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
if (!sess)
goto out_term;
@@ -3723,7 +3951,7 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
out_term:
spin_lock_irqsave(&ha->hardware_lock, flags);
- qlt_send_term_exchange(vha, NULL, &op->atio, 1);
+ qlt_send_term_exchange(vha, NULL, &op->atio, 1, 0);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
kfree(op);
@@ -3787,13 +4015,24 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
cmd->cmd_in_wq = 1;
cmd->cmd_flags |= BIT_0;
+ cmd->se_cmd.cpuid = ha->msix_count ?
+ ha->tgt.rspq_vector_cpuid : WORK_CPU_UNBOUND;
spin_lock(&vha->cmd_list_lock);
list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
spin_unlock(&vha->cmd_list_lock);
INIT_WORK(&cmd->work, qlt_do_work);
- queue_work(qla_tgt_wq, &cmd->work);
+ if (ha->msix_count) {
+ if (cmd->atio.u.isp24.fcp_cmnd.rddata)
+ queue_work_on(smp_processor_id(), qla_tgt_wq,
+ &cmd->work);
+ else
+ queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq,
+ &cmd->work);
+ } else {
+ queue_work(qla_tgt_wq, &cmd->work);
+ }
return 0;
}
@@ -3917,13 +4156,18 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb)
struct qla_tgt_sess *sess;
uint32_t lun, unpacked_lun;
int fn;
+ unsigned long flags;
tgt = vha->vha_tgt.qla_tgt;
lun = a->u.isp24.fcp_cmnd.lun;
fn = a->u.isp24.fcp_cmnd.task_mgmt_flags;
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
a->u.isp24.fcp_hdr.s_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
if (!sess) {
@@ -3987,10 +4231,14 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess;
int loop_id;
+ unsigned long flags;
loop_id = GET_TARGET_ID(ha, (struct atio_from_isp *)iocb);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (sess == NULL) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025,
"qla_target(%d): task abort for unexisting "
@@ -4022,15 +4270,6 @@ void qlt_logo_completion_handler(fc_port_t *fcport, int rc)
}
}
-static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
- struct imm_ntfy_from_isp *b)
-{
- struct imm_ntfy_from_isp tmp;
- memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp));
- memcpy(a, b, sizeof(struct imm_ntfy_from_isp));
- memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp));
-}
-
/*
* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list)
*
@@ -4040,11 +4279,13 @@ static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
*/
static struct qla_tgt_sess *
qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
- port_id_t port_id, uint16_t loop_id)
+ port_id_t port_id, uint16_t loop_id, struct qla_tgt_sess **conflict_sess)
{
struct qla_tgt_sess *sess = NULL, *other_sess;
uint64_t other_wwn;
+ *conflict_sess = NULL;
+
list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) {
other_wwn = wwn_to_u64(other_sess->port_name);
@@ -4072,9 +4313,10 @@ qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
} else {
/*
* Another wwn used to have our s_id/loop_id
- * combo - kill the session, but don't log out
+ * kill the session, but don't free the loop_id
*/
- sess->logout_on_delete = 0;
+ other_sess->keep_nport_handle = 1;
+ *conflict_sess = other_sess;
qlt_schedule_sess_for_deletion(other_sess,
true);
}
@@ -4119,7 +4361,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id)
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
if (cmd_key == key) {
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
count++;
}
}
@@ -4136,12 +4378,14 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
struct qla_hw_data *ha = vha->hw;
- struct qla_tgt_sess *sess = NULL;
+ struct qla_tgt_sess *sess = NULL, *conflict_sess = NULL;
uint64_t wwn;
port_id_t port_id;
uint16_t loop_id;
uint16_t wd3_lo;
int res = 0;
+ qlt_plogi_ack_t *pla;
+ unsigned long flags;
wwn = wwn_to_u64(iocb->u.isp24.port_name);
@@ -4165,27 +4409,20 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
/* Mark all stale commands in qla_tgt_wq for deletion */
abort_cmds_for_s_id(vha, &port_id);
- if (wwn)
+ if (wwn) {
+ spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
sess = qlt_find_sess_invalidate_other(tgt, wwn,
- port_id, loop_id);
+ port_id, loop_id, &conflict_sess);
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+ }
- if (!sess || IS_SW_RESV_ADDR(sess->s_id)) {
+ if (IS_SW_RESV_ADDR(port_id) || (!sess && !conflict_sess)) {
res = 1;
break;
}
- if (sess->plogi_ack_needed) {
- /*
- * Initiator sent another PLOGI before last PLOGI could
- * finish. Swap plogi iocbs and terminate old one
- * without acking, new one will get acked when session
- * deletion completes.
- */
- ql_log(ql_log_warn, sess->vha, 0xf094,
- "sess %p received double plogi.\n", sess);
-
- qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb);
-
+ pla = qlt_plogi_ack_find_add(vha, &port_id, iocb);
+ if (!pla) {
qlt_send_term_imm_notif(vha, iocb, 1);
res = 0;
@@ -4194,13 +4431,14 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
res = 0;
- /*
- * Save immediate Notif IOCB for Ack when sess is done
- * and being deleted.
- */
- memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb));
- sess->plogi_ack_needed = 1;
+ if (conflict_sess)
+ qlt_plogi_ack_link(vha, pla, conflict_sess,
+ QLT_PLOGI_LINK_CONFLICT);
+ if (!sess)
+ break;
+
+ qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
/*
* Under normal circumstances we want to release nport handle
* during LOGO process to avoid nport handle leaks inside FW.
@@ -4227,9 +4465,21 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
case ELS_PRLI:
wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
- if (wwn)
+ if (wwn) {
+ spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
- loop_id);
+ loop_id, &conflict_sess);
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+ }
+
+ if (conflict_sess) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09b,
+ "PRLI with conflicting sess %p port %8phC\n",
+ conflict_sess, conflict_sess->port_name);
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ res = 0;
+ break;
+ }
if (sess != NULL) {
if (sess->deleted) {
@@ -4554,7 +4804,7 @@ out_reject:
dump_stack();
} else {
cmd->cmd_flags |= BIT_9;
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
@@ -4733,7 +4983,7 @@ static void qlt_prepare_srr_imm(struct scsi_qla_host *vha,
sctio, sctio->srr_id);
list_del(&sctio->srr_list_entry);
qlt_send_term_exchange(vha, sctio->cmd,
- &sctio->cmd->atio, 1);
+ &sctio->cmd->atio, 1, 0);
kfree(sctio);
}
}
@@ -4899,11 +5149,14 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
struct qla_hw_data *ha = vha->hw;
request_t *pkt;
struct qla_tgt_sess *sess = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
atio->u.isp24.fcp_hdr.s_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
if (!sess) {
- qlt_send_term_exchange(vha, NULL, atio, 1);
+ qlt_send_term_exchange(vha, NULL, atio, 1, 0);
return 0;
}
/* Sending marker isn't necessary, since we called from ISR */
@@ -4916,6 +5169,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
return -ENOMEM;
}
+ vha->tgt_counters.num_q_full_sent++;
pkt->entry_count = 1;
pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
@@ -5129,11 +5383,12 @@ qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha,
/* ha->hardware_lock supposed to be held on entry */
/* called via callback from qla2xxx */
static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
- struct atio_from_isp *atio)
+ struct atio_from_isp *atio, uint8_t ha_locked)
{
struct qla_hw_data *ha = vha->hw;
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
int rc;
+ unsigned long flags;
if (unlikely(tgt == NULL)) {
ql_dbg(ql_dbg_io, vha, 0x3064,
@@ -5145,7 +5400,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
* Otherwise, some commands can stuck.
*/
- tgt->irq_cmd_count++;
+ tgt->atio_irq_cmd_count++;
switch (atio->u.raw.entry_type) {
case ATIO_TYPE7:
@@ -5155,7 +5410,11 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
"qla_target(%d): ATIO_TYPE7 "
"received with UNKNOWN exchange address, "
"sending QUEUE_FULL\n", vha->vp_idx);
+ if (!ha_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_send_busy(vha, atio, SAM_STAT_TASK_SET_FULL);
+ if (!ha_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
break;
}
@@ -5164,7 +5423,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) {
rc = qlt_chk_qfull_thresh_hold(vha, atio);
if (rc != 0) {
- tgt->irq_cmd_count--;
+ tgt->atio_irq_cmd_count--;
return;
}
rc = qlt_handle_cmd_for_atio(vha, atio);
@@ -5173,11 +5432,20 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
}
if (unlikely(rc != 0)) {
if (rc == -ESRCH) {
+ if (!ha_locked)
+ spin_lock_irqsave
+ (&ha->hardware_lock, flags);
+
#if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
qlt_send_busy(vha, atio, SAM_STAT_BUSY);
#else
- qlt_send_term_exchange(vha, NULL, atio, 1);
+ qlt_send_term_exchange(vha, NULL, atio, 1, 0);
#endif
+
+ if (!ha_locked)
+ spin_unlock_irqrestore
+ (&ha->hardware_lock, flags);
+
} else {
if (tgt->tgt_stop) {
ql_dbg(ql_dbg_tgt, vha, 0xe059,
@@ -5189,7 +5457,13 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
"qla_target(%d): Unable to send "
"command to target, sending BUSY "
"status.\n", vha->vp_idx);
+ if (!ha_locked)
+ spin_lock_irqsave(
+ &ha->hardware_lock, flags);
qlt_send_busy(vha, atio, SAM_STAT_BUSY);
+ if (!ha_locked)
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
}
}
}
@@ -5206,7 +5480,12 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
break;
}
ql_dbg(ql_dbg_tgt, vha, 0xe02e, "%s", "IMMED_NOTIFY ATIO");
+
+ if (!ha_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)atio);
+ if (!ha_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
break;
}
@@ -5217,7 +5496,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
break;
}
- tgt->irq_cmd_count--;
+ tgt->atio_irq_cmd_count--;
}
/* ha->hardware_lock supposed to be held on entry */
@@ -5277,7 +5556,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
#if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
qlt_send_busy(vha, atio, 0);
#else
- qlt_send_term_exchange(vha, NULL, atio, 1);
+ qlt_send_term_exchange(vha, NULL, atio, 1, 0);
#endif
} else {
if (tgt->tgt_stop) {
@@ -5286,7 +5565,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
"command to target, sending TERM "
"EXCHANGE for rsp\n");
qlt_send_term_exchange(vha, NULL,
- atio, 1);
+ atio, 1, 0);
} else {
ql_dbg(ql_dbg_tgt, vha, 0xe060,
"qla_target(%d): Unable to send "
@@ -5534,12 +5813,16 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *vha,
int rc, global_resets;
uint16_t loop_id = 0;
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+
retry:
global_resets =
atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
rc = qla24xx_get_loop_id(vha, s_id, &loop_id);
if (rc != 0) {
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
if ((s_id[0] == 0xFF) &&
(s_id[1] == 0xFC)) {
/*
@@ -5550,17 +5833,27 @@ retry:
"Unable to find initiator with S_ID %x:%x:%x",
s_id[0], s_id[1], s_id[2]);
} else
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf071,
+ ql_log(ql_log_info, vha, 0xf071,
"qla_target(%d): Unable to find "
"initiator with S_ID %x:%x:%x",
vha->vp_idx, s_id[0], s_id[1],
s_id[2]);
+
+ if (rc == -ENOENT) {
+ qlt_port_logo_t logo;
+ sid_to_portid(s_id, &logo.id);
+ logo.cmd_count = 1;
+ qlt_send_first_logo(vha, &logo);
+ }
+
return NULL;
}
fcport = qlt_get_port_database(vha, loop_id);
- if (!fcport)
+ if (!fcport) {
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
return NULL;
+ }
if (global_resets !=
atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) {
@@ -5575,6 +5868,8 @@ retry:
sess = qlt_create_sess(vha, fcport, true);
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
kfree(fcport);
return sess;
}
@@ -5585,15 +5880,15 @@ static void qlt_abort_work(struct qla_tgt *tgt,
struct scsi_qla_host *vha = tgt->vha;
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess = NULL;
- unsigned long flags;
+ unsigned long flags = 0, flags2 = 0;
uint32_t be_s_id;
uint8_t s_id[3];
int rc;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
if (tgt->tgt_stop)
- goto out_term;
+ goto out_term2;
s_id[0] = prm->abts.fcp_hdr_le.s_id[2];
s_id[1] = prm->abts.fcp_hdr_le.s_id[1];
@@ -5602,41 +5897,47 @@ static void qlt_abort_work(struct qla_tgt *tgt,
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
(unsigned char *)&be_s_id);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has got an extra creation ref */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
if (!sess)
- goto out_term;
+ goto out_term2;
} else {
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
sess = NULL;
- goto out_term;
+ goto out_term2;
}
kref_get(&sess->se_sess->sess_kref);
}
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
if (tgt->tgt_stop)
goto out_term;
rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
if (rc != 0)
goto out_term;
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
return;
+out_term2:
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
out_term:
qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
}
static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -5653,7 +5954,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
int fn;
void *iocb;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (tgt->tgt_stop)
goto out_term;
@@ -5661,14 +5962,12 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id;
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has got an extra creation ref */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (!sess)
goto out_term;
} else {
@@ -5690,14 +5989,14 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
goto out_term;
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
out_term:
- qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
+ qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
static void qlt_sess_work_fn(struct work_struct *work)
@@ -6002,6 +6301,7 @@ qlt_enable_vha(struct scsi_qla_host *vha)
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
unsigned long flags;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+ int rspq_ent = QLA83XX_RSPQ_MSIX_ENTRY_NUMBER;
if (!tgt) {
ql_dbg(ql_dbg_tgt, vha, 0xe069,
@@ -6020,6 +6320,17 @@ qlt_enable_vha(struct scsi_qla_host *vha)
qla24xx_disable_vp(vha);
qla24xx_enable_vp(vha);
} else {
+ if (ha->msix_entries) {
+ ql_dbg(ql_dbg_tgt, vha, 0xffff,
+ "%s: host%ld : vector %d cpu %d\n",
+ __func__, vha->host_no,
+ ha->msix_entries[rspq_ent].vector,
+ ha->msix_entries[rspq_ent].cpuid);
+
+ ha->tgt.rspq_vector_cpuid =
+ ha->msix_entries[rspq_ent].cpuid;
+ }
+
set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
qla2xxx_wake_dpc(base_vha);
qla2x00_wait_for_hba_online(base_vha);
@@ -6131,7 +6442,7 @@ qlt_init_atio_q_entries(struct scsi_qla_host *vha)
* @ha: SCSI driver HA context
*/
void
-qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
+qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked)
{
struct qla_hw_data *ha = vha->hw;
struct atio_from_isp *pkt;
@@ -6144,7 +6455,8 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr;
cnt = pkt->u.raw.entry_count;
- qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt);
+ qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt,
+ ha_locked);
for (i = 0; i < cnt; i++) {
ha->tgt.atio_ring_index++;
@@ -6265,10 +6577,21 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha,
{
struct qla_hw_data *ha = vha->hw;
+ if (!QLA_TGT_MODE_ENABLED())
+ return;
+
if (ha->tgt.node_name_set) {
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+ /* disable ZIO at start time. */
+ if (!vha->flags.init_done) {
+ uint32_t tmp;
+ tmp = le32_to_cpu(icb->firmware_options_2);
+ tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ icb->firmware_options_2 = cpu_to_le32(tmp);
+ }
}
void
@@ -6359,6 +6682,15 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+ /* disable ZIO at start time. */
+ if (!vha->flags.init_done) {
+ uint32_t tmp;
+ tmp = le32_to_cpu(icb->firmware_options_2);
+ tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ icb->firmware_options_2 = cpu_to_le32(tmp);
+ }
+
}
void
@@ -6428,16 +6760,59 @@ qla83xx_msix_atio_q(int irq, void *dev_id)
ha = rsp->hw;
vha = pci_get_drvdata(ha->pdev);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
- qlt_24xx_process_atio_queue(vha);
- qla24xx_process_response_queue(vha, rsp);
+ qlt_24xx_process_atio_queue(vha, 0);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
return IRQ_HANDLED;
}
+static void
+qlt_handle_abts_recv_work(struct work_struct *work)
+{
+ struct qla_tgt_sess_op *op = container_of(work,
+ struct qla_tgt_sess_op, work);
+ scsi_qla_host_t *vha = op->vha;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags;
+
+ if (qla2x00_reset_active(vha) || (op->chip_reset != ha->chip_reset))
+ return;
+
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ qlt_response_pkt_all_vps(vha, (response_t *)&op->atio);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qlt_handle_abts_recv(struct scsi_qla_host *vha, response_t *pkt)
+{
+ struct qla_tgt_sess_op *op;
+
+ op = kzalloc(sizeof(*op), GFP_ATOMIC);
+
+ if (!op) {
+ /* do not reach for ATIO queue here. This is best effort err
+ * recovery at this point.
+ */
+ qlt_response_pkt_all_vps(vha, pkt);
+ return;
+ }
+
+ memcpy(&op->atio, pkt, sizeof(*pkt));
+ op->vha = vha;
+ op->chip_reset = vha->hw->chip_reset;
+ INIT_WORK(&op->work, qlt_handle_abts_recv_work);
+ queue_work(qla_tgt_wq, &op->work);
+ return;
+}
+
int
qlt_mem_alloc(struct qla_hw_data *ha)
{
@@ -6532,13 +6907,25 @@ int __init qlt_init(void)
return -ENOMEM;
}
+ qla_tgt_plogi_cachep = kmem_cache_create("qla_tgt_plogi_cachep",
+ sizeof(qlt_plogi_ack_t),
+ __alignof__(qlt_plogi_ack_t),
+ 0, NULL);
+
+ if (!qla_tgt_plogi_cachep) {
+ ql_log(ql_log_fatal, NULL, 0xe06d,
+ "kmem_cache_create for qla_tgt_plogi_cachep failed\n");
+ ret = -ENOMEM;
+ goto out_mgmt_cmd_cachep;
+ }
+
qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab,
mempool_free_slab, qla_tgt_mgmt_cmd_cachep);
if (!qla_tgt_mgmt_cmd_mempool) {
ql_log(ql_log_fatal, NULL, 0xe06e,
"mempool_create for qla_tgt_mgmt_cmd_mempool failed\n");
ret = -ENOMEM;
- goto out_mgmt_cmd_cachep;
+ goto out_plogi_cachep;
}
qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0);
@@ -6555,6 +6942,8 @@ int __init qlt_init(void)
out_cmd_mempool:
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+out_plogi_cachep:
+ kmem_cache_destroy(qla_tgt_plogi_cachep);
out_mgmt_cmd_cachep:
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
return ret;
@@ -6567,5 +6956,6 @@ void qlt_exit(void)
destroy_workqueue(qla_tgt_wq);
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+ kmem_cache_destroy(qla_tgt_plogi_cachep);
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
}
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index bca584a..d857fee 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -731,7 +731,7 @@ struct qla_tgt_func_tmpl {
void (*free_session)(struct qla_tgt_sess *);
int (*check_initiator_node_acl)(struct scsi_qla_host *, unsigned char *,
- void *, uint8_t *, uint16_t);
+ struct qla_tgt_sess *);
void (*update_sess)(struct qla_tgt_sess *, port_id_t, uint16_t, bool);
struct qla_tgt_sess *(*find_sess_by_loop_id)(struct scsi_qla_host *,
const uint16_t);
@@ -787,7 +787,7 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
#define QLA_TGT_STATE_NEED_DATA 1 /* target needs data to continue */
#define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */
#define QLA_TGT_STATE_PROCESSED 3 /* target done processing */
-#define QLA_TGT_STATE_ABORTED 4 /* Command aborted */
+
/* Special handles */
#define QLA_TGT_NULL_HANDLE 0
@@ -835,6 +835,7 @@ struct qla_tgt {
* HW lock.
*/
int irq_cmd_count;
+ int atio_irq_cmd_count;
int datasegs_per_cmd, datasegs_per_cont, sg_tablesize;
@@ -883,6 +884,7 @@ struct qla_tgt {
struct qla_tgt_sess_op {
struct scsi_qla_host *vha;
+ uint32_t chip_reset;
struct atio_from_isp atio;
struct work_struct work;
struct list_head cmd_list;
@@ -896,6 +898,19 @@ enum qla_sess_deletion {
QLA_SESS_DELETION_IN_PROGRESS = 2,
};
+typedef enum {
+ QLT_PLOGI_LINK_SAME_WWN,
+ QLT_PLOGI_LINK_CONFLICT,
+ QLT_PLOGI_LINK_MAX
+} qlt_plogi_link_t;
+
+typedef struct {
+ struct list_head list;
+ struct imm_ntfy_from_isp iocb;
+ port_id_t id;
+ int ref_count;
+} qlt_plogi_ack_t;
+
/*
* Equivilant to IT Nexus (Initiator-Target)
*/
@@ -907,8 +922,8 @@ struct qla_tgt_sess {
unsigned int deleted:2;
unsigned int local:1;
unsigned int logout_on_delete:1;
- unsigned int plogi_ack_needed:1;
unsigned int keep_nport_handle:1;
+ unsigned int send_els_logo:1;
unsigned char logout_completed;
@@ -925,11 +940,39 @@ struct qla_tgt_sess {
uint8_t port_name[WWN_SIZE];
struct work_struct free_work;
- union {
- struct imm_ntfy_from_isp tm_iocb;
- };
+ qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
};
+typedef enum {
+ /*
+ * BIT_0 - Atio Arrival / schedule to work
+ * BIT_1 - qlt_do_work
+ * BIT_2 - qlt_do work failed
+ * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
+ * BIT_4 - read respond/tcm_qla2xx_queue_data_in
+ * BIT_5 - status respond / tcm_qla2xx_queue_status
+ * BIT_6 - tcm request to abort/Term exchange.
+ * pre_xmit_response->qlt_send_term_exchange
+ * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
+ * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
+ * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
+ * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
+
+ * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
+ * BIT_13 - Bad completion -
+ * qlt_ctio_do_completion --> qlt_term_ctio_exchange
+ * BIT_14 - Back end data received/sent.
+ * BIT_15 - SRR prepare ctio
+ * BIT_16 - complete free
+ * BIT_17 - flush - qlt_abort_cmd_on_host_reset
+ * BIT_18 - completion w/abort status
+ * BIT_19 - completion w/unknown status
+ * BIT_20 - tcm_qla2xxx_free_cmd
+ */
+ CMD_FLAG_DATA_WORK = BIT_11,
+ CMD_FLAG_DATA_WORK_FREE = BIT_21,
+} cmd_flags_t;
+
struct qla_tgt_cmd {
struct se_cmd se_cmd;
struct qla_tgt_sess *sess;
@@ -939,6 +982,7 @@ struct qla_tgt_cmd {
/* Sense buffer that will be mapped into outgoing status */
unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
+ spinlock_t cmd_lock;
/* to save extra sess dereferences */
unsigned int conf_compl_supported:1;
unsigned int sg_mapped:1;
@@ -949,6 +993,7 @@ struct qla_tgt_cmd {
unsigned int term_exchg:1;
unsigned int cmd_sent_to_fw:1;
unsigned int cmd_in_wq:1;
+ unsigned int aborted:1;
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
@@ -972,30 +1017,8 @@ struct qla_tgt_cmd {
uint64_t jiffies_at_alloc;
uint64_t jiffies_at_free;
- /* BIT_0 - Atio Arrival / schedule to work
- * BIT_1 - qlt_do_work
- * BIT_2 - qlt_do work failed
- * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
- * BIT_4 - read respond/tcm_qla2xx_queue_data_in
- * BIT_5 - status respond / tcm_qla2xx_queue_status
- * BIT_6 - tcm request to abort/Term exchange.
- * pre_xmit_response->qlt_send_term_exchange
- * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
- * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
- * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
- * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
- * BIT_11 - Data actually going to TCM : tcm_qla2xx_handle_data_work
- * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
- * BIT_13 - Bad completion -
- * qlt_ctio_do_completion --> qlt_term_ctio_exchange
- * BIT_14 - Back end data received/sent.
- * BIT_15 - SRR prepare ctio
- * BIT_16 - complete free
- * BIT_17 - flush - qlt_abort_cmd_on_host_reset
- * BIT_18 - completion w/abort status
- * BIT_19 - completion w/unknown status
- */
- uint32_t cmd_flags;
+
+ cmd_flags_t cmd_flags;
};
struct qla_tgt_sess_work_param {
@@ -1120,13 +1143,21 @@ static inline uint32_t sid_to_key(const uint8_t *s_id)
return key;
}
+static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
+{
+ memset(p, 0, sizeof(*p));
+ p->b.domain = s_id[0];
+ p->b.area = s_id[1];
+ p->b.al_pa = s_id[2];
+}
+
/*
* Exported symbols from qla_target.c LLD logic used by qla2xxx code..
*/
extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
-extern void qlt_abort_cmd(struct qla_tgt_cmd *);
+extern int qlt_abort_cmd(struct qla_tgt_cmd *);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
@@ -1135,7 +1166,7 @@ extern void qlt_enable_vha(struct scsi_qla_host *);
extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
extern void qlt_rff_id(struct scsi_qla_host *, struct ct_sns_req *);
extern void qlt_init_atio_q_entries(struct scsi_qla_host *);
-extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *);
+extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *, uint8_t);
extern void qlt_24xx_config_rings(struct scsi_qla_host *);
extern void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *,
struct nvram_24xx *);
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c
index ddbe2e7..c3e6225 100644
--- a/drivers/scsi/qla2xxx/qla_tmpl.c
+++ b/drivers/scsi/qla2xxx/qla_tmpl.c
@@ -395,6 +395,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
for (i = 0; i < vha->hw->max_req_queues; i++) {
struct req_que *req = vha->hw->req_q_map[i];
+
+ if (!test_bit(i, vha->hw->req_qid_map))
+ continue;
+
if (req || !buf) {
length = req ?
req->length : REQUEST_ENTRY_CNT_24XX;
@@ -408,6 +412,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
} else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
for (i = 0; i < vha->hw->max_rsp_queues; i++) {
struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+
+ if (!test_bit(i, vha->hw->rsp_qid_map))
+ continue;
+
if (rsp || !buf) {
length = rsp ?
rsp->length : RESPONSE_ENTRY_CNT_MQ;
@@ -634,6 +642,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) {
for (i = 0; i < vha->hw->max_req_queues; i++) {
struct req_que *req = vha->hw->req_q_map[i];
+
+ if (!test_bit(i, vha->hw->req_qid_map))
+ continue;
+
if (req || !buf) {
qla27xx_insert16(i, buf, len);
qla27xx_insert16(1, buf, len);
@@ -645,6 +657,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
} else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) {
for (i = 0; i < vha->hw->max_rsp_queues; i++) {
struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+
+ if (!test_bit(i, vha->hw->rsp_qid_map))
+ continue;
+
if (rsp || !buf) {
qla27xx_insert16(i, buf, len);
qla27xx_insert16(1, buf, len);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 6d31faa..0bc93fa 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.07.00.26-k"
+#define QLA2XXX_VERSION "8.07.00.33-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 7
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index ac65cb7..c1461d2 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -43,8 +43,6 @@
#include <scsi/scsi_cmnd.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include "qla_def.h"
#include "qla_target.h"
@@ -286,6 +284,7 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
WARN_ON(cmd->cmd_flags & BIT_16);
+ cmd->vha->tgt_counters.qla_core_ret_sta_ctio++;
cmd->cmd_flags |= BIT_16;
transport_generic_free_cmd(&cmd->se_cmd, 0);
}
@@ -297,9 +296,14 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
*/
static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
{
+ cmd->vha->tgt_counters.core_qla_free_cmd++;
cmd->cmd_in_wq = 1;
+
+ BUG_ON(cmd->cmd_flags & BIT_20);
+ cmd->cmd_flags |= BIT_20;
+
INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
- queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+ queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
}
/*
@@ -344,9 +348,9 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess)
BUG_ON(!sess);
vha = sess->vha;
- spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
target_sess_cmd_list_set_waiting(se_sess);
- spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return 1;
}
@@ -360,9 +364,9 @@ static void tcm_qla2xxx_close_session(struct se_session *se_sess)
BUG_ON(!sess);
vha = sess->vha;
- spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
qlt_unreg_sess(sess);
- spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
@@ -374,6 +378,20 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
{
struct qla_tgt_cmd *cmd = container_of(se_cmd,
struct qla_tgt_cmd, se_cmd);
+
+ if (cmd->aborted) {
+ /* Cmd can loop during Q-full. tcm_qla2xxx_aborted_task
+ * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+ * already kick start the free.
+ */
+ pr_debug("write_pending aborted cmd[%p] refcount %d "
+ "transport_state %x, t_state %x, se_cmd_flags %x\n",
+ cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+ cmd->se_cmd.transport_state,
+ cmd->se_cmd.t_state,
+ cmd->se_cmd.se_cmd_flags);
+ return 0;
+ }
cmd->cmd_flags |= BIT_3;
cmd->bufflen = se_cmd->data_length;
cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -405,7 +423,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
- 3 * HZ);
+ 50);
return 0;
}
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@ -444,6 +462,9 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
if (bidi)
flags |= TARGET_SCF_BIDI_OP;
+ if (se_cmd->cpuid != WORK_CPU_UNBOUND)
+ flags |= TARGET_SCF_USE_CPUID;
+
sess = cmd->sess;
if (!sess) {
pr_err("Unable to locate struct qla_tgt_sess from qla_tgt_cmd\n");
@@ -456,6 +477,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
return -EINVAL;
}
+ cmd->vha->tgt_counters.qla_core_sbt_cmd++;
return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0],
cmd->unpacked_lun, data_length, fcp_task_attr,
data_dir, flags);
@@ -464,13 +486,26 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
{
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+ unsigned long flags;
/*
* Ensure that the complete FCP WRITE payload has been received.
* Otherwise return an exception via CHECK_CONDITION status.
*/
cmd->cmd_in_wq = 0;
- cmd->cmd_flags |= BIT_11;
+
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
+ if (cmd->aborted) {
+ cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+ tcm_qla2xxx_free_cmd(cmd);
+ return;
+ }
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+ cmd->vha->tgt_counters.qla_core_ret_ctio++;
if (!cmd->write_data_transferred) {
/*
* Check if se_cmd has already been aborted via LUN_RESET, and
@@ -502,7 +537,7 @@ static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
cmd->cmd_flags |= BIT_10;
cmd->cmd_in_wq = 1;
INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work);
- queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+ queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
}
static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
@@ -544,6 +579,20 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
struct qla_tgt_cmd *cmd = container_of(se_cmd,
struct qla_tgt_cmd, se_cmd);
+ if (cmd->aborted) {
+ /* Cmd can loop during Q-full. tcm_qla2xxx_aborted_task
+ * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+ * already kick start the free.
+ */
+ pr_debug("queue_data_in aborted cmd[%p] refcount %d "
+ "transport_state %x, t_state %x, se_cmd_flags %x\n",
+ cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+ cmd->se_cmd.transport_state,
+ cmd->se_cmd.t_state,
+ cmd->se_cmd.se_cmd_flags);
+ return 0;
+ }
+
cmd->cmd_flags |= BIT_4;
cmd->bufflen = se_cmd->data_length;
cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -635,17 +684,40 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
qlt_xmit_tm_rsp(mcmd);
}
+
+#define DATA_WORK_NOT_FREE(_flags) \
+ (( _flags & (CMD_FLAG_DATA_WORK|CMD_FLAG_DATA_WORK_FREE)) == \
+ CMD_FLAG_DATA_WORK)
static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
{
struct qla_tgt_cmd *cmd = container_of(se_cmd,
struct qla_tgt_cmd, se_cmd);
- qlt_abort_cmd(cmd);
+ unsigned long flags;
+
+ if (qlt_abort_cmd(cmd))
+ return;
+
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ if ((cmd->state == QLA_TGT_STATE_NEW)||
+ ((cmd->state == QLA_TGT_STATE_DATA_IN) &&
+ DATA_WORK_NOT_FREE(cmd->cmd_flags)) ) {
+
+ cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ /* Cmd have not reached firmware.
+ * Use this trigger to free it. */
+ tcm_qla2xxx_free_cmd(cmd);
+ return;
+ }
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ return;
+
}
static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *);
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess)
{
@@ -699,13 +771,13 @@ static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
if (!sess)
return;
- assert_spin_locked(&sess->vha->hw->hardware_lock);
+ assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
}
static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess)
{
- assert_spin_locked(&sess->vha->hw->hardware_lock);
+ assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
target_sess_cmd_list_set_waiting(sess->se_sess);
}
@@ -729,23 +801,23 @@ static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl,
#define DEF_QLA_TPG_ATTRIB(name) \
\
-static ssize_t tcm_qla2xxx_tpg_attrib_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
+static ssize_t tcm_qla2xxx_tpg_attrib_##name##_show( \
+ struct config_item *item, char *page) \
{ \
+ struct se_portal_group *se_tpg = attrib_to_tpg(item); \
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \
struct tcm_qla2xxx_tpg, se_tpg); \
\
return sprintf(page, "%u\n", tpg->tpg_attrib.name); \
} \
\
-static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \
- struct se_portal_group *se_tpg, \
- const char *page, \
- size_t count) \
+static ssize_t tcm_qla2xxx_tpg_attrib_##name##_store( \
+ struct config_item *item, const char *page, size_t count) \
{ \
+ struct se_portal_group *se_tpg = attrib_to_tpg(item); \
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \
struct tcm_qla2xxx_tpg, se_tpg); \
+ struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \
unsigned long val; \
int ret; \
\
@@ -755,81 +827,39 @@ static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \
" ret: %d\n", ret); \
return -EINVAL; \
} \
- ret = tcm_qla2xxx_set_attrib_##name(tpg, val); \
- \
- return (!ret) ? count : -EINVAL; \
-}
-
-#define DEF_QLA_TPG_ATTR_BOOL(_name) \
- \
-static int tcm_qla2xxx_set_attrib_##_name( \
- struct tcm_qla2xxx_tpg *tpg, \
- unsigned long val) \
-{ \
- struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \
\
if ((val != 0) && (val != 1)) { \
pr_err("Illegal boolean value %lu\n", val); \
return -EINVAL; \
} \
\
- a->_name = val; \
- return 0; \
-}
-
-#define QLA_TPG_ATTR(_name, _mode) \
- TF_TPG_ATTRIB_ATTR(tcm_qla2xxx, _name, _mode);
+ a->name = val; \
+ \
+ return count; \
+} \
+CONFIGFS_ATTR(tcm_qla2xxx_tpg_attrib_, name)
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_generate_node_acls
- */
-DEF_QLA_TPG_ATTR_BOOL(generate_node_acls);
DEF_QLA_TPG_ATTRIB(generate_node_acls);
-QLA_TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR);
-
-/*
- Define tcm_qla2xxx_attrib_s_cache_dynamic_acls
- */
-DEF_QLA_TPG_ATTR_BOOL(cache_dynamic_acls);
DEF_QLA_TPG_ATTRIB(cache_dynamic_acls);
-QLA_TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR);
-
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_write_protect
- */
-DEF_QLA_TPG_ATTR_BOOL(demo_mode_write_protect);
DEF_QLA_TPG_ATTRIB(demo_mode_write_protect);
-QLA_TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR);
-
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_prod_mode_write_protect
- */
-DEF_QLA_TPG_ATTR_BOOL(prod_mode_write_protect);
DEF_QLA_TPG_ATTRIB(prod_mode_write_protect);
-QLA_TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR);
-
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_login_only
- */
-DEF_QLA_TPG_ATTR_BOOL(demo_mode_login_only);
DEF_QLA_TPG_ATTRIB(demo_mode_login_only);
-QLA_TPG_ATTR(demo_mode_login_only, S_IRUGO | S_IWUSR);
static struct configfs_attribute *tcm_qla2xxx_tpg_attrib_attrs[] = {
- &tcm_qla2xxx_tpg_attrib_generate_node_acls.attr,
- &tcm_qla2xxx_tpg_attrib_cache_dynamic_acls.attr,
- &tcm_qla2xxx_tpg_attrib_demo_mode_write_protect.attr,
- &tcm_qla2xxx_tpg_attrib_prod_mode_write_protect.attr,
- &tcm_qla2xxx_tpg_attrib_demo_mode_login_only.attr,
+ &tcm_qla2xxx_tpg_attrib_attr_generate_node_acls,
+ &tcm_qla2xxx_tpg_attrib_attr_cache_dynamic_acls,
+ &tcm_qla2xxx_tpg_attrib_attr_demo_mode_write_protect,
+ &tcm_qla2xxx_tpg_attrib_attr_prod_mode_write_protect,
+ &tcm_qla2xxx_tpg_attrib_attr_demo_mode_login_only,
NULL,
};
/* End items for tcm_qla2xxx_tpg_attrib_cit */
-static ssize_t tcm_qla2xxx_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_tpg_enable_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
@@ -865,11 +895,10 @@ static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
complete(&base_tpg->tpg_base_comp);
}
-static ssize_t tcm_qla2xxx_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_qla2xxx_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
unsigned long op;
@@ -909,22 +938,16 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
return count;
}
-TF_TPG_BASE_ATTR(tcm_qla2xxx, enable, S_IRUGO | S_IWUSR);
-
-static ssize_t tcm_qla2xxx_tpg_show_dynamic_sessions(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_tpg_dynamic_sessions_show(struct config_item *item,
+ char *page)
{
- return target_show_dynamic_sessions(se_tpg, page);
+ return target_show_dynamic_sessions(to_tpg(item), page);
}
-TF_TPG_BASE_ATTR_RO(tcm_qla2xxx, dynamic_sessions);
-
-static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
unsigned long val;
@@ -943,21 +966,24 @@ static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type(
return count;
}
-static ssize_t tcm_qla2xxx_tpg_show_fabric_prot_type(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type);
}
-TF_TPG_BASE_ATTR(tcm_qla2xxx, fabric_prot_type, S_IRUGO | S_IWUSR);
+
+CONFIGFS_ATTR(tcm_qla2xxx_tpg_, enable);
+CONFIGFS_ATTR_RO(tcm_qla2xxx_tpg_, dynamic_sessions);
+CONFIGFS_ATTR(tcm_qla2xxx_tpg_, fabric_prot_type);
static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = {
- &tcm_qla2xxx_tpg_enable.attr,
- &tcm_qla2xxx_tpg_dynamic_sessions.attr,
- &tcm_qla2xxx_tpg_fabric_prot_type.attr,
+ &tcm_qla2xxx_tpg_attr_enable,
+ &tcm_qla2xxx_tpg_attr_dynamic_sessions,
+ &tcm_qla2xxx_tpg_attr_fabric_prot_type,
NULL,
};
@@ -1030,18 +1056,16 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
kfree(tpg);
}
-static ssize_t tcm_qla2xxx_npiv_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_npiv_tpg_enable_show(struct config_item *item,
+ char *page)
{
- return tcm_qla2xxx_tpg_show_enable(se_tpg, page);
+ return tcm_qla2xxx_tpg_enable_show(item, page);
}
-static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_qla2xxx_npiv_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
struct tcm_qla2xxx_lport, lport_wwn);
@@ -1077,10 +1101,10 @@ static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
return count;
}
-TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(tcm_qla2xxx_npiv_tpg_, enable);
static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = {
- &tcm_qla2xxx_npiv_tpg_enable.attr,
+ &tcm_qla2xxx_npiv_tpg_attr_enable,
NULL,
};
@@ -1127,7 +1151,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
scsi_qla_host_t *vha,
@@ -1166,7 +1190,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_set_sess_by_s_id(
struct tcm_qla2xxx_lport *lport,
@@ -1232,7 +1256,7 @@ static void tcm_qla2xxx_set_sess_by_s_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
scsi_qla_host_t *vha,
@@ -1271,7 +1295,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_set_sess_by_loop_id(
struct tcm_qla2xxx_lport *lport,
@@ -1335,7 +1359,7 @@ static void tcm_qla2xxx_set_sess_by_loop_id(
}
/*
- * Should always be called with qla_hw_data->hardware_lock held.
+ * Should always be called with qla_hw_data->tgt.sess_lock held.
*/
static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *lport,
struct tcm_qla2xxx_nacl *nacl, struct qla_tgt_sess *sess)
@@ -1382,6 +1406,39 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess)
transport_deregister_session(sess->se_sess);
}
+static int tcm_qla2xxx_session_cb(struct se_portal_group *se_tpg,
+ struct se_session *se_sess, void *p)
+{
+ struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+ struct tcm_qla2xxx_tpg, se_tpg);
+ struct tcm_qla2xxx_lport *lport = tpg->lport;
+ struct qla_hw_data *ha = lport->qla_vha->hw;
+ struct se_node_acl *se_nacl = se_sess->se_node_acl;
+ struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl,
+ struct tcm_qla2xxx_nacl, se_node_acl);
+ struct qla_tgt_sess *qlat_sess = p;
+ uint16_t loop_id = qlat_sess->loop_id;
+ unsigned long flags;
+ unsigned char be_sid[3];
+
+ be_sid[0] = qlat_sess->s_id.b.domain;
+ be_sid[1] = qlat_sess->s_id.b.area;
+ be_sid[2] = qlat_sess->s_id.b.al_pa;
+
+ /*
+ * And now setup se_nacl and session pointers into HW lport internal
+ * mappings for fabric S_ID and LOOP_ID.
+ */
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+ tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl,
+ se_sess, qlat_sess, be_sid);
+ tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl,
+ se_sess, qlat_sess, loop_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
+ return 0;
+}
+
/*
* Called via qlt_create_sess():ha->qla2x_tmpl->check_initiator_node_acl()
* to locate struct se_node_acl
@@ -1389,21 +1446,14 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess)
static int tcm_qla2xxx_check_initiator_node_acl(
scsi_qla_host_t *vha,
unsigned char *fc_wwpn,
- void *qla_tgt_sess,
- uint8_t *s_id,
- uint16_t loop_id)
+ struct qla_tgt_sess *qlat_sess)
{
struct qla_hw_data *ha = vha->hw;
struct tcm_qla2xxx_lport *lport;
struct tcm_qla2xxx_tpg *tpg;
- struct tcm_qla2xxx_nacl *nacl;
- struct se_portal_group *se_tpg;
- struct se_node_acl *se_nacl;
struct se_session *se_sess;
- struct qla_tgt_sess *sess = qla_tgt_sess;
unsigned char port_name[36];
- unsigned long flags;
- int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count :
+ int num_tags = (ha->cur_fw_xcb_count) ? ha->cur_fw_xcb_count :
TCM_QLA2XXX_DEFAULT_TAGS;
lport = vha->vha_tgt.target_lport_ptr;
@@ -1420,15 +1470,6 @@ static int tcm_qla2xxx_check_initiator_node_acl(
pr_err("Unable to lcoate struct tcm_qla2xxx_lport->tpg_1\n");
return -EINVAL;
}
- se_tpg = &tpg->se_tpg;
-
- se_sess = transport_init_session_tags(num_tags,
- sizeof(struct qla_tgt_cmd),
- TARGET_PROT_ALL);
- if (IS_ERR(se_sess)) {
- pr_err("Unable to initialize struct se_session\n");
- return PTR_ERR(se_sess);
- }
/*
* Format the FCP Initiator port_name into colon seperated values to
* match the format by tcm_qla2xxx explict ConfigFS NodeACLs.
@@ -1439,28 +1480,12 @@ static int tcm_qla2xxx_check_initiator_node_acl(
* Locate our struct se_node_acl either from an explict NodeACL created
* via ConfigFS, or via running in TPG demo mode.
*/
- se_sess->se_node_acl = core_tpg_check_initiator_node_acl(se_tpg,
- port_name);
- if (!se_sess->se_node_acl) {
- transport_free_session(se_sess);
- return -EINVAL;
- }
- se_nacl = se_sess->se_node_acl;
- nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl);
- /*
- * And now setup the new se_nacl and session pointers into our HW lport
- * mappings for fabric S_ID and LOOP_ID.
- */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess,
- qla_tgt_sess, s_id);
- tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, se_sess,
- qla_tgt_sess, loop_id);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- /*
- * Finally register the new FC Nexus with TCM
- */
- transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
+ se_sess = target_alloc_session(&tpg->se_tpg, num_tags,
+ sizeof(struct qla_tgt_cmd),
+ TARGET_PROT_ALL, port_name,
+ qlat_sess, tcm_qla2xxx_session_cb);
+ if (IS_ERR(se_sess))
+ return PTR_ERR(se_sess);
return 0;
}
@@ -1783,9 +1808,8 @@ static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn)
}
-static ssize_t tcm_qla2xxx_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t tcm_qla2xxx_wwn_version_show(struct config_item *item,
+ char *page)
{
return sprintf(page,
"TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on "
@@ -1793,10 +1817,10 @@ static ssize_t tcm_qla2xxx_wwn_show_attr_version(
utsname()->machine);
}
-TF_WWN_ATTR_RO(tcm_qla2xxx, version);
+CONFIGFS_ATTR_RO(tcm_qla2xxx_wwn_, version);
static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = {
- &tcm_qla2xxx_wwn_version.attr,
+ &tcm_qla2xxx_wwn_attr_version,
NULL,
};
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index 5d4f8e6..638f72c 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -46,11 +46,13 @@ int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
ret_val = qla4_83xx_set_win_base(ha, addr);
- if (ret_val == QLA_SUCCESS)
+ if (ret_val == QLA_SUCCESS) {
*data = qla4_83xx_rd_reg(ha, QLA83XX_WILDCARD);
- else
+ } else {
+ *data = 0xffffffff;
ql4_printk(KERN_ERR, ha, "%s: failed read of addr 0x%x!\n",
__func__, addr);
+ }
return ret_val;
}
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 6d25879..01c3610 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -212,7 +212,6 @@ static struct scsi_host_template qla4xxx_driver_template = {
.shost_attrs = qla4xxx_host_attrs,
.host_reset = qla4xxx_host_reset,
.vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
- .use_blk_tags = 1,
};
static struct iscsi_transport qla4xxx_iscsi_transport = {
@@ -8697,13 +8696,6 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
host->can_queue = MAX_SRBS ;
host->transportt = qla4xxx_scsi_transport;
- ret = scsi_init_shared_tag_map(host, MAX_SRBS);
- if (ret) {
- ql4_printk(KERN_WARNING, ha,
- "%s: scsi_init_shared_tag_map failed\n", __func__);
- goto probe_failed;
- }
-
pci_set_drvdata(pdev, ha);
ret = scsi_add_host(host, &pdev->dev);
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 676385f..69bfc0a 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -710,7 +710,7 @@ static int qpti_map_regs(struct qlogicpti *qpti)
"PTI Qlogic/ISP");
if (!qpti->qregs) {
printk("PTI: Qlogic/ISP registers are unmappable\n");
- return -1;
+ return -ENODEV;
}
if (qpti->is_pti) {
qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096),
@@ -718,7 +718,7 @@ static int qpti_map_regs(struct qlogicpti *qpti)
"PTI Qlogic/ISP statreg");
if (!qpti->sreg) {
printk("PTI: Qlogic/ISP status register is unmappable\n");
- return -1;
+ return -ENODEV;
}
}
return 0;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 207d6a7..1deb6ad 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -616,32 +616,11 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
*/
int scsi_change_queue_depth(struct scsi_device *sdev, int depth)
{
- unsigned long flags;
-
- if (depth <= 0)
- goto out;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-
- /*
- * Check to see if the queue is managed by the block layer.
- * If it is, and we fail to adjust the depth, exit.
- *
- * Do not resize the tag map if it is a host wide share bqt,
- * because the size should be the hosts's can_queue. If there
- * is more IO than the LLD's can_queue (so there are not enuogh
- * tags) request_fn's host queue ready check will handle it.
- */
- if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) {
- if (blk_queue_tagged(sdev->request_queue) &&
- blk_queue_resize_tags(sdev->request_queue, depth) != 0)
- goto out_unlock;
+ if (depth > 0) {
+ sdev->queue_depth = depth;
+ wmb();
}
- sdev->queue_depth = depth;
-out_unlock:
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-out:
return sdev->queue_depth;
}
EXPORT_SYMBOL(scsi_change_queue_depth);
@@ -803,10 +782,11 @@ void scsi_attach_vpd(struct scsi_device *sdev)
int vpd_len = SCSI_VPD_PG_LEN;
int pg80_supported = 0;
int pg83_supported = 0;
- unsigned char *vpd_buf;
+ unsigned char __rcu *vpd_buf, *orig_vpd_buf = NULL;
- if (sdev->skip_vpd_pages)
+ if (!scsi_device_supports_vpd(sdev))
return;
+
retry_pg0:
vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
if (!vpd_buf)
@@ -849,8 +829,16 @@ retry_pg80:
kfree(vpd_buf);
goto retry_pg80;
}
+ mutex_lock(&sdev->inquiry_mutex);
+ orig_vpd_buf = sdev->vpd_pg80;
sdev->vpd_pg80_len = result;
- sdev->vpd_pg80 = vpd_buf;
+ rcu_assign_pointer(sdev->vpd_pg80, vpd_buf);
+ mutex_unlock(&sdev->inquiry_mutex);
+ synchronize_rcu();
+ if (orig_vpd_buf) {
+ kfree(orig_vpd_buf);
+ orig_vpd_buf = NULL;
+ }
vpd_len = SCSI_VPD_PG_LEN;
}
@@ -870,8 +858,14 @@ retry_pg83:
kfree(vpd_buf);
goto retry_pg83;
}
+ mutex_lock(&sdev->inquiry_mutex);
+ orig_vpd_buf = sdev->vpd_pg83;
sdev->vpd_pg83_len = result;
- sdev->vpd_pg83 = vpd_buf;
+ rcu_assign_pointer(sdev->vpd_pg83, vpd_buf);
+ mutex_unlock(&sdev->inquiry_mutex);
+ synchronize_rcu();
+ if (orig_vpd_buf)
+ kfree(orig_vpd_buf);
}
}
diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c
index c126966..ce79de8 100644
--- a/drivers/scsi/scsi_common.c
+++ b/drivers/scsi/scsi_common.c
@@ -278,8 +278,16 @@ int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
ucp[3] = 0;
put_unaligned_be64(info, &ucp[4]);
} else if ((buf[0] & 0x7f) == 0x70) {
- buf[0] |= 0x80;
- put_unaligned_be64(info, &buf[3]);
+ /*
+ * Only set the 'VALID' bit if we can represent the value
+ * correctly; otherwise just fill out the lower bytes and
+ * clear the 'VALID' flag.
+ */
+ if (info <= 0xffffffffUL)
+ buf[0] |= 0x80;
+ else
+ buf[0] &= 0x7f;
+ put_unaligned_be32((u32)info, &buf[3]);
}
return 0;
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index dfcc45b..f3d69a98 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -129,7 +129,7 @@ static const char *scsi_debug_version_date = "20141022";
#define DEF_NO_LUN_0 0
#define DEF_NUM_PARTS 0
#define DEF_OPTS 0
-#define DEF_OPT_BLKS 64
+#define DEF_OPT_BLKS 1024
#define DEF_PHYSBLK_EXP 0
#define DEF_PTYPE 0
#define DEF_REMOVABLE false
@@ -465,8 +465,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
0} },
{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
- {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
+ {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
+ 0, 0, 0, 0, 0, 0} },
{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
@@ -477,8 +478,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
{10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
0} },
/* 20 */
- {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
+ {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
{6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
@@ -678,7 +679,7 @@ static void *fake_store(unsigned long long lba)
static struct sd_dif_tuple *dif_store(sector_t sector)
{
- sector = do_div(sector, sdebug_store_sectors);
+ sector = sector_div(sector, sdebug_store_sectors);
return dif_storep + sector;
}
@@ -2780,7 +2781,7 @@ static unsigned long lba_to_map_index(sector_t lba)
lba += scsi_debug_unmap_granularity -
scsi_debug_unmap_alignment;
}
- do_div(lba, scsi_debug_unmap_granularity);
+ sector_div(lba, scsi_debug_unmap_granularity);
return lba;
}
@@ -4139,7 +4140,7 @@ MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
-MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
+MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
@@ -4846,10 +4847,10 @@ static int __init scsi_debug_init(void)
/* play around with geometry, don't waste too much on track 0 */
sdebug_heads = 8;
sdebug_sectors_per = 32;
- if (scsi_debug_dev_size_mb >= 16)
- sdebug_heads = 32;
- else if (scsi_debug_dev_size_mb >= 256)
+ if (scsi_debug_dev_size_mb >= 256)
sdebug_heads = 64;
+ else if (scsi_debug_dev_size_mb >= 16)
+ sdebug_heads = 32;
sdebug_cylinders_per = (unsigned long)sdebug_capacity /
(sdebug_sectors_per * sdebug_heads);
if (sdebug_cylinders_per >= 1024) {
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 2c1160c7..3408578 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -205,6 +205,8 @@ static struct {
{"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC},
{"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+ {"Marvell", "Console", NULL, BLIST_SKIP_VPD_PAGES},
+ {"Marvell", "91xx Config", "1.01", BLIST_SKIP_VPD_PAGES},
{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
{"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
@@ -218,6 +220,8 @@ static struct {
{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
+ {"NETAPP", "LUN C-Mode", NULL, BLIST_SYNC_ALUA},
+ {"NETAPP", "INF-01-00", NULL, BLIST_SYNC_ALUA},
{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -227,6 +231,7 @@ static struct {
{"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC},
{"Promise", "", NULL, BLIST_SPARSELUN},
{"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024},
+ {"SYNOLOGY", "iSCSI Storage", NULL, BLIST_MAX_1024},
{"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
{"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index e7649ed..54d446c 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -153,76 +153,11 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev)
module_put(sdev->handler->module);
}
-/*
- * Functions for sysfs attribute 'dh_state'
- */
-static ssize_t
-store_dh_state(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_device_handler *scsi_dh;
- int err = -EINVAL;
-
- if (sdev->sdev_state == SDEV_CANCEL ||
- sdev->sdev_state == SDEV_DEL)
- return -ENODEV;
-
- if (!sdev->handler) {
- /*
- * Attach to a device handler
- */
- scsi_dh = scsi_dh_lookup(buf);
- if (!scsi_dh)
- return err;
- err = scsi_dh_handler_attach(sdev, scsi_dh);
- } else {
- if (!strncmp(buf, "detach", 6)) {
- /*
- * Detach from a device handler
- */
- sdev_printk(KERN_WARNING, sdev,
- "can't detach handler %s.\n",
- sdev->handler->name);
- err = -EINVAL;
- } else if (!strncmp(buf, "activate", 8)) {
- /*
- * Activate a device handler
- */
- if (sdev->handler->activate)
- err = sdev->handler->activate(sdev, NULL, NULL);
- else
- err = 0;
- }
- }
-
- return err<0?err:count;
-}
-
-static ssize_t
-show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
-
- if (!sdev->handler)
- return snprintf(buf, 20, "detached\n");
-
- return snprintf(buf, 20, "%s\n", sdev->handler->name);
-}
-
-static struct device_attribute scsi_dh_state_attr =
- __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
- store_dh_state);
-
int scsi_dh_add_device(struct scsi_device *sdev)
{
struct scsi_device_handler *devinfo = NULL;
const char *drv;
- int err;
-
- err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
- if (err)
- return err;
+ int err = 0;
drv = scsi_dh_find_driver(sdev);
if (drv)
@@ -238,11 +173,6 @@ void scsi_dh_release_device(struct scsi_device *sdev)
scsi_dh_handler_detach(sdev);
}
-void scsi_dh_remove_device(struct scsi_device *sdev)
-{
- device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
-}
-
/*
* scsi_register_device_handler - register a device handler personality
* module.
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 66a96cd..984ddcb 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1970,7 +1970,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
struct request *req;
/*
- * blk_get_request with GFP_KERNEL (__GFP_WAIT) sleeps until a
+ * blk_get_request with GFP_KERNEL (__GFP_RECLAIM) sleeps until a
* request becomes available
*/
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 126a48c..8106515 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -23,6 +23,7 @@
#include <linux/scatterlist.h>
#include <linux/blk-mq.h>
#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -222,13 +223,13 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int write = (data_direction == DMA_TO_DEVICE);
int ret = DRIVER_ERROR << 24;
- req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
+ req = blk_get_request(sdev->request_queue, write, __GFP_RECLAIM);
if (IS_ERR(req))
return ret;
blk_rq_set_block_pc(req);
if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
- buffer, bufflen, __GFP_WAIT))
+ buffer, bufflen, __GFP_RECLAIM))
goto out;
req->cmd_len = COMMAND_SIZE(cmd[0]);
@@ -1343,6 +1344,7 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
switch (ret) {
case BLKPREP_KILL:
+ case BLKPREP_INVALID:
req->errors = DID_NO_CONNECT << 16;
/* release the command and kill it */
if (req->special) {
@@ -2698,6 +2700,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
envp[idx++] = "SDEV_MEDIA_CHANGE=1";
break;
case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+ scsi_rescan_device(&sdev->sdev_gendev);
envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED";
break;
case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
@@ -3154,3 +3157,190 @@ void sdev_enable_disk_events(struct scsi_device *sdev)
atomic_dec(&sdev->disk_events_disable_depth);
}
EXPORT_SYMBOL(sdev_enable_disk_events);
+
+/**
+ * scsi_vpd_lun_id - return a unique device identification
+ * @sdev: SCSI device
+ * @id: buffer for the identification
+ * @id_len: length of the buffer
+ *
+ * Copies a unique device identification into @id based
+ * on the information in the VPD page 0x83 of the device.
+ * The string will be formatted as a SCSI name string.
+ *
+ * Returns the length of the identification or error on failure.
+ * If the identifier is longer than the supplied buffer the actual
+ * identifier length is returned and the buffer is not zero-padded.
+ */
+int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
+{
+ u8 cur_id_type = 0xff;
+ u8 cur_id_size = 0;
+ unsigned char *d, *cur_id_str;
+ unsigned char __rcu *vpd_pg83;
+ int id_size = -EINVAL;
+
+ rcu_read_lock();
+ vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+ if (!vpd_pg83) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+
+ /*
+ * Look for the correct descriptor.
+ * Order of preference for lun descriptor:
+ * - SCSI name string
+ * - NAA IEEE Registered Extended
+ * - EUI-64 based 16-byte
+ * - EUI-64 based 12-byte
+ * - NAA IEEE Registered
+ * - NAA IEEE Extended
+ * as longer descriptors reduce the likelyhood
+ * of identification clashes.
+ */
+
+ /* The id string must be at least 20 bytes + terminating NULL byte */
+ if (id_len < 21) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ memset(id, 0, id_len);
+ d = vpd_pg83 + 4;
+ while (d < vpd_pg83 + sdev->vpd_pg83_len) {
+ /* Skip designators not referring to the LUN */
+ if ((d[1] & 0x30) != 0x00)
+ goto next_desig;
+
+ switch (d[1] & 0xf) {
+ case 0x2:
+ /* EUI-64 */
+ if (cur_id_size > d[3])
+ break;
+ /* Prefer NAA IEEE Registered Extended */
+ if (cur_id_type == 0x3 &&
+ cur_id_size == d[3])
+ break;
+ cur_id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ switch (cur_id_size) {
+ case 8:
+ id_size = snprintf(id, id_len,
+ "eui.%8phN",
+ cur_id_str);
+ break;
+ case 12:
+ id_size = snprintf(id, id_len,
+ "eui.%12phN",
+ cur_id_str);
+ break;
+ case 16:
+ id_size = snprintf(id, id_len,
+ "eui.%16phN",
+ cur_id_str);
+ break;
+ default:
+ cur_id_size = 0;
+ break;
+ }
+ break;
+ case 0x3:
+ /* NAA */
+ if (cur_id_size > d[3])
+ break;
+ cur_id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ switch (cur_id_size) {
+ case 8:
+ id_size = snprintf(id, id_len,
+ "naa.%8phN",
+ cur_id_str);
+ break;
+ case 16:
+ id_size = snprintf(id, id_len,
+ "naa.%16phN",
+ cur_id_str);
+ break;
+ default:
+ cur_id_size = 0;
+ break;
+ }
+ break;
+ case 0x8:
+ /* SCSI name string */
+ if (cur_id_size + 4 > d[3])
+ break;
+ /* Prefer others for truncated descriptor */
+ if (cur_id_size && d[3] > id_len)
+ break;
+ cur_id_size = id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ if (cur_id_size >= id_len)
+ cur_id_size = id_len - 1;
+ memcpy(id, cur_id_str, cur_id_size);
+ /* Decrease priority for truncated descriptor */
+ if (cur_id_size != id_size)
+ cur_id_size = 6;
+ break;
+ default:
+ break;
+ }
+next_desig:
+ d += d[3] + 4;
+ }
+ rcu_read_unlock();
+
+ return id_size;
+}
+EXPORT_SYMBOL(scsi_vpd_lun_id);
+
+/*
+ * scsi_vpd_tpg_id - return a target port group identifier
+ * @sdev: SCSI device
+ *
+ * Returns the Target Port Group identifier from the information
+ * froom VPD page 0x83 of the device.
+ *
+ * Returns the identifier or error on failure.
+ */
+int scsi_vpd_tpg_id(struct scsi_device *sdev, int *rel_id)
+{
+ unsigned char *d;
+ unsigned char __rcu *vpd_pg83;
+ int group_id = -EAGAIN, rel_port = -1;
+
+ rcu_read_lock();
+ vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+ if (!vpd_pg83) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+
+ d = sdev->vpd_pg83 + 4;
+ while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
+ switch (d[1] & 0xf) {
+ case 0x4:
+ /* Relative target port */
+ rel_port = get_unaligned_be16(&d[6]);
+ break;
+ case 0x5:
+ /* Target port group */
+ group_id = get_unaligned_be16(&d[6]);
+ break;
+ default:
+ break;
+ }
+ d += d[3] + 4;
+ }
+ rcu_read_unlock();
+
+ if (group_id >= 0 && rel_id && rel_port != -1)
+ *rel_id = rel_port;
+
+ return group_id;
+}
+EXPORT_SYMBOL(scsi_vpd_tpg_id);
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index e4b7998..b44c1bb 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -139,6 +139,16 @@ static int scsi_bus_resume_common(struct device *dev,
else
fn = NULL;
+ /*
+ * Forcibly set runtime PM status of request queue to "active" to
+ * make sure we can again get requests from the queue (see also
+ * blk_pm_peek_request()).
+ *
+ * The resume hook will correct runtime PM status of the disk.
+ */
+ if (scsi_is_sdev_device(dev) && pm_runtime_suspended(dev))
+ blk_set_runtime_active(to_scsi_device(dev)->request_queue);
+
if (fn) {
async_schedule_domain(fn, dev, &scsi_sd_pm_domain);
@@ -219,13 +229,13 @@ static int sdev_runtime_suspend(struct device *dev)
struct scsi_device *sdev = to_scsi_device(dev);
int err = 0;
- if (pm && pm->runtime_suspend) {
- err = blk_pre_runtime_suspend(sdev->request_queue);
- if (err)
- return err;
+ err = blk_pre_runtime_suspend(sdev->request_queue);
+ if (err)
+ return err;
+ if (pm && pm->runtime_suspend)
err = pm->runtime_suspend(dev);
- blk_post_runtime_suspend(sdev->request_queue, err);
- }
+ blk_post_runtime_suspend(sdev->request_queue, err);
+
return err;
}
@@ -248,11 +258,11 @@ static int sdev_runtime_resume(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int err = 0;
- if (pm && pm->runtime_resume) {
- blk_pre_runtime_resume(sdev->request_queue);
+ blk_pre_runtime_resume(sdev->request_queue);
+ if (pm && pm->runtime_resume)
err = pm->runtime_resume(dev);
- blk_post_runtime_resume(sdev->request_queue, err);
- }
+ blk_post_runtime_resume(sdev->request_queue, err);
+
return err;
}
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 4d01cdb..27b4d0a 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -174,12 +174,11 @@ extern struct async_domain scsi_sd_probe_domain;
#ifdef CONFIG_SCSI_DH
int scsi_dh_add_device(struct scsi_device *sdev);
void scsi_dh_release_device(struct scsi_device *sdev);
-void scsi_dh_remove_device(struct scsi_device *sdev);
#else
static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; }
static inline void scsi_dh_release_device(struct scsi_device *sdev) { }
-static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
#endif
+static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
/*
* internal scsi timeout functions: for use by mid-layer and transport
diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h
index 6266a5d..e659912 100644
--- a/drivers/scsi/scsi_sas_internal.h
+++ b/drivers/scsi/scsi_sas_internal.h
@@ -4,7 +4,7 @@
#define SAS_HOST_ATTRS 0
#define SAS_PHY_ATTRS 17
#define SAS_PORT_ATTRS 1
-#define SAS_RPORT_ATTRS 7
+#define SAS_RPORT_ATTRS 8
#define SAS_END_DEV_ATTRS 5
#define SAS_EXPANDER_ATTRS 7
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index f9f3f82..97074c9 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -43,6 +43,7 @@
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
+#include <scsi/scsi_dh.h>
#include <scsi/scsi_eh.h>
#include "scsi_priv.h"
@@ -55,6 +56,7 @@
* Default timeout
*/
#define SCSI_TIMEOUT (2*HZ)
+#define SCSI_REPORT_LUNS_TIMEOUT (30*HZ)
/*
* Prefix values for the SCSI id's (stored in sysfs name field)
@@ -235,6 +237,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
INIT_LIST_HEAD(&sdev->starved_entry);
INIT_LIST_HEAD(&sdev->event_list);
spin_lock_init(&sdev->list_lock);
+ mutex_init(&sdev->inquiry_mutex);
INIT_WORK(&sdev->event_work, scsi_evt_thread);
INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue);
@@ -274,8 +277,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
WARN_ON_ONCE(!blk_get_queue(sdev->request_queue));
sdev->request_queue->queuedata = sdev;
- if (!shost_use_blk_mq(sdev->host) &&
- (shost->bqt || shost->hostt->use_blk_tags)) {
+ if (!shost_use_blk_mq(sdev->host)) {
blk_queue_init_tags(sdev->request_queue,
sdev->host->cmd_per_lun, shost->bqt,
shost->hostt->tag_alloc_policy);
@@ -517,7 +519,8 @@ void scsi_target_reap(struct scsi_target *starget)
}
/**
- * sanitize_inquiry_string - remove non-graphical chars from an INQUIRY result string
+ * scsi_sanitize_inquiry_string - remove non-graphical chars from an
+ * INQUIRY result string
* @s: INQUIRY result string to sanitize
* @len: length of the string
*
@@ -530,7 +533,7 @@ void scsi_target_reap(struct scsi_target *starget)
* string terminator, so all the following characters are set to
* spaces.
**/
-static void sanitize_inquiry_string(unsigned char *s, int len)
+void scsi_sanitize_inquiry_string(unsigned char *s, int len)
{
int terminated = 0;
@@ -541,6 +544,7 @@ static void sanitize_inquiry_string(unsigned char *s, int len)
*s = ' ';
}
}
+EXPORT_SYMBOL(scsi_sanitize_inquiry_string);
/**
* scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
@@ -626,9 +630,9 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
}
if (result == 0) {
- sanitize_inquiry_string(&inq_result[8], 8);
- sanitize_inquiry_string(&inq_result[16], 16);
- sanitize_inquiry_string(&inq_result[32], 4);
+ scsi_sanitize_inquiry_string(&inq_result[8], 8);
+ scsi_sanitize_inquiry_string(&inq_result[16], 16);
+ scsi_sanitize_inquiry_string(&inq_result[32], 4);
response_len = inq_result[4] + 5;
if (response_len > 255)
@@ -701,9 +705,12 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
* strings.
*/
if (sdev->inquiry_len < 36) {
- sdev_printk(KERN_INFO, sdev,
- "scsi scan: INQUIRY result too short (%d),"
- " using 36\n", sdev->inquiry_len);
+ if (!sdev->host->short_inquiry) {
+ shost_printk(KERN_INFO, sdev->host,
+ "scsi scan: INQUIRY result too short (%d),"
+ " using 36\n", sdev->inquiry_len);
+ sdev->host->short_inquiry = 1;
+ }
sdev->inquiry_len = 36;
}
@@ -958,6 +965,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
if (*bflags & BLIST_NO_DIF)
sdev->no_dif = 1;
+ if (*bflags & BLIST_SYNC_ALUA)
+ sdev->synchronous_alua = 1;
+
sdev->eh_timeout = SCSI_DEFAULT_EH_TIMEOUT;
if (*bflags & BLIST_TRY_VPD_PAGES)
@@ -1383,7 +1393,7 @@ retry:
result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
lun_data, length, &sshdr,
- SCSI_TIMEOUT + 4 * HZ, 3, NULL);
+ SCSI_REPORT_LUNS_TIMEOUT, 3, NULL);
SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev,
"scsi scan: REPORT LUNS"
@@ -1515,7 +1525,15 @@ EXPORT_SYMBOL(scsi_add_device);
void scsi_rescan_device(struct device *dev)
{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
device_lock(dev);
+
+ scsi_attach_vpd(sdev);
+
+ if (sdev->handler && sdev->handler->rescan)
+ sdev->handler->rescan(sdev);
+
if (dev->driver && try_module_get(dev->driver->owner)) {
struct scsi_driver *drv = to_scsi_driver(dev->driver);
@@ -1712,8 +1730,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
return NULL;
if (shost->async_scan) {
- shost_printk(KERN_INFO, shost, "%s called twice\n", __func__);
- dump_stack();
+ shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__);
return NULL;
}
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index dff8faf..2b642b1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -17,6 +17,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_driver.h>
@@ -80,6 +81,35 @@ const char *scsi_host_state_name(enum scsi_host_state state)
return name;
}
+#ifdef CONFIG_SCSI_DH
+static const struct {
+ unsigned char value;
+ char *name;
+} sdev_access_states[] = {
+ { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" },
+ { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" },
+ { SCSI_ACCESS_STATE_STANDBY, "standby" },
+ { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" },
+ { SCSI_ACCESS_STATE_LBA, "lba-dependent" },
+ { SCSI_ACCESS_STATE_OFFLINE, "offline" },
+ { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" },
+};
+
+static const char *scsi_access_state_name(unsigned char state)
+{
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) {
+ if (sdev_access_states[i].value == state) {
+ name = sdev_access_states[i].name;
+ break;
+ }
+ }
+ return name;
+}
+#endif
+
static int check_set(unsigned long long *val, char *src)
{
char *last;
@@ -198,7 +228,7 @@ show_shost_state(struct device *dev, struct device_attribute *attr, char *buf)
}
/* DEVICE_ATTR(state) clashes with dev_attr_state for sdev */
-struct device_attribute dev_attr_hstate =
+static struct device_attribute dev_attr_hstate =
__ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state);
static ssize_t
@@ -373,7 +403,7 @@ static struct attribute *scsi_sysfs_shost_attrs[] = {
NULL
};
-struct attribute_group scsi_shost_attr_group = {
+static struct attribute_group scsi_shost_attr_group = {
.attrs = scsi_sysfs_shost_attrs,
};
@@ -760,11 +790,15 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \
{ \
struct device *dev = container_of(kobj, struct device, kobj); \
struct scsi_device *sdev = to_scsi_device(dev); \
+ int ret; \
if (!sdev->vpd_##_page) \
return -EINVAL; \
- return memory_read_from_buffer(buf, count, &off, \
- sdev->vpd_##_page, \
+ rcu_read_lock(); \
+ ret = memory_read_from_buffer(buf, count, &off, \
+ rcu_dereference(sdev->vpd_##_page), \
sdev->vpd_##_page##_len); \
+ rcu_read_unlock(); \
+ return ret; \
} \
static struct bin_attribute dev_attr_vpd_##_page = { \
.attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \
@@ -775,6 +809,29 @@ static struct bin_attribute dev_attr_vpd_##_page = { \
sdev_vpd_pg_attr(pg83);
sdev_vpd_pg_attr(pg80);
+static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->inquiry)
+ return -EINVAL;
+
+ return memory_read_from_buffer(buf, count, &off, sdev->inquiry,
+ sdev->inquiry_len);
+}
+
+static struct bin_attribute dev_attr_inquiry = {
+ .attr = {
+ .name = "inquiry",
+ .mode = S_IRUGO,
+ },
+ .size = 0,
+ .read = show_inquiry,
+};
+
static ssize_t
show_iostat_counterbits(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -878,6 +935,113 @@ static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
sdev_store_queue_depth);
static ssize_t
+sdev_show_wwid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ ssize_t count;
+
+ count = scsi_vpd_lun_id(sdev, buf, PAGE_SIZE);
+ if (count > 0) {
+ buf[count] = '\n';
+ count++;
+ }
+ return count;
+}
+static DEVICE_ATTR(wwid, S_IRUGO, sdev_show_wwid, NULL);
+
+#ifdef CONFIG_SCSI_DH
+static ssize_t
+sdev_show_dh_state(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->handler)
+ return snprintf(buf, 20, "detached\n");
+
+ return snprintf(buf, 20, "%s\n", sdev->handler->name);
+}
+
+static ssize_t
+sdev_store_dh_state(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int err = -EINVAL;
+
+ if (sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
+ return -ENODEV;
+
+ if (!sdev->handler) {
+ /*
+ * Attach to a device handler
+ */
+ err = scsi_dh_attach(sdev->request_queue, buf);
+ } else if (!strncmp(buf, "activate", 8)) {
+ /*
+ * Activate a device handler
+ */
+ if (sdev->handler->activate)
+ err = sdev->handler->activate(sdev, NULL, NULL);
+ else
+ err = 0;
+ } else if (!strncmp(buf, "detach", 6)) {
+ /*
+ * Detach from a device handler
+ */
+ sdev_printk(KERN_WARNING, sdev,
+ "can't detach handler %s.\n",
+ sdev->handler->name);
+ err = -EINVAL;
+ }
+
+ return err < 0 ? err : count;
+}
+
+static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
+ sdev_store_dh_state);
+
+static ssize_t
+sdev_show_access_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ unsigned char access_state;
+ const char *access_state_name;
+
+ if (!sdev->handler)
+ return -EINVAL;
+
+ access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK);
+ access_state_name = scsi_access_state_name(access_state);
+
+ return sprintf(buf, "%s\n",
+ access_state_name ? access_state_name : "unknown");
+}
+static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL);
+
+static ssize_t
+sdev_show_preferred_path(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->handler)
+ return -EINVAL;
+
+ if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+static DEVICE_ATTR(preferred_path, S_IRUGO, sdev_show_preferred_path, NULL);
+#endif
+
+static ssize_t
sdev_show_queue_ramp_up_period(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -900,7 +1064,7 @@ sdev_store_queue_ramp_up_period(struct device *dev,
return -EINVAL;
sdev->queue_ramp_up_period = msecs_to_jiffies(period);
- return period;
+ return count;
}
static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
@@ -922,9 +1086,33 @@ static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj,
!sdev->host->hostt->change_queue_depth)
return 0;
+#ifdef CONFIG_SCSI_DH
+ if (attr == &dev_attr_access_state.attr &&
+ !sdev->handler)
+ return 0;
+ if (attr == &dev_attr_preferred_path.attr &&
+ !sdev->handler)
+ return 0;
+#endif
return attr->mode;
}
+static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
+ struct bin_attribute *attr, int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+
+ if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80)
+ return 0;
+
+ if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83)
+ return 0;
+
+ return S_IRUGO;
+}
+
/* Default template for device attributes. May NOT be modified */
static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_device_blocked.attr,
@@ -946,6 +1134,12 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_queue_depth.attr,
&dev_attr_queue_type.attr,
+ &dev_attr_wwid.attr,
+#ifdef CONFIG_SCSI_DH
+ &dev_attr_dh_state.attr,
+ &dev_attr_access_state.attr,
+ &dev_attr_preferred_path.attr,
+#endif
&dev_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
REF_EVT(inquiry_change_reported),
@@ -959,12 +1153,14 @@ static struct attribute *scsi_sdev_attrs[] = {
static struct bin_attribute *scsi_sdev_bin_attrs[] = {
&dev_attr_vpd_pg83,
&dev_attr_vpd_pg80,
+ &dev_attr_inquiry,
NULL
};
static struct attribute_group scsi_sdev_attr_group = {
.attrs = scsi_sdev_attrs,
.bin_attrs = scsi_sdev_bin_attrs,
.is_visible = scsi_sdev_attr_is_visible,
+ .is_bin_visible = scsi_sdev_bin_attr_is_visible,
};
static const struct attribute_group *scsi_sdev_attr_groups[] = {
@@ -1026,17 +1222,19 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
scsi_autopm_get_device(sdev);
- error = device_add(&sdev->sdev_gendev);
- if (error) {
+ error = scsi_dh_add_device(sdev);
+ if (error)
+ /*
+ * device_handler is optional, so any error can be ignored
+ */
sdev_printk(KERN_INFO, sdev,
- "failed to add device: %d\n", error);
- return error;
- }
+ "failed to add device handler: %d\n", error);
- error = scsi_dh_add_device(sdev);
+ error = device_add(&sdev->sdev_gendev);
if (error) {
sdev_printk(KERN_INFO, sdev,
- "failed to add device handler: %d\n", error);
+ "failed to add device: %d\n", error);
+ scsi_dh_remove_device(sdev);
return error;
}
@@ -1078,6 +1276,14 @@ void __scsi_remove_device(struct scsi_device *sdev)
{
struct device *dev = &sdev->sdev_gendev;
+ /*
+ * This cleanup path is not reentrant and while it is impossible
+ * to get a new reference with scsi_device_get() someone can still
+ * hold a previously acquired one.
+ */
+ if (sdev->sdev_state == SDEV_DEL)
+ return;
+
if (sdev->is_visible) {
if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
return;
@@ -1160,31 +1366,25 @@ static void __scsi_remove_target(struct scsi_target *starget)
void scsi_remove_target(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev->parent);
- struct scsi_target *starget, *last = NULL;
+ struct scsi_target *starget, *last_target = NULL;
unsigned long flags;
- /* remove targets being careful to lookup next entry before
- * deleting the last
- */
+restart:
spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(starget, &shost->__targets, siblings) {
- if (starget->state == STARGET_DEL)
+ if (starget->state == STARGET_DEL ||
+ starget == last_target)
continue;
if (starget->dev.parent == dev || &starget->dev == dev) {
- /* assuming new targets arrive at the end */
kref_get(&starget->reap_ref);
+ last_target = starget;
spin_unlock_irqrestore(shost->host_lock, flags);
- if (last)
- scsi_target_reap(last);
- last = starget;
__scsi_remove_target(starget);
- spin_lock_irqsave(shost->host_lock, flags);
+ scsi_target_reap(starget);
+ goto restart;
}
}
spin_unlock_irqrestore(shost->host_lock, flags);
-
- if (last)
- scsi_target_reap(last);
}
EXPORT_SYMBOL(scsi_remove_target);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 24eaaf6..8a88226 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2586,7 +2586,7 @@ fc_rport_final_delete(struct work_struct *work)
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
- put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_put(shost); /* for fc_host->rport list */
put_device(dev); /* for self-reference */
}
@@ -2650,7 +2650,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
else
rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host->rports);
- get_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_get(shost); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -2685,7 +2685,7 @@ delete_rport:
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&rport->peers);
- put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_put(shost); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
kfree(rport);
@@ -3383,7 +3383,7 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
fc_host->npiv_vports_inuse++;
vport->number = fc_host->next_vport_number++;
list_add_tail(&vport->peers, &fc_host->vports);
- get_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_get(shost); /* for fc_host->vport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -3441,7 +3441,7 @@ delete_vport:
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&vport->peers);
- put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_put(shost); /* for fc_host->vport list */
fc_host->npiv_vports_inuse--;
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
@@ -3504,7 +3504,7 @@ fc_vport_terminate(struct fc_vport *vport)
vport->flags |= FC_VPORT_DELETED;
list_del(&vport->peers);
fc_host->npiv_vports_inuse--;
- put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_put(shost); /* for fc_host->vport list */
}
spin_unlock_irqrestore(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index e4b3d8f..4414816 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -4308,6 +4308,8 @@ static const struct {
{ISCSI_PORT_SPEED_100MBPS, "100 Mbps" },
{ISCSI_PORT_SPEED_1GBPS, "1 Gbps" },
{ISCSI_PORT_SPEED_10GBPS, "10 Gbps" },
+ {ISCSI_PORT_SPEED_25GBPS, "25 Gbps" },
+ {ISCSI_PORT_SPEED_40GBPS, "40 Gbps" },
};
char *iscsi_get_port_speed_name(struct Scsi_Host *shost)
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 30d26e3..b6f958193 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -341,6 +341,22 @@ static int do_sas_phy_delete(struct device *dev, void *data)
}
/**
+ * is_sas_attached - check if device is SAS attached
+ * @sdev: scsi device to check
+ *
+ * returns true if the device is SAS attached
+ */
+int is_sas_attached(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost = sdev->host;
+
+ return shost->transportt->host_attrs.ac.class ==
+ &sas_host_class.class;
+}
+EXPORT_SYMBOL(is_sas_attached);
+
+
+/**
* sas_remove_children - tear down a devices SAS data structures
* @dev: device belonging to the sas object
*
@@ -367,6 +383,20 @@ void sas_remove_host(struct Scsi_Host *shost)
EXPORT_SYMBOL(sas_remove_host);
/**
+ * sas_get_address - return the SAS address of the device
+ * @sdev: scsi device
+ *
+ * Returns the SAS address of the scsi device
+ */
+u64 sas_get_address(struct scsi_device *sdev)
+{
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+
+ return rdev->rphy.identify.sas_address;
+}
+EXPORT_SYMBOL(sas_get_address);
+
+/**
* sas_tlr_supported - checking TLR bit in vpd 0x90
* @sdev: scsi device struct
*
@@ -1256,6 +1286,7 @@ sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
unsigned long long);
sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
+sas_rphy_simple_attr(scsi_target_id, scsi_target_id, "%d\n", u32);
/* only need 8 bytes of data plus header (4 or 8) */
#define BUF_SIZE 64
@@ -1856,6 +1887,7 @@ sas_attach_transport(struct sas_function_template *ft)
SETUP_RPORT_ATTRIBUTE(rphy_device_type);
SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
+ SETUP_RPORT_ATTRIBUTE(rphy_scsi_target_id);
SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
get_enclosure_identifier);
SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5e170a6..f52b74c 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -205,6 +205,7 @@ cache_type_store(struct device *dev, struct device_attribute *attr,
buffer_data[2] &= ~0x05;
buffer_data[2] |= wce << 2 | rcd;
sp = buffer_data[0] & 0x80 ? 1 : 0;
+ buffer_data[0] &= ~0x80;
if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
SD_MAX_RETRIES, &data, &sshdr)) {
@@ -637,11 +638,24 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
unsigned int max_blocks = 0;
q->limits.discard_zeroes_data = 0;
- q->limits.discard_alignment = sdkp->unmap_alignment *
- logical_block_size;
- q->limits.discard_granularity =
- max(sdkp->physical_block_size,
- sdkp->unmap_granularity * logical_block_size);
+
+ /*
+ * When LBPRZ is reported, discard alignment and granularity
+ * must be fixed to the logical block size. Otherwise the block
+ * layer will drop misaligned portions of the request which can
+ * lead to data corruption. If LBPRZ is not set, we honor the
+ * device preference.
+ */
+ if (sdkp->lbprz) {
+ q->limits.discard_alignment = 0;
+ q->limits.discard_granularity = logical_block_size;
+ } else {
+ q->limits.discard_alignment = sdkp->unmap_alignment *
+ logical_block_size;
+ q->limits.discard_granularity =
+ max(sdkp->physical_block_size,
+ sdkp->unmap_granularity * logical_block_size);
+ }
sdkp->provisioning_mode = mode;
@@ -747,7 +761,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd)
break;
default:
- ret = BLKPREP_KILL;
+ ret = BLKPREP_INVALID;
goto out;
}
@@ -825,7 +839,7 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
int ret;
if (sdkp->device->no_write_same)
- return BLKPREP_KILL;
+ return BLKPREP_INVALID;
BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size);
@@ -1261,18 +1275,19 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
struct scsi_device *sdp = sdkp->device;
struct Scsi_Host *host = sdp->host;
+ sector_t capacity = logical_to_sectors(sdp, sdkp->capacity);
int diskinfo[4];
/* default to most commonly used values */
- diskinfo[0] = 0x40; /* 1 << 6 */
- diskinfo[1] = 0x20; /* 1 << 5 */
- diskinfo[2] = sdkp->capacity >> 11;
-
+ diskinfo[0] = 0x40; /* 1 << 6 */
+ diskinfo[1] = 0x20; /* 1 << 5 */
+ diskinfo[2] = capacity >> 11;
+
/* override with calculated, extended default, or driver values */
if (host->hostt->bios_param)
- host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo);
+ host->hostt->bios_param(sdp, bdev, capacity, diskinfo);
else
- scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
+ scsicam_bios_param(bdev, capacity, diskinfo);
geo->heads = diskinfo[0];
geo->sectors = diskinfo[1];
@@ -2320,19 +2335,8 @@ got_data:
}
}
- if (sdkp->capacity > 0xffffffff) {
+ if (sdkp->capacity > 0xffffffff)
sdp->use_16_for_rw = 1;
- sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS;
- } else
- sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS;
-
- /* Rescale capacity to 512-byte units */
- if (sector_size == 4096)
- sdkp->capacity <<= 3;
- else if (sector_size == 2048)
- sdkp->capacity <<= 2;
- else if (sector_size == 1024)
- sdkp->capacity <<= 1;
blk_queue_physical_block_size(sdp->request_queue,
sdkp->physical_block_size);
@@ -2641,7 +2645,6 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
{
unsigned int sector_sz = sdkp->device->sector_size;
const int vpd_len = 64;
- u32 max_xfer_length;
unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
if (!buffer ||
@@ -2649,14 +2652,11 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
goto out;
- max_xfer_length = get_unaligned_be32(&buffer[8]);
- if (max_xfer_length)
- sdkp->max_xfer_blocks = max_xfer_length;
-
blk_queue_io_min(sdkp->disk->queue,
get_unaligned_be16(&buffer[6]) * sector_sz);
- blk_queue_io_opt(sdkp->disk->queue,
- get_unaligned_be32(&buffer[12]) * sector_sz);
+
+ sdkp->max_xfer_blocks = get_unaligned_be32(&buffer[8]);
+ sdkp->opt_xfer_blocks = get_unaligned_be32(&buffer[12]);
if (buffer[3] == 0x3c) {
unsigned int lba_count, desc_count;
@@ -2788,23 +2788,6 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
sdkp->ws10 = 1;
}
-static int sd_try_extended_inquiry(struct scsi_device *sdp)
-{
- /* Attempt VPD inquiry if the device blacklist explicitly calls
- * for it.
- */
- if (sdp->try_vpd_pages)
- return 1;
- /*
- * Although VPD inquiries can go to SCSI-2 type devices,
- * some USB ones crash on receiving them, and the pages
- * we currently ask for are for SPC-3 and beyond
- */
- if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages)
- return 1;
- return 0;
-}
-
/**
* sd_revalidate_disk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc.
@@ -2814,8 +2797,9 @@ static int sd_revalidate_disk(struct gendisk *disk)
{
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdp = sdkp->device;
+ struct request_queue *q = sdkp->disk->queue;
unsigned char *buffer;
- unsigned int max_xfer;
+ unsigned int dev_max, rw_max;
SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
"sd_revalidate_disk\n"));
@@ -2843,7 +2827,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
if (sdkp->media_present) {
sd_read_capacity(sdkp, buffer);
- if (sd_try_extended_inquiry(sdp)) {
+ if (scsi_device_supports_vpd(sdp)) {
sd_read_block_provisioning(sdkp);
sd_read_block_limits(sdkp);
sd_read_block_characteristics(sdkp);
@@ -2863,13 +2847,31 @@ static int sd_revalidate_disk(struct gendisk *disk)
*/
sd_set_flush_flag(sdkp);
- max_xfer = sdkp->max_xfer_blocks;
- max_xfer <<= ilog2(sdp->sector_size) - 9;
+ /* Initial block count limit based on CDB TRANSFER LENGTH field size. */
+ dev_max = sdp->use_16_for_rw ? SD_MAX_XFER_BLOCKS : SD_DEF_XFER_BLOCKS;
+
+ /* Some devices report a maximum block count for READ/WRITE requests. */
+ dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks);
+ q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max);
+
+ /*
+ * Use the device's preferred I/O size for reads and writes
+ * unless the reported value is unreasonably small, large, or
+ * garbage.
+ */
+ if (sdkp->opt_xfer_blocks &&
+ sdkp->opt_xfer_blocks <= dev_max &&
+ sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS &&
+ sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_SIZE)
+ rw_max = q->limits.io_opt =
+ sdkp->opt_xfer_blocks * sdp->sector_size;
+ else
+ rw_max = BLK_DEF_MAX_SECTORS;
- sdkp->disk->queue->limits.max_sectors =
- min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer);
+ /* Combine with controller limits */
+ q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q));
- set_capacity(disk, sdkp->capacity);
+ set_capacity(disk, logical_to_sectors(sdp, sdkp->capacity));
sd_config_write_same(sdkp);
kfree(buffer);
@@ -3237,8 +3239,8 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
struct scsi_disk *sdkp = dev_get_drvdata(dev);
int ret = 0;
- if (!sdkp)
- return 0; /* this can happen */
+ if (!sdkp) /* E.g.: runtime suspend following sd_remove() */
+ return 0;
if (sdkp->WCE && sdkp->media_present) {
sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
@@ -3277,6 +3279,9 @@ static int sd_resume(struct device *dev)
{
struct scsi_disk *sdkp = dev_get_drvdata(dev);
+ if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */
+ return 0;
+
if (!sdkp->device->manage_start_stop)
return 0;
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 63ba5ca..654630b 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -65,8 +65,9 @@ struct scsi_disk {
struct device dev;
struct gendisk *disk;
atomic_t openers;
- sector_t capacity; /* size in 512-byte sectors */
+ sector_t capacity; /* size in logical blocks */
u32 max_xfer_blocks;
+ u32 opt_xfer_blocks;
u32 max_ws_blocks;
u32 max_unmap_blocks;
u32 unmap_granularity;
@@ -145,6 +146,11 @@ static inline int scsi_medium_access_command(struct scsi_cmnd *scmd)
return 0;
}
+static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blocks)
+{
+ return blocks << (ilog2(sdev->sector_size) - 9);
+}
+
/*
* A DIF-capable target device can be formatted with different
* protection schemes. Currently 0 through 3 are defined:
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index dcb0d76..53ef1cb 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -34,6 +34,8 @@
#include <scsi/scsi_driver.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_sas.h>
+
struct ses_device {
unsigned char *page1;
unsigned char *page1_types;
@@ -84,6 +86,7 @@ static void init_device_slot_control(unsigned char *dest_desc,
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
void *buf, int bufflen)
{
+ int ret;
unsigned char cmd[] = {
RECEIVE_DIAGNOSTIC,
1, /* Set PCV bit */
@@ -92,9 +95,26 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code,
bufflen & 0xff,
0
};
+ unsigned char recv_page_code;
- return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
+ ret = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
NULL, SES_TIMEOUT, SES_RETRIES, NULL);
+ if (unlikely(!ret))
+ return ret;
+
+ recv_page_code = ((unsigned char *)buf)[0];
+
+ if (likely(recv_page_code == page_code))
+ return ret;
+
+ /* successful diagnostic but wrong page code. This happens to some
+ * USB devices, just print a message and pretend there was an error */
+
+ sdev_printk(KERN_ERR, sdev,
+ "Wrong diagnostic page; asked for %d got %u\n",
+ page_code, recv_page_code);
+
+ return -EINVAL;
}
static int ses_send_diag(struct scsi_device *sdev, int page_code,
@@ -541,7 +561,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
if (desc_ptr)
desc_ptr += len;
- if (addl_desc_ptr)
+ if (addl_desc_ptr &&
+ /* only find additional descriptions for specific devices */
+ (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_SAS_EXPANDER ||
+ /* these elements are optional */
+ type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS))
addl_desc_ptr += addl_desc_ptr[1] + 2;
}
@@ -553,31 +581,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
static void ses_match_to_enclosure(struct enclosure_device *edev,
struct scsi_device *sdev)
{
- unsigned char *desc;
struct efd efd = {
.addr = 0,
};
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
- if (!sdev->vpd_pg83_len)
- return;
-
- desc = sdev->vpd_pg83 + 4;
- while (desc < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
- enum scsi_protocol proto = desc[0] >> 4;
- u8 code_set = desc[0] & 0x0f;
- u8 piv = desc[1] & 0x80;
- u8 assoc = (desc[1] & 0x30) >> 4;
- u8 type = desc[1] & 0x0f;
- u8 len = desc[3];
+ if (is_sas_attached(sdev))
+ efd.addr = sas_get_address(sdev);
- if (piv && code_set == 1 && assoc == 1
- && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
- efd.addr = get_unaligned_be64(&desc[4]);
-
- desc += len + 4;
- }
if (efd.addr) {
efd.dev = &sdev->sdev_gendev;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9d7b7db..ae7d9bd 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -652,7 +652,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
else
hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
hp->dxfer_len = mxsize;
- if (hp->dxfer_direction == SG_DXFER_TO_DEV)
+ if ((hp->dxfer_direction == SG_DXFER_TO_DEV) ||
+ (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV))
hp->dxferp = (char __user *)buf + cmd_size;
else
hp->dxferp = NULL;
@@ -787,8 +788,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
return k; /* probably out of space --> ENOMEM */
}
if (atomic_read(&sdp->detaching)) {
- if (srp->bio)
+ if (srp->bio) {
+ if (srp->rq->cmd != srp->rq->__cmd)
+ kfree(srp->rq->cmd);
+
blk_end_request_all(srp->rq, -EIO);
+ srp->rq = NULL;
+ }
+
sg_finish_rem_req(srp);
return -ENODEV;
}
@@ -1255,7 +1262,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
}
sfp->mmap_called = 1;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_private_data = sfp;
vma->vm_ops = &sg_mmap_vm_ops;
return 0;
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 3b3b56f..82ed998 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -176,8 +176,7 @@ static struct eisa_device_id sim710_eisa_ids[] = {
};
MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
-static __init int
-sim710_eisa_probe(struct device *dev)
+static int sim710_eisa_probe(struct device *dev)
{
struct eisa_device *edev = to_eisa_device(dev);
unsigned long io_addr = edev->base_addr;
diff --git a/drivers/scsi/snic/snic_ctl.c b/drivers/scsi/snic/snic_ctl.c
index aebe753..ab0e06b 100644
--- a/drivers/scsi/snic/snic_ctl.c
+++ b/drivers/scsi/snic/snic_ctl.c
@@ -75,7 +75,7 @@ snic_ver_enc(const char *s)
continue;
}
- if (i > 4 || !isdigit(c))
+ if (i > 3 || !isdigit(c))
goto end;
v[i] = v[i] * 10 + (c - '0');
diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c
index b2b87ce..2b3c253 100644
--- a/drivers/scsi/snic/snic_main.c
+++ b/drivers/scsi/snic/snic_main.c
@@ -124,7 +124,6 @@ static struct scsi_host_template snic_host_template = {
.sg_tablesize = SNIC_MAX_SG_DESC_CNT,
.max_sectors = 0x800,
.shost_attrs = snic_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
.cmd_size = sizeof(struct snic_internal_io_state),
.proc_name = "snic_scsi",
@@ -533,15 +532,6 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
snic->max_tag_id = shost->can_queue;
- ret = scsi_init_shared_tag_map(shost, snic->max_tag_id);
- if (ret) {
- SNIC_HOST_ERR(shost,
- "Unable to alloc shared tag map. %d\n",
- ret);
-
- goto err_dev_close;
- }
-
shost->max_lun = snic->config.luns_per_tgt;
shost->max_id = SNIC_MAX_TARGET;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 8bd54a6..64c8674 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -144,6 +144,9 @@ static int sr_runtime_suspend(struct device *dev)
{
struct scsi_cd *cd = dev_get_drvdata(dev);
+ if (!cd) /* E.g.: runtime suspend following sr_remove() */
+ return 0;
+
if (cd->media_present)
return -EBUSY;
else
@@ -985,6 +988,7 @@ static int sr_remove(struct device *dev)
scsi_autopm_get_device(cd->device);
del_gendisk(cd->disk);
+ dev_set_drvdata(dev, NULL);
mutex_lock(&sr_ref_mutex);
kref_put(&cd->kref, sr_kref_release);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index b37b9b0..dbf1882c 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -9,7 +9,7 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2010 Kai Makisara
+ Copyright 1992 - 2016 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20101219";
+static const char *verstr = "20160209";
#include <linux/module.h>
@@ -3296,7 +3296,10 @@ static int switch_partition(struct scsi_tape *STp)
#define PP_OFF_RESERVED 7
#define PP_BIT_IDP 0x20
+#define PP_BIT_FDP 0x80
#define PP_MSK_PSUM_MB 0x10
+#define PP_MSK_PSUM_UNITS 0x18
+#define PP_MSK_POFM 0x04
/* Get the number of partitions on the tape. As a side effect reads the
mode page into the tape buffer. */
@@ -3322,6 +3325,29 @@ static int nbr_partitions(struct scsi_tape *STp)
}
+static int format_medium(struct scsi_tape *STp, int format)
+{
+ int result = 0;
+ int timeout = STp->long_timeout;
+ unsigned char scmd[MAX_COMMAND_SIZE];
+ struct st_request *SRpnt;
+
+ memset(scmd, 0, MAX_COMMAND_SIZE);
+ scmd[0] = FORMAT_UNIT;
+ scmd[2] = format;
+ if (STp->immediate) {
+ scmd[1] |= 1; /* Don't wait for completion */
+ timeout = STp->device->request_queue->rq_timeout;
+ }
+ DEBC_printk(STp, "Sending FORMAT MEDIUM\n");
+ SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
+ timeout, MAX_RETRIES, 1);
+ if (!SRpnt)
+ result = STp->buffer->syscall_result;
+ return result;
+}
+
+
/* Partition the tape into two partitions if size > 0 or one partition if
size == 0.
@@ -3340,11 +3366,16 @@ static int nbr_partitions(struct scsi_tape *STp)
and 10 when 1 partition is defined (information from Eric Lee Green). This is
is acceptable also to some other old drives and enforced if the first partition
size field is used for the first additional partition size.
+
+ For drives that advertize SCSI-3 or newer, use the SSC-3 methods.
*/
static int partition_tape(struct scsi_tape *STp, int size)
{
int result;
+ int target_partition;
+ bool scsi3 = STp->device->scsi_level >= SCSI_3, needs_format = false;
int pgo, psd_cnt, psdo;
+ int psum = PP_MSK_PSUM_MB, units = 0;
unsigned char *bp;
result = read_mode_page(STp, PART_PAGE, 0);
@@ -3352,6 +3383,12 @@ static int partition_tape(struct scsi_tape *STp, int size)
DEBC_printk(STp, "Can't read partition mode page.\n");
return result;
}
+ target_partition = 1;
+ if (size < 0) {
+ target_partition = 0;
+ size = -size;
+ }
+
/* The mode page is in the buffer. Let's modify it and write it. */
bp = (STp->buffer)->b_data;
pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
@@ -3359,9 +3396,52 @@ static int partition_tape(struct scsi_tape *STp, int size)
bp[pgo + MP_OFF_PAGE_LENGTH] + 2);
psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
+
+ if (scsi3) {
+ needs_format = (bp[pgo + PP_OFF_FLAGS] & PP_MSK_POFM) != 0;
+ if (needs_format && size == 0) {
+ /* No need to write the mode page when clearing
+ * partitioning
+ */
+ DEBC_printk(STp, "Formatting tape with one partition.\n");
+ result = format_medium(STp, 0);
+ goto out;
+ }
+ if (needs_format) /* Leave the old value for HP DATs claiming SCSI_3 */
+ psd_cnt = 2;
+ if ((bp[pgo + PP_OFF_FLAGS] & PP_MSK_PSUM_UNITS) == PP_MSK_PSUM_UNITS) {
+ /* Use units scaling for large partitions if the device
+ * suggests it and no precision lost. Required for IBM
+ * TS1140/50 drives that don't support MB units.
+ */
+ if (size >= 1000 && (size % 1000) == 0) {
+ size /= 1000;
+ psum = PP_MSK_PSUM_UNITS;
+ units = 9; /* GB */
+ }
+ }
+ /* Try it anyway if too large to specify in MB */
+ if (psum == PP_MSK_PSUM_MB && size >= 65534) {
+ size /= 1000;
+ psum = PP_MSK_PSUM_UNITS;
+ units = 9; /* GB */
+ }
+ }
+
+ if (size >= 65535 || /* Does not fit into two bytes */
+ (target_partition == 0 && psd_cnt < 2)) {
+ result = -EINVAL;
+ goto out;
+ }
+
psdo = pgo + PART_PAGE_FIXED_LENGTH;
- if (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS]) {
- bp[psdo] = bp[psdo + 1] = 0xff; /* Rest of the tape */
+ /* The second condition is for HP DDS which use only one partition size
+ * descriptor
+ */
+ if (target_partition > 0 &&
+ (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS] ||
+ bp[pgo + PP_OFF_MAX_ADD_PARTS] != 1)) {
+ bp[psdo] = bp[psdo + 1] = 0xff; /* Rest to partition 0 */
psdo += 2;
}
memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
@@ -3370,7 +3450,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
bp[pgo + PP_OFF_NBR_ADD_PARTS]);
- if (size <= 0) {
+ if (size == 0) {
bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
@@ -3378,22 +3458,37 @@ static int partition_tape(struct scsi_tape *STp, int size)
} else {
bp[psdo] = (size >> 8) & 0xff;
bp[psdo + 1] = size & 0xff;
+ if (target_partition == 0)
+ bp[psdo + 2] = bp[psdo + 3] = 0xff;
bp[pgo + 3] = 1;
if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
- DEBC_printk(STp, "Formatting tape with two partitions "
- "(1 = %d MB).\n", size);
+ DEBC_printk(STp,
+ "Formatting tape with two partitions (%i = %d MB).\n",
+ target_partition, units > 0 ? size * 1000 : size);
}
bp[pgo + PP_OFF_PART_UNITS] = 0;
bp[pgo + PP_OFF_RESERVED] = 0;
- bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
+ if (size != 1 || units != 0) {
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | psum |
+ (bp[pgo + PP_OFF_FLAGS] & 0x07);
+ bp[pgo + PP_OFF_PART_UNITS] = units;
+ } else
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_FDP |
+ (bp[pgo + PP_OFF_FLAGS] & 0x1f);
+ bp[pgo + MP_OFF_PAGE_LENGTH] = 6 + psd_cnt * 2;
result = write_mode_page(STp, PART_PAGE, 1);
+
+ if (!result && needs_format)
+ result = format_medium(STp, 1);
+
if (result) {
st_printk(KERN_INFO, STp, "Partitioning of tape failed.\n");
result = (-EIO);
}
+out:
return result;
}
@@ -3570,8 +3665,13 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
retval = (-EINVAL);
goto out;
}
- if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
- (i = partition_tape(STp, mtc.mt_count)) < 0) {
+ i = do_load_unload(STp, file, 1);
+ if (i < 0) {
+ retval = i;
+ goto out;
+ }
+ i = partition_tape(STp, mtc.mt_count);
+ if (i < 0) {
retval = i;
goto out;
}
@@ -3581,7 +3681,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
STp->ps[i].last_block_valid = 0;
}
STp->partition = STp->new_partition = 0;
- STp->nbr_partitions = 1; /* Bad guess ?-) */
+ STp->nbr_partitions = mtc.mt_count != 0 ? 2 : 1;
STps->drv_block = STps->drv_file = 0;
retval = 0;
goto out;
@@ -4083,6 +4183,7 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
}
cdev->owner = THIS_MODULE;
cdev->ops = &st_fops;
+ STm->cdevs[rew] = cdev;
error = cdev_add(cdev, cdev_devno, 1);
if (error) {
@@ -4091,7 +4192,6 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
pr_err("st%d: Device not attached.\n", dev_num);
goto out_free;
}
- STm->cdevs[rew] = cdev;
i = mode << (4 - ST_NBR_MODE_BITS);
snprintf(name, 10, "%s%s%s", rew ? "n" : "",
@@ -4110,8 +4210,9 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
return 0;
out_free:
cdev_del(STm->cdevs[rew]);
- STm->cdevs[rew] = NULL;
out:
+ STm->cdevs[rew] = NULL;
+ STm->devs[rew] = NULL;
return error;
}
@@ -4452,11 +4553,41 @@ static ssize_t version_show(struct device_driver *ddd, char *buf)
}
static DRIVER_ATTR_RO(version);
+#if DEBUG
+static ssize_t debug_flag_store(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+/* We only care what the first byte of the data is the rest is unused.
+ * if it's a '1' we turn on debug and if it's a '0' we disable it. All
+ * other values have -EINVAL returned if they are passed in.
+ */
+ if (count > 0) {
+ if (buf[0] == '0') {
+ debugging = NO_DEBUG;
+ return count;
+ } else if (buf[0] == '1') {
+ debugging = 1;
+ return count;
+ }
+ }
+ return -EINVAL;
+}
+
+static ssize_t debug_flag_show(struct device_driver *ddp, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", debugging);
+}
+static DRIVER_ATTR_RW(debug_flag);
+#endif
+
static struct attribute *st_drv_attrs[] = {
&driver_attr_try_direct_io.attr,
&driver_attr_fixed_buffer_size.attr,
&driver_attr_max_sg_segs.attr,
&driver_attr_version.attr,
+#if DEBUG
+ &driver_attr_debug_flag.attr,
+#endif
NULL,
};
ATTRIBUTE_GROUPS(st_drv);
@@ -4786,8 +4917,6 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
/* Try to fault in all of the necessary pages */
/* rw==READ means read from drive, write into memory area */
res = get_user_pages_unlocked(
- current,
- current->mm,
uaddr,
nr_pages,
rw == READ,
@@ -4812,7 +4941,7 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
out_unmap:
if (res > 0) {
for (j=0; j < res; j++)
- page_cache_release(pages[j]);
+ put_page(pages[j]);
res = 0;
}
kfree(pages);
@@ -4834,7 +4963,7 @@ static int sgl_unmap_user_pages(struct st_buffer *STbp,
/* FIXME: cache flush missing for rw==READ
* FIXME: call the correct reference counting function
*/
- page_cache_release(page);
+ put_page(page);
}
kfree(STbp->mapped_pages);
STbp->mapped_pages = NULL;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index b6486b5..8c732c8 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -148,8 +148,6 @@ struct scsi_tape {
int tape_type;
int long_timeout; /* timeout for commands known to take long time */
- unsigned long max_pfn; /* the maximum page number reachable by the HBA */
-
/* Mode characteristics */
struct st_modedef modes[ST_NBR_MODES];
int current_mode;
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 98a62bc..5b23175 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -1,7 +1,7 @@
/*
* SuperTrak EX Series Storage Controller driver for Linux
*
- * Copyright (C) 2005-2009 Promise Technology Inc.
+ * Copyright (C) 2005-2015 Promise Technology Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,6 +25,7 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/ktime.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -37,11 +38,11 @@
#include <scsi/scsi_eh.h>
#define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "4.6.0000.4"
-#define ST_VER_MAJOR 4
-#define ST_VER_MINOR 6
-#define ST_OEM 0
-#define ST_BUILD_VER 4
+#define ST_DRIVER_VERSION "5.00.0000.01"
+#define ST_VER_MAJOR 5
+#define ST_VER_MINOR 00
+#define ST_OEM 0000
+#define ST_BUILD_VER 01
enum {
/* MU register offset */
@@ -83,6 +84,8 @@ enum {
MU_STATE_STARTED = 2,
MU_STATE_RESETTING = 3,
MU_STATE_FAILED = 4,
+ MU_STATE_STOP = 5,
+ MU_STATE_NOCONNECT = 6,
MU_MAX_DELAY = 120,
MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
@@ -164,6 +167,14 @@ enum {
ST_ADDITIONAL_MEM = 0x200000,
ST_ADDITIONAL_MEM_MIN = 0x80000,
+ PMIC_SHUTDOWN = 0x0D,
+ PMIC_REUMSE = 0x10,
+ ST_IGNORED = -1,
+ ST_NOTHANDLED = 7,
+ ST_S3 = 3,
+ ST_S4 = 4,
+ ST_S5 = 5,
+ ST_S6 = 6,
};
struct st_sgitem {
@@ -327,6 +338,7 @@ struct st_hba {
u16 rq_count;
u16 rq_size;
u16 sts_count;
+ u8 supports_pm;
};
struct st_card_info {
@@ -362,14 +374,6 @@ MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers");
MODULE_LICENSE("GPL");
MODULE_VERSION(ST_DRIVER_VERSION);
-static void stex_gettime(__le64 *time)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
- *time = cpu_to_le64(tv.tv_sec);
-}
-
static struct status_msg *stex_get_status(struct st_hba *hba)
{
struct status_msg *status = hba->status_buffer + hba->status_tail;
@@ -543,6 +547,27 @@ stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
readl(hba->mmio_base + YH2I_REQ); /* flush */
}
+static void return_abnormal_state(struct st_hba *hba, int status)
+{
+ struct st_ccb *ccb;
+ unsigned long flags;
+ u16 tag;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ for (tag = 0; tag < hba->host->can_queue; tag++) {
+ ccb = &hba->ccb[tag];
+ if (ccb->req == NULL)
+ continue;
+ ccb->req = NULL;
+ if (ccb->cmd) {
+ scsi_dma_unmap(ccb->cmd);
+ ccb->cmd->result = status << 16;
+ ccb->cmd->scsi_done(ccb->cmd);
+ ccb->cmd = NULL;
+ }
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
static int
stex_slave_config(struct scsi_device *sdev)
{
@@ -566,8 +591,12 @@ stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
id = cmd->device->id;
lun = cmd->device->lun;
hba = (struct st_hba *) &host->hostdata[0];
-
- if (unlikely(hba->mu_status == MU_STATE_RESETTING))
+ if (hba->mu_status == MU_STATE_NOCONNECT) {
+ cmd->result = DID_NO_CONNECT;
+ done(cmd);
+ return 0;
+ }
+ if (unlikely(hba->mu_status != MU_STATE_STARTED))
return SCSI_MLQUEUE_HOST_BUSY;
switch (cmd->cmnd[0]) {
@@ -1002,7 +1031,7 @@ static int stex_common_handshake(struct st_hba *hba)
h->req_cnt = cpu_to_le16(hba->rq_count+1);
h->status_sz = cpu_to_le16(sizeof(struct status_msg));
h->status_cnt = cpu_to_le16(hba->sts_count+1);
- stex_gettime(&h->hosttime);
+ h->hosttime = cpu_to_le64(ktime_get_real_seconds());
h->partner_type = HMU_PARTNER_TYPE;
if (hba->extra_offset) {
h->extra_offset = cpu_to_le32(hba->extra_offset);
@@ -1076,7 +1105,7 @@ static int stex_ss_handshake(struct st_hba *hba)
h->req_cnt = cpu_to_le16(hba->rq_count+1);
h->status_sz = cpu_to_le16(sizeof(struct status_msg));
h->status_cnt = cpu_to_le16(hba->sts_count+1);
- stex_gettime(&h->hosttime);
+ h->hosttime = cpu_to_le64(ktime_get_real_seconds());
h->partner_type = HMU_PARTNER_TYPE;
h->extra_offset = h->extra_size = 0;
scratch_size = (hba->sts_count+1)*sizeof(u32);
@@ -1266,10 +1295,8 @@ static void stex_ss_reset(struct st_hba *hba)
static int stex_do_reset(struct st_hba *hba)
{
- struct st_ccb *ccb;
unsigned long flags;
unsigned int mu_status = MU_STATE_RESETTING;
- u16 tag;
spin_lock_irqsave(hba->host->host_lock, flags);
if (hba->mu_status == MU_STATE_STARTING) {
@@ -1303,20 +1330,8 @@ static int stex_do_reset(struct st_hba *hba)
else if (hba->cardtype == st_yel)
stex_ss_reset(hba);
- spin_lock_irqsave(hba->host->host_lock, flags);
- for (tag = 0; tag < hba->host->can_queue; tag++) {
- ccb = &hba->ccb[tag];
- if (ccb->req == NULL)
- continue;
- ccb->req = NULL;
- if (ccb->cmd) {
- scsi_dma_unmap(ccb->cmd);
- ccb->cmd->result = DID_RESET << 16;
- ccb->cmd->scsi_done(ccb->cmd);
- ccb->cmd = NULL;
- }
- }
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return_abnormal_state(hba, DID_RESET);
if (stex_handshake(hba) == 0)
return 0;
@@ -1374,7 +1389,6 @@ static struct scsi_host_template driver_template = {
.eh_abort_handler = stex_abort,
.eh_host_reset_handler = stex_reset,
.this_id = -1,
- .use_blk_tags = 1,
};
static struct pci_device_id stex_pci_tbl[] = {
@@ -1568,6 +1582,25 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hba->cardtype = (unsigned int) id->driver_data;
ci = &stex_card_info[hba->cardtype];
+ switch (id->subdevice) {
+ case 0x4221:
+ case 0x4222:
+ case 0x4223:
+ case 0x4224:
+ case 0x4225:
+ case 0x4226:
+ case 0x4227:
+ case 0x4261:
+ case 0x4262:
+ case 0x4263:
+ case 0x4264:
+ case 0x4265:
+ break;
+ default:
+ if (hba->cardtype == st_yel)
+ hba->supports_pm = 1;
+ }
+
sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size;
if (hba->cardtype == st_yel)
sts_offset += (ci->sts_count+1) * sizeof(u32);
@@ -1659,13 +1692,6 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto out_free_irq;
- err = scsi_init_shared_tag_map(host, host->can_queue);
- if (err) {
- printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
- pci_name(pdev));
- goto out_free_irq;
- }
-
pci_set_drvdata(pdev, hba);
err = scsi_add_host(host, &pdev->dev);
@@ -1700,7 +1726,7 @@ out_disable:
return err;
}
-static void stex_hba_stop(struct st_hba *hba)
+static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic)
{
struct req_msg *req;
struct st_msg_header *msg_h;
@@ -1709,6 +1735,15 @@ static void stex_hba_stop(struct st_hba *hba)
u16 tag = 0;
spin_lock_irqsave(hba->host->host_lock, flags);
+
+ if (hba->cardtype == st_yel && hba->supports_pm == 1)
+ {
+ if(st_sleep_mic == ST_NOTHANDLED)
+ {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return;
+ }
+ }
req = hba->alloc_rq(hba);
if (hba->cardtype == st_yel) {
msg_h = (struct st_msg_header *)req - 1;
@@ -1716,11 +1751,18 @@ static void stex_hba_stop(struct st_hba *hba)
} else
memset(req, 0, hba->rq_size);
- if (hba->cardtype == st_yosemite || hba->cardtype == st_yel) {
+ if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel)
+ && st_sleep_mic == ST_IGNORED) {
req->cdb[0] = MGT_CMD;
req->cdb[1] = MGT_CMD_SIGNATURE;
req->cdb[2] = CTLR_CONFIG_CMD;
req->cdb[3] = CTLR_SHUTDOWN;
+ } else if (hba->cardtype == st_yel && st_sleep_mic != ST_IGNORED) {
+ req->cdb[0] = MGT_CMD;
+ req->cdb[1] = MGT_CMD_SIGNATURE;
+ req->cdb[2] = CTLR_CONFIG_CMD;
+ req->cdb[3] = PMIC_SHUTDOWN;
+ req->cdb[4] = st_sleep_mic;
} else {
req->cdb[0] = CONTROLLER_CMD;
req->cdb[1] = CTLR_POWER_STATE_CHANGE;
@@ -1740,10 +1782,12 @@ static void stex_hba_stop(struct st_hba *hba)
while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
hba->ccb[tag].req_type = 0;
+ hba->mu_status = MU_STATE_STOP;
return;
}
msleep(1);
}
+ hba->mu_status = MU_STATE_STOP;
}
static void stex_hba_free(struct st_hba *hba)
@@ -1766,9 +1810,11 @@ static void stex_remove(struct pci_dev *pdev)
{
struct st_hba *hba = pci_get_drvdata(pdev);
+ hba->mu_status = MU_STATE_NOCONNECT;
+ return_abnormal_state(hba, DID_NO_CONNECT);
scsi_remove_host(hba->host);
- stex_hba_stop(hba);
+ scsi_block_requests(hba->host);
stex_hba_free(hba);
@@ -1781,9 +1827,43 @@ static void stex_shutdown(struct pci_dev *pdev)
{
struct st_hba *hba = pci_get_drvdata(pdev);
- stex_hba_stop(hba);
+ if (hba->supports_pm == 0)
+ stex_hba_stop(hba, ST_IGNORED);
+ else
+ stex_hba_stop(hba, ST_S5);
+}
+
+static int stex_choice_sleep_mic(pm_message_t state)
+{
+ switch (state.event) {
+ case PM_EVENT_SUSPEND:
+ return ST_S3;
+ case PM_EVENT_HIBERNATE:
+ return ST_S4;
+ default:
+ return ST_NOTHANDLED;
+ }
}
+static int stex_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ if (hba->cardtype == st_yel && hba->supports_pm == 1)
+ stex_hba_stop(hba, stex_choice_sleep_mic(state));
+ else
+ stex_hba_stop(hba, ST_IGNORED);
+ return 0;
+}
+
+static int stex_resume(struct pci_dev *pdev)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ hba->mu_status = MU_STATE_STARTING;
+ stex_handshake(hba);
+ return 0;
+}
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
static struct pci_driver stex_pci_driver = {
@@ -1792,6 +1872,8 @@ static struct pci_driver stex_pci_driver = {
.probe = stex_probe,
.remove = stex_remove,
.shutdown = stex_shutdown,
+ .suspend = stex_suspend,
+ .resume = stex_resume,
};
static int __init stex_init(void)
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 40c43ae..3ddcabb 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -41,6 +41,8 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
/*
* All wire protocol details (storage protocol between the guest and the host)
@@ -92,9 +94,8 @@ enum vstor_packet_operation {
*/
struct hv_fc_wwn_packet {
- bool primary_active;
- u8 reserved1;
- u8 reserved2;
+ u8 primary_active;
+ u8 reserved1[3];
u8 primary_port_wwn[8];
u8 primary_node_wwn[8];
u8 secondary_port_wwn[8];
@@ -164,6 +165,26 @@ static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
*/
static int vmstor_proto_version;
+#define STORVSC_LOGGING_NONE 0
+#define STORVSC_LOGGING_ERROR 1
+#define STORVSC_LOGGING_WARN 2
+
+static int logging_level = STORVSC_LOGGING_ERROR;
+module_param(logging_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(logging_level,
+ "Logging level, 0 - None, 1 - Error (default), 2 - Warning.");
+
+static inline bool do_logging(int level)
+{
+ return logging_level >= level;
+}
+
+#define storvsc_log(dev, level, fmt, ...) \
+do { \
+ if (do_logging(level)) \
+ dev_warn(&(dev)->device, fmt, ##__VA_ARGS__); \
+} while (0)
+
struct vmscsi_win8_extension {
/*
* The following were added in Windows 8
@@ -349,11 +370,14 @@ enum storvsc_request_type {
*/
#define SRB_STATUS_AUTOSENSE_VALID 0x80
+#define SRB_STATUS_QUEUE_FROZEN 0x40
#define SRB_STATUS_INVALID_LUN 0x20
#define SRB_STATUS_SUCCESS 0x01
#define SRB_STATUS_ABORTED 0x02
#define SRB_STATUS_ERROR 0x04
+#define SRB_STATUS(status) \
+ (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
/*
* This is the end of Protocol specific defines.
*/
@@ -367,7 +391,7 @@ module_param(storvsc_ringbuffer_size, int, S_IRUGO);
MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
module_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO);
-MODULE_PARM_DESC(vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
+MODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
/*
* Timeout in seconds for all devices managed by this driver.
*/
@@ -375,6 +399,9 @@ static int storvsc_timeout = 180;
static int msft_blist_flags = BLIST_TRY_VPD_PAGES;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct scsi_transport_template *fc_transport_template;
+#endif
static void storvsc_on_channel_callback(void *context);
@@ -393,9 +420,6 @@ static void storvsc_on_channel_callback(void *context);
struct storvsc_cmd_request {
struct scsi_cmnd *cmd;
- unsigned int bounce_sgl_count;
- struct scatterlist *bounce_sgl;
-
struct hv_device *device;
/* Synchronize the request/response if needed */
@@ -437,6 +461,11 @@ struct storvsc_device {
/* Used for vsc/vsp channel reset process */
struct storvsc_cmd_request init_request;
struct storvsc_cmd_request reset_request;
+ /*
+ * Currently active port and node names for FC devices.
+ */
+ u64 node_name;
+ u64 port_name;
};
struct hv_host_device {
@@ -449,19 +478,18 @@ struct hv_host_device {
struct storvsc_scan_work {
struct work_struct work;
struct Scsi_Host *host;
- uint lun;
+ u8 lun;
+ u8 tgt_id;
};
static void storvsc_device_scan(struct work_struct *work)
{
struct storvsc_scan_work *wrk;
- uint lun;
struct scsi_device *sdev;
wrk = container_of(work, struct storvsc_scan_work, work);
- lun = wrk->lun;
- sdev = scsi_device_lookup(wrk->host, 0, 0, lun);
+ sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
if (!sdev)
goto done;
scsi_rescan_device(&sdev->sdev_gendev);
@@ -512,7 +540,7 @@ static void storvsc_remove_lun(struct work_struct *work)
if (!scsi_host_get(wrk->host))
goto done;
- sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun);
+ sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
if (sdev) {
scsi_remove_device(sdev);
@@ -586,241 +614,6 @@ get_in_err:
}
-static void destroy_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count)
-{
- int i;
- struct page *page_buf;
-
- for (i = 0; i < sg_count; i++) {
- page_buf = sg_page((&sgl[i]));
- if (page_buf != NULL)
- __free_page(page_buf);
- }
-
- kfree(sgl);
-}
-
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
-{
- int i;
-
- /* No need to check */
- if (sg_count < 2)
- return -1;
-
- /* We have at least 2 sg entries */
- for (i = 0; i < sg_count; i++) {
- if (i == 0) {
- /* make sure 1st one does not have hole */
- if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
- return i;
- } else if (i == sg_count - 1) {
- /* make sure last one does not have hole */
- if (sgl[i].offset != 0)
- return i;
- } else {
- /* make sure no hole in the middle */
- if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
- return i;
- }
- }
- return -1;
-}
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count,
- unsigned int len,
- int write)
-{
- int i;
- int num_pages;
- struct scatterlist *bounce_sgl;
- struct page *page_buf;
- unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
-
- num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
-
- bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
- if (!bounce_sgl)
- return NULL;
-
- sg_init_table(bounce_sgl, num_pages);
- for (i = 0; i < num_pages; i++) {
- page_buf = alloc_page(GFP_ATOMIC);
- if (!page_buf)
- goto cleanup;
- sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
- }
-
- return bounce_sgl;
-
-cleanup:
- destroy_bounce_buffer(bounce_sgl, num_pages);
- return NULL;
-}
-
-/* Assume the original sgl has enough room */
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count,
- unsigned int bounce_sgl_count)
-{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long dest_addr = 0;
- unsigned long flags;
- struct scatterlist *cur_dest_sgl;
- struct scatterlist *cur_src_sgl;
-
- local_irq_save(flags);
- cur_dest_sgl = orig_sgl;
- cur_src_sgl = bounce_sgl;
- for (i = 0; i < orig_sgl_count; i++) {
- dest_addr = (unsigned long)
- kmap_atomic(sg_page(cur_dest_sgl)) +
- cur_dest_sgl->offset;
- dest = dest_addr;
- destlen = cur_dest_sgl->length;
-
- if (bounce_addr == 0)
- bounce_addr = (unsigned long)kmap_atomic(
- sg_page(cur_src_sgl));
-
- while (destlen) {
- src = bounce_addr + cur_src_sgl->offset;
- srclen = cur_src_sgl->length - cur_src_sgl->offset;
-
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
-
- total_copied += copylen;
- cur_src_sgl->offset += copylen;
- destlen -= copylen;
- dest += copylen;
-
- if (cur_src_sgl->offset == cur_src_sgl->length) {
- /* full */
- kunmap_atomic((void *)bounce_addr);
- j++;
-
- /*
- * It is possible that the number of elements
- * in the bounce buffer may not be equal to
- * the number of elements in the original
- * scatter list. Handle this correctly.
- */
-
- if (j == bounce_sgl_count) {
- /*
- * We are done; cleanup and return.
- */
- kunmap_atomic((void *)(dest_addr -
- cur_dest_sgl->offset));
- local_irq_restore(flags);
- return total_copied;
- }
-
- /* if we need to use another bounce buffer */
- if (destlen || i != orig_sgl_count - 1) {
- cur_src_sgl = sg_next(cur_src_sgl);
- bounce_addr = (unsigned long)
- kmap_atomic(
- sg_page(cur_src_sgl));
- }
- } else if (destlen == 0 && i == orig_sgl_count - 1) {
- /* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr);
- }
- }
-
- kunmap_atomic((void *)(dest_addr - cur_dest_sgl->offset));
- cur_dest_sgl = sg_next(cur_dest_sgl);
- }
-
- local_irq_restore(flags);
-
- return total_copied;
-}
-
-/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
-static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count)
-{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long src_addr = 0;
- unsigned long flags;
- struct scatterlist *cur_src_sgl;
- struct scatterlist *cur_dest_sgl;
-
- local_irq_save(flags);
-
- cur_src_sgl = orig_sgl;
- cur_dest_sgl = bounce_sgl;
-
- for (i = 0; i < orig_sgl_count; i++) {
- src_addr = (unsigned long)
- kmap_atomic(sg_page(cur_src_sgl)) +
- cur_src_sgl->offset;
- src = src_addr;
- srclen = cur_src_sgl->length;
-
- if (bounce_addr == 0)
- bounce_addr = (unsigned long)
- kmap_atomic(sg_page(cur_dest_sgl));
-
- while (srclen) {
- /* assume bounce offset always == 0 */
- dest = bounce_addr + cur_dest_sgl->length;
- destlen = PAGE_SIZE - cur_dest_sgl->length;
-
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
-
- total_copied += copylen;
- cur_dest_sgl->length += copylen;
- srclen -= copylen;
- src += copylen;
-
- if (cur_dest_sgl->length == PAGE_SIZE) {
- /* full..move to next entry */
- kunmap_atomic((void *)bounce_addr);
- bounce_addr = 0;
- j++;
- }
-
- /* if we need to use another bounce buffer */
- if (srclen && bounce_addr == 0) {
- cur_dest_sgl = sg_next(cur_dest_sgl);
- bounce_addr = (unsigned long)
- kmap_atomic(
- sg_page(cur_dest_sgl));
- }
-
- }
-
- kunmap_atomic((void *)(src_addr - cur_src_sgl->offset));
- cur_src_sgl = sg_next(cur_src_sgl);
- }
-
- if (bounce_addr)
- kunmap_atomic((void *)bounce_addr);
-
- local_irq_restore(flags);
-
- return total_copied;
-}
-
static void handle_sc_creation(struct vmbus_channel *new_sc)
{
struct hv_device *device = new_sc->primary_channel->device_obj;
@@ -911,29 +704,36 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns)
vmbus_are_subchannels_present(device->channel);
}
-static int storvsc_channel_init(struct hv_device *device)
+static void cache_wwn(struct storvsc_device *stor_device,
+ struct vstor_packet *vstor_packet)
{
- struct storvsc_device *stor_device;
- struct storvsc_cmd_request *request;
- struct vstor_packet *vstor_packet;
- int ret, t, i;
- int max_chns;
- bool process_sub_channels = false;
+ /*
+ * Cache the currently active port and node ww names.
+ */
+ if (vstor_packet->wwn_packet.primary_active) {
+ stor_device->node_name =
+ wwn_to_u64(vstor_packet->wwn_packet.primary_node_wwn);
+ stor_device->port_name =
+ wwn_to_u64(vstor_packet->wwn_packet.primary_port_wwn);
+ } else {
+ stor_device->node_name =
+ wwn_to_u64(vstor_packet->wwn_packet.secondary_node_wwn);
+ stor_device->port_name =
+ wwn_to_u64(vstor_packet->wwn_packet.secondary_port_wwn);
+ }
+}
- stor_device = get_out_stor_device(device);
- if (!stor_device)
- return -ENODEV;
- request = &stor_device->init_request;
+static int storvsc_execute_vstor_op(struct hv_device *device,
+ struct storvsc_cmd_request *request,
+ bool status_check)
+{
+ struct vstor_packet *vstor_packet;
+ int ret, t;
+
vstor_packet = &request->vstor_packet;
- /*
- * Now, initiate the vsc/vsp initialization protocol on the open
- * channel
- */
- memset(request, 0, sizeof(struct storvsc_cmd_request));
init_completion(&request->wait_event);
- vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
ret = vmbus_sendpacket(device->channel, vstor_packet,
@@ -943,27 +743,56 @@ static int storvsc_channel_init(struct hv_device *device)
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
- goto cleanup;
+ return ret;
t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ if (t == 0)
+ return -ETIMEDOUT;
+
+ if (!status_check)
+ return ret;
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ vstor_packet->status != 0)
+ return -EINVAL;
+
+ return ret;
+}
+
+static int storvsc_channel_init(struct hv_device *device, bool is_fc)
+{
+ struct storvsc_device *stor_device;
+ struct storvsc_cmd_request *request;
+ struct vstor_packet *vstor_packet;
+ int ret, i;
+ int max_chns;
+ bool process_sub_channels = false;
+
+ stor_device = get_out_stor_device(device);
+ if (!stor_device)
+ return -ENODEV;
+ request = &stor_device->init_request;
+ vstor_packet = &request->vstor_packet;
+
+ /*
+ * Now, initiate the vsc/vsp initialization protocol on the open
+ * channel
+ */
+ memset(request, 0, sizeof(struct storvsc_cmd_request));
+ vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+ ret = storvsc_execute_vstor_op(device, request, true);
+ if (ret)
+ return ret;
+ /*
+ * Query host supported protocol version.
+ */
for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
/* reuse the packet for version range supported */
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation =
VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
vstor_packet->version.major_minor =
vmstor_protocols[i].protocol_version;
@@ -972,26 +801,12 @@ static int storvsc_channel_init(struct hv_device *device)
* The revision number is only used in Windows; set it to 0.
*/
vstor_packet->version.revision = 0;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = storvsc_execute_vstor_op(device, request, false);
if (ret != 0)
- goto cleanup;
+ return ret;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) {
- ret = -EINVAL;
- goto cleanup;
- }
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO)
+ return -EINVAL;
if (vstor_packet->status == 0) {
vmstor_proto_version =
@@ -1007,37 +822,15 @@ static int storvsc_channel_init(struct hv_device *device)
}
}
- if (vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ if (vstor_packet->status != 0)
+ return -EINVAL;
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
+ ret = storvsc_execute_vstor_op(device, request, true);
if (ret != 0)
- goto cleanup;
-
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ return ret;
/*
* Check to see if multi-channel support is there.
@@ -1053,37 +846,34 @@ static int storvsc_channel_init(struct hv_device *device)
stor_device->max_transfer_bytes =
vstor_packet->storage_channel_properties.max_transfer_bytes;
- memset(vstor_packet, 0, sizeof(struct vstor_packet));
- vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (!is_fc)
+ goto done;
+ /*
+ * For FC devices retrieve FC HBA data.
+ */
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_FCHBA_DATA;
+ ret = storvsc_execute_vstor_op(device, request, true);
if (ret != 0)
- goto cleanup;
+ return ret;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ /*
+ * Cache the currently active port and node ww names.
+ */
+ cache_wwn(stor_device, vstor_packet);
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+done:
+
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+ ret = storvsc_execute_vstor_op(device, request, true);
+ if (ret != 0)
+ return ret;
if (process_sub_channels)
handle_multichannel_storage(device, max_chns);
-
-cleanup:
return ret;
}
@@ -1096,7 +886,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
void (*process_err_fn)(struct work_struct *work);
bool do_work = false;
- switch (vm_srb->srb_status) {
+ switch (SRB_STATUS(vm_srb->srb_status)) {
case SRB_STATUS_ERROR:
/*
* If there is an error; offline the device since all
@@ -1124,8 +914,9 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
do_work = true;
process_err_fn = storvsc_remove_lun;
break;
- case (SRB_STATUS_ABORTED | SRB_STATUS_AUTOSENSE_VALID):
- if ((asc == 0x2a) && (ascq == 0x9)) {
+ case SRB_STATUS_ABORTED:
+ if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
+ (asc == 0x2a) && (ascq == 0x9)) {
do_work = true;
process_err_fn = storvsc_device_scan;
/*
@@ -1150,42 +941,32 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
wrk->host = host;
wrk->lun = vm_srb->lun;
+ wrk->tgt_id = vm_srb->target_id;
INIT_WORK(&wrk->work, process_err_fn);
schedule_work(&wrk->work);
}
-static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
+ struct storvsc_device *stor_dev)
{
struct scsi_cmnd *scmnd = cmd_request->cmd;
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
struct Scsi_Host *host;
- struct storvsc_device *stor_dev;
- struct hv_device *dev = host_dev->dev;
u32 payload_sz = cmd_request->payload_sz;
void *payload = cmd_request->payload;
- stor_dev = get_in_stor_device(dev);
host = stor_dev->host;
vm_srb = &cmd_request->vstor_packet.vm_srb;
- if (cmd_request->bounce_sgl_count) {
- if (vm_srb->data_in == READ_TYPE)
- copy_from_bounce_buffer(scsi_sglist(scmnd),
- cmd_request->bounce_sgl,
- scsi_sg_count(scmnd),
- cmd_request->bounce_sgl_count);
- destroy_bounce_buffer(cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
- }
scmnd->result = vm_srb->scsi_status;
if (scmnd->result) {
if (scsi_normalize_sense(scmnd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
+ do_logging(STORVSC_LOGGING_ERROR))
scsi_print_sense_hdr(scmnd->device, "storvsc",
&sense_hdr);
}
@@ -1205,14 +986,13 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
kfree(payload);
}
-static void storvsc_on_io_completion(struct hv_device *device,
+static void storvsc_on_io_completion(struct storvsc_device *stor_device,
struct vstor_packet *vstor_packet,
struct storvsc_cmd_request *request)
{
- struct storvsc_device *stor_device;
struct vstor_packet *stor_pkt;
+ struct hv_device *device = stor_device->device;
- stor_device = hv_get_drvdata(device);
stor_pkt = &request->vstor_packet;
/*
@@ -1239,6 +1019,13 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.sense_info_length =
vstor_packet->vm_srb.sense_info_length;
+ if (vstor_packet->vm_srb.scsi_status != 0 ||
+ vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS)
+ storvsc_log(device, STORVSC_LOGGING_WARN,
+ "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
+ stor_pkt->vm_srb.cdb[0],
+ vstor_packet->vm_srb.scsi_status,
+ vstor_packet->vm_srb.srb_status);
if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
/* CHECK_CONDITION */
@@ -1246,6 +1033,10 @@ static void storvsc_on_io_completion(struct hv_device *device,
SRB_STATUS_AUTOSENSE_VALID) {
/* autosense data available */
+ storvsc_log(device, STORVSC_LOGGING_WARN,
+ "stor pkt %p autosense data valid - len %d\n",
+ request, vstor_packet->vm_srb.sense_info_length);
+
memcpy(request->cmd->sense_buffer,
vstor_packet->vm_srb.sense_data,
vstor_packet->vm_srb.sense_info_length);
@@ -1256,7 +1047,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.data_transfer_length =
vstor_packet->vm_srb.data_transfer_length;
- storvsc_command_completion(request);
+ storvsc_command_completion(request, stor_device);
if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
stor_device->drain_notify)
@@ -1265,21 +1056,19 @@ static void storvsc_on_io_completion(struct hv_device *device,
}
-static void storvsc_on_receive(struct hv_device *device,
+static void storvsc_on_receive(struct storvsc_device *stor_device,
struct vstor_packet *vstor_packet,
struct storvsc_cmd_request *request)
{
struct storvsc_scan_work *work;
- struct storvsc_device *stor_device;
switch (vstor_packet->operation) {
case VSTOR_OPERATION_COMPLETE_IO:
- storvsc_on_io_completion(device, vstor_packet, request);
+ storvsc_on_io_completion(stor_device, vstor_packet, request);
break;
case VSTOR_OPERATION_REMOVE_DEVICE:
case VSTOR_OPERATION_ENUMERATE_BUS:
- stor_device = get_in_stor_device(device);
work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
if (!work)
return;
@@ -1289,6 +1078,13 @@ static void storvsc_on_receive(struct hv_device *device,
schedule_work(&work->work);
break;
+ case VSTOR_OPERATION_FCHBA_DATA:
+ cache_wwn(stor_device, vstor_packet);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_host_node_name(stor_device->host) = stor_device->node_name;
+ fc_host_port_name(stor_device->host) = stor_device->port_name;
+#endif
+ break;
default:
break;
}
@@ -1332,7 +1128,7 @@ static void storvsc_on_channel_callback(void *context)
vmscsi_size_delta));
complete(&request->wait_event);
} else {
- storvsc_on_receive(device,
+ storvsc_on_receive(stor_device,
(struct vstor_packet *)packet,
request);
}
@@ -1344,7 +1140,8 @@ static void storvsc_on_channel_callback(void *context)
return;
}
-static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
+static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
+ bool is_fc)
{
struct vmstorage_channel_properties props;
int ret;
@@ -1361,7 +1158,7 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
if (ret != 0)
return ret;
- ret = storvsc_channel_init(device);
+ ret = storvsc_channel_init(device, is_fc);
return ret;
}
@@ -1474,6 +1271,9 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ));
+ /* Ensure there are no gaps in presented sgls */
+ blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1);
+
sdevice->no_write_same = 1;
/*
@@ -1647,8 +1447,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
vm_srb->win8_extension.time_out_value = 60;
vm_srb->win8_extension.srb_flags |=
- (SRB_FLAGS_QUEUE_ACTION_ENABLE |
- SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
+ SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
/* Build the SRB */
switch (scmnd->sc_data_direction) {
@@ -1692,40 +1491,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
payload_sz = sizeof(cmd_request->mpb);
if (sg_count) {
- /* check if we need to bounce the sgl */
- if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
- cmd_request->bounce_sgl =
- create_bounce_buffer(sgl, sg_count,
- length,
- vm_srb->data_in);
- if (!cmd_request->bounce_sgl)
- return SCSI_MLQUEUE_HOST_BUSY;
-
- cmd_request->bounce_sgl_count =
- ALIGN(length, PAGE_SIZE) >> PAGE_SHIFT;
-
- if (vm_srb->data_in == WRITE_TYPE)
- copy_to_bounce_buffer(sgl,
- cmd_request->bounce_sgl, sg_count);
-
- sgl = cmd_request->bounce_sgl;
- sg_count = cmd_request->bounce_sgl_count;
- }
-
-
if (sg_count > MAX_PAGE_BUFFER_COUNT) {
payload_sz = (sg_count * sizeof(void *) +
sizeof(struct vmbus_packet_mpb_array));
payload = kmalloc(payload_sz, GFP_ATOMIC);
- if (!payload) {
- if (cmd_request->bounce_sgl_count)
- destroy_bounce_buffer(
- cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
-
- return SCSI_MLQUEUE_DEVICE_BUSY;
- }
+ if (!payload)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
}
payload->range.len = length;
@@ -1754,11 +1526,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
if (ret == -EAGAIN) {
/* no more space */
-
- if (cmd_request->bounce_sgl_count)
- destroy_bounce_buffer(cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
-
return SCSI_MLQUEUE_DEVICE_BUSY;
}
@@ -1816,6 +1583,7 @@ static int storvsc_probe(struct hv_device *device,
struct Scsi_Host *host;
struct hv_host_device *host_dev;
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
+ bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false);
int target = 0;
struct storvsc_device *stor_device;
int max_luns_per_target;
@@ -1873,7 +1641,7 @@ static int storvsc_probe(struct hv_device *device,
hv_set_drvdata(device, stor_device);
stor_device->port_number = host->host_no;
- ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
+ ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
if (ret)
goto err_out1;
@@ -1885,6 +1653,9 @@ static int storvsc_probe(struct hv_device *device,
host->max_lun = STORVSC_FC_MAX_LUNS_PER_TARGET;
host->max_id = STORVSC_FC_MAX_TARGETS;
host->max_channel = STORVSC_FC_MAX_CHANNELS - 1;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ host->transportt = fc_transport_template;
+#endif
break;
case SCSI_GUID:
@@ -1924,6 +1695,12 @@ static int storvsc_probe(struct hv_device *device,
goto err_out2;
}
}
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (host->transportt == fc_transport_template) {
+ fc_host_node_name(host) = stor_device->node_name;
+ fc_host_port_name(host) = stor_device->port_name;
+ }
+#endif
return 0;
err_out2:
@@ -1949,6 +1726,10 @@ static int storvsc_remove(struct hv_device *dev)
struct storvsc_device *stor_device = hv_get_drvdata(dev);
struct Scsi_Host *host = stor_device->host;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (host->transportt == fc_transport_template)
+ fc_remove_host(host);
+#endif
scsi_remove_host(host);
storvsc_dev_remove(dev);
scsi_host_put(host);
@@ -1963,8 +1744,16 @@ static struct hv_driver storvsc_drv = {
.remove = storvsc_remove,
};
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct fc_function_template fc_transport_functions = {
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+};
+#endif
+
static int __init storvsc_drv_init(void)
{
+ int ret;
/*
* Divide the ring buffer data size (which is 1 page less
@@ -1979,12 +1768,33 @@ static int __init storvsc_drv_init(void)
vmscsi_size_delta,
sizeof(u64)));
- return vmbus_driver_register(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_transport_template = fc_attach_transport(&fc_transport_functions);
+ if (!fc_transport_template)
+ return -ENODEV;
+
+ /*
+ * Install Hyper-V specific timeout handler.
+ */
+ fc_transport_template->eh_timed_out = storvsc_eh_timed_out;
+#endif
+
+ ret = vmbus_driver_register(&storvsc_drv);
+
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (ret)
+ fc_release_transport(fc_transport_template);
+#endif
+
+ return ret;
}
static void __exit storvsc_drv_exit(void)
{
vmbus_driver_unregister(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_release_transport(fc_transport_template);
+#endif
}
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 22a4283..b9de487 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -53,13 +53,12 @@
#define NCR5380_queue_command sun3scsi_queue_command
#define NCR5380_bus_reset sun3scsi_bus_reset
#define NCR5380_abort sun3scsi_abort
-#define NCR5380_show_info sun3scsi_show_info
#define NCR5380_info sun3scsi_info
#define NCR5380_dma_read_setup(instance, data, count) \
- sun3scsi_dma_setup(data, count, 0)
+ sun3scsi_dma_setup(instance, data, count, 0)
#define NCR5380_dma_write_setup(instance, data, count) \
- sun3scsi_dma_setup(data, count, 1)
+ sun3scsi_dma_setup(instance, data, count, 1)
#define NCR5380_dma_residual(instance) \
sun3scsi_dma_residual(instance)
#define NCR5380_dma_xfer_len(instance, cmd, phase) \
@@ -86,10 +85,6 @@ module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-/* #define RESET_BOOT */
-
-#define AFTER_RESET_DELAY (HZ/2)
-
/* ms to wait after hitting dma regs */
#define SUN3_DMA_DELAY 10
@@ -100,11 +95,10 @@ static struct scsi_cmnd *sun3_dma_setup_done;
static unsigned char *sun3_scsi_regp;
static volatile struct sun3_dma_regs *dregs;
static struct sun3_udc_regs *udc_regs;
-static unsigned char *sun3_dma_orig_addr = NULL;
-static unsigned long sun3_dma_orig_count = 0;
-static int sun3_dma_active = 0;
-static unsigned long last_residual = 0;
-static struct Scsi_Host *default_instance;
+static unsigned char *sun3_dma_orig_addr;
+static unsigned long sun3_dma_orig_count;
+static int sun3_dma_active;
+static unsigned long last_residual;
/*
* NCR 5380 register access functions
@@ -144,50 +138,12 @@ static inline void sun3_udc_write(unsigned short val, unsigned char reg)
}
#endif
-#ifdef RESET_BOOT
-static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
-{
- unsigned long end;
-
- /*
- * Do a SCSI reset to clean up the bus during initialization. No
- * messing with the queues, interrupts, or locks necessary here.
- */
-
- printk( "Sun3 SCSI: resetting the SCSI bus..." );
-
- /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-// sun3_disable_irq( IRQ_SUN3_SCSI );
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
-
- /* The min. reset hold time is 25us, so 40us should be enough */
- udelay( 50 );
-
- /* reset RST and interrupt */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
- for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
- barrier();
-
- /* switch on SCSI IRQ again */
-// sun3_enable_irq( IRQ_SUN3_SCSI );
-
- printk( " done\n" );
-}
-#endif
-
// safe bits for the CSR
#define CSR_GOOD 0x060f
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
+static irqreturn_t scsi_sun3_intr(int irq, void *dev)
{
+ struct Scsi_Host *instance = dev;
unsigned short csr = dregs->csr;
int handled = 0;
@@ -196,46 +152,24 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
#endif
if(csr & ~CSR_GOOD) {
- if(csr & CSR_DMA_BUSERR) {
- printk("scsi%d: bus error in dma\n", default_instance->host_no);
- }
-
- if(csr & CSR_DMA_CONFLICT) {
- printk("scsi%d: dma conflict\n", default_instance->host_no);
- }
+ if (csr & CSR_DMA_BUSERR)
+ shost_printk(KERN_ERR, instance, "bus error in DMA\n");
+ if (csr & CSR_DMA_CONFLICT)
+ shost_printk(KERN_ERR, instance, "DMA conflict\n");
handled = 1;
}
if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
- NCR5380_intr(irq, dummy);
+ NCR5380_intr(irq, dev);
handled = 1;
}
return IRQ_RETVAL(handled);
}
-/*
- * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
- * reentering NCR5380_print_status seems to have ugly side effects
- */
-
-/* this doesn't seem to get used at all -- sam */
-#if 0
-void sun3_sun3_debug (void)
-{
- unsigned long flags;
-
- if (default_instance) {
- local_irq_save(flags);
- NCR5380_print_status(default_instance);
- local_irq_restore(flags);
- }
-}
-#endif
-
-
/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
-static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
+static unsigned long sun3scsi_dma_setup(struct Scsi_Host *instance,
+ void *data, unsigned long count, int write_flag)
{
void *addr;
@@ -287,10 +221,9 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
dregs->csr |= CSR_FIFO;
if(dregs->fifo_count != count) {
- printk("scsi%d: fifo_mismatch %04x not %04x\n",
- default_instance->host_no, dregs->fifo_count,
- (unsigned int) count);
- NCR5380_dprint(NDEBUG_DMA, default_instance);
+ shost_printk(KERN_ERR, instance, "FIFO mismatch %04x not %04x\n",
+ dregs->fifo_count, (unsigned int) count);
+ NCR5380_dprint(NDEBUG_DMA, instance);
}
/* setup udc */
@@ -325,21 +258,6 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
}
-#ifndef SUN3_SCSI_VME
-static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
-{
- unsigned short resid;
-
- dregs->udc_addr = 0x32;
- udelay(SUN3_DMA_DELAY);
- resid = dregs->udc_data;
- udelay(SUN3_DMA_DELAY);
- resid *= 2;
-
- return (unsigned long) resid;
-}
-#endif
-
static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
{
return last_residual;
@@ -437,7 +355,10 @@ static int sun3scsi_dma_finish(int write_flag)
}
}
- count = sun3scsi_dma_count(default_instance);
+ dregs->udc_addr = 0x32;
+ udelay(SUN3_DMA_DELAY);
+ count = 2 * dregs->udc_data;
+ udelay(SUN3_DMA_DELAY);
fifo = dregs->fifo_count;
last_residual = fifo;
@@ -502,17 +423,17 @@ static int sun3scsi_dma_finish(int write_flag)
static struct scsi_host_template sun3_scsi_template = {
.module = THIS_MODULE,
.proc_name = DRV_MODULE_NAME,
- .show_info = sun3scsi_show_info,
.name = SUN3_SCSI_NAME,
.info = sun3scsi_info,
.queuecommand = sun3scsi_queue_command,
- .eh_abort_handler = sun3scsi_abort,
- .eh_bus_reset_handler = sun3scsi_bus_reset,
+ .eh_abort_handler = sun3scsi_abort,
+ .eh_bus_reset_handler = sun3scsi_bus_reset,
.can_queue = 16,
.this_id = 7,
.sg_tablesize = SG_NONE,
.cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
};
static int __init sun3_scsi_probe(struct platform_device *pdev)
@@ -591,7 +512,6 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
error = -ENOMEM;
goto fail_alloc;
}
- default_instance = instance;
instance->io_port = (unsigned long)ioaddr;
instance->irq = irq->start;
@@ -600,7 +520,9 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
#endif
- NCR5380_init(instance, host_flags);
+ error = NCR5380_init(instance, host_flags);
+ if (error)
+ goto fail_init;
error = request_irq(instance->irq, scsi_sun3_intr, 0,
"NCR5380", instance);
@@ -631,9 +553,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
#endif
-#ifdef RESET_BOOT
- sun3_scsi_reset_boot(instance);
-#endif
+ NCR5380_maybe_reset_bus(instance);
error = scsi_add_host(instance, NULL);
if (error)
@@ -649,6 +569,7 @@ fail_host:
free_irq(instance->irq, instance);
fail_irq:
NCR5380_exit(instance);
+fail_init:
scsi_host_put(instance);
fail_alloc:
if (udc_regs)
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 87828ac..4615fda 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -68,14 +68,11 @@
* 15 9-11
*/
-#include <linux/signal.h>
#include <linux/io.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
-#include <linux/stat.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include "t128.h"
@@ -126,7 +123,7 @@ static struct signature {
static int __init t128_setup(char *str)
{
- static int commandline_current = 0;
+ static int commandline_current;
int i;
int ints[10];
@@ -165,7 +162,7 @@ __setup("t128=", t128_setup);
static int __init t128_detect(struct scsi_host_template *tpnt)
{
- static int current_override = 0, current_base = 0;
+ static int current_override, current_base;
struct Scsi_Host *instance;
unsigned long base;
void __iomem *p;
@@ -182,9 +179,8 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
base = 0;
} else
for (; !base && (current_base < NO_BASES); ++current_base) {
-#if (TDEBUG & TDEBUG_INIT)
- printk("scsi-t128 : probing address %08x\n", bases[current_base].address);
-#endif
+ dprintk(NDEBUG_INIT, "t128: probing address 0x%08x\n",
+ bases[current_base].address);
if (bases[current_base].noauto)
continue;
p = ioremap(bases[current_base].address, 0x2000);
@@ -195,17 +191,13 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
signatures[sig].string,
strlen(signatures[sig].string))) {
base = bases[current_base].address;
-#if (TDEBUG & TDEBUG_INIT)
- printk("scsi-t128 : detected board.\n");
-#endif
+ dprintk(NDEBUG_INIT, "t128: detected board\n");
goto found;
}
iounmap(p);
}
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
- printk("scsi-t128 : base = %08x\n", (unsigned int) base);
-#endif
+ dprintk(NDEBUG_INIT, "t128: base = 0x%08x\n", (unsigned int)base);
if (!base)
break;
@@ -213,12 +205,15 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
found:
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
if(instance == NULL)
- break;
-
+ goto out_unmap;
+
instance->base = base;
((struct NCR5380_hostdata *)instance->hostdata)->base = p;
- NCR5380_init(instance, 0);
+ if (NCR5380_init(instance, 0))
+ goto out_unregister;
+
+ NCR5380_maybe_reset_bus(instance);
if (overrides[current_override].irq != IRQ_AUTO)
instance->irq = overrides[current_override].irq;
@@ -242,27 +237,30 @@ found:
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
- printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+ dprintk(NDEBUG_INIT, "scsi%d: irq = %d\n",
+ instance->host_no, instance->irq);
++current_override;
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out_unmap:
+ iounmap(p);
+ return count;
}
static int t128_release(struct Scsi_Host *shost)
{
- NCR5380_local_declare();
- NCR5380_setup(shost);
+ struct NCR5380_hostdata *hostdata = shost_priv(shost);
+
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
scsi_unregister(shost);
- iounmap(base);
+ iounmap(hostdata->base);
return 0;
}
@@ -308,14 +306,14 @@ static int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev,
* timeout.
*/
-static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
- int len) {
- NCR5380_local_declare();
- void __iomem *reg;
+static inline int
+NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ void __iomem *reg, *base = hostdata->base;
unsigned char *d = dst;
register int i = len;
- NCR5380_setup(instance);
reg = base + T_DATA_REG_OFFSET;
#if 0
@@ -354,14 +352,14 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
* timeout.
*/
-static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
- int len) {
- NCR5380_local_declare();
- void __iomem *reg;
+static inline int
+NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ void __iomem *reg, *base = hostdata->base;
unsigned char *s = src;
register int i = len;
- NCR5380_setup(instance);
reg = base + T_DATA_REG_OFFSET;
#if 0
@@ -392,21 +390,23 @@ MODULE_LICENSE("GPL");
#include "NCR5380.c"
static struct scsi_host_template driver_template = {
- .name = "Trantor T128/T128F/T228",
- .detect = t128_detect,
- .release = t128_release,
- .proc_name = "t128",
- .show_info = t128_show_info,
- .write_info = t128_write_info,
- .info = t128_info,
- .queuecommand = t128_queue_command,
- .eh_abort_handler = t128_abort,
- .eh_bus_reset_handler = t128_bus_reset,
- .bios_param = t128_biosparam,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .name = "Trantor T128/T128F/T228",
+ .detect = t128_detect,
+ .release = t128_release,
+ .proc_name = "t128",
+ .show_info = t128_show_info,
+ .write_info = t128_write_info,
+ .info = t128_info,
+ .queuecommand = t128_queue_command,
+ .eh_abort_handler = t128_abort,
+ .eh_bus_reset_handler = t128_bus_reset,
+ .bios_param = t128_biosparam,
+ .can_queue = 32,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 2c73714..dd16d85 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -23,10 +23,6 @@
#ifndef T128_H
#define T128_H
-#define TDEBUG 0
-#define TDEBUG_INIT 0x1
-#define TDEBUG_TRANSFER 0x2
-
/*
* The trantor boards are memory mapped. They use an NCR5380 or
* equivalent (my sample board had part second sourced from ZILOG).
@@ -71,44 +67,18 @@
#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
-#endif
-
#define NCR5380_implementation_fields \
void __iomem *base
-#define NCR5380_local_declare() \
- void __iomem *base
-
-#define NCR5380_setup(instance) \
- base = ((struct NCR5380_hostdata *)(instance->hostdata))->base
+#define T128_address(reg) \
+ (((struct NCR5380_hostdata *)shost_priv(instance))->base + T_5380_OFFSET + ((reg) * 0x20))
-#define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20))
-
-#if !(TDEBUG & TDEBUG_TRANSFER)
#define NCR5380_read(reg) readb(T128_address(reg))
#define NCR5380_write(reg, value) writeb((value),(T128_address(reg)))
-#else
-#define NCR5380_read(reg) \
- (((unsigned char) printk("scsi%d : read register %d at address %08x\n"\
- , instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg)))
-
-#define NCR5380_write(reg, value) { \
- printk("scsi%d : write %02x to register %d at address %08x\n", \
- instance->hostno, (value), (reg), T128_address(reg)); \
- writeb((value), (T128_address(reg))); \
-}
-#endif
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_intr t128_intr
-#define do_NCR5380_intr do_t128_intr
#define NCR5380_queue_command t128_queue_command
#define NCR5380_abort t128_abort
#define NCR5380_bus_reset t128_bus_reset
@@ -121,5 +91,4 @@
#define T128_IRQS 0xc4a8
-#endif /* ndef ASM */
#endif /* T128_H */
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index e945383..097894a 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -37,6 +37,7 @@ config SCSI_UFSHCD
depends on SCSI && SCSI_DMA
select PM_DEVFREQ
select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ select NLS
---help---
This selects the support for UFS devices in Linux, say Y and make
sure that you know the name of your UFS host adapter (the card
@@ -72,7 +73,7 @@ config SCSI_UFSHCD_PLATFORM
If unsure, say N.
config SCSI_UFS_QCOM
- bool "QCOM specific hooks to UFS controller platform driver"
+ tristate "QCOM specific hooks to UFS controller platform driver"
depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
select PHY_QCOM_UFS
help
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 4cdffa4..3aedf73 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, Linux Foundation. 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 and
@@ -16,19 +16,53 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
-
#include <linux/phy/phy-qcom-ufs.h>
+
#include "ufshcd.h"
+#include "ufshcd-pltfrm.h"
#include "unipro.h"
#include "ufs-qcom.h"
#include "ufshci.h"
+#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
+ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+
+enum {
+ TSTBUS_UAWM,
+ TSTBUS_UARM,
+ TSTBUS_TXUC,
+ TSTBUS_RXUC,
+ TSTBUS_DFC,
+ TSTBUS_TRLUT,
+ TSTBUS_TMRLUT,
+ TSTBUS_OCSC,
+ TSTBUS_UTP_HCI,
+ TSTBUS_COMBINED,
+ TSTBUS_WRAPPER,
+ TSTBUS_UNIPRO,
+ TSTBUS_MAX,
+};
static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
-static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result);
-static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
- const char *speed_mode);
static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote);
+static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
+static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
+ u32 clk_cycles);
+
+static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len,
+ char *prefix)
+{
+ print_hex_dump(KERN_ERR, prefix,
+ len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE,
+ 16, 4, (void __force *)hba->mmio_base + offset,
+ len * 4, false);
+}
+
+static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len,
+ char *prefix, void *priv)
+{
+ ufs_qcom_dump_regs(hba, offset, len, prefix);
+}
static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
{
@@ -78,9 +112,11 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
if (!host->is_lane_clks_enabled)
return;
- clk_disable_unprepare(host->tx_l1_sync_clk);
+ if (host->hba->lanes_per_direction > 1)
+ clk_disable_unprepare(host->tx_l1_sync_clk);
clk_disable_unprepare(host->tx_l0_sync_clk);
- clk_disable_unprepare(host->rx_l1_sync_clk);
+ if (host->hba->lanes_per_direction > 1)
+ clk_disable_unprepare(host->rx_l1_sync_clk);
clk_disable_unprepare(host->rx_l0_sync_clk);
host->is_lane_clks_enabled = false;
@@ -104,21 +140,24 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
if (err)
goto disable_rx_l0;
- err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
- host->rx_l1_sync_clk);
- if (err)
- goto disable_tx_l0;
+ if (host->hba->lanes_per_direction > 1) {
+ err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+ host->rx_l1_sync_clk);
+ if (err)
+ goto disable_tx_l0;
- err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
- host->tx_l1_sync_clk);
- if (err)
- goto disable_rx_l1;
+ err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+ host->tx_l1_sync_clk);
+ if (err)
+ goto disable_rx_l1;
+ }
host->is_lane_clks_enabled = true;
goto out;
disable_rx_l1:
- clk_disable_unprepare(host->rx_l1_sync_clk);
+ if (host->hba->lanes_per_direction > 1)
+ clk_disable_unprepare(host->rx_l1_sync_clk);
disable_tx_l0:
clk_disable_unprepare(host->tx_l0_sync_clk);
disable_rx_l0:
@@ -142,20 +181,23 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
if (err)
goto out;
- err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
- &host->rx_l1_sync_clk);
- if (err)
- goto out;
+ /* In case of single lane per direction, don't read lane1 clocks */
+ if (host->hba->lanes_per_direction > 1) {
+ err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
+ &host->rx_l1_sync_clk);
+ if (err)
+ goto out;
- err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
- &host->tx_l1_sync_clk);
+ err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
+ &host->tx_l1_sync_clk);
+ }
out:
return err;
}
static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
u32 tx_lanes;
int err = 0;
@@ -181,7 +223,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
do {
err = ufshcd_dme_get(hba,
- UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val);
+ UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+ &tx_fsm_val);
if (err || tx_fsm_val == TX_FSM_HIBERN8)
break;
@@ -195,7 +239,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
*/
if (time_after(jiffies, timeout))
err = ufshcd_dme_get(hba,
- UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val);
+ UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+ &tx_fsm_val);
if (err) {
dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
@@ -209,9 +255,18 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
return err;
}
+static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host)
+{
+ ufshcd_rmwl(host->hba, QUNIPRO_SEL,
+ ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0,
+ REG_UFS_CFG1);
+ /* make sure above configuration is applied before we return */
+ mb();
+}
+
static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int ret = 0;
bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
@@ -223,6 +278,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
usleep_range(1000, 1100);
ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B);
+
if (ret) {
dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n",
__func__, ret);
@@ -246,9 +302,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
ret = ufs_qcom_phy_is_pcs_ready(phy);
if (ret)
- dev_err(hba->dev, "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n",
+ dev_err(hba->dev,
+ "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n",
__func__, ret);
+ ufs_qcom_select_unipro_mode(host);
+
out:
return ret;
}
@@ -271,9 +330,10 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)
mb();
}
-static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
+static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err = 0;
switch (status) {
@@ -301,13 +361,13 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
}
/**
- * Returns non-zero for success (which rate of core_clk) and 0
- * in case of a failure
+ * Returns zero for success and non-zero in case of a failure
*/
-static unsigned long
-ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
+static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
+ u32 hs, u32 rate, bool update_link_startup_timer)
{
- struct ufs_qcom_host *host = hba->priv;
+ int ret = 0;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct ufs_clk_info *clki;
u32 core_clk_period_in_ns;
u32 tx_clk_cycles_per_us = 0;
@@ -324,11 +384,13 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
static u32 hs_fr_table_rA[][2] = {
{UFS_HS_G1, 0x1F},
{UFS_HS_G2, 0x3e},
+ {UFS_HS_G3, 0x7D},
};
static u32 hs_fr_table_rB[][2] = {
{UFS_HS_G1, 0x24},
{UFS_HS_G2, 0x49},
+ {UFS_HS_G3, 0x92},
};
/*
@@ -356,7 +418,17 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
core_clk_rate = DEFAULT_CLK_RATE_HZ;
core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC;
- ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
+ if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) {
+ ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
+ /*
+ * make sure above write gets applied before we return from
+ * this function.
+ */
+ mb();
+ }
+
+ if (ufs_qcom_cap_qunipro(host))
+ goto out;
core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate;
core_clk_period_in_ns <<= OFFSET_CLK_NS_REG;
@@ -406,35 +478,71 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
goto out_error;
}
- /* this register 2 fields shall be written at once */
- ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us,
- REG_UFS_TX_SYMBOL_CLK_NS_US);
+ if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) !=
+ (core_clk_period_in_ns | tx_clk_cycles_per_us)) {
+ /* this register 2 fields shall be written at once */
+ ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us,
+ REG_UFS_TX_SYMBOL_CLK_NS_US);
+ /*
+ * make sure above write gets applied before we return from
+ * this function.
+ */
+ mb();
+ }
+
+ if (update_link_startup_timer) {
+ ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100),
+ REG_UFS_PA_LINK_STARTUP_TIMER);
+ /*
+ * make sure that this configuration is applied before
+ * we return
+ */
+ mb();
+ }
goto out;
out_error:
- core_clk_rate = 0;
+ ret = -EINVAL;
out:
- return core_clk_rate;
+ return ret;
}
-static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status)
+static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
{
- unsigned long core_clk_rate = 0;
- u32 core_clk_cycles_per_100ms;
+ int err = 0;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
switch (status) {
case PRE_CHANGE:
- core_clk_rate = ufs_qcom_cfg_timers(hba, UFS_PWM_G1,
- SLOWAUTO_MODE, 0);
- if (!core_clk_rate) {
+ if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE,
+ 0, true)) {
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
__func__);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- core_clk_cycles_per_100ms =
- (core_clk_rate / MSEC_PER_SEC) * 100;
- ufshcd_writel(hba, core_clk_cycles_per_100ms,
- REG_UFS_PA_LINK_STARTUP_TIMER);
+
+ if (ufs_qcom_cap_qunipro(host))
+ /*
+ * set unipro core clock cycles to 150 & clear clock
+ * divider
+ */
+ err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba,
+ 150);
+
+ /*
+ * Some UFS devices (and may be host) have issues if LCC is
+ * enabled. So we are setting PA_Local_TX_LCC_Enable to 0
+ * before link startup which will make sure that both host
+ * and device TX LCC are disabled once link startup is
+ * completed.
+ */
+ if (ufshcd_get_local_unipro_ver(hba) != UFS_UNIPRO_VER_1_41)
+ err = ufshcd_dme_set(hba,
+ UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE),
+ 0);
+
break;
case POST_CHANGE:
ufs_qcom_link_startup_post_change(hba);
@@ -443,12 +551,13 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status)
break;
}
- return 0;
+out:
+ return err;
}
static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int ret = 0;
@@ -470,8 +579,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
* If UniPro link is not active, PHY ref_clk, main PHY analog power
* rail and low noise analog power rail for PLL can be switched off.
*/
- if (!ufs_qcom_is_link_active(hba))
+ if (!ufs_qcom_is_link_active(hba)) {
+ ufs_qcom_disable_lane_clks(host);
phy_power_off(phy);
+ }
out:
return ret;
@@ -479,7 +590,7 @@ out:
static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int err;
@@ -490,6 +601,10 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
goto out;
}
+ err = ufs_qcom_enable_lane_clks(host);
+ if (err)
+ goto out;
+
hba->is_sys_suspended = false;
out:
@@ -594,6 +709,81 @@ static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param,
return 0;
}
+#ifdef CONFIG_MSM_BUS_SCALING
+static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
+ const char *speed_mode)
+{
+ struct device *dev = host->hba->dev;
+ struct device_node *np = dev->of_node;
+ int err;
+ const char *key = "qcom,bus-vector-names";
+
+ if (!speed_mode) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN"))
+ err = of_property_match_string(np, key, "MAX");
+ else
+ err = of_property_match_string(np, key, speed_mode);
+
+out:
+ if (err < 0)
+ dev_err(dev, "%s: Invalid %s mode %d\n",
+ __func__, speed_mode, err);
+ return err;
+}
+
+static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result)
+{
+ int gear = max_t(u32, p->gear_rx, p->gear_tx);
+ int lanes = max_t(u32, p->lane_rx, p->lane_tx);
+ int pwr;
+
+ /* default to PWM Gear 1, Lane 1 if power mode is not initialized */
+ if (!gear)
+ gear = 1;
+
+ if (!lanes)
+ lanes = 1;
+
+ if (!p->pwr_rx && !p->pwr_tx) {
+ pwr = SLOWAUTO_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "MIN");
+ } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE ||
+ p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) {
+ pwr = FAST_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS",
+ p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes);
+ } else {
+ pwr = SLOW_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d",
+ "PWM", gear, lanes);
+ }
+}
+
+static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+{
+ int err = 0;
+
+ if (vote != host->bus_vote.curr_vote) {
+ err = msm_bus_scale_client_update_request(
+ host->bus_vote.client_handle, vote);
+ if (err) {
+ dev_err(host->hba->dev,
+ "%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n",
+ __func__, host->bus_vote.client_handle,
+ vote, err);
+ goto out;
+ }
+
+ host->bus_vote.curr_vote = vote;
+ }
+out:
+ return err;
+}
+
static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
{
int vote;
@@ -615,13 +805,137 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
return err;
}
+static ssize_t
+show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ host->bus_vote.is_max_bw_needed);
+}
+
+static ssize_t
+store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ uint32_t value;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ host->bus_vote.is_max_bw_needed = !!value;
+ ufs_qcom_update_bus_bw_vote(host);
+ }
+
+ return count;
+}
+
+static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
+{
+ int err;
+ struct msm_bus_scale_pdata *bus_pdata;
+ struct device *dev = host->hba->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *np = dev->of_node;
+
+ bus_pdata = msm_bus_cl_get_pdata(pdev);
+ if (!bus_pdata) {
+ dev_err(dev, "%s: failed to get bus vectors\n", __func__);
+ err = -ENODATA;
+ goto out;
+ }
+
+ err = of_property_count_strings(np, "qcom,bus-vector-names");
+ if (err < 0 || err != bus_pdata->num_usecases) {
+ dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ host->bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata);
+ if (!host->bus_vote.client_handle) {
+ dev_err(dev, "%s: msm_bus_scale_register_client failed\n",
+ __func__);
+ err = -EFAULT;
+ goto out;
+ }
+
+ /* cache the vote index for minimum and maximum bandwidth */
+ host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN");
+ host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX");
+
+ host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw;
+ host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw;
+ sysfs_attr_init(&host->bus_vote.max_bus_bw.attr);
+ host->bus_vote.max_bus_bw.attr.name = "max_bus_bw";
+ host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+ err = device_create_file(dev, &host->bus_vote.max_bus_bw);
+out:
+ return err;
+}
+#else /* CONFIG_MSM_BUS_SCALING */
+static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
+{
+ return 0;
+}
+
+static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+{
+ return 0;
+}
+
+static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
+{
+ return 0;
+}
+#endif /* CONFIG_MSM_BUS_SCALING */
+
+static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
+{
+ if (host->dev_ref_clk_ctrl_mmio &&
+ (enable ^ host->is_dev_ref_clk_enabled)) {
+ u32 temp = readl_relaxed(host->dev_ref_clk_ctrl_mmio);
+
+ if (enable)
+ temp |= host->dev_ref_clk_en_mask;
+ else
+ temp &= ~host->dev_ref_clk_en_mask;
+
+ /*
+ * If we are here to disable this clock it might be immediately
+ * after entering into hibern8 in which case we need to make
+ * sure that device ref_clk is active at least 1us after the
+ * hibern8 enter.
+ */
+ if (!enable)
+ udelay(1);
+
+ writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio);
+
+ /* ensure that ref_clk is enabled/disabled before we return */
+ wmb();
+
+ /*
+ * If we call hibern8 exit after this, we need to make sure that
+ * device ref_clk is stable for at least 1us before the hibern8
+ * exit command.
+ */
+ if (enable)
+ udelay(1);
+
+ host->is_dev_ref_clk_enabled = enable;
+ }
+}
+
static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
- bool status,
+ enum ufs_notify_change_status status,
struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
u32 val;
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
struct ufs_qcom_dev_params ufs_qcom_cap;
int ret = 0;
@@ -649,6 +963,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
ufs_qcom_cap.desired_working_mode =
UFS_QCOM_LIMIT_DESIRED_MODE;
+ if (host->hw_ver.major == 0x1) {
+ /*
+ * HS-G3 operations may not reliably work on legacy QCOM
+ * UFS host controller hardware even though capability
+ * exchange during link startup phase may end up
+ * negotiating maximum supported gear as G3.
+ * Hence downgrade the maximum supported gear to HS-G2.
+ */
+ if (ufs_qcom_cap.hs_tx_gear > UFS_HS_G2)
+ ufs_qcom_cap.hs_tx_gear = UFS_HS_G2;
+ if (ufs_qcom_cap.hs_rx_gear > UFS_HS_G2)
+ ufs_qcom_cap.hs_rx_gear = UFS_HS_G2;
+ }
+
ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap,
dev_max_params,
dev_req_params);
@@ -658,11 +986,15 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
goto out;
}
+ /* enable the device ref clock before changing to HS mode */
+ if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
+ ufshcd_is_hs_mode(dev_req_params))
+ ufs_qcom_dev_ref_clk_ctrl(host, true);
break;
case POST_CHANGE:
- if (!ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
+ if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
dev_req_params->pwr_rx,
- dev_req_params->hs_rate)) {
+ dev_req_params->hs_rate, false)) {
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
__func__);
/*
@@ -685,6 +1017,11 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
memcpy(&host->dev_req_params,
dev_req_params, sizeof(*dev_req_params));
ufs_qcom_update_bus_bw_vote(host);
+
+ /* disable the device ref clock if entered PWM mode */
+ if (ufshcd_is_hs_mode(&hba->pwr_info) &&
+ !ufshcd_is_hs_mode(dev_req_params))
+ ufs_qcom_dev_ref_clk_ctrl(host, false);
break;
default:
ret = -EINVAL;
@@ -696,7 +1033,7 @@ out:
static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
if (host->hw_ver.major == 0x1)
return UFSHCI_VERSION_11;
@@ -715,7 +1052,7 @@ static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
*/
static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
if (host->hw_ver.major == 0x01) {
hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
@@ -724,10 +1061,11 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001)
hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR;
+
+ hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
}
if (host->hw_ver.major >= 0x2) {
- hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
if (!ufs_qcom_cap_qunipro(host))
@@ -740,79 +1078,29 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
static void ufs_qcom_set_caps(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
-
- if (host->hw_ver.major >= 0x2)
- host->caps = UFS_QCOM_CAP_QUNIPRO;
-}
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
- const char *speed_mode)
-{
- struct device *dev = host->hba->dev;
- struct device_node *np = dev->of_node;
- int err;
- const char *key = "qcom,bus-vector-names";
-
- if (!speed_mode) {
- err = -EINVAL;
- goto out;
- }
-
- if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN"))
- err = of_property_match_string(np, key, "MAX");
- else
- err = of_property_match_string(np, key, speed_mode);
-
-out:
- if (err < 0)
- dev_err(dev, "%s: Invalid %s mode %d\n",
- __func__, speed_mode, err);
- return err;
-}
-
-static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
-{
- int err = 0;
-
- if (vote != host->bus_vote.curr_vote)
- host->bus_vote.curr_vote = vote;
-
- return err;
-}
-
-static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result)
-{
- int gear = max_t(u32, p->gear_rx, p->gear_tx);
- int lanes = max_t(u32, p->lane_rx, p->lane_tx);
- int pwr;
-
- /* default to PWM Gear 1, Lane 1 if power mode is not initialized */
- if (!gear)
- gear = 1;
-
- if (!lanes)
- lanes = 1;
+ hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
+ hba->caps |= UFSHCD_CAP_CLK_SCALING;
+ hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
- if (!p->pwr_rx && !p->pwr_tx) {
- pwr = SLOWAUTO_MODE;
- snprintf(result, BUS_VECTOR_NAME_LEN, "MIN");
- } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE ||
- p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) {
- pwr = FAST_MODE;
- snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS",
- p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes);
- } else {
- pwr = SLOW_MODE;
- snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d",
- "PWM", gear, lanes);
+ if (host->hw_ver.major >= 0x2) {
+ host->caps = UFS_QCOM_CAP_QUNIPRO |
+ UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE;
}
}
+/**
+ * ufs_qcom_setup_clocks - enables/disable clocks
+ * @hba: host controller instance
+ * @on: If true, enable clocks else disable them.
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
{
- struct ufs_qcom_host *host = hba->priv;
- int err = 0;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ int err;
int vote = 0;
/*
@@ -835,20 +1123,21 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
goto out;
}
- /* enable the device ref clock */
- ufs_qcom_phy_enable_dev_ref_clk(host->generic_phy);
+ /* enable the device ref clock for HS mode*/
+ if (ufshcd_is_hs_mode(&hba->pwr_info))
+ ufs_qcom_dev_ref_clk_ctrl(host, true);
vote = host->bus_vote.saved_vote;
if (vote == host->bus_vote.min_bw_vote)
ufs_qcom_update_bus_bw_vote(host);
+
} else {
+
/* M-PHY RMMI interface clocks can be turned off */
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
- if (!ufs_qcom_is_link_active(hba)) {
- /* turn off UFS local PHY ref_clk */
- ufs_qcom_phy_disable_ref_clk(host->generic_phy);
+ if (!ufs_qcom_is_link_active(hba))
/* disable device ref_clk */
- ufs_qcom_phy_disable_dev_ref_clk(host->generic_phy);
- }
+ ufs_qcom_dev_ref_clk_ctrl(host, false);
+
vote = host->bus_vote.min_bw_vote;
}
@@ -861,68 +1150,17 @@ out:
return err;
}
-static ssize_t
-show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ufs_hba *hba = dev_get_drvdata(dev);
- struct ufs_qcom_host *host = hba->priv;
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- host->bus_vote.is_max_bw_needed);
-}
-
-static ssize_t
-store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ufs_hba *hba = dev_get_drvdata(dev);
- struct ufs_qcom_host *host = hba->priv;
- uint32_t value;
-
- if (!kstrtou32(buf, 0, &value)) {
- host->bus_vote.is_max_bw_needed = !!value;
- ufs_qcom_update_bus_bw_vote(host);
- }
-
- return count;
-}
-
-static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
-{
- int err;
- struct device *dev = host->hba->dev;
- struct device_node *np = dev->of_node;
-
- err = of_property_count_strings(np, "qcom,bus-vector-names");
- if (err < 0 ) {
- dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n",
- __func__, err);
- goto out;
- }
-
- /* cache the vote index for minimum and maximum bandwidth */
- host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN");
- host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX");
-
- host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw;
- host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw;
- sysfs_attr_init(&host->bus_vote.max_bus_bw.attr);
- host->bus_vote.max_bus_bw.attr.name = "max_bus_bw";
- host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
- err = device_create_file(dev, &host->bus_vote.max_bus_bw);
-out:
- return err;
-}
-
#define ANDROID_BOOT_DEV_MAX 30
static char android_boot_dev[ANDROID_BOOT_DEV_MAX];
-static int get_android_boot_dev(char *str)
+
+#ifndef MODULE
+static int __init get_android_boot_dev(char *str)
{
strlcpy(android_boot_dev, str, ANDROID_BOOT_DEV_MAX);
return 1;
}
__setup("androidboot.bootdevice=", get_android_boot_dev);
+#endif
/**
* ufs_qcom_init - bind phy with controller
@@ -938,7 +1176,9 @@ static int ufs_qcom_init(struct ufs_hba *hba)
{
int err;
struct device *dev = hba->dev;
+ struct platform_device *pdev = to_platform_device(dev);
struct ufs_qcom_host *host;
+ struct resource *res;
if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev)))
return -ENODEV;
@@ -950,9 +1190,15 @@ static int ufs_qcom_init(struct ufs_hba *hba)
goto out;
}
+ /* Make a two way bind between the qcom host and the hba */
host->hba = hba;
- hba->priv = (void *)host;
+ ufshcd_set_variant(hba, host);
+ /*
+ * voting/devoting device ref_clk source is time consuming hence
+ * skip devoting it during aggressive clock gating. This clock
+ * will still be gated off during runtime suspend.
+ */
host->generic_phy = devm_phy_get(dev, "ufsphy");
if (IS_ERR(host->generic_phy)) {
@@ -968,6 +1214,30 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_get_controller_revision(hba, &host->hw_ver.major,
&host->hw_ver.minor, &host->hw_ver.step);
+ /*
+ * for newer controllers, device reference clock control bit has
+ * moved inside UFS controller register address space itself.
+ */
+ if (host->hw_ver.major >= 0x02) {
+ host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1;
+ host->dev_ref_clk_en_mask = BIT(26);
+ } else {
+ /* "dev_ref_clk_ctrl_mem" is optional resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ host->dev_ref_clk_ctrl_mmio =
+ devm_ioremap_resource(dev, res);
+ if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) {
+ dev_warn(dev,
+ "%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n",
+ __func__,
+ PTR_ERR(host->dev_ref_clk_ctrl_mmio));
+ host->dev_ref_clk_ctrl_mmio = NULL;
+ }
+ host->dev_ref_clk_en_mask = BIT(5);
+ }
+ }
+
/* update phy revision information before calling phy_init() */
ufs_qcom_phy_save_controller_version(host->generic_phy,
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
@@ -984,14 +1254,20 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
- hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING;
- hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
-
ufs_qcom_setup_clocks(hba, true);
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
+ host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN;
+ ufs_qcom_get_default_testbus_cfg(host);
+ err = ufs_qcom_testbus_config(host);
+ if (err) {
+ dev_warn(dev, "%s: failed to configure the testbus %d\n",
+ __func__, err);
+ err = 0;
+ }
+
goto out;
out_disable_phy:
@@ -1000,31 +1276,328 @@ out_unregister_bus:
phy_exit(host->generic_phy);
out_host_free:
devm_kfree(dev, host);
- hba->priv = NULL;
+ ufshcd_set_variant(hba, NULL);
out:
return err;
}
static void ufs_qcom_exit(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
ufs_qcom_disable_lane_clks(host);
phy_power_off(host->generic_phy);
}
-static
-void ufs_qcom_clk_scale_notify(struct ufs_hba *hba)
+static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
+ u32 clk_cycles)
+{
+ int err;
+ u32 core_clk_ctrl_reg;
+
+ if (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK)
+ return -EINVAL;
+
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ &core_clk_ctrl_reg);
+ if (err)
+ goto out;
+
+ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK;
+ core_clk_ctrl_reg |= clk_cycles;
+
+ /* Clear CORE_CLK_DIV_EN */
+ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
+
+ err = ufshcd_dme_set(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ core_clk_ctrl_reg);
+out:
+ return err;
+}
+
+static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
+{
+ /* nothing to do as of now */
+ return 0;
+}
+
+static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ if (!ufs_qcom_cap_qunipro(host))
+ return 0;
+
+ /* set unipro core clock cycles to 150 and clear clock divider */
+ return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150);
+}
+
+static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ int err;
+ u32 core_clk_ctrl_reg;
+
+ if (!ufs_qcom_cap_qunipro(host))
+ return 0;
+
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ &core_clk_ctrl_reg);
+
+ /* make sure CORE_CLK_DIV_EN is cleared */
+ if (!err &&
+ (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) {
+ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
+ err = ufshcd_dme_set(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ core_clk_ctrl_reg);
+ }
+
+ return err;
+}
+
+static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ if (!ufs_qcom_cap_qunipro(host))
+ return 0;
+
+ /* set unipro core clock cycles to 75 and clear clock divider */
+ return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75);
+}
+
+static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
+ bool scale_up, enum ufs_notify_change_status status)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;
+ int err = 0;
+
+ if (status == PRE_CHANGE) {
+ if (scale_up)
+ err = ufs_qcom_clk_scale_up_pre_change(hba);
+ else
+ err = ufs_qcom_clk_scale_down_pre_change(hba);
+ } else {
+ if (scale_up)
+ err = ufs_qcom_clk_scale_up_post_change(hba);
+ else
+ err = ufs_qcom_clk_scale_down_post_change(hba);
- if (!dev_req_params)
+ if (err || !dev_req_params)
+ goto out;
+
+ ufs_qcom_cfg_timers(hba,
+ dev_req_params->gear_rx,
+ dev_req_params->pwr_rx,
+ dev_req_params->hs_rate,
+ false);
+ ufs_qcom_update_bus_bw_vote(host);
+ }
+
+out:
+ return err;
+}
+
+static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba,
+ void *priv, void (*print_fn)(struct ufs_hba *hba,
+ int offset, int num_regs, char *str, void *priv))
+{
+ u32 reg;
+ struct ufs_qcom_host *host;
+
+ if (unlikely(!hba)) {
+ pr_err("%s: hba is NULL\n", __func__);
+ return;
+ }
+ if (unlikely(!print_fn)) {
+ dev_err(hba->dev, "%s: print_fn is NULL\n", __func__);
+ return;
+ }
+
+ host = ufshcd_get_variant(hba);
+ if (!(host->dbg_print_en & UFS_QCOM_DBG_PRINT_REGS_EN))
return;
- ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
- dev_req_params->pwr_rx,
- dev_req_params->hs_rate);
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_REG_OCSC);
+ print_fn(hba, reg, 44, "UFS_UFS_DBG_RD_REG_OCSC ", priv);
+
+ reg = ufshcd_readl(hba, REG_UFS_CFG1);
+ reg |= UFS_BIT(17);
+ ufshcd_writel(hba, reg, REG_UFS_CFG1);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_EDTL_RAM);
+ print_fn(hba, reg, 32, "UFS_UFS_DBG_RD_EDTL_RAM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_DESC_RAM);
+ print_fn(hba, reg, 128, "UFS_UFS_DBG_RD_DESC_RAM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM);
+ print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv);
+
+ ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM);
+ print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UARM);
+ print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UARM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TXUC);
+ print_fn(hba, reg, 48, "UFS_DBG_RD_REG_TXUC ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_RXUC);
+ print_fn(hba, reg, 27, "UFS_DBG_RD_REG_RXUC ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_DFC);
+ print_fn(hba, reg, 19, "UFS_DBG_RD_REG_DFC ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TRLUT);
+ print_fn(hba, reg, 34, "UFS_DBG_RD_REG_TRLUT ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT);
+ print_fn(hba, reg, 9, "UFS_DBG_RD_REG_TMRLUT ", priv);
+}
+
+static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
+{
+ if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+ ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
+ else
+ ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+}
+
+static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
+{
+ /* provide a legal default configuration */
+ host->testbus.select_major = TSTBUS_UAWM;
+ host->testbus.select_minor = 1;
+}
+
+static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
+{
+ if (host->testbus.select_major >= TSTBUS_MAX) {
+ dev_err(host->hba->dev,
+ "%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n",
+ __func__, host->testbus.select_major);
+ return false;
+ }
+
+ /*
+ * Not performing check for each individual select_major
+ * mappings of select_minor, since there is no harm in
+ * configuring a non-existent select_minor
+ */
+ if (host->testbus.select_minor > 0x1F) {
+ dev_err(host->hba->dev,
+ "%s: 0x%05X is not a legal testbus option\n",
+ __func__, host->testbus.select_minor);
+ return false;
+ }
+
+ return true;
+}
+
+int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
+{
+ int reg;
+ int offset;
+ u32 mask = TEST_BUS_SUB_SEL_MASK;
+
+ if (!host)
+ return -EINVAL;
+
+ if (!ufs_qcom_testbus_cfg_is_ok(host))
+ return -EPERM;
+
+ switch (host->testbus.select_major) {
+ case TSTBUS_UAWM:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 24;
+ break;
+ case TSTBUS_UARM:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 16;
+ break;
+ case TSTBUS_TXUC:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 8;
+ break;
+ case TSTBUS_RXUC:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 0;
+ break;
+ case TSTBUS_DFC:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 24;
+ break;
+ case TSTBUS_TRLUT:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 16;
+ break;
+ case TSTBUS_TMRLUT:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 8;
+ break;
+ case TSTBUS_OCSC:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 0;
+ break;
+ case TSTBUS_WRAPPER:
+ reg = UFS_TEST_BUS_CTRL_2;
+ offset = 16;
+ break;
+ case TSTBUS_COMBINED:
+ reg = UFS_TEST_BUS_CTRL_2;
+ offset = 8;
+ break;
+ case TSTBUS_UTP_HCI:
+ reg = UFS_TEST_BUS_CTRL_2;
+ offset = 0;
+ break;
+ case TSTBUS_UNIPRO:
+ reg = UFS_UNIPRO_CFG;
+ offset = 1;
+ break;
+ /*
+ * No need for a default case, since
+ * ufs_qcom_testbus_cfg_is_ok() checks that the configuration
+ * is legal
+ */
+ }
+ mask <<= offset;
+
+ pm_runtime_get_sync(host->hba->dev);
+ ufshcd_hold(host->hba, false);
+ ufshcd_rmwl(host->hba, TEST_BUS_SEL,
+ (u32)host->testbus.select_major << 19,
+ REG_UFS_CFG1);
+ ufshcd_rmwl(host->hba, mask,
+ (u32)host->testbus.select_minor << offset,
+ reg);
+ ufs_qcom_enable_test_bus(host);
+ ufshcd_release(host->hba);
+ pm_runtime_put_sync(host->hba->dev);
+
+ return 0;
+}
+
+static void ufs_qcom_testbus_read(struct ufs_hba *hba)
+{
+ ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
+}
+
+static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
+{
+ ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
+ "HCI Vendor Specific Registers ");
+
+ ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+ ufs_qcom_testbus_read(hba);
}
/**
@@ -1033,7 +1606,7 @@ void ufs_qcom_clk_scale_notify(struct ufs_hba *hba)
* The variant operations configure the necessary controller and PHY
* handshake during initialization.
*/
-static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
+static struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.name = "qcom",
.init = ufs_qcom_init,
.exit = ufs_qcom_exit,
@@ -1045,5 +1618,66 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.pwr_change_notify = ufs_qcom_pwr_change_notify,
.suspend = ufs_qcom_suspend,
.resume = ufs_qcom_resume,
+ .dbg_register_dump = ufs_qcom_dump_dbg_regs,
};
-EXPORT_SYMBOL(ufs_hba_qcom_vops);
+
+/**
+ * ufs_qcom_probe - probe routine of the driver
+ * @pdev: pointer to Platform device handle
+ *
+ * Return zero for success and non-zero for failure
+ */
+static int ufs_qcom_probe(struct platform_device *pdev)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+
+ /* Perform generic probe */
+ err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops);
+ if (err)
+ dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
+
+ return err;
+}
+
+/**
+ * ufs_qcom_remove - set driver_data of the device to NULL
+ * @pdev: pointer to platform device handle
+ *
+ * Always returns 0
+ */
+static int ufs_qcom_remove(struct platform_device *pdev)
+{
+ struct ufs_hba *hba = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&(pdev)->dev);
+ ufshcd_remove(hba);
+ return 0;
+}
+
+static const struct of_device_id ufs_qcom_of_match[] = {
+ { .compatible = "qcom,ufshc"},
+ {},
+};
+
+static const struct dev_pm_ops ufs_qcom_pm_ops = {
+ .suspend = ufshcd_pltfrm_suspend,
+ .resume = ufshcd_pltfrm_resume,
+ .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
+ .runtime_resume = ufshcd_pltfrm_runtime_resume,
+ .runtime_idle = ufshcd_pltfrm_runtime_idle,
+};
+
+static struct platform_driver ufs_qcom_pltform = {
+ .probe = ufs_qcom_probe,
+ .remove = ufs_qcom_remove,
+ .shutdown = ufshcd_pltfrm_shutdown,
+ .driver = {
+ .name = "ufshcd-qcom",
+ .pm = &ufs_qcom_pm_ops,
+ .of_match_table = of_match_ptr(ufs_qcom_of_match),
+ },
+};
+module_platform_driver(ufs_qcom_pltform);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index db2c0a0..a19307a 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -35,8 +35,8 @@
#define UFS_QCOM_LIMIT_NUM_LANES_RX 2
#define UFS_QCOM_LIMIT_NUM_LANES_TX 2
-#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2
-#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2
+#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3
+#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3
#define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4
#define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4
#define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE
@@ -58,6 +58,21 @@ enum {
REG_UFS_CFG2 = 0xE0,
REG_UFS_HW_VERSION = 0xE4,
+ UFS_TEST_BUS = 0xE8,
+ UFS_TEST_BUS_CTRL_0 = 0xEC,
+ UFS_TEST_BUS_CTRL_1 = 0xF0,
+ UFS_TEST_BUS_CTRL_2 = 0xF4,
+ UFS_UNIPRO_CFG = 0xF8,
+
+ /*
+ * QCOM UFS host controller vendor specific registers
+ * added in HW Version 3.0.0
+ */
+ UFS_AH8_CFG = 0xFC,
+};
+
+/* QCOM UFS host controller vendor specific debug registers */
+enum {
UFS_DBG_RD_REG_UAWM = 0x100,
UFS_DBG_RD_REG_UARM = 0x200,
UFS_DBG_RD_REG_TXUC = 0x300,
@@ -73,6 +88,14 @@ enum {
UFS_UFS_DBG_RD_EDTL_RAM = 0x1900,
};
+#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x)
+#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x)
+
+/* bit definitions for REG_UFS_CFG1 register */
+#define QUNIPRO_SEL UFS_BIT(0)
+#define TEST_BUS_EN BIT(18)
+#define TEST_BUS_SEL GENMASK(22, 19)
+
/* bit definitions for REG_UFS_CFG2 register */
#define UAWM_HW_CGC_EN (1 << 0)
#define UARM_HW_CGC_EN (1 << 1)
@@ -83,6 +106,9 @@ enum {
#define TMRLUT_HW_CGC_EN (1 << 6)
#define OCSC_HW_CGC_EN (1 << 7)
+/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */
+#define TEST_BUS_SUB_SEL_MASK 0x1F /* All XXX_SEL fields are 5 bits wide */
+
#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\
@@ -106,6 +132,21 @@ enum ufs_qcom_phy_init_type {
UFS_PHY_INIT_CFG_RESTORE,
};
+/* QCOM UFS debug print bit mask */
+#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
+#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1)
+#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN BIT(2)
+
+#define UFS_QCOM_DBG_PRINT_ALL \
+ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \
+ UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+
+/* QUniPro Vendor specific attributes */
+#define DME_VS_CORE_CLK_CTRL 0xD002
+/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
+#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
+#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF
+
static inline void
ufs_qcom_get_controller_revision(struct ufs_hba *hba,
u8 *major, u16 *minor, u16 *step)
@@ -157,8 +198,13 @@ struct ufs_hw_version {
u16 minor;
u8 major;
};
-struct ufs_qcom_host {
+struct ufs_qcom_testbus {
+ u8 select_major;
+ u8 select_minor;
+};
+
+struct ufs_qcom_host {
/*
* Set this capability if host controller supports the QUniPro mode
* and if driver wants the Host controller to operate in QUniPro mode.
@@ -166,6 +212,12 @@ struct ufs_qcom_host {
* controller supports the QUniPro mode.
*/
#define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0)
+
+ /*
+ * Set this capability if host controller can retain the secure
+ * configuration even after UFS controller core power collapse.
+ */
+ #define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE UFS_BIT(1)
u32 caps;
struct phy *generic_phy;
@@ -178,13 +230,32 @@ struct ufs_qcom_host {
struct clk *tx_l1_sync_clk;
bool is_lane_clks_enabled;
+ void __iomem *dev_ref_clk_ctrl_mmio;
+ bool is_dev_ref_clk_enabled;
struct ufs_hw_version hw_ver;
+
+ u32 dev_ref_clk_en_mask;
+
+ /* Bitmask for enabling debug prints */
+ u32 dbg_print_en;
+ struct ufs_qcom_testbus testbus;
+};
+
+static inline u32
+ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg)
+{
+ if (host->hw_ver.major <= 0x02)
+ return UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(reg);
+
+ return UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(reg);
};
#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
+int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
+
static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host)
{
if (host->caps & UFS_QCOM_CAP_QUNIPRO)
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 42c459a..b291fa6 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -43,6 +43,7 @@
#define GENERAL_UPIU_REQUEST_SIZE 32
#define QUERY_DESC_MAX_SIZE 255
#define QUERY_DESC_MIN_SIZE 2
+#define QUERY_DESC_HDR_SIZE 2
#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \
(sizeof(struct utp_upiu_header)))
@@ -170,7 +171,7 @@ enum ufs_desc_max_size {
* of descriptor header.
*/
QUERY_DESC_STRING_MAX_SIZE = 0xFE,
- QUERY_DESC_GEOMETRY_MAZ_SIZE = 0x44,
+ QUERY_DESC_GEOMETRY_MAX_SIZE = 0x44,
QUERY_DESC_POWER_MAX_SIZE = 0x62,
QUERY_DESC_RFU_MAX_SIZE = 0x00,
};
@@ -195,6 +196,37 @@ enum unit_desc_param {
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
};
+/* Device descriptor parameters offsets in bytes*/
+enum device_desc_param {
+ DEVICE_DESC_PARAM_LEN = 0x0,
+ DEVICE_DESC_PARAM_TYPE = 0x1,
+ DEVICE_DESC_PARAM_DEVICE_TYPE = 0x2,
+ DEVICE_DESC_PARAM_DEVICE_CLASS = 0x3,
+ DEVICE_DESC_PARAM_DEVICE_SUB_CLASS = 0x4,
+ DEVICE_DESC_PARAM_PRTCL = 0x5,
+ DEVICE_DESC_PARAM_NUM_LU = 0x6,
+ DEVICE_DESC_PARAM_NUM_WLU = 0x7,
+ DEVICE_DESC_PARAM_BOOT_ENBL = 0x8,
+ DEVICE_DESC_PARAM_DESC_ACCSS_ENBL = 0x9,
+ DEVICE_DESC_PARAM_INIT_PWR_MODE = 0xA,
+ DEVICE_DESC_PARAM_HIGH_PR_LUN = 0xB,
+ DEVICE_DESC_PARAM_SEC_RMV_TYPE = 0xC,
+ DEVICE_DESC_PARAM_SEC_LU = 0xD,
+ DEVICE_DESC_PARAM_BKOP_TERM_LT = 0xE,
+ DEVICE_DESC_PARAM_ACTVE_ICC_LVL = 0xF,
+ DEVICE_DESC_PARAM_SPEC_VER = 0x10,
+ DEVICE_DESC_PARAM_MANF_DATE = 0x12,
+ DEVICE_DESC_PARAM_MANF_NAME = 0x14,
+ DEVICE_DESC_PARAM_PRDCT_NAME = 0x15,
+ DEVICE_DESC_PARAM_SN = 0x16,
+ DEVICE_DESC_PARAM_OEM_ID = 0x17,
+ DEVICE_DESC_PARAM_MANF_ID = 0x18,
+ DEVICE_DESC_PARAM_UD_OFFSET = 0x1A,
+ DEVICE_DESC_PARAM_UD_LEN = 0x1B,
+ DEVICE_DESC_PARAM_RTT_CAP = 0x1C,
+ DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
+};
+
/*
* Logical Unit Write Protect
* 00h: LU not write protected
@@ -469,6 +501,7 @@ struct ufs_vreg {
struct regulator *reg;
const char *name;
bool enabled;
+ bool unused;
int min_uV;
int max_uV;
int min_uA;
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
new file mode 100644
index 0000000..ee4ab85
--- /dev/null
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014-2016, The Linux Foundation. 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 and
+ * only 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 _UFS_QUIRKS_H_
+#define _UFS_QUIRKS_H_
+
+/* return true if s1 is a prefix of s2 */
+#define STR_PRFX_EQUAL(s1, s2) !strncmp(s1, s2, strlen(s1))
+
+#define UFS_ANY_VENDOR 0xFFFF
+#define UFS_ANY_MODEL "ANY_MODEL"
+
+#define MAX_MODEL_LEN 16
+
+#define UFS_VENDOR_TOSHIBA 0x198
+#define UFS_VENDOR_SAMSUNG 0x1CE
+
+/**
+ * ufs_device_info - ufs device details
+ * @wmanufacturerid: card details
+ * @model: card model
+ */
+struct ufs_device_info {
+ u16 wmanufacturerid;
+ char model[MAX_MODEL_LEN + 1];
+};
+
+/**
+ * ufs_dev_fix - ufs device quirk info
+ * @card: ufs card details
+ * @quirk: device quirk
+ */
+struct ufs_dev_fix {
+ struct ufs_device_info card;
+ unsigned int quirk;
+};
+
+#define END_FIX { { 0 }, 0 }
+
+/* add specific device quirk */
+#define UFS_FIX(_vendor, _model, _quirk) \
+ { \
+ .card.wmanufacturerid = (_vendor),\
+ .card.model = (_model), \
+ .quirk = (_quirk), \
+ }
+
+/*
+ * If UFS device is having issue in processing LCC (Line Control
+ * Command) coming from UFS host controller then enable this quirk.
+ * When this quirk is enabled, host controller driver should disable
+ * the LCC transmission on UFS host controller (by clearing
+ * TX_LCC_ENABLE attribute of host to 0).
+ */
+#define UFS_DEVICE_QUIRK_BROKEN_LCC (1 << 0)
+
+/*
+ * Some UFS devices don't need VCCQ rail for device operations. Enabling this
+ * quirk for such devices will make sure that VCCQ rail is not voted.
+ */
+#define UFS_DEVICE_NO_VCCQ (1 << 1)
+
+/*
+ * Some vendor's UFS device sends back to back NACs for the DL data frames
+ * causing the host controller to raise the DFES error status. Sometimes
+ * such UFS devices send back to back NAC without waiting for new
+ * retransmitted DL frame from the host and in such cases it might be possible
+ * the Host UniPro goes into bad state without raising the DFES error
+ * interrupt. If this happens then all the pending commands would timeout
+ * only after respective SW command (which is generally too large).
+ *
+ * We can workaround such device behaviour like this:
+ * - As soon as SW sees the DL NAC error, it should schedule the error handler
+ * - Error handler would sleep for 50ms to see if there are any fatal errors
+ * raised by UFS controller.
+ * - If there are fatal errors then SW does normal error recovery.
+ * - If there are no fatal errors then SW sends the NOP command to device
+ * to check if link is alive.
+ * - If NOP command times out, SW does normal error recovery
+ * - If NOP command succeed, skip the error handling.
+ *
+ * If DL NAC error is seen multiple times with some vendor's UFS devices then
+ * enable this quirk to initiate quick error recovery and also silence related
+ * error logs to reduce spamming of kernel logs.
+ */
+#define UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS (1 << 2)
+
+/*
+ * Some UFS devices may not work properly after resume if the link was kept
+ * in off state during suspend. Enabling this quirk will not allow the
+ * link to be kept in off state during suspend.
+ */
+#define UFS_DEVICE_QUIRK_NO_LINK_OFF (1 << 3)
+
+/*
+ * Few Toshiba UFS device models advertise RX_MIN_ACTIVATETIME_CAPABILITY as
+ * 600us which may not be enough for reliable hibern8 exit hardware sequence
+ * from UFS device.
+ * To workaround this issue, host should set its PA_TACTIVATE time to 1ms even
+ * if device advertises RX_MIN_ACTIVATETIME_CAPABILITY less than 1ms.
+ */
+#define UFS_DEVICE_QUIRK_PA_TACTIVATE (1 << 4)
+
+/*
+ * Some UFS memory devices may have really low read/write throughput in
+ * FAST AUTO mode, enable this quirk to make sure that FAST AUTO mode is
+ * never enabled for such devices.
+ */
+#define UFS_DEVICE_NO_FASTAUTO (1 << 5)
+
+/*
+ * It seems some UFS devices may keep drawing more than sleep current
+ * (atleast for 500us) from UFS rails (especially from VCCQ rail).
+ * To avoid this situation, add 2ms delay before putting these UFS
+ * rails in LPM mode.
+ */
+#define UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM (1 << 6)
+
+struct ufs_hba;
+void ufs_advertise_fixup_device(struct ufs_hba *hba);
+
+static struct ufs_dev_fix ufs_fixups[] = {
+ /* UFS cards deviations table */
+ UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+ UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
+ UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
+ UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+ UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
+ UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
+ UFS_DEVICE_NO_FASTAUTO),
+ UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL,
+ UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
+ UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
+ UFS_DEVICE_QUIRK_PA_TACTIVATE),
+ UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG",
+ UFS_DEVICE_QUIRK_PA_TACTIVATE),
+
+ END_FIX
+};
+#endif /* UFS_QUIRKS_H_ */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7db9564..718f12e 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -38,20 +38,9 @@
#include <linux/of.h>
#include "ufshcd.h"
+#include "ufshcd-pltfrm.h"
-static const struct of_device_id ufs_of_match[];
-static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
-{
- if (dev->of_node) {
- const struct of_device_id *match;
-
- match = of_match_node(ufs_of_match, dev->of_node);
- if (match)
- return (struct ufs_hba_variant_ops *)match->data;
- }
-
- return NULL;
-}
+#define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2
static int ufshcd_parse_clock_info(struct ufs_hba *hba)
{
@@ -245,10 +234,11 @@ out:
* Returns 0 if successful
* Returns non-zero otherwise
*/
-static int ufshcd_pltfrm_suspend(struct device *dev)
+int ufshcd_pltfrm_suspend(struct device *dev)
{
return ufshcd_system_suspend(dev_get_drvdata(dev));
}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_suspend);
/**
* ufshcd_pltfrm_resume - resume power management function
@@ -257,43 +247,62 @@ static int ufshcd_pltfrm_suspend(struct device *dev)
* Returns 0 if successful
* Returns non-zero otherwise
*/
-static int ufshcd_pltfrm_resume(struct device *dev)
+int ufshcd_pltfrm_resume(struct device *dev)
{
return ufshcd_system_resume(dev_get_drvdata(dev));
}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_resume);
-static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
+int ufshcd_pltfrm_runtime_suspend(struct device *dev)
{
return ufshcd_runtime_suspend(dev_get_drvdata(dev));
}
-static int ufshcd_pltfrm_runtime_resume(struct device *dev)
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_suspend);
+
+int ufshcd_pltfrm_runtime_resume(struct device *dev)
{
return ufshcd_runtime_resume(dev_get_drvdata(dev));
}
-static int ufshcd_pltfrm_runtime_idle(struct device *dev)
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_resume);
+
+int ufshcd_pltfrm_runtime_idle(struct device *dev)
{
return ufshcd_runtime_idle(dev_get_drvdata(dev));
}
-#else /* !CONFIG_PM */
-#define ufshcd_pltfrm_suspend NULL
-#define ufshcd_pltfrm_resume NULL
-#define ufshcd_pltfrm_runtime_suspend NULL
-#define ufshcd_pltfrm_runtime_resume NULL
-#define ufshcd_pltfrm_runtime_idle NULL
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle);
+
#endif /* CONFIG_PM */
-static void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
+void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
{
ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev));
}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown);
+
+static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
+{
+ struct device *dev = hba->dev;
+ int ret;
+
+ ret = of_property_read_u32(dev->of_node, "lanes-per-direction",
+ &hba->lanes_per_direction);
+ if (ret) {
+ dev_dbg(hba->dev,
+ "%s: failed to read lanes-per-direction, ret=%d\n",
+ __func__, ret);
+ hba->lanes_per_direction = UFSHCD_DEFAULT_LANES_PER_DIRECTION;
+ }
+}
/**
- * ufshcd_pltfrm_probe - probe routine of the driver
+ * ufshcd_pltfrm_init - probe routine of the driver
* @pdev: pointer to Platform device handle
+ * @vops: pointer to variant ops
*
* Returns 0 on success, non-zero value on failure
*/
-static int ufshcd_pltfrm_probe(struct platform_device *pdev)
+int ufshcd_pltfrm_init(struct platform_device *pdev,
+ struct ufs_hba_variant_ops *vops)
{
struct ufs_hba *hba;
void __iomem *mmio_base;
@@ -321,27 +330,29 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
goto out;
}
- hba->vops = get_variant_ops(&pdev->dev);
+ hba->vops = vops;
err = ufshcd_parse_clock_info(hba);
if (err) {
dev_err(&pdev->dev, "%s: clock parse failed %d\n",
__func__, err);
- goto out;
+ goto dealloc_host;
}
err = ufshcd_parse_regulator_info(hba);
if (err) {
dev_err(&pdev->dev, "%s: regulator init failed %d\n",
__func__, err);
- goto out;
+ goto dealloc_host;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ ufshcd_init_lanes_per_dir(hba);
+
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
- dev_err(dev, "Intialization failed\n");
+ dev_err(dev, "Initialization failed\n");
goto out_disable_rpm;
}
@@ -352,50 +363,12 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
out_disable_rpm:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+dealloc_host:
+ ufshcd_dealloc_host(hba);
out:
return err;
}
-
-/**
- * ufshcd_pltfrm_remove - remove platform driver routine
- * @pdev: pointer to platform device handle
- *
- * Returns 0 on success, non-zero value on failure
- */
-static int ufshcd_pltfrm_remove(struct platform_device *pdev)
-{
- struct ufs_hba *hba = platform_get_drvdata(pdev);
-
- pm_runtime_get_sync(&(pdev)->dev);
- ufshcd_remove(hba);
- return 0;
-}
-
-static const struct of_device_id ufs_of_match[] = {
- { .compatible = "jedec,ufs-1.1"},
- {},
-};
-
-static const struct dev_pm_ops ufshcd_dev_pm_ops = {
- .suspend = ufshcd_pltfrm_suspend,
- .resume = ufshcd_pltfrm_resume,
- .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
- .runtime_resume = ufshcd_pltfrm_runtime_resume,
- .runtime_idle = ufshcd_pltfrm_runtime_idle,
-};
-
-static struct platform_driver ufshcd_pltfrm_driver = {
- .probe = ufshcd_pltfrm_probe,
- .remove = ufshcd_pltfrm_remove,
- .shutdown = ufshcd_pltfrm_shutdown,
- .driver = {
- .name = "ufshcd",
- .pm = &ufshcd_dev_pm_ops,
- .of_match_table = ufs_of_match,
- },
-};
-
-module_platform_driver(ufshcd_pltfrm_driver);
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h
new file mode 100644
index 0000000..df64c41
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2015, The Linux Foundation. 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 and
+ * only 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 UFSHCD_PLTFRM_H_
+#define UFSHCD_PLTFRM_H_
+
+#include "ufshcd.h"
+
+int ufshcd_pltfrm_init(struct platform_device *pdev,
+ struct ufs_hba_variant_ops *vops);
+void ufshcd_pltfrm_shutdown(struct platform_device *pdev);
+
+#ifdef CONFIG_PM
+
+int ufshcd_pltfrm_suspend(struct device *dev);
+int ufshcd_pltfrm_resume(struct device *dev);
+int ufshcd_pltfrm_runtime_suspend(struct device *dev);
+int ufshcd_pltfrm_runtime_resume(struct device *dev);
+int ufshcd_pltfrm_runtime_idle(struct device *dev);
+
+#else /* !CONFIG_PM */
+
+#define ufshcd_pltfrm_suspend NULL
+#define ufshcd_pltfrm_resume NULL
+#define ufshcd_pltfrm_runtime_suspend NULL
+#define ufshcd_pltfrm_runtime_resume NULL
+#define ufshcd_pltfrm_runtime_idle NULL
+
+#endif /* CONFIG_PM */
+
+#endif /* UFSHCD_PLTFRM_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b0ade73..f8fa72c 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.c
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -39,8 +39,10 @@
#include <linux/async.h>
#include <linux/devfreq.h>
-
+#include <linux/nls.h>
+#include <linux/of.h>
#include "ufshcd.h"
+#include "ufs_quirks.h"
#include "unipro.h"
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
@@ -58,13 +60,25 @@
#define QUERY_REQ_RETRIES 10
/* Query request timeout */
#define QUERY_REQ_TIMEOUT 30 /* msec */
+/*
+ * Query request timeout for fDeviceInit flag
+ * fDeviceInit query response time for some devices is too large that default
+ * QUERY_REQ_TIMEOUT may not be enough for such devices.
+ */
+#define QUERY_FDEVICEINIT_REQ_TIMEOUT 600 /* msec */
/* Task management command timeout */
#define TM_CMD_TIMEOUT 100 /* msecs */
+/* maximum number of retries for a general UIC command */
+#define UFS_UIC_COMMAND_RETRIES 3
+
/* maximum number of link-startup retries */
#define DME_LINKSTARTUP_RETRIES 3
+/* Maximum retries for Hibern8 enter */
+#define UIC_HIBERN8_ENTER_RETRIES 3
+
/* maximum number of reset retries before giving up */
#define MAX_HOST_RESET_RETRIES 5
@@ -92,7 +106,7 @@ static u32 ufs_query_desc_max_size[] = {
QUERY_DESC_INTERCONNECT_MAX_SIZE,
QUERY_DESC_STRING_MAX_SIZE,
QUERY_DESC_RFU_MAX_SIZE,
- QUERY_DESC_GEOMETRY_MAZ_SIZE,
+ QUERY_DESC_GEOMETRY_MAX_SIZE,
QUERY_DESC_POWER_MAX_SIZE,
QUERY_DESC_RFU_MAX_SIZE,
};
@@ -119,9 +133,11 @@ enum {
/* UFSHCD UIC layer error flags */
enum {
UFSHCD_UIC_DL_PA_INIT_ERROR = (1 << 0), /* Data link layer error */
- UFSHCD_UIC_NL_ERROR = (1 << 1), /* Network layer error */
- UFSHCD_UIC_TL_ERROR = (1 << 2), /* Transport Layer error */
- UFSHCD_UIC_DME_ERROR = (1 << 3), /* DME error */
+ UFSHCD_UIC_DL_NAC_RECEIVED_ERROR = (1 << 1), /* Data link layer error */
+ UFSHCD_UIC_DL_TCx_REPLAY_ERROR = (1 << 2), /* Data link layer error */
+ UFSHCD_UIC_NL_ERROR = (1 << 3), /* Network layer error */
+ UFSHCD_UIC_TL_ERROR = (1 << 4), /* Transport Layer error */
+ UFSHCD_UIC_DME_ERROR = (1 << 5), /* DME error */
};
/* Interrupt configuration options */
@@ -181,6 +197,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba);
static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
bool skip_ref_clk);
static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
+static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused);
static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
@@ -190,6 +207,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode);
static int ufshcd_change_power_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *pwr_mode);
+static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
+{
+ return tag >= 0 && tag < hba->nutrs;
+}
static inline int ufshcd_enable_irq(struct ufs_hba *hba)
{
@@ -215,6 +236,16 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
}
}
+/* replace non-printable or non-ASCII characters with spaces */
+static inline void ufshcd_remove_non_printable(char *val)
+{
+ if (!val)
+ return;
+
+ if (*val < 0x20 || *val > 0x7e)
+ *val = ' ';
+}
+
/*
* ufshcd_wait_for_register - wait for register value to change
* @hba - per-adapter interface
@@ -223,11 +254,13 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
* @val - wait condition
* @interval_us - polling interval in microsecs
* @timeout_ms - timeout in millisecs
+ * @can_sleep - perform sleep or just spin
*
* Returns -ETIMEDOUT on error, zero on success
*/
-static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
- u32 val, unsigned long interval_us, unsigned long timeout_ms)
+int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+ u32 val, unsigned long interval_us,
+ unsigned long timeout_ms, bool can_sleep)
{
int err = 0;
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
@@ -236,9 +269,10 @@ static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
val = val & mask;
while ((ufshcd_readl(hba, reg) & mask) != val) {
- /* wakeup within 50us of expiry */
- usleep_range(interval_us, interval_us + 50);
-
+ if (can_sleep)
+ usleep_range(interval_us, interval_us + 50);
+ else
+ udelay(interval_us);
if (time_after(jiffies, timeout)) {
if ((ufshcd_readl(hba, reg) & mask) != val)
err = -ETIMEDOUT;
@@ -271,10 +305,8 @@ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
*/
static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
{
- if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION) {
- if (hba->vops && hba->vops->get_ufs_hci_version)
- return hba->vops->get_ufs_hci_version(hba);
- }
+ if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION)
+ return ufshcd_vops_get_ufs_hci_version(hba);
return ufshcd_readl(hba, REG_UFS_VERSION);
}
@@ -362,6 +394,16 @@ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
}
/**
+ * ufshcd_outstanding_req_clear - Clear a bit in outstanding request field
+ * @hba: per adapter instance
+ * @tag: position of the bit to be cleared
+ */
+static inline void ufshcd_outstanding_req_clear(struct ufs_hba *hba, int tag)
+{
+ __clear_bit(tag, &hba->outstanding_reqs);
+}
+
+/**
* ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
* @reg: Register value of host controller status
*
@@ -376,11 +418,9 @@ static inline int ufshcd_get_lists_status(u32 reg)
* 1 UTRLRDY
* 2 UTMRLRDY
* 3 UCRDY
- * 4 HEI
- * 5 DEI
- * 6-7 reserved
+ * 4-7 reserved
*/
- return (((reg) & (0xFF)) >> 1) ^ (0x07);
+ return ((reg & 0xFF) >> 1) ^ 0x07;
}
/**
@@ -530,6 +570,34 @@ static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
}
+u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
+{
+ /* HCI version 1.0 and 1.1 supports UniPro 1.41 */
+ if ((hba->ufs_version == UFSHCI_VERSION_10) ||
+ (hba->ufs_version == UFSHCI_VERSION_11))
+ return UFS_UNIPRO_VER_1_41;
+ else
+ return UFS_UNIPRO_VER_1_6;
+}
+EXPORT_SYMBOL(ufshcd_get_local_unipro_ver);
+
+static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
+{
+ /*
+ * If both host and device support UniPro ver1.6 or later, PA layer
+ * parameters tuning happens during link startup itself.
+ *
+ * We can manually tune PA layer parameters if either host or device
+ * doesn't support UniPro ver 1.6 or later. But to keep manual tuning
+ * logic simple, we will only do manual tuning if local unipro version
+ * doesn't support ver1.6 or later.
+ */
+ if (ufshcd_get_local_unipro_ver(hba) < UFS_UNIPRO_VER_1_6)
+ return true;
+ else
+ return false;
+}
+
static void ufshcd_ungate_work(struct work_struct *work)
{
int ret;
@@ -584,6 +652,11 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
spin_lock_irqsave(hba->host->host_lock, flags);
hba->clk_gating.active_reqs++;
+ if (ufshcd_eh_in_progress(hba)) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return 0;
+ }
+
start:
switch (hba->clk_gating.state) {
case CLKS_ON:
@@ -627,6 +700,7 @@ start:
out:
return rc;
}
+EXPORT_SYMBOL_GPL(ufshcd_hold);
static void ufshcd_gate_work(struct work_struct *work)
{
@@ -698,7 +772,8 @@ static void __ufshcd_release(struct ufs_hba *hba)
if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended
|| hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL
|| hba->lrb_in_use || hba->outstanding_tasks
- || hba->active_uic_cmd || hba->uic_async_done)
+ || hba->active_uic_cmd || hba->uic_async_done
+ || ufshcd_eh_in_progress(hba))
return;
hba->clk_gating.state = REQ_CLKS_OFF;
@@ -714,6 +789,7 @@ void ufshcd_release(struct ufs_hba *hba)
__ufshcd_release(hba);
spin_unlock_irqrestore(hba->host->host_lock, flags);
}
+EXPORT_SYMBOL_GPL(ufshcd_release);
static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -953,13 +1029,15 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
* __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
* @hba: per adapter instance
* @uic_cmd: UIC command
+ * @completion: initialize the completion only if this is set to true
*
* Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
* with mutex held and host_lock locked.
* Returns 0 only if success.
*/
static int
-__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd,
+ bool completion)
{
if (!ufshcd_ready_for_uic_cmd(hba)) {
dev_err(hba->dev,
@@ -967,7 +1045,8 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
return -EIO;
}
- init_completion(&uic_cmd->done);
+ if (completion)
+ init_completion(&uic_cmd->done);
ufshcd_dispatch_uic_cmd(hba, uic_cmd);
@@ -992,7 +1071,7 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
ufshcd_add_delay_before_dme_cmd(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
- ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
+ ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true);
spin_unlock_irqrestore(hba->host->host_lock, flags);
if (!ret)
ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
@@ -1035,6 +1114,7 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
cpu_to_le32(lower_32_bits(sg->dma_address));
prd_table[i].upper_addr =
cpu_to_le32(upper_32_bits(sg->dma_address));
+ prd_table[i].reserved = 0;
}
} else {
lrbp->utr_descriptor_ptr->prd_table_length = 0;
@@ -1117,7 +1197,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
/* Transfer request descriptor header fields */
req_desc->header.dword_0 = cpu_to_le32(dword_0);
-
+ /* dword_1 is reserved, hence it is set to 0 */
+ req_desc->header.dword_1 = 0;
/*
* assigning invalid value for command status. Controller
* updates OCS on command completion, with the command
@@ -1125,6 +1206,10 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
*/
req_desc->header.dword_2 =
cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+ /* dword_3 is reserved, hence it is set to 0 */
+ req_desc->header.dword_3 = 0;
+
+ req_desc->prd_table_length = 0;
}
/**
@@ -1137,6 +1222,7 @@ static
void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
{
struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+ unsigned short cdb_len;
/* command descriptor fields */
ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
@@ -1151,8 +1237,11 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
ucd_req_ptr->sc.exp_data_transfer_len =
cpu_to_be32(lrbp->cmd->sdb.length);
- memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
- (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+ cdb_len = min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE);
+ memset(ucd_req_ptr->sc.cdb, 0, MAX_CDB_SIZE);
+ memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd, cdb_len);
+
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
}
/**
@@ -1189,6 +1278,7 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
memcpy(descp, query->descriptor, len);
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
}
static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
@@ -1201,6 +1291,11 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
ucd_req_ptr->header.dword_0 =
UPIU_HEADER_DWORD(
UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
+ /* clear rest of the fields of basic header */
+ ucd_req_ptr->header.dword_1 = 0;
+ ucd_req_ptr->header.dword_2 = 0;
+
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
}
/**
@@ -1293,6 +1388,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
hba = shost_priv(host);
tag = cmd->request->tag;
+ if (!ufshcd_valid_tag(hba, tag)) {
+ dev_err(hba->dev,
+ "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
+ __func__, tag, cmd, cmd->request);
+ BUG();
+ }
spin_lock_irqsave(hba->host->host_lock, flags);
switch (hba->ufshcd_state) {
@@ -1312,6 +1413,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
cmd->scsi_done(cmd);
goto out_unlock;
}
+
+ /* if error handling is in progress, don't issue commands */
+ if (ufshcd_eh_in_progress(hba)) {
+ set_host_byte(cmd, DID_ERROR);
+ cmd->scsi_done(cmd);
+ goto out_unlock;
+ }
spin_unlock_irqrestore(hba->host->host_lock, flags);
/* acquire the tag to make sure device cmds don't use it */
@@ -1396,7 +1504,7 @@ ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
*/
err = ufshcd_wait_for_register(hba,
REG_UTP_TRANSFER_REQ_DOOR_BELL,
- mask, ~mask, 1000, 1000);
+ mask, ~mask, 1000, 1000, true);
return err;
}
@@ -1475,9 +1583,17 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
if (!time_left) {
err = -ETIMEDOUT;
+ dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n",
+ __func__, lrbp->task_tag);
if (!ufshcd_clear_cmd(hba, lrbp->task_tag))
- /* sucessfully cleared the command, retry if needed */
+ /* successfully cleared the command, retry if needed */
err = -EAGAIN;
+ /*
+ * in case of an error, after clearing the doorbell,
+ * we also need to clear the outstanding_request
+ * field in hba
+ */
+ ufshcd_outstanding_req_clear(hba, lrbp->task_tag);
}
return err;
@@ -1555,6 +1671,8 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
hba->dev_cmd.complete = &wait;
+ /* Make sure descriptors are ready before ringing the doorbell */
+ wmb();
spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_send_command(hba, tag);
spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -1591,6 +1709,29 @@ static inline void ufshcd_init_query(struct ufs_hba *hba,
(*request)->upiu_req.selector = selector;
}
+static int ufshcd_query_flag_retry(struct ufs_hba *hba,
+ enum query_opcode opcode, enum flag_idn idn, bool *flag_res)
+{
+ int ret;
+ int retries;
+
+ for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) {
+ ret = ufshcd_query_flag(hba, opcode, idn, flag_res);
+ if (ret)
+ dev_dbg(hba->dev,
+ "%s: failed with error %d, retries %d\n",
+ __func__, ret, retries);
+ else
+ break;
+ }
+
+ if (ret)
+ dev_err(hba->dev,
+ "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n",
+ __func__, opcode, idn, ret, retries);
+ return ret;
+}
+
/**
* ufshcd_query_flag() - API function for sending flag query requests
* hba: per-adapter instance
@@ -1600,12 +1741,13 @@ static inline void ufshcd_init_query(struct ufs_hba *hba,
*
* Returns 0 for success, non-zero in case of failure
*/
-static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
enum flag_idn idn, bool *flag_res)
{
struct ufs_query_req *request = NULL;
struct ufs_query_res *response = NULL;
int err, index = 0, selector = 0;
+ int timeout = QUERY_REQ_TIMEOUT;
BUG_ON(!hba);
@@ -1638,7 +1780,10 @@ static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
goto out_unlock;
}
- err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+ if (idn == QUERY_FLAG_IDN_FDEVICEINIT)
+ timeout = QUERY_FDEVICEINIT_REQ_TIMEOUT;
+
+ err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout);
if (err) {
dev_err(hba->dev,
@@ -1722,20 +1867,43 @@ out:
}
/**
- * ufshcd_query_descriptor - API function for sending descriptor requests
- * hba: per-adapter instance
- * opcode: attribute opcode
- * idn: attribute idn to access
- * index: index field
- * selector: selector field
- * desc_buf: the buffer that contains the descriptor
- * buf_len: length parameter passed to the device
+ * ufshcd_query_attr_retry() - API function for sending query
+ * attribute with retries
+ * @hba: per-adapter instance
+ * @opcode: attribute opcode
+ * @idn: attribute idn to access
+ * @index: index field
+ * @selector: selector field
+ * @attr_val: the attribute value after the query request
+ * completes
*
- * Returns 0 for success, non-zero in case of failure.
- * The buf_len parameter will contain, on return, the length parameter
- * received on the response.
- */
-static int ufshcd_query_descriptor(struct ufs_hba *hba,
+ * Returns 0 for success, non-zero in case of failure
+*/
+static int ufshcd_query_attr_retry(struct ufs_hba *hba,
+ enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector,
+ u32 *attr_val)
+{
+ int ret = 0;
+ u32 retries;
+
+ for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+ ret = ufshcd_query_attr(hba, opcode, idn, index,
+ selector, attr_val);
+ if (ret)
+ dev_dbg(hba->dev, "%s: failed with error %d, retries %d\n",
+ __func__, ret, retries);
+ else
+ break;
+ }
+
+ if (ret)
+ dev_err(hba->dev,
+ "%s: query attribute, idn %d, failed with error %d after %d retires\n",
+ __func__, idn, ret, QUERY_REQ_RETRIES);
+ return ret;
+}
+
+static int __ufshcd_query_descriptor(struct ufs_hba *hba,
enum query_opcode opcode, enum desc_idn idn, u8 index,
u8 selector, u8 *desc_buf, int *buf_len)
{
@@ -1800,6 +1968,39 @@ out:
}
/**
+ * ufshcd_query_descriptor_retry - API function for sending descriptor
+ * requests
+ * hba: per-adapter instance
+ * opcode: attribute opcode
+ * idn: attribute idn to access
+ * index: index field
+ * selector: selector field
+ * desc_buf: the buffer that contains the descriptor
+ * buf_len: length parameter passed to the device
+ *
+ * Returns 0 for success, non-zero in case of failure.
+ * The buf_len parameter will contain, on return, the length parameter
+ * received on the response.
+ */
+int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
+ enum query_opcode opcode, enum desc_idn idn, u8 index,
+ u8 selector, u8 *desc_buf, int *buf_len)
+{
+ int err;
+ int retries;
+
+ for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+ err = __ufshcd_query_descriptor(hba, opcode, idn, index,
+ selector, desc_buf, buf_len);
+ if (!err || err == -EINVAL)
+ break;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(ufshcd_query_descriptor_retry);
+
+/**
* ufshcd_read_desc_param - read the specified descriptor parameter
* @hba: Pointer to adapter instance
* @desc_id: descriptor idn value
@@ -1841,9 +2042,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
return -ENOMEM;
}
- ret = ufshcd_query_descriptor(hba, UPIU_QUERY_OPCODE_READ_DESC,
- desc_id, desc_index, 0, desc_buf,
- &buff_len);
+ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
+ desc_id, desc_index, 0, desc_buf,
+ &buff_len);
if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) ||
(desc_buf[QUERY_DESC_LENGTH_OFFSET] !=
@@ -1881,6 +2082,82 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba,
return ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size);
}
+int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
+{
+ return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
+}
+EXPORT_SYMBOL(ufshcd_read_device_desc);
+
+/**
+ * ufshcd_read_string_desc - read string descriptor
+ * @hba: pointer to adapter instance
+ * @desc_index: descriptor index
+ * @buf: pointer to buffer where descriptor would be read
+ * @size: size of buf
+ * @ascii: if true convert from unicode to ascii characters
+ *
+ * Return 0 in case of success, non-zero otherwise
+ */
+int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
+ u32 size, bool ascii)
+{
+ int err = 0;
+
+ err = ufshcd_read_desc(hba,
+ QUERY_DESC_IDN_STRING, desc_index, buf, size);
+
+ if (err) {
+ dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n",
+ __func__, QUERY_REQ_RETRIES, err);
+ goto out;
+ }
+
+ if (ascii) {
+ int desc_len;
+ int ascii_len;
+ int i;
+ char *buff_ascii;
+
+ desc_len = buf[0];
+ /* remove header and divide by 2 to move from UTF16 to UTF8 */
+ ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1;
+ if (size < ascii_len + QUERY_DESC_HDR_SIZE) {
+ dev_err(hba->dev, "%s: buffer allocated size is too small\n",
+ __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
+ if (!buff_ascii) {
+ err = -ENOMEM;
+ goto out_free_buff;
+ }
+
+ /*
+ * the descriptor contains string in UTF16 format
+ * we need to convert to utf-8 so it can be displayed
+ */
+ utf16s_to_utf8s((wchar_t *)&buf[QUERY_DESC_HDR_SIZE],
+ desc_len - QUERY_DESC_HDR_SIZE,
+ UTF16_BIG_ENDIAN, buff_ascii, ascii_len);
+
+ /* replace non-printable or non-ASCII characters with spaces */
+ for (i = 0; i < ascii_len; i++)
+ ufshcd_remove_non_printable(&buff_ascii[i]);
+
+ memset(buf + QUERY_DESC_HDR_SIZE, 0,
+ size - QUERY_DESC_HDR_SIZE);
+ memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len);
+ buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE;
+out_free_buff:
+ kfree(buff_ascii);
+ }
+out:
+ return err;
+}
+EXPORT_SYMBOL(ufshcd_read_string_desc);
+
/**
* ufshcd_read_unit_desc_param - read the specified unit descriptor parameter
* @hba: Pointer to adapter instance
@@ -2128,6 +2405,7 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
};
const char *set = action[!!peer];
int ret;
+ int retries = UFS_UIC_COMMAND_RETRIES;
uic_cmd.command = peer ?
UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
@@ -2135,10 +2413,18 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
uic_cmd.argument3 = mib_val;
- ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
- if (ret)
- dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
- set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+ do {
+ /* for peer attributes we retry upon failure */
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
+ set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+ } while (ret && peer && --retries);
+
+ if (!retries)
+ dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n",
+ set, UIC_GET_ATTR_ID(attr_sel), mib_val,
+ retries);
return ret;
}
@@ -2163,6 +2449,7 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
};
const char *get = action[!!peer];
int ret;
+ int retries = UFS_UIC_COMMAND_RETRIES;
struct ufs_pa_layer_attr orig_pwr_info;
struct ufs_pa_layer_attr temp_pwr_info;
bool pwr_mode_change = false;
@@ -2193,14 +2480,19 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
uic_cmd.argument1 = attr_sel;
- ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
- if (ret) {
- dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
- get, UIC_GET_ATTR_ID(attr_sel), ret);
- goto out;
- }
+ do {
+ /* for peer attributes we retry upon failure */
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n",
+ get, UIC_GET_ATTR_ID(attr_sel), ret);
+ } while (ret && peer && --retries);
+
+ if (!retries)
+ dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n",
+ get, UIC_GET_ATTR_ID(attr_sel), retries);
- if (mib_val)
+ if (mib_val && !ret)
*mib_val = uic_cmd.argument3;
if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE)
@@ -2233,6 +2525,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
unsigned long flags;
u8 status;
int ret;
+ bool reenable_intr = false;
mutex_lock(&hba->uic_cmd_mutex);
init_completion(&uic_async_done);
@@ -2240,15 +2533,17 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
spin_lock_irqsave(hba->host->host_lock, flags);
hba->uic_async_done = &uic_async_done;
- ret = __ufshcd_send_uic_cmd(hba, cmd);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- if (ret) {
- dev_err(hba->dev,
- "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n",
- cmd->command, cmd->argument3, ret);
- goto out;
+ if (ufshcd_readl(hba, REG_INTERRUPT_ENABLE) & UIC_COMMAND_COMPL) {
+ ufshcd_disable_intr(hba, UIC_COMMAND_COMPL);
+ /*
+ * Make sure UIC command completion interrupt is disabled before
+ * issuing UIC command.
+ */
+ wmb();
+ reenable_intr = true;
}
- ret = ufshcd_wait_for_uic_cmd(hba, cmd);
+ ret = __ufshcd_send_uic_cmd(hba, cmd, false);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
if (ret) {
dev_err(hba->dev,
"pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n",
@@ -2274,7 +2569,10 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
}
out:
spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->active_uic_cmd = NULL;
hba->uic_async_done = NULL;
+ if (reenable_intr)
+ ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
spin_unlock_irqrestore(hba->host->host_lock, flags);
mutex_unlock(&hba->uic_cmd_mutex);
@@ -2315,13 +2613,65 @@ out:
return ret;
}
-static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
+static int ufshcd_link_recovery(struct ufs_hba *hba)
{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->ufshcd_state = UFSHCD_STATE_RESET;
+ ufshcd_set_eh_in_progress(hba);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ ret = ufshcd_host_reset_and_restore(hba);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (ret)
+ hba->ufshcd_state = UFSHCD_STATE_ERROR;
+ ufshcd_clear_eh_in_progress(hba);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ if (ret)
+ dev_err(hba->dev, "%s: link recovery failed, err %d",
+ __func__, ret);
+
+ return ret;
+}
+
+static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
+{
+ int ret;
struct uic_command uic_cmd = {0};
uic_cmd.command = UIC_CMD_DME_HIBER_ENTER;
+ ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+
+ if (ret) {
+ dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n",
+ __func__, ret);
+
+ /*
+ * If link recovery fails then return error so that caller
+ * don't retry the hibern8 enter again.
+ */
+ if (ufshcd_link_recovery(hba))
+ ret = -ENOLINK;
+ }
- return ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+ return ret;
+}
+
+static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
+{
+ int ret = 0, retries;
+
+ for (retries = UIC_HIBERN8_ENTER_RETRIES; retries > 0; retries--) {
+ ret = __ufshcd_uic_hibern8_enter(hba);
+ if (!ret || ret == -ENOLINK)
+ goto out;
+ }
+out:
+ return ret;
}
static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
@@ -2332,8 +2682,9 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
uic_cmd.command = UIC_CMD_DME_HIBER_EXIT;
ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
if (ret) {
- ufshcd_set_link_off(hba);
- ret = ufshcd_host_reset_and_restore(hba);
+ dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d\n",
+ __func__, ret);
+ ret = ufshcd_link_recovery(hba);
}
return ret;
@@ -2473,9 +2824,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
dev_err(hba->dev,
"%s: power mode change failed %d\n", __func__, ret);
} else {
- if (hba->vops && hba->vops->pwr_change_notify)
- hba->vops->pwr_change_notify(hba,
- POST_CHANGE, NULL, pwr_mode);
+ ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
+ pwr_mode);
memcpy(&hba->pwr_info, pwr_mode,
sizeof(struct ufs_pa_layer_attr));
@@ -2495,10 +2845,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr final_params = { 0 };
int ret;
- if (hba->vops && hba->vops->pwr_change_notify)
- hba->vops->pwr_change_notify(hba,
- PRE_CHANGE, desired_pwr_mode, &final_params);
- else
+ ret = ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE,
+ desired_pwr_mode, &final_params);
+
+ if (ret)
memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
ret = ufshcd_change_power_mode(hba, &final_params);
@@ -2514,17 +2864,12 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
*/
static int ufshcd_complete_dev_init(struct ufs_hba *hba)
{
- int i, retries, err = 0;
+ int i;
+ int err;
bool flag_res = 1;
- for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
- /* Set the fDeviceInit flag */
- err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
- QUERY_FLAG_IDN_FDEVICEINIT, NULL);
- if (!err || err == -ETIMEDOUT)
- break;
- dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
- }
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT, NULL);
if (err) {
dev_err(hba->dev,
"%s setting fDeviceInit flag failed with error %d\n",
@@ -2532,18 +2877,11 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba)
goto out;
}
- /* poll for max. 100 iterations for fDeviceInit flag to clear */
- for (i = 0; i < 100 && !err && flag_res; i++) {
- for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
- err = ufshcd_query_flag(hba,
- UPIU_QUERY_OPCODE_READ_FLAG,
- QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
- if (!err || err == -ETIMEDOUT)
- break;
- dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
- err);
- }
- }
+ /* poll for max. 1000 iterations for fDeviceInit flag to clear */
+ for (i = 0; i < 1000 && !err && flag_res; i++)
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
+ QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+
if (err)
dev_err(hba->dev,
"%s reading fDeviceInit flag failed with error %d\n",
@@ -2564,7 +2902,7 @@ out:
* To bring UFS host controller to operational state,
* 1. Enable required interrupts
* 2. Configure interrupt aggregation
- * 3. Program UTRL and UTMRL base addres
+ * 3. Program UTRL and UTMRL base address
* 4. Configure run-stop-registers
*
* Returns 0 on success, non-zero value on failure
@@ -2594,8 +2932,13 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
REG_UTP_TASK_REQ_LIST_BASE_H);
/*
+ * Make sure base address and interrupt setup are updated before
+ * enabling the run/stop registers below.
+ */
+ wmb();
+
+ /*
* UCRDY, UTMRLDY and UTRLRDY bits must be 1
- * DEI, HEI bits must be 0
*/
reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
if (!(ufshcd_get_lists_status(reg))) {
@@ -2612,6 +2955,23 @@ out:
}
/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ * @can_sleep: perform sleep or just spin
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep)
+{
+ int err;
+
+ ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
+ err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
+ CONTROLLER_ENABLE, CONTROLLER_DISABLE,
+ 10, 1, can_sleep);
+ if (err)
+ dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
+}
+
+/**
* ufshcd_hba_enable - initialize the controller
* @hba: per adapter instance
*
@@ -2631,24 +2991,14 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
* development and testing of this driver. msleep can be changed to
* mdelay and retry count can be reduced based on the controller.
*/
- if (!ufshcd_is_hba_active(hba)) {
-
+ if (!ufshcd_is_hba_active(hba))
/* change controller state to "reset state" */
- ufshcd_hba_stop(hba);
-
- /*
- * This delay is based on the testing done with UFS host
- * controller FPGA. The delay can be changed based on the
- * host controller used.
- */
- msleep(5);
- }
+ ufshcd_hba_stop(hba, true);
/* UniPro link is disabled at this point */
ufshcd_set_link_off(hba);
- if (hba->vops && hba->vops->hce_enable_notify)
- hba->vops->hce_enable_notify(hba, PRE_CHANGE);
+ ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE);
/* start controller initialization sequence */
ufshcd_hba_start(hba);
@@ -2681,8 +3031,7 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
/* enable UIC related interrupts */
ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
- if (hba->vops && hba->vops->hce_enable_notify)
- hba->vops->hce_enable_notify(hba, POST_CHANGE);
+ ufshcd_vops_hce_enable_notify(hba, POST_CHANGE);
return 0;
}
@@ -2735,8 +3084,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
int retries = DME_LINKSTARTUP_RETRIES;
do {
- if (hba->vops && hba->vops->link_startup_notify)
- hba->vops->link_startup_notify(hba, PRE_CHANGE);
+ ufshcd_vops_link_startup_notify(hba, PRE_CHANGE);
ret = ufshcd_dme_link_startup(hba);
@@ -2767,11 +3115,9 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
}
/* Include any host controller configuration via UIC commands */
- if (hba->vops && hba->vops->link_startup_notify) {
- ret = hba->vops->link_startup_notify(hba, POST_CHANGE);
- if (ret)
- goto out;
- }
+ ret = ufshcd_vops_link_startup_notify(hba, POST_CHANGE);
+ if (ret)
+ goto out;
ret = ufshcd_make_hba_operational(hba);
out:
@@ -3096,7 +3442,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
scsi_status = result & MASK_SCSI_STATUS;
result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
- if (ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
+ /*
+ * Currently we are only supporting BKOPs exception
+ * events hence we can ignore BKOPs exception event
+ * during power management callbacks. BKOPs exception
+ * event is not expected to be raised in runtime suspend
+ * callback as it allows the urgent bkops.
+ * During system suspend, we are anyway forcefully
+ * disabling the bkops and if urgent bkops is needed
+ * it will be enabled on system resume. Long term
+ * solution could be to abort the system suspend if
+ * UFS device needs urgent BKOPs.
+ */
+ if (!hba->pm_op_in_progress &&
+ ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
schedule_work(&hba->eeh_work);
break;
case UPIU_TRANSACTION_REJECT_UPIU:
@@ -3155,31 +3514,18 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
}
/**
- * ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * __ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
+ * @completed_reqs: requests to complete
*/
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
+ unsigned long completed_reqs)
{
struct ufshcd_lrb *lrbp;
struct scsi_cmnd *cmd;
- unsigned long completed_reqs;
- u32 tr_doorbell;
int result;
int index;
- /* Resetting interrupt aggregation counters first and reading the
- * DOOR_BELL afterward allows us to handle all the completed requests.
- * In order to prevent other interrupts starvation the DB is read once
- * after reset. The down side of this solution is the possibility of
- * false interrupt if device completes another request after resetting
- * aggregation and before reading the DB.
- */
- if (ufshcd_is_intr_aggr_allowed(hba))
- ufshcd_reset_intr_aggr(hba);
-
- tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
- completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
-
for_each_set_bit(index, &completed_reqs, hba->nutrs) {
lrbp = &hba->lrb[index];
cmd = lrbp->cmd;
@@ -3209,6 +3555,31 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
}
/**
+ * ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * @hba: per adapter instance
+ */
+static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+{
+ unsigned long completed_reqs;
+ u32 tr_doorbell;
+
+ /* Resetting interrupt aggregation counters first and reading the
+ * DOOR_BELL afterward allows us to handle all the completed requests.
+ * In order to prevent other interrupts starvation the DB is read once
+ * after reset. The down side of this solution is the possibility of
+ * false interrupt if device completes another request after resetting
+ * aggregation and before reading the DB.
+ */
+ if (ufshcd_is_intr_aggr_allowed(hba))
+ ufshcd_reset_intr_aggr(hba);
+
+ tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
+
+ __ufshcd_transfer_req_compl(hba, completed_reqs);
+}
+
+/**
* ufshcd_disable_ee - disable exception event
* @hba: per-adapter instance
* @mask: exception event to disable
@@ -3228,7 +3599,7 @@ static int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask)
val = hba->ee_ctrl_mask & ~mask;
val &= 0xFFFF; /* 2 bytes */
- err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
if (!err)
hba->ee_ctrl_mask &= ~mask;
@@ -3256,7 +3627,7 @@ static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask)
val = hba->ee_ctrl_mask | mask;
val &= 0xFFFF; /* 2 bytes */
- err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
if (!err)
hba->ee_ctrl_mask |= mask;
@@ -3282,7 +3653,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba)
if (hba->auto_bkops_enabled)
goto out;
- err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
QUERY_FLAG_IDN_BKOPS_EN, NULL);
if (err) {
dev_err(hba->dev, "%s: failed to enable bkops %d\n",
@@ -3331,7 +3702,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba)
goto out;
}
- err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
+ err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
QUERY_FLAG_IDN_BKOPS_EN, NULL);
if (err) {
dev_err(hba->dev, "%s: failed to disable bkops %d\n",
@@ -3362,7 +3733,7 @@ static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status)
{
- return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ return ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, status);
}
@@ -3420,15 +3791,52 @@ out:
*/
static int ufshcd_urgent_bkops(struct ufs_hba *hba)
{
- return ufshcd_bkops_ctrl(hba, BKOPS_STATUS_PERF_IMPACT);
+ return ufshcd_bkops_ctrl(hba, hba->urgent_bkops_lvl);
}
static inline int ufshcd_get_ee_status(struct ufs_hba *hba, u32 *status)
{
- return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ return ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
QUERY_ATTR_IDN_EE_STATUS, 0, 0, status);
}
+static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba)
+{
+ int err;
+ u32 curr_status = 0;
+
+ if (hba->is_urgent_bkops_lvl_checked)
+ goto enable_auto_bkops;
+
+ err = ufshcd_get_bkops_status(hba, &curr_status);
+ if (err) {
+ dev_err(hba->dev, "%s: failed to get BKOPS status %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ /*
+ * We are seeing that some devices are raising the urgent bkops
+ * exception events even when BKOPS status doesn't indicate performace
+ * impacted or critical. Handle these device by determining their urgent
+ * bkops status at runtime.
+ */
+ if (curr_status < BKOPS_STATUS_PERF_IMPACT) {
+ dev_err(hba->dev, "%s: device raised urgent BKOPS exception for bkops status %d\n",
+ __func__, curr_status);
+ /* update the current status as the urgent bkops level */
+ hba->urgent_bkops_lvl = curr_status;
+ hba->is_urgent_bkops_lvl_checked = true;
+ }
+
+enable_auto_bkops:
+ err = ufshcd_enable_auto_bkops(hba);
+out:
+ if (err < 0)
+ dev_err(hba->dev, "%s: failed to handle urgent bkops %d\n",
+ __func__, err);
+}
+
/**
* ufshcd_exception_event_handler - handle exceptions raised by device
* @work: pointer to work data
@@ -3452,17 +3860,95 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
}
status &= hba->ee_ctrl_mask;
- if (status & MASK_EE_URGENT_BKOPS) {
- err = ufshcd_urgent_bkops(hba);
- if (err < 0)
- dev_err(hba->dev, "%s: failed to handle urgent bkops %d\n",
- __func__, err);
- }
+
+ if (status & MASK_EE_URGENT_BKOPS)
+ ufshcd_bkops_exception_event_handler(hba);
+
out:
pm_runtime_put_sync(hba->dev);
return;
}
+/* Complete requests that have door-bell cleared */
+static void ufshcd_complete_requests(struct ufs_hba *hba)
+{
+ ufshcd_transfer_req_compl(hba);
+ ufshcd_tmc_handler(hba);
+}
+
+/**
+ * ufshcd_quirk_dl_nac_errors - This function checks if error handling is
+ * to recover from the DL NAC errors or not.
+ * @hba: per-adapter instance
+ *
+ * Returns true if error handling is required, false otherwise
+ */
+static bool ufshcd_quirk_dl_nac_errors(struct ufs_hba *hba)
+{
+ unsigned long flags;
+ bool err_handling = true;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ /*
+ * UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS only workaround the
+ * device fatal error and/or DL NAC & REPLAY timeout errors.
+ */
+ if (hba->saved_err & (CONTROLLER_FATAL_ERROR | SYSTEM_BUS_FATAL_ERROR))
+ goto out;
+
+ if ((hba->saved_err & DEVICE_FATAL_ERROR) ||
+ ((hba->saved_err & UIC_ERROR) &&
+ (hba->saved_uic_err & UFSHCD_UIC_DL_TCx_REPLAY_ERROR)))
+ goto out;
+
+ if ((hba->saved_err & UIC_ERROR) &&
+ (hba->saved_uic_err & UFSHCD_UIC_DL_NAC_RECEIVED_ERROR)) {
+ int err;
+ /*
+ * wait for 50ms to see if we can get any other errors or not.
+ */
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ msleep(50);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ /*
+ * now check if we have got any other severe errors other than
+ * DL NAC error?
+ */
+ if ((hba->saved_err & INT_FATAL_ERRORS) ||
+ ((hba->saved_err & UIC_ERROR) &&
+ (hba->saved_uic_err & ~UFSHCD_UIC_DL_NAC_RECEIVED_ERROR)))
+ goto out;
+
+ /*
+ * As DL NAC is the only error received so far, send out NOP
+ * command to confirm if link is still active or not.
+ * - If we don't get any response then do error recovery.
+ * - If we get response then clear the DL NAC error bit.
+ */
+
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ err = ufshcd_verify_dev_init(hba);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ if (err)
+ goto out;
+
+ /* Link seems to be alive hence ignore the DL NAC errors */
+ if (hba->saved_uic_err == UFSHCD_UIC_DL_NAC_RECEIVED_ERROR)
+ hba->saved_err &= ~UIC_ERROR;
+ /* clear NAC error */
+ hba->saved_uic_err &= ~UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
+ if (!hba->saved_uic_err) {
+ err_handling = false;
+ goto out;
+ }
+ }
+out:
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return err_handling;
+}
+
/**
* ufshcd_err_handler - handle UFS errors that require s/w attention
* @work: pointer to work structure
@@ -3475,6 +3961,7 @@ static void ufshcd_err_handler(struct work_struct *work)
u32 err_tm = 0;
int err = 0;
int tag;
+ bool needs_reset = false;
hba = container_of(work, struct ufs_hba, eh_work);
@@ -3482,40 +3969,86 @@ static void ufshcd_err_handler(struct work_struct *work)
ufshcd_hold(hba, false);
spin_lock_irqsave(hba->host->host_lock, flags);
- if (hba->ufshcd_state == UFSHCD_STATE_RESET) {
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (hba->ufshcd_state == UFSHCD_STATE_RESET)
goto out;
- }
hba->ufshcd_state = UFSHCD_STATE_RESET;
ufshcd_set_eh_in_progress(hba);
/* Complete requests that have door-bell cleared by h/w */
- ufshcd_transfer_req_compl(hba);
- ufshcd_tmc_handler(hba);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ ufshcd_complete_requests(hba);
+
+ if (hba->dev_quirks & UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
+ bool ret;
+
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ /* release the lock as ufshcd_quirk_dl_nac_errors() may sleep */
+ ret = ufshcd_quirk_dl_nac_errors(hba);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (!ret)
+ goto skip_err_handling;
+ }
+ if ((hba->saved_err & INT_FATAL_ERRORS) ||
+ ((hba->saved_err & UIC_ERROR) &&
+ (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
+ UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
+ UFSHCD_UIC_DL_TCx_REPLAY_ERROR))))
+ needs_reset = true;
+
+ /*
+ * if host reset is required then skip clearing the pending
+ * transfers forcefully because they will automatically get
+ * cleared after link startup.
+ */
+ if (needs_reset)
+ goto skip_pending_xfer_clear;
+ /* release lock as clear command might sleep */
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
/* Clear pending transfer requests */
- for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs)
- if (ufshcd_clear_cmd(hba, tag))
- err_xfer |= 1 << tag;
+ for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) {
+ if (ufshcd_clear_cmd(hba, tag)) {
+ err_xfer = true;
+ goto lock_skip_pending_xfer_clear;
+ }
+ }
/* Clear pending task management requests */
- for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs)
- if (ufshcd_clear_tm_cmd(hba, tag))
- err_tm |= 1 << tag;
+ for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs) {
+ if (ufshcd_clear_tm_cmd(hba, tag)) {
+ err_tm = true;
+ goto lock_skip_pending_xfer_clear;
+ }
+ }
- /* Complete the requests that are cleared by s/w */
+lock_skip_pending_xfer_clear:
spin_lock_irqsave(hba->host->host_lock, flags);
- ufshcd_transfer_req_compl(hba);
- ufshcd_tmc_handler(hba);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ /* Complete the requests that are cleared by s/w */
+ ufshcd_complete_requests(hba);
+
+ if (err_xfer || err_tm)
+ needs_reset = true;
+
+skip_pending_xfer_clear:
/* Fatal errors need reset */
- if (err_xfer || err_tm || (hba->saved_err & INT_FATAL_ERRORS) ||
- ((hba->saved_err & UIC_ERROR) &&
- (hba->saved_uic_err & UFSHCD_UIC_DL_PA_INIT_ERROR))) {
+ if (needs_reset) {
+ unsigned long max_doorbells = (1UL << hba->nutrs) - 1;
+
+ /*
+ * ufshcd_reset_and_restore() does the link reinitialization
+ * which will need atleast one empty doorbell slot to send the
+ * device management commands (NOP and query commands).
+ * If there is no slot empty at this moment then free up last
+ * slot forcefully.
+ */
+ if (hba->outstanding_reqs == max_doorbells)
+ __ufshcd_transfer_req_compl(hba,
+ (1UL << (hba->nutrs - 1)));
+
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
err = ufshcd_reset_and_restore(hba);
+ spin_lock_irqsave(hba->host->host_lock, flags);
if (err) {
dev_err(hba->dev, "%s: reset and restore failed\n",
__func__);
@@ -3529,9 +4062,19 @@ static void ufshcd_err_handler(struct work_struct *work)
hba->saved_err = 0;
hba->saved_uic_err = 0;
}
+
+skip_err_handling:
+ if (!needs_reset) {
+ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+ if (hba->saved_err || hba->saved_uic_err)
+ dev_err_ratelimited(hba->dev, "%s: exit: saved_err 0x%x saved_uic_err 0x%x",
+ __func__, hba->saved_err, hba->saved_uic_err);
+ }
+
ufshcd_clear_eh_in_progress(hba);
out:
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
scsi_unblock_requests(hba->host);
ufshcd_release(hba);
pm_runtime_put_sync(hba->dev);
@@ -3549,6 +4092,14 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
+ else if (hba->dev_quirks &
+ UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
+ if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
+ hba->uic_error |=
+ UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
+ else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
+ hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+ }
/* UIC NL/TL/DME errors needs software retry */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
@@ -3586,15 +4137,18 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
}
if (queue_eh_work) {
+ /*
+ * update the transfer error masks to sticky bits, let's do this
+ * irrespective of current ufshcd_state.
+ */
+ hba->saved_err |= hba->errors;
+ hba->saved_uic_err |= hba->uic_error;
+
/* handle fatal errors only when link is functional */
if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
/* block commands from scsi mid-layer */
scsi_block_requests(hba->host);
- /* transfer error masks to sticky bits */
- hba->saved_err |= hba->errors;
- hba->saved_uic_err |= hba->uic_error;
-
hba->ufshcd_state = UFSHCD_STATE_ERROR;
schedule_work(&hba->eh_work);
}
@@ -3651,16 +4205,20 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
*/
static irqreturn_t ufshcd_intr(int irq, void *__hba)
{
- u32 intr_status;
+ u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+ enabled_intr_status =
+ intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
- if (intr_status) {
+ if (intr_status)
ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
- ufshcd_sl_intr(hba, intr_status);
+
+ if (enabled_intr_status) {
+ ufshcd_sl_intr(hba, enabled_intr_status);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
@@ -3683,7 +4241,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag)
/* poll for max. 1 sec to clear door bell register by h/w */
err = ufshcd_wait_for_register(hba,
REG_UTP_TASK_REQ_DOOR_BELL,
- mask, 0, 1000, 1000);
+ mask, 0, 1000, 1000, true);
out:
return err;
}
@@ -3746,6 +4304,10 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
/* send command to the controller */
__set_bit(free_slot, &hba->outstanding_tasks);
+
+ /* Make sure descriptors are ready before ringing the task doorbell */
+ wmb();
+
ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
spin_unlock_irqrestore(host->host_lock, flags);
@@ -3851,13 +4413,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
host = cmd->device->host;
hba = shost_priv(host);
tag = cmd->request->tag;
+ if (!ufshcd_valid_tag(hba, tag)) {
+ dev_err(hba->dev,
+ "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
+ __func__, tag, cmd, cmd->request);
+ BUG();
+ }
ufshcd_hold(hba, false);
+ reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
/* If command is already aborted/completed, return SUCCESS */
- if (!(test_bit(tag, &hba->outstanding_reqs)))
+ if (!(test_bit(tag, &hba->outstanding_reqs))) {
+ dev_err(hba->dev,
+ "%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
+ __func__, tag, hba->outstanding_reqs, reg);
goto out;
+ }
- reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
if (!(reg & (1 << tag))) {
dev_err(hba->dev,
"%s: cmd was completed, but without a notifying intr, tag = %d",
@@ -3911,7 +4483,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
scsi_dma_unmap(cmd);
spin_lock_irqsave(host->host_lock, flags);
- __clear_bit(tag, &hba->outstanding_reqs);
+ ufshcd_outstanding_req_clear(hba, tag);
hba->lrb[tag].cmd = NULL;
spin_unlock_irqrestore(host->host_lock, flags);
@@ -3951,7 +4523,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
/* Reset the host controller */
spin_lock_irqsave(hba->host->host_lock, flags);
- ufshcd_hba_stop(hba);
+ ufshcd_hba_stop(hba, false);
spin_unlock_irqrestore(hba->host->host_lock, flags);
err = ufshcd_hba_enable(hba);
@@ -4161,9 +4733,9 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
dev_dbg(hba->dev, "%s: setting icc_level 0x%x",
__func__, hba->init_prefetch_data.icc_level);
- ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
- QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0,
- &hba->init_prefetch_data.icc_level);
+ ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+ QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0,
+ &hba->init_prefetch_data.icc_level);
if (ret)
dev_err(hba->dev,
@@ -4238,6 +4810,164 @@ out:
return ret;
}
+static int ufs_get_device_info(struct ufs_hba *hba,
+ struct ufs_device_info *card_data)
+{
+ int err;
+ u8 model_index;
+ u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1] = {0};
+ u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
+
+ err = ufshcd_read_device_desc(hba, desc_buf,
+ QUERY_DESC_DEVICE_MAX_SIZE);
+ if (err) {
+ dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ /*
+ * getting vendor (manufacturerID) and Bank Index in big endian
+ * format
+ */
+ card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
+ desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
+
+ model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
+
+ err = ufshcd_read_string_desc(hba, model_index, str_desc_buf,
+ QUERY_DESC_STRING_MAX_SIZE, ASCII_STD);
+ if (err) {
+ dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
+ strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
+ min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
+ MAX_MODEL_LEN));
+
+ /* Null terminate the model string */
+ card_data->model[MAX_MODEL_LEN] = '\0';
+
+out:
+ return err;
+}
+
+void ufs_advertise_fixup_device(struct ufs_hba *hba)
+{
+ int err;
+ struct ufs_dev_fix *f;
+ struct ufs_device_info card_data;
+
+ card_data.wmanufacturerid = 0;
+
+ err = ufs_get_device_info(hba, &card_data);
+ if (err) {
+ dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
+ __func__, err);
+ return;
+ }
+
+ for (f = ufs_fixups; f->quirk; f++) {
+ if (((f->card.wmanufacturerid == card_data.wmanufacturerid) ||
+ (f->card.wmanufacturerid == UFS_ANY_VENDOR)) &&
+ (STR_PRFX_EQUAL(f->card.model, card_data.model) ||
+ !strcmp(f->card.model, UFS_ANY_MODEL)))
+ hba->dev_quirks |= f->quirk;
+ }
+}
+
+/**
+ * ufshcd_tune_pa_tactivate - Tunes PA_TActivate of local UniPro
+ * @hba: per-adapter instance
+ *
+ * PA_TActivate parameter can be tuned manually if UniPro version is less than
+ * 1.61. PA_TActivate needs to be greater than or equal to peerM-PHY's
+ * RX_MIN_ACTIVATETIME_CAPABILITY attribute. This optimal value can help reduce
+ * the hibern8 exit latency.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_tune_pa_tactivate(struct ufs_hba *hba)
+{
+ int ret = 0;
+ u32 peer_rx_min_activatetime = 0, tuned_pa_tactivate;
+
+ ret = ufshcd_dme_peer_get(hba,
+ UIC_ARG_MIB_SEL(
+ RX_MIN_ACTIVATETIME_CAPABILITY,
+ UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+ &peer_rx_min_activatetime);
+ if (ret)
+ goto out;
+
+ /* make sure proper unit conversion is applied */
+ tuned_pa_tactivate =
+ ((peer_rx_min_activatetime * RX_MIN_ACTIVATETIME_UNIT_US)
+ / PA_TACTIVATE_TIME_UNIT_US);
+ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE),
+ tuned_pa_tactivate);
+
+out:
+ return ret;
+}
+
+/**
+ * ufshcd_tune_pa_hibern8time - Tunes PA_Hibern8Time of local UniPro
+ * @hba: per-adapter instance
+ *
+ * PA_Hibern8Time parameter can be tuned manually if UniPro version is less than
+ * 1.61. PA_Hibern8Time needs to be maximum of local M-PHY's
+ * TX_HIBERN8TIME_CAPABILITY & peer M-PHY's RX_HIBERN8TIME_CAPABILITY.
+ * This optimal value can help reduce the hibern8 exit latency.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_tune_pa_hibern8time(struct ufs_hba *hba)
+{
+ int ret = 0;
+ u32 local_tx_hibern8_time_cap = 0, peer_rx_hibern8_time_cap = 0;
+ u32 max_hibern8_time, tuned_pa_hibern8time;
+
+ ret = ufshcd_dme_get(hba,
+ UIC_ARG_MIB_SEL(TX_HIBERN8TIME_CAPABILITY,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+ &local_tx_hibern8_time_cap);
+ if (ret)
+ goto out;
+
+ ret = ufshcd_dme_peer_get(hba,
+ UIC_ARG_MIB_SEL(RX_HIBERN8TIME_CAPABILITY,
+ UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+ &peer_rx_hibern8_time_cap);
+ if (ret)
+ goto out;
+
+ max_hibern8_time = max(local_tx_hibern8_time_cap,
+ peer_rx_hibern8_time_cap);
+ /* make sure proper unit conversion is applied */
+ tuned_pa_hibern8time = ((max_hibern8_time * HIBERN8TIME_UNIT_US)
+ / PA_HIBERN8_TIME_UNIT_US);
+ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME),
+ tuned_pa_hibern8time);
+out:
+ return ret;
+}
+
+static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
+{
+ if (ufshcd_is_unipro_pa_params_tuning_req(hba)) {
+ ufshcd_tune_pa_tactivate(hba);
+ ufshcd_tune_pa_hibern8time(hba);
+ }
+
+ if (hba->dev_quirks & UFS_DEVICE_QUIRK_PA_TACTIVATE)
+ /* set 1ms timeout for PA_TACTIVATE */
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 10);
+}
+
/**
* ufshcd_probe_hba - probe hba to detect device and initialize
* @hba: per-adapter instance
@@ -4254,6 +4984,10 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
ufshcd_init_pwr_info(hba);
+ /* set the default level for urgent bkops */
+ hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT;
+ hba->is_urgent_bkops_lvl_checked = false;
+
/* UniPro link is active now */
ufshcd_set_link_active(hba);
@@ -4265,10 +4999,17 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (ret)
goto out;
+ ufs_advertise_fixup_device(hba);
+ ufshcd_tune_unipro_params(hba);
+
+ ret = ufshcd_set_vccq_rail_unused(hba,
+ (hba->dev_quirks & UFS_DEVICE_NO_VCCQ) ? true : false);
+ if (ret)
+ goto out;
+
/* UFS device is also active now */
ufshcd_set_ufs_dev_active(hba);
ufshcd_force_reset_auto_bkops(hba);
- hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
hba->wlun_dev_clr_ua = true;
if (ufshcd_get_max_pwr_mode(hba)) {
@@ -4282,6 +5023,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
__func__, ret);
}
+ /* set the state as operational after switching to desired gear */
+ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
/*
* If we are in error handling context or in power management callbacks
* context, no need to scan the host
@@ -4291,8 +5034,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
/* clear any previous UFS device information */
memset(&hba->dev_info, 0, sizeof(hba->dev_info));
- if (!ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,
- QUERY_FLAG_IDN_PWR_ON_WPE, &flag))
+ if (!ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
+ QUERY_FLAG_IDN_PWR_ON_WPE, &flag))
hba->dev_info.f_power_on_wp_en = flag;
if (!hba->is_init_prefetch)
@@ -4338,6 +5081,41 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
ufshcd_probe_hba(hba);
}
+static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+ struct Scsi_Host *host;
+ struct ufs_hba *hba;
+ int index;
+ bool found = false;
+
+ if (!scmd || !scmd->device || !scmd->device->host)
+ return BLK_EH_NOT_HANDLED;
+
+ host = scmd->device->host;
+ hba = shost_priv(host);
+ if (!hba)
+ return BLK_EH_NOT_HANDLED;
+
+ spin_lock_irqsave(host->host_lock, flags);
+
+ for_each_set_bit(index, &hba->outstanding_reqs, hba->nutrs) {
+ if (hba->lrb[index].cmd == scmd) {
+ found = true;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(host->host_lock, flags);
+
+ /*
+ * Bypass SCSI error handling and reset the block layer timer if this
+ * SCSI command was not actually dispatched to UFS driver, otherwise
+ * let SCSI layer handle the error as usual.
+ */
+ return found ? BLK_EH_NOT_HANDLED : BLK_EH_RESET_TIMER;
+}
+
static struct scsi_host_template ufshcd_driver_template = {
.module = THIS_MODULE,
.name = UFSHCD,
@@ -4350,12 +5128,12 @@ static struct scsi_host_template ufshcd_driver_template = {
.eh_abort_handler = ufshcd_abort,
.eh_device_reset_handler = ufshcd_eh_device_reset_handler,
.eh_host_reset_handler = ufshcd_eh_host_reset_handler,
+ .eh_timed_out = ufshcd_eh_timed_out,
.this_id = -1,
.sg_tablesize = SG_ALL,
.cmd_per_lun = UFSHCD_CMD_PER_LUN,
.can_queue = UFSHCD_CAN_QUEUE,
.max_host_blocked = 1,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -4379,13 +5157,24 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
struct ufs_vreg *vreg)
{
- return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA);
+ if (!vreg)
+ return 0;
+ else if (vreg->unused)
+ return 0;
+ else
+ return ufshcd_config_vreg_load(hba->dev, vreg,
+ UFS_VREG_LPM_LOAD_UA);
}
static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
struct ufs_vreg *vreg)
{
- return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
+ if (!vreg)
+ return 0;
+ else if (vreg->unused)
+ return 0;
+ else
+ return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
}
static int ufshcd_config_vreg(struct device *dev,
@@ -4420,7 +5209,9 @@ static int ufshcd_enable_vreg(struct device *dev, struct ufs_vreg *vreg)
{
int ret = 0;
- if (!vreg || vreg->enabled)
+ if (!vreg)
+ goto out;
+ else if (vreg->enabled || vreg->unused)
goto out;
ret = ufshcd_config_vreg(dev, vreg, true);
@@ -4440,7 +5231,9 @@ static int ufshcd_disable_vreg(struct device *dev, struct ufs_vreg *vreg)
{
int ret = 0;
- if (!vreg || !vreg->enabled)
+ if (!vreg)
+ goto out;
+ else if (!vreg->enabled || vreg->unused)
goto out;
ret = regulator_disable(vreg->reg);
@@ -4546,6 +5339,36 @@ static int ufshcd_init_hba_vreg(struct ufs_hba *hba)
return 0;
}
+static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused)
+{
+ int ret = 0;
+ struct ufs_vreg_info *info = &hba->vreg_info;
+
+ if (!info)
+ goto out;
+ else if (!info->vccq)
+ goto out;
+
+ if (unused) {
+ /* shut off the rail here */
+ ret = ufshcd_toggle_vreg(hba->dev, info->vccq, false);
+ /*
+ * Mark this rail as no longer used, so it doesn't get enabled
+ * later by mistake
+ */
+ if (!ret)
+ info->vccq->unused = true;
+ } else {
+ /*
+ * rail should have been already enabled hence just make sure
+ * that unused flag is cleared.
+ */
+ info->vccq->unused = false;
+ }
+out:
+ return ret;
+}
+
static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
bool skip_ref_clk)
{
@@ -4578,8 +5401,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
}
}
- if (hba->vops && hba->vops->setup_clocks)
- ret = hba->vops->setup_clocks(hba, on);
+ ret = ufshcd_vops_setup_clocks(hba, on);
out:
if (ret) {
list_for_each_entry(clki, head, list) {
@@ -4645,27 +5467,22 @@ static int ufshcd_variant_hba_init(struct ufs_hba *hba)
if (!hba->vops)
goto out;
- if (hba->vops->init) {
- err = hba->vops->init(hba);
- if (err)
- goto out;
- }
+ err = ufshcd_vops_init(hba);
+ if (err)
+ goto out;
- if (hba->vops->setup_regulators) {
- err = hba->vops->setup_regulators(hba, true);
- if (err)
- goto out_exit;
- }
+ err = ufshcd_vops_setup_regulators(hba, true);
+ if (err)
+ goto out_exit;
goto out;
out_exit:
- if (hba->vops->exit)
- hba->vops->exit(hba);
+ ufshcd_vops_exit(hba);
out:
if (err)
dev_err(hba->dev, "%s: variant %s init failed err %d\n",
- __func__, hba->vops ? hba->vops->name : "", err);
+ __func__, ufshcd_get_var_name(hba), err);
return err;
}
@@ -4674,14 +5491,11 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
if (!hba->vops)
return;
- if (hba->vops->setup_clocks)
- hba->vops->setup_clocks(hba, false);
+ ufshcd_vops_setup_clocks(hba, false);
- if (hba->vops->setup_regulators)
- hba->vops->setup_regulators(hba, false);
+ ufshcd_vops_setup_regulators(hba, false);
- if (hba->vops->exit)
- hba->vops->exit(hba);
+ ufshcd_vops_exit(hba);
}
static int ufshcd_hba_init(struct ufs_hba *hba)
@@ -4874,10 +5688,20 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba,
(!check_for_bkops || (check_for_bkops &&
!hba->auto_bkops_enabled))) {
/*
+ * Let's make sure that link is in low power mode, we are doing
+ * this currently by putting the link in Hibern8. Otherway to
+ * put the link in low power mode is to send the DME end point
+ * to device and then send the DME reset command to local
+ * unipro. But putting the link in hibern8 is much faster.
+ */
+ ret = ufshcd_uic_hibern8_enter(hba);
+ if (ret)
+ goto out;
+ /*
* Change controller state to "reset state" which
* should also put the link in off/reset state
*/
- ufshcd_hba_stop(hba);
+ ufshcd_hba_stop(hba, true);
/*
* TODO: Check if we need any delay to make sure that
* controller is reset
@@ -4892,6 +5716,16 @@ out:
static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
{
/*
+ * It seems some UFS devices may keep drawing more than sleep current
+ * (atleast for 500us) from UFS rails (especially from VCCQ rail).
+ * To avoid this situation, add 2ms delay before putting these UFS
+ * rails in LPM mode.
+ */
+ if (!ufshcd_is_link_active(hba) &&
+ hba->dev_quirks & UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM)
+ usleep_range(2000, 2100);
+
+ /*
* If UFS device is either in UFS_Sleep turn off VCC rail to save some
* power.
*
@@ -5058,17 +5892,13 @@ disable_clks:
* vendor specific host controller register space call them before the
* host clocks are ON.
*/
- if (hba->vops && hba->vops->suspend) {
- ret = hba->vops->suspend(hba, pm_op);
- if (ret)
- goto set_link_active;
- }
+ ret = ufshcd_vops_suspend(hba, pm_op);
+ if (ret)
+ goto set_link_active;
- if (hba->vops && hba->vops->setup_clocks) {
- ret = hba->vops->setup_clocks(hba, false);
- if (ret)
- goto vops_resume;
- }
+ ret = ufshcd_vops_setup_clocks(hba, false);
+ if (ret)
+ goto vops_resume;
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
@@ -5079,7 +5909,7 @@ disable_clks:
hba->clk_gating.state = CLKS_OFF;
/*
* Disable the host irq as host controller as there won't be any
- * host controller trasanction expected till resume.
+ * host controller transaction expected till resume.
*/
ufshcd_disable_irq(hba);
/* Put the host controller in low power mode if possible */
@@ -5087,8 +5917,7 @@ disable_clks:
goto out;
vops_resume:
- if (hba->vops && hba->vops->resume)
- hba->vops->resume(hba, pm_op);
+ ufshcd_vops_resume(hba, pm_op);
set_link_active:
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
@@ -5144,11 +5973,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
* vendor specific host controller register space call them when the
* host clocks are ON.
*/
- if (hba->vops && hba->vops->resume) {
- ret = hba->vops->resume(hba, pm_op);
- if (ret)
- goto disable_vreg;
- }
+ ret = ufshcd_vops_resume(hba, pm_op);
+ if (ret)
+ goto disable_vreg;
if (ufshcd_is_link_hibern8(hba)) {
ret = ufshcd_uic_hibern8_exit(hba);
@@ -5189,8 +6016,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
set_old_link_state:
ufshcd_link_state_transition(hba, old_link_state, 0);
vendor_suspend:
- if (hba->vops && hba->vops->suspend)
- hba->vops->suspend(hba, pm_op);
+ ufshcd_vops_suspend(hba, pm_op);
disable_vreg:
ufshcd_vreg_set_lpm(hba);
disable_irq_and_vops_clks:
@@ -5361,7 +6187,7 @@ void ufshcd_remove(struct ufs_hba *hba)
scsi_remove_host(hba->host);
/* disable interrupts */
ufshcd_disable_intr(hba, hba->intr_mask);
- ufshcd_hba_stop(hba);
+ ufshcd_hba_stop(hba, true);
scsi_host_put(hba->host);
@@ -5373,6 +6199,16 @@ void ufshcd_remove(struct ufs_hba *hba)
EXPORT_SYMBOL_GPL(ufshcd_remove);
/**
+ * ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA)
+ * @hba: pointer to Host Bus Adapter (HBA)
+ */
+void ufshcd_dealloc_host(struct ufs_hba *hba)
+{
+ scsi_host_put(hba->host);
+}
+EXPORT_SYMBOL_GPL(ufshcd_dealloc_host);
+
+/**
* ufshcd_set_dma_mask - Set dma mask based on the controller
* addressing capability
* @hba: per adapter instance
@@ -5433,6 +6269,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
if (!head || list_empty(head))
goto out;
+ ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+ if (ret)
+ return ret;
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
if (scale_up && clki->max_freq) {
@@ -5463,8 +6303,9 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
clki->name, clk_get_rate(clki->clk));
}
- if (hba->vops->clk_scale_notify)
- hba->vops->clk_scale_notify(hba);
+
+ ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+
out:
return ret;
}
@@ -5610,6 +6451,21 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
init_waitqueue_head(&hba->dev_cmd.tag_wq);
ufshcd_init_clk_gating(hba);
+
+ /*
+ * In order to avoid any spurious interrupt immediately after
+ * registering UFS controller interrupt handler, clear any pending UFS
+ * interrupt status and disable all the UFS interrupts.
+ */
+ ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS),
+ REG_INTERRUPT_STATUS);
+ ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE);
+ /*
+ * Make sure that UFS interrupts are disabled and any pending interrupt
+ * status is cleared before registering UFS interrupt handler.
+ */
+ mb();
+
/* IRQ registration */
err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
@@ -5619,13 +6475,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
hba->is_irq_enabled = true;
}
- /* Enable SCSI tag mapping */
- err = scsi_init_shared_tag_map(host, host->can_queue);
- if (err) {
- dev_err(hba->dev, "init shared queue failed\n");
- goto exit_gating;
- }
-
err = scsi_add_host(host, hba->dev);
if (err) {
dev_err(hba->dev, "scsi_add_host failed\n");
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index c40a0e7..4bb6566 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -3,6 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.h
* Copyright (C) 2011-2013 Samsung India Software Operations
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -53,6 +54,7 @@
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
+#include "unipro.h"
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -177,7 +179,7 @@ struct ufshcd_lrb {
};
/**
- * struct ufs_query - holds relevent data structures for query request
+ * struct ufs_query - holds relevant data structures for query request
* @request: request upiu and function
* @descriptor: buffer for sending/receiving descriptor
* @response: response upiu and response
@@ -223,8 +225,10 @@ struct ufs_clk_info {
bool enabled;
};
-#define PRE_CHANGE 0
-#define POST_CHANGE 1
+enum ufs_notify_change_status {
+ PRE_CHANGE,
+ POST_CHANGE,
+};
struct ufs_pa_layer_attr {
u32 gear_rx;
@@ -259,22 +263,28 @@ struct ufs_pwr_mode_info {
* to be set.
* @suspend: called during host controller PM callback
* @resume: called during host controller PM callback
+ * @dbg_register_dump: used to dump controller debug information
*/
struct ufs_hba_variant_ops {
const char *name;
int (*init)(struct ufs_hba *);
void (*exit)(struct ufs_hba *);
u32 (*get_ufs_hci_version)(struct ufs_hba *);
- void (*clk_scale_notify)(struct ufs_hba *);
- int (*setup_clocks)(struct ufs_hba *, bool);
+ int (*clk_scale_notify)(struct ufs_hba *, bool,
+ enum ufs_notify_change_status);
+ int (*setup_clocks)(struct ufs_hba *, bool);
int (*setup_regulators)(struct ufs_hba *, bool);
- int (*hce_enable_notify)(struct ufs_hba *, bool);
- int (*link_startup_notify)(struct ufs_hba *, bool);
+ int (*hce_enable_notify)(struct ufs_hba *,
+ enum ufs_notify_change_status);
+ int (*link_startup_notify)(struct ufs_hba *,
+ enum ufs_notify_change_status);
int (*pwr_change_notify)(struct ufs_hba *,
- bool, struct ufs_pa_layer_attr *,
+ enum ufs_notify_change_status status,
+ struct ufs_pa_layer_attr *,
struct ufs_pa_layer_attr *);
int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
+ void (*dbg_register_dump)(struct ufs_hba *hba);
};
/* clock gating state */
@@ -374,6 +384,9 @@ struct ufs_init_prefetch {
* @clk_list_head: UFS host controller clocks list node head
* @pwr_info: holds current power mode
* @max_pwr_info: keeps the device max valid pwm
+ * @urgent_bkops_lvl: keeps track of urgent bkops level for device
+ * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for
+ * device is known or not.
*/
struct ufs_hba {
void __iomem *mmio_base;
@@ -461,6 +474,9 @@ struct ufs_hba {
unsigned int quirks; /* Deviations from standard UFSHCI spec. */
+ /* Device deviations from standard UFS device spec. */
+ unsigned int dev_quirks;
+
wait_queue_head_t tm_wq;
wait_queue_head_t tm_tag_wq;
unsigned long tm_condition;
@@ -500,6 +516,8 @@ struct ufs_hba {
bool wlun_dev_clr_ua;
+ /* Number of lanes available (1 or 2) for Rx/Tx */
+ u32 lanes_per_direction;
struct ufs_pa_layer_attr pwr_info;
struct ufs_pwr_mode_info max_pwr_info;
@@ -524,6 +542,9 @@ struct ufs_hba {
struct devfreq *devfreq;
struct ufs_clk_scaling clk_scaling;
bool is_sys_suspended;
+
+ enum bkops_status urgent_bkops_lvl;
+ bool is_urgent_bkops_lvl_checked;
};
/* Returns true if clocks can be gated. Otherwise false */
@@ -576,22 +597,38 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
}
int ufshcd_alloc_host(struct device *, struct ufs_hba **);
+void ufshcd_dealloc_host(struct ufs_hba *);
int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
void ufshcd_remove(struct ufs_hba *);
+int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+ u32 val, unsigned long interval_us,
+ unsigned long timeout_ms, bool can_sleep);
+
+static inline void check_upiu_size(void)
+{
+ BUILD_BUG_ON(ALIGNED_UPIU_SIZE <
+ GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE);
+}
/**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
+ * ufshcd_set_variant - set variant specific data to the hba
+ * @hba - per adapter instance
+ * @variant - pointer to variant specific data
*/
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant)
{
- ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
+ BUG_ON(!hba);
+ hba->priv = variant;
}
-static inline void check_upiu_size(void)
+/**
+ * ufshcd_get_variant - get variant specific data from the hba
+ * @hba - per adapter instance
+ */
+static inline void *ufshcd_get_variant(struct ufs_hba *hba)
{
- BUILD_BUG_ON(ALIGNED_UPIU_SIZE <
- GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE);
+ BUG_ON(!hba);
+ return hba->priv;
}
extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
@@ -651,6 +688,130 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
}
+int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size);
+
+static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
+{
+ return (pwr_info->pwr_rx == FAST_MODE ||
+ pwr_info->pwr_rx == FASTAUTO_MODE) &&
+ (pwr_info->pwr_tx == FAST_MODE ||
+ pwr_info->pwr_tx == FASTAUTO_MODE);
+}
+
+#define ASCII_STD true
+
+int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
+ u32 size, bool ascii);
+
+/* Expose Query-Request API */
+int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+ enum flag_idn idn, bool *flag_res);
int ufshcd_hold(struct ufs_hba *hba, bool async);
void ufshcd_release(struct ufs_hba *hba);
+u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);
+
+/* Wrapper functions for safely calling variant operations */
+static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
+{
+ if (hba->vops)
+ return hba->vops->name;
+ return "";
+}
+
+static inline int ufshcd_vops_init(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->init)
+ return hba->vops->init(hba);
+
+ return 0;
+}
+
+static inline void ufshcd_vops_exit(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->exit)
+ return hba->vops->exit(hba);
+}
+
+static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->get_ufs_hci_version)
+ return hba->vops->get_ufs_hci_version(hba);
+
+ return ufshcd_readl(hba, REG_UFS_VERSION);
+}
+
+static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
+ bool up, enum ufs_notify_change_status status)
+{
+ if (hba->vops && hba->vops->clk_scale_notify)
+ return hba->vops->clk_scale_notify(hba, up, status);
+ return 0;
+}
+
+static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on)
+{
+ if (hba->vops && hba->vops->setup_clocks)
+ return hba->vops->setup_clocks(hba, on);
+ return 0;
+}
+
+static inline int ufshcd_vops_setup_regulators(struct ufs_hba *hba, bool status)
+{
+ if (hba->vops && hba->vops->setup_regulators)
+ return hba->vops->setup_regulators(hba, status);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba,
+ bool status)
+{
+ if (hba->vops && hba->vops->hce_enable_notify)
+ return hba->vops->hce_enable_notify(hba, status);
+
+ return 0;
+}
+static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba,
+ bool status)
+{
+ if (hba->vops && hba->vops->link_startup_notify)
+ return hba->vops->link_startup_notify(hba, status);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba,
+ bool status,
+ struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ if (hba->vops && hba->vops->pwr_change_notify)
+ return hba->vops->pwr_change_notify(hba, status,
+ dev_max_params, dev_req_params);
+
+ return -ENOTSUPP;
+}
+
+static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op)
+{
+ if (hba->vops && hba->vops->suspend)
+ return hba->vops->suspend(hba, op);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op)
+{
+ if (hba->vops && hba->vops->resume)
+ return hba->vops->resume(hba, op);
+
+ return 0;
+}
+
+static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->dbg_register_dump)
+ hba->vops->dbg_register_dump(hba);
+}
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 0ae0967..4cb1cc63f 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -92,6 +92,7 @@ enum {
UFSHCI_VERSION_10 = 0x00010000, /* 1.0 */
UFSHCI_VERSION_11 = 0x00010100, /* 1.1 */
UFSHCI_VERSION_20 = 0x00000200, /* 2.0 */
+ UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */
};
/*
@@ -170,6 +171,8 @@ enum {
#define UIC_DATA_LINK_LAYER_ERROR UFS_BIT(31)
#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK 0x7FFF
#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT 0x2000
+#define UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED 0x0001
+#define UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT 0x0002
/* UECN - Host UIC Error Code Network Layer 40h */
#define UIC_NETWORK_LAYER_ERROR UFS_BIT(31)
@@ -209,6 +212,7 @@ enum {
/* GenSelectorIndex calculation macros for M-PHY attributes */
#define UIC_ARG_MPHY_TX_GEN_SEL_INDEX(lane) (lane)
+#define UIC_ARG_MPHY_RX_GEN_SEL_INDEX(lane) (PA_MAXDATALANES + (lane))
#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
((sel) & 0xFFFF))
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 816a8a4..e2854e4 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -15,6 +15,7 @@
/*
* M-TX Configuration Attributes
*/
+#define TX_HIBERN8TIME_CAPABILITY 0x000F
#define TX_MODE 0x0021
#define TX_HSRATE_SERIES 0x0022
#define TX_HSGEAR 0x0023
@@ -48,8 +49,12 @@
#define RX_ENTER_HIBERN8 0x00A7
#define RX_BYPASS_8B10B_ENABLE 0x00A8
#define RX_TERMINATION_FORCE_ENABLE 0x0089
+#define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F
+#define RX_HIBERN8TIME_CAPABILITY 0x0092
#define is_mphy_tx_attr(attr) (attr < RX_MODE)
+#define RX_MIN_ACTIVATETIME_UNIT_US 100
+#define HIBERN8TIME_UNIT_US 100
/*
* PHY Adpater attributes
*/
@@ -70,6 +75,7 @@
#define PA_MAXRXSPEEDFAST 0x1541
#define PA_MAXRXSPEEDSLOW 0x1542
#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_LOCAL_TX_LCC_ENABLE 0x155E
#define PA_TXSPEEDFAST 0x1565
#define PA_TXSPEEDSLOW 0x1566
#define PA_REMOTEVERINFO 0x15A0
@@ -110,6 +116,12 @@
#define PA_STALLNOCONFIGTIME 0x15A3
#define PA_SAVECONFIGTIME 0x15A4
+#define PA_TACTIVATE_TIME_UNIT_US 10
+#define PA_HIBERN8_TIME_UNIT_US 100
+
+/* PHY Adapter Protocol Constants */
+#define PA_MAXDATALANES 4
+
/* PA power modes */
enum {
FAST_MODE = 1,
@@ -143,6 +155,16 @@ enum ufs_hs_gear_tag {
UFS_HS_G3, /* HS Gear 3 */
};
+enum ufs_unipro_ver {
+ UFS_UNIPRO_VER_RESERVED = 0,
+ UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */
+ UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */
+ UFS_UNIPRO_VER_1_6 = 3, /* UniPro version 1.6 */
+ UFS_UNIPRO_VER_MAX = 4, /* UniPro unsupported version */
+ /* UniPro version field mask in PA_LOCALVERINFO */
+ UFS_UNIPRO_VER_MASK = 0xF,
+};
+
/*
* Data Link Layer Attributes
*/
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 0f133c1..6164634 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -349,9 +349,9 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
* Map all data buffers for a command into PCI space and
* setup the scatter/gather list if needed.
*/
-static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
- struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
- struct PVSCSIRingReqDesc *e)
+static int pvscsi_map_buffers(struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
+ struct PVSCSIRingReqDesc *e)
{
unsigned count;
unsigned bufflen = scsi_bufflen(cmd);
@@ -360,18 +360,30 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
e->dataLen = bufflen;
e->dataAddr = 0;
if (bufflen == 0)
- return;
+ return 0;
sg = scsi_sglist(cmd);
count = scsi_sg_count(cmd);
if (count != 0) {
int segs = scsi_dma_map(cmd);
- if (segs > 1) {
+
+ if (segs == -ENOMEM) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map cmd sglist for DMA.\n");
+ return -ENOMEM;
+ } else if (segs > 1) {
pvscsi_create_sg(ctx, sg, segs);
e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl,
SGL_SIZE, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(adapter->dev, ctx->sglPA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map ctx sglist for DMA.\n");
+ scsi_dma_unmap(cmd);
+ ctx->sglPA = 0;
+ return -ENOMEM;
+ }
e->dataAddr = ctx->sglPA;
} else
e->dataAddr = sg_dma_address(sg);
@@ -382,8 +394,15 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
*/
ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen,
cmd->sc_data_direction);
+ if (pci_dma_mapping_error(adapter->dev, ctx->dataPA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map direct data buffer for DMA.\n");
+ return -ENOMEM;
+ }
e->dataAddr = ctx->dataPA;
}
+
+ return 0;
}
static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
@@ -690,6 +709,12 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(adapter->dev, ctx->sensePA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map sense buffer for DMA.\n");
+ ctx->sensePA = 0;
+ return -ENOMEM;
+ }
e->senseAddr = ctx->sensePA;
e->senseLen = SCSI_SENSE_BUFFERSIZE;
} else {
@@ -711,7 +736,15 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
else
e->flags = 0;
- pvscsi_map_buffers(adapter, ctx, cmd, e);
+ if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) {
+ if (cmd->sense_buffer) {
+ pci_unmap_single(adapter->dev, ctx->sensePA,
+ SCSI_SENSE_BUFFERSIZE,
+ PCI_DMA_FROMDEVICE);
+ ctx->sensePA = 0;
+ }
+ return -ENOMEM;
+ }
e->context = pvscsi_map_context(adapter, ctx);
diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
index ee16f0c..12712c9 100644
--- a/drivers/scsi/vmw_pvscsi.h
+++ b/drivers/scsi/vmw_pvscsi.h
@@ -26,7 +26,7 @@
#include <linux/types.h>
-#define PVSCSI_DRIVER_VERSION_STRING "1.0.5.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING "1.0.6.0-k"
#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128